summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt29
-rw-r--r--sql/Makefile.am122
-rw-r--r--sql/authors.h8
-rw-r--r--sql/client_settings.h5
-rw-r--r--sql/contributors.h7
-rw-r--r--sql/custom_conf.h5
-rw-r--r--sql/derror.cc62
-rw-r--r--sql/des_key_file.cc5
-rw-r--r--sql/discover.cc23
-rw-r--r--sql/event_data_objects.cc1296
-rw-r--r--sql/event_data_objects.h156
-rw-r--r--sql/event_db_repository.cc787
-rw-r--r--sql/event_db_repository.h39
-rw-r--r--sql/event_queue.cc465
-rw-r--r--sql/event_queue.h72
-rw-r--r--sql/event_scheduler.cc287
-rw-r--r--sql/event_scheduler.h56
-rw-r--r--sql/events.cc976
-rw-r--r--sql/events.h126
-rwxr-xr-xsql/examples/CMakeLists.txt15
-rw-r--r--sql/field.cc1614
-rw-r--r--sql/field.h724
-rw-r--r--sql/field_conv.cc150
-rw-r--r--sql/filesort.cc128
-rw-r--r--sql/frm_crypt.cc5
-rw-r--r--sql/gen_lex_hash.cc31
-rw-r--r--sql/gstream.cc3
-rw-r--r--sql/gstream.h7
-rw-r--r--sql/ha_ndbcluster.cc3259
-rw-r--r--sql/ha_ndbcluster.h553
-rw-r--r--sql/ha_ndbcluster_binlog.cc695
-rw-r--r--sql/ha_ndbcluster_binlog.h16
-rw-r--r--sql/ha_ndbcluster_cond.cc1426
-rw-r--r--sql/ha_ndbcluster_cond.h475
-rw-r--r--sql/ha_ndbcluster_tables.h5
-rw-r--r--sql/ha_partition.cc220
-rw-r--r--sql/ha_partition.h92
-rw-r--r--sql/handler.cc554
-rw-r--r--sql/handler.h183
-rw-r--r--sql/hash_filo.cc5
-rw-r--r--sql/hash_filo.h13
-rw-r--r--sql/hostname.cc15
-rw-r--r--sql/init.cc11
-rw-r--r--sql/item.cc579
-rw-r--r--sql/item.h349
-rw-r--r--sql/item_buff.cc5
-rw-r--r--sql/item_cmpfunc.cc1252
-rw-r--r--sql/item_cmpfunc.h359
-rw-r--r--sql/item_create.cc464
-rw-r--r--sql/item_create.h14
-rw-r--r--sql/item_func.cc1013
-rw-r--r--sql/item_func.h210
-rw-r--r--sql/item_geofunc.cc46
-rw-r--r--sql/item_geofunc.h40
-rw-r--r--sql/item_row.cc7
-rw-r--r--sql/item_row.h9
-rw-r--r--sql/item_strfunc.cc237
-rw-r--r--sql/item_strfunc.h51
-rw-r--r--sql/item_subselect.cc511
-rw-r--r--sql/item_subselect.h132
-rw-r--r--sql/item_sum.cc589
-rw-r--r--sql/item_sum.h114
-rw-r--r--sql/item_timefunc.cc276
-rw-r--r--sql/item_timefunc.h141
-rw-r--r--sql/item_uniq.cc32
-rw-r--r--sql/item_uniq.h63
-rw-r--r--sql/item_xmlfunc.cc209
-rw-r--r--sql/item_xmlfunc.h5
-rw-r--r--sql/key.cc92
-rw-r--r--sql/lex.h15
-rw-r--r--sql/lex_symbol.h5
-rw-r--r--sql/lock.cc91
-rw-r--r--sql/log.cc507
-rw-r--r--sql/log.h23
-rw-r--r--sql/log_event.cc2189
-rw-r--r--sql/log_event.h682
-rw-r--r--sql/log_event_old.cc104
-rw-r--r--sql/log_event_old.h127
-rw-r--r--sql/matherr.c5
-rw-r--r--sql/mf_iocache.cc11
-rw-r--r--sql/my_decimal.cc22
-rw-r--r--sql/my_decimal.h29
-rw-r--r--sql/my_lock.c5
-rw-r--r--sql/mysql_priv.h438
-rw-r--r--sql/mysqld.cc2231
-rw-r--r--sql/mysqld.cc.rej17
-rw-r--r--sql/mysqld_suffix.h3
-rw-r--r--sql/net_serv.cc190
-rw-r--r--sql/opt_range.cc884
-rw-r--r--sql/opt_range.h81
-rw-r--r--sql/opt_sum.cc128
-rw-r--r--sql/parse_file.cc87
-rw-r--r--sql/parse_file.h13
-rw-r--r--sql/partition_element.h11
-rw-r--r--sql/partition_info.cc85
-rw-r--r--sql/partition_info.h21
-rw-r--r--sql/password.c12
-rw-r--r--sql/procedure.cc5
-rw-r--r--sql/procedure.h5
-rw-r--r--sql/protocol.cc188
-rw-r--r--sql/protocol.h74
-rw-r--r--sql/records.cc18
-rw-r--r--sql/repl_failsafe.cc57
-rw-r--r--sql/repl_failsafe.h5
-rw-r--r--sql/rpl_constants.h18
-rw-r--r--sql/rpl_filter.cc25
-rw-r--r--sql/rpl_filter.h5
-rw-r--r--sql/rpl_injector.cc34
-rw-r--r--sql/rpl_injector.h18
-rw-r--r--sql/rpl_mi.cc75
-rw-r--r--sql/rpl_mi.h6
-rw-r--r--sql/rpl_record.cc280
-rw-r--r--sql/rpl_record.h33
-rw-r--r--sql/rpl_record_old.cc173
-rw-r--r--sql/rpl_record_old.h32
-rw-r--r--sql/rpl_rli.cc108
-rw-r--r--sql/rpl_rli.h114
-rw-r--r--sql/rpl_tblmap.cc9
-rw-r--r--sql/rpl_tblmap.h5
-rw-r--r--sql/rpl_utility.cc12
-rw-r--r--sql/rpl_utility.h123
-rw-r--r--sql/scheduler.cc88
-rw-r--r--sql/scheduler.h60
-rw-r--r--sql/set_var.cc1716
-rw-r--r--sql/set_var.h590
-rw-r--r--sql/share/Makefile.am3
-rw-r--r--sql/share/charsets/Index.xml3
-rw-r--r--sql/share/charsets/armscii8.xml3
-rw-r--r--sql/share/charsets/ascii.xml3
-rw-r--r--sql/share/charsets/cp1250.xml3
-rw-r--r--sql/share/charsets/cp1251.xml3
-rw-r--r--sql/share/charsets/cp1256.xml3
-rw-r--r--sql/share/charsets/cp1257.xml3
-rw-r--r--sql/share/charsets/cp850.xml3
-rw-r--r--sql/share/charsets/cp852.xml3
-rw-r--r--sql/share/charsets/cp866.xml3
-rw-r--r--sql/share/charsets/dec8.xml3
-rw-r--r--sql/share/charsets/geostd8.xml3
-rw-r--r--sql/share/charsets/greek.xml3
-rw-r--r--sql/share/charsets/hebrew.xml7
-rw-r--r--sql/share/charsets/hp8.xml3
-rw-r--r--sql/share/charsets/keybcs2.xml3
-rw-r--r--sql/share/charsets/koi8r.xml3
-rw-r--r--sql/share/charsets/koi8u.xml3
-rw-r--r--sql/share/charsets/latin1.xml3
-rw-r--r--sql/share/charsets/latin2.xml3
-rw-r--r--sql/share/charsets/latin5.xml3
-rw-r--r--sql/share/charsets/latin7.xml3
-rw-r--r--sql/share/charsets/macce.xml3
-rw-r--r--sql/share/charsets/macroman.xml3
-rw-r--r--sql/share/charsets/swe7.xml3
-rw-r--r--sql/share/errmsg.txt4408
-rw-r--r--sql/slave.cc403
-rw-r--r--sql/slave.h35
-rw-r--r--sql/sp.cc541
-rw-r--r--sql/sp.h36
-rw-r--r--sql/sp_cache.cc17
-rw-r--r--sql/sp_cache.h3
-rw-r--r--sql/sp_head.cc508
-rw-r--r--sql/sp_head.h119
-rw-r--r--sql/sp_pcontext.cc113
-rw-r--r--sql/sp_pcontext.h70
-rw-r--r--sql/sp_rcontext.cc3
-rw-r--r--sql/sp_rcontext.h3
-rw-r--r--sql/spatial.cc42
-rw-r--r--sql/spatial.h64
-rw-r--r--sql/sql_acl.cc312
-rw-r--r--sql/sql_acl.h8
-rw-r--r--sql/sql_analyse.cc37
-rw-r--r--sql/sql_analyse.h9
-rw-r--r--sql/sql_array.h5
-rw-r--r--sql/sql_base.cc1510
-rw-r--r--sql/sql_binlog.cc28
-rw-r--r--sql/sql_bitmap.h3
-rw-r--r--sql/sql_builtin.cc.in14
-rw-r--r--sql/sql_cache.cc316
-rw-r--r--sql/sql_cache.h47
-rw-r--r--sql/sql_class.cc762
-rw-r--r--sql/sql_class.h464
-rw-r--r--sql/sql_client.cc5
-rw-r--r--sql/sql_connect.cc1110
-rw-r--r--sql/sql_crypt.cc5
-rw-r--r--sql/sql_crypt.h5
-rw-r--r--sql/sql_cursor.cc5
-rw-r--r--sql/sql_cursor.h10
-rw-r--r--sql/sql_db.cc401
-rw-r--r--sql/sql_delete.cc100
-rw-r--r--sql/sql_derived.cc11
-rw-r--r--sql/sql_do.cc5
-rw-r--r--sql/sql_error.cc15
-rw-r--r--sql/sql_error.h3
-rw-r--r--sql/sql_handler.cc62
-rw-r--r--sql/sql_help.cc30
-rw-r--r--sql/sql_insert.cc1176
-rw-r--r--sql/sql_lex.cc656
-rw-r--r--sql/sql_lex.h400
-rw-r--r--sql/sql_list.cc39
-rw-r--r--sql/sql_list.h100
-rw-r--r--sql/sql_load.cc126
-rw-r--r--sql/sql_locale.cc3
-rw-r--r--sql/sql_manager.cc7
-rw-r--r--sql/sql_map.cc17
-rw-r--r--sql/sql_map.h17
-rw-r--r--sql/sql_olap.cc9
-rw-r--r--sql/sql_parse.cc2625
-rw-r--r--sql/sql_parse.cc.rej166
-rw-r--r--sql/sql_partition.cc196
-rw-r--r--sql/sql_partition.h19
-rw-r--r--sql/sql_plugin.cc2501
-rw-r--r--sql/sql_plugin.h72
-rw-r--r--sql/sql_prepare.cc375
-rw-r--r--sql/sql_rename.cc5
-rw-r--r--sql/sql_repl.cc193
-rw-r--r--sql/sql_repl.h6
-rw-r--r--sql/sql_select.cc1436
-rw-r--r--sql/sql_select.h149
-rw-r--r--sql/sql_servers.cc1278
-rw-r--r--sql/sql_servers.h43
-rw-r--r--sql/sql_show.cc1222
-rw-r--r--sql/sql_show.h14
-rw-r--r--sql/sql_sort.h3
-rw-r--r--sql/sql_state.c3
-rw-r--r--sql/sql_string.cc34
-rw-r--r--sql/sql_string.h6
-rw-r--r--sql/sql_table.cc2485
-rw-r--r--sql/sql_tablespace.cc7
-rw-r--r--sql/sql_test.cc25
-rw-r--r--sql/sql_trigger.cc97
-rw-r--r--sql/sql_trigger.h17
-rw-r--r--sql/sql_udf.cc104
-rw-r--r--sql/sql_udf.h5
-rw-r--r--sql/sql_union.cc135
-rw-r--r--sql/sql_update.cc564
-rw-r--r--sql/sql_view.cc257
-rw-r--r--sql/sql_view.h3
-rw-r--r--sql/sql_yacc.yy2447
-rw-r--r--sql/stacktrace.c36
-rw-r--r--sql/stacktrace.h7
-rw-r--r--sql/strfunc.cc9
-rw-r--r--sql/structs.h22
-rw-r--r--sql/table.cc936
-rw-r--r--sql/table.cc.rej17
-rw-r--r--sql/table.h194
-rw-r--r--sql/thr_malloc.cc36
-rw-r--r--sql/time.cc62
-rw-r--r--sql/tzfile.h19
-rw-r--r--sql/tztime.cc404
-rw-r--r--sql/tztime.h50
-rw-r--r--sql/udf_example.c10
-rw-r--r--sql/udf_example.def1
-rw-r--r--sql/uniques.cc22
-rw-r--r--sql/unireg.cc160
-rw-r--r--sql/unireg.h5
253 files changed, 40747 insertions, 25430 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 69754924b4d..2aef0e0dc25 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -1,3 +1,19 @@
+# Copyright (C) 2006 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; version 2 of the License.
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
+
SET(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX -DUSE_SYMDIR")
SET(CMAKE_C_FLAGS_DEBUG
@@ -32,7 +48,9 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
item_create.cc item_func.cc item_geofunc.cc item_row.cc
item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
- item_uniq.cc key.cc log.cc lock.cc log_event.cc message.rc
+ key.cc log.cc lock.cc message.rc
+ log_event.cc rpl_record.cc
+ log_event_old.cc rpl_record_old.cc
message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
mysqld.cc net_serv.cc
nt_servc.cc nt_servc.h opt_range.cc opt_range.h opt_sum.cc
@@ -53,7 +71,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
- rpl_rli.cc rpl_mi.cc
+ rpl_rli.cc rpl_mi.cc sql_servers.cc
+ sql_connect.cc scheduler.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
@@ -63,7 +82,11 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
${PROJECT_SOURCE_DIR}/sql/sql_builtin.cc
${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
TARGET_LINK_LIBRARIES(mysqld heap myisam myisammrg mysys yassl zlib dbug yassl
- taocrypt strings vio regex wsock32)
+ taocrypt strings vio regex wsock32 ws2_32)
+
+IF(EMBED_MANIFESTS)
+ MYSQL_EMBED_MANIFEST("mysqld" "asInvoker")
+ENDIF(EMBED_MANIFESTS)
IF(WITH_ARCHIVE_STORAGE_ENGINE)
TARGET_LINK_LIBRARIES(mysqld archive)
ENDIF(WITH_ARCHIVE_STORAGE_ENGINE)
diff --git a/sql/Makefile.am b/sql/Makefile.am
index d3e1f2c197e..63b164b16b4 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -1,9 +1,8 @@
-# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+# Copyright (C) 2000-2006 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.
+# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,54 +21,56 @@ MYSQLBASEdir= $(prefix)
MYSQLLIBdir= $(pkglibdir)
INCLUDES = @ZLIB_INCLUDES@ \
-I$(top_builddir)/include -I$(top_srcdir)/include \
- -I$(top_srcdir)/regex -I$(srcdir) \
- $(openssl_includes)
+ -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
-noinst_PROGRAMS = gen_lex_hash
+EXTRA_PROGRAMS = gen_lex_hash
bin_PROGRAMS = mysql_tzinfo_to_sql
-gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
-SUPPORTING_LIBS = $(top_builddir)/vio/libvio.a \
+SUPPORTING_LIBS = $(top_builddir)/vio/libvio.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/regex/libregex.a \
$(top_builddir)/strings/libmystrings.a
mysqld_DEPENDENCIES= @mysql_plugin_libs@ $(SUPPORTING_LIBS)
-LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@
+LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@pstack_libs@ \
@mysql_plugin_libs@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \
- @yassl_libs@ @openssl_libs@
+ $(yassl_libs) $(openssl_libs)
+
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
- item_strfunc.h item_timefunc.h item_uniq.h \
+ item_strfunc.h item_timefunc.h \
item_xmlfunc.h \
item_create.h item_subselect.h item_row.h \
mysql_priv.h item_geofunc.h sql_bitmap.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_map.h sql_string.h unireg.h \
sql_error.h field.h handler.h mysqld_suffix.h \
- ha_partition.h \
- ha_ndbcluster.h ha_ndbcluster_binlog.h \
- ha_ndbcluster_tables.h \
+ ha_ndbcluster.h ha_ndbcluster_cond.h \
+ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \
+ ha_partition.h rpl_constants.h \
opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
rpl_reporting.h \
log.h sql_show.h rpl_rli.h rpl_mi.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 sql_repl.h slave.h rpl_filter.h \
- rpl_injector.h \
+ sql_repl.h slave.h rpl_filter.h rpl_injector.h \
+ log_event.h rpl_record.h \
+ log_event_old.h rpl_record_old.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h tzfile.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
- sql_array.h sql_cursor.h events.h \
+ sql_array.h sql_cursor.h events.h scheduler.h \
event_db_repository.h event_queue.h \
- sql_plugin.h authors.h sql_partition.h event_data_objects.h \
- partition_info.h partition_element.h event_scheduler.h \
- contributors.h
+ sql_plugin.h authors.h \
+ event_data_objects.h event_scheduler.h \
+ sql_partition.h partition_info.h partition_element.h \
+ contributors.h sql_servers.h
+
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -80,17 +81,20 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
- set_var.cc sql_parse.cc sql_yacc.yy \
+ sql_connect.cc scheduler.cc sql_parse.cc \
+ set_var.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
sql_prepare.cc sql_error.cc sql_locale.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
- procedure.cc item_uniq.cc sql_test.cc \
- log.cc log_event.cc init.cc derror.cc sql_acl.cc \
+ procedure.cc sql_test.cc \
+ log.cc init.cc derror.cc sql_acl.cc \
unireg.cc des_key_file.cc \
+ log_event.cc rpl_record.cc \
+ log_event_old.cc rpl_record_old.cc \
discover.cc time.cc opt_range.cc opt_sum.cc \
records.cc filesort.cc handler.cc \
- ha_partition.cc \
- ha_ndbcluster.cc ha_ndbcluster_binlog.cc \
+ ha_ndbcluster.cc ha_ndbcluster_cond.cc \
+ ha_ndbcluster_binlog.cc ha_partition.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
@@ -108,13 +112,14 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
event_scheduler.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc events.cc \
sql_plugin.cc sql_binlog.cc \
- sql_builtin.cc sql_tablespace.cc partition_info.cc
-
+ sql_builtin.cc sql_tablespace.cc partition_info.cc \
+ sql_servers.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
-gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
-mysql_tzinfo_to_sql_SOURCES = mysql_tzinfo_to_sql.cc
-mysql_tzinfo_to_sql_LDADD = @MYSQLD_EXTRA_LDFLAGS@ $(LDADD) $(CXXLDFLAGS)
+gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
+
+mysql_tzinfo_to_sql_SOURCES = tztime.cc
+mysql_tzinfo_to_sql_CXXFLAGS= -DTZINFO2SQL
DEFS = -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
@@ -123,19 +128,17 @@ DEFS = -DMYSQL_SERVER \
-DLIBDIR="\"$(MYSQLLIBdir)\"" \
@DEFS@
-BUILT_DIST_SRC = sql_yacc.cc sql_yacc.h
-BUILT_SOURCES = $(BUILT_DIST_SRC) lex_hash.h
-EXTRA_DIST = udf_example.c udf_example.def $(BUILT_DIST_SRC) \
+BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h
+BUILT_SOURCES = $(BUILT_MAINT_SRC) lex_hash.h link_sources
+EXTRA_DIST = udf_example.c udf_example.def $(BUILT_MAINT_SRC) \
nt_servc.cc nt_servc.h message.mc CMakeLists.txt \
udf_example.c udf_example.def
-CLEANFILES = lex_hash.h sql_yacc.cc sql_yacc.h sql_yacc.output
-AM_YFLAGS = -d --debug --verbose
-
-mysql_tzinfo_to_sql.cc:
- rm -f mysql_tzinfo_to_sql.cc
- @LN_CP_F@ $(srcdir)/tztime.cc mysql_tzinfo_to_sql.cc
+CLEANFILES = lex_hash.h sql_yacc.output link_sources
+DISTCLEANFILES = $(EXTRA_PROGRAMS)
+MAINTAINERCLEANFILES = $(BUILT_MAINT_SRC)
+AM_YFLAGS = -d --verbose
-link_sources: mysql_tzinfo_to_sql.cc
+link_sources:
rm -f mini_client_errors.c
@LN_CP_F@ $(top_srcdir)/libmysql/errmsg.c mini_client_errors.c
rm -f pack.c
@@ -147,36 +150,21 @@ link_sources: mysql_tzinfo_to_sql.cc
rm -f my_user.c
@LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c
-mysql_tzinfo_to_sql.o: $(mysql_tzinfo_to_sql_SOURCES)
- $(CXXCOMPILE) -c $(INCLUDES) -DTZINFO2SQL $<
-
-# Try to get better dependencies for the grammar. Othervise really bad
-# things like different grammars for different pars of MySQL can
-# happen if you are unlucky.
-sql_yacc.cc: sql_yacc.yy
-
-sql_yacc.h: sql_yacc.yy
-
-# Be careful here, note that we use VPATH and might or might not have
-# a pregenerated "sql_yacc.cc" in $(srcdir) or one we just built in
-# $(builddir). And it has to work if $(srcdir) == $(builddir).
-sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS)
- @SED@ -e 's/__attribute__ ((__unused__))//' $< > sql_yacc.cc-new
- @MV@ sql_yacc.cc-new sql_yacc.cc
- @echo "Note: The following compile may take a long time."
- @echo "If it fails, re-run configure with --with-low-memory"
- $(CXXCOMPILE) $(LM_CFLAGS) -c sql_yacc.cc
-
-# FIXME seems like now "lex_hash.h" differs depending on configure
-# flags, so can't pregenerate and include in source TAR. Revert to
-# dist pregenerated if this changes, so the file doesn't differ.
-lex_hash.h: gen_lex_hash$(EXEEXT)
- ./gen_lex_hash$(EXEEXT) > $@
-
-# the following three should eventually be moved out of this directory
+# This generates lex_hash.h
+# NOTE Built sources should depend on their sources not the tool
+# this avoid the rebuild of the built files in a source dist
+lex_hash.h: gen_lex_hash.cc lex.h
+ $(MAKE) $(AM_MAKEFLAGS) gen_lex_hash$(EXEEXT)
+ ./gen_lex_hash$(EXEEXT) > $@-t
+ $(MV) $@-t $@
+
+# the following four should eventually be moved out of this directory
ha_ndbcluster.o:ha_ndbcluster.cc ha_ndbcluster.h
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+ha_ndbcluster_cond.o:ha_ndbcluster_cond.cc ha_ndbcluster_cond.h
+ $(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+
ha_ndbcluster_binlog.o:ha_ndbcluster_binlog.cc ha_ndbcluster_binlog.h
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
diff --git a/sql/authors.h b/sql/authors.h
index 980ec7670de..dfe3b143e2f 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Structure of the name list */
@@ -67,6 +66,7 @@ struct show_table_authors_st show_table_authors[]= {
"Parser, port to OS/2, storage engines and some random stuff" },
{ "Yuri Dario", "", "OS/2 port" },
{ "Andrei Elkin", "Espoo, Finland", "Replication" },
+ { "Patrick Galbraith", "Sharon, NH", "Federated Engine, mysqlslap" },
{ "Sergei Golubchik", "Kerpen, Germany",
"Full-text search, precision math" },
{ "Lenz Grimmer", "Hamburg, Germany",
diff --git a/sql/client_settings.h b/sql/client_settings.h
index a8cd36af102..f0742cd8046 100644
--- a/sql/client_settings.h
+++ b/sql/client_settings.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/contributors.h b/sql/contributors.h
index dca232b9b69..87001e29d88 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Structure of the name list */
diff --git a/sql/custom_conf.h b/sql/custom_conf.h
index 19ced12bfbb..137b7e9eef2 100644
--- a/sql/custom_conf.h
+++ b/sql/custom_conf.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/derror.cc b/sql/derror.cc
index bee818a14c1..3b67e0f5bf0 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -32,6 +31,9 @@ static void init_myfunc_errs(void);
DESCRIPTION
This function can be called multiple times to reload the messages.
+ If it fails to load the messages, it will fail softly by initializing
+ the errmesg pointer to an array of empty strings or by keeping the
+ old array if it exists.
RETURN
FALSE OK
@@ -40,7 +42,7 @@ static void init_myfunc_errs(void);
bool init_errmessage(void)
{
- const char **errmsgs;
+ const char **errmsgs, **ptr;
DBUG_ENTER("init_errmessage");
/*
@@ -50,13 +52,20 @@ bool init_errmessage(void)
errmsgs= my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST);
/* Read messages from file. */
- if (read_texts(ERRMSG_FILE, &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1))
- DBUG_RETURN(TRUE);
+ if (read_texts(ERRMSG_FILE, &errmsgs, ER_ERROR_LAST - ER_ERROR_FIRST + 1) &&
+ !errmsgs)
+ {
+ if (!(errmsgs= (const char**) my_malloc((ER_ERROR_LAST-ER_ERROR_FIRST+1)*
+ sizeof(char*), MYF(0))))
+ DBUG_RETURN(TRUE);
+ for (ptr= errmsgs; ptr < errmsgs + ER_ERROR_LAST - ER_ERROR_FIRST; ptr++)
+ *ptr= "";
+ }
/* Register messages for use with my_error(). */
if (my_error_register(errmsgs, ER_ERROR_FIRST, ER_ERROR_LAST))
{
- x_free((gptr) errmsgs);
+ x_free((uchar*) errmsgs);
DBUG_RETURN(TRUE);
}
@@ -67,20 +76,20 @@ bool init_errmessage(void)
/* Read text from packed textfile in language-directory */
- /* If we can't read messagefile then it's panic- we can't continue */
static bool read_texts(const char *file_name,const char ***point,
uint error_messages)
{
register uint i;
- uint count,funktpos,length,textcount;
+ uint count,funktpos,textcount;
+ size_t length;
File file;
char name[FN_REFLEN];
- const char *buff;
+ uchar *buff;
uchar head[32],*pos;
+ const char *errmsg;
DBUG_ENTER("read_texts");
- *point=0; // If something goes wrong
LINT_INIT(buff);
funktpos=0;
if ((file=my_open(fn_format(name,file_name,language,"",4),
@@ -89,7 +98,7 @@ static bool read_texts(const char *file_name,const char ***point,
goto err; /* purecov: inspected */
funktpos=1;
- if (my_read(file,(byte*) head,32,MYF(MY_NABP))) goto err;
+ if (my_read(file,(uchar*) head,32,MYF(MY_NABP))) goto err;
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
@@ -120,25 +129,27 @@ but it should contain at least %d error messages.\n\
Check that the above file is the right version for this program!",
name,count,error_messages);
VOID(my_close(file,MYF(MY_WME)));
- unireg_abort(1);
+ DBUG_RETURN(1);
}
- x_free((gptr) *point); /* Free old language */
+ x_free((uchar*) *point); /* Free old language */
if (!(*point= (const char**)
- my_malloc((uint) (length+count*sizeof(char*)),MYF(0))))
+ my_malloc((size_t) (length+count*sizeof(char*)),MYF(0))))
{
funktpos=2; /* purecov: inspected */
goto err; /* purecov: inspected */
}
- buff= (char*) (*point + count);
+ buff= (uchar*) (*point + count);
- if (my_read(file,(byte*) buff,(uint) count*2,MYF(MY_NABP))) goto err;
- for (i=0, pos= (uchar*) buff ; i< count ; i++)
+ if (my_read(file, buff, (size_t) count*2,MYF(MY_NABP)))
+ goto err;
+ for (i=0, pos= buff ; i< count ; i++)
{
- (*point)[i]=buff+uint2korr(pos);
+ (*point)[i]= (char*) buff+uint2korr(pos);
pos+=2;
}
- if (my_read(file,(byte*) buff,(uint) length,MYF(MY_NABP))) goto err;
+ if (my_read(file, buff, length, MYF(MY_NABP)))
+ goto err;
for (i=1 ; i < textcount ; i++)
{
@@ -150,21 +161,20 @@ Check that the above file is the right version for this program!",
err:
switch (funktpos) {
case 2:
- buff="Not enough memory for messagefile '%s'";
+ errmsg= "Not enough memory for messagefile '%s'";
break;
case 1:
- buff="Can't read from messagefile '%s'";
+ errmsg= "Can't read from messagefile '%s'";
break;
default:
- buff="Can't find messagefile '%s'";
+ errmsg= "Can't find messagefile '%s'";
break;
}
- sql_print_error(buff,name);
+ sql_print_error(errmsg, name);
err1:
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
- unireg_abort(1);
- DBUG_RETURN(1); // keep compiler happy
+ DBUG_RETURN(1);
} /* read_texts */
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index 77cb0c8de0f..d99d712b45a 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2001-2003, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/discover.cc b/sql/discover.cc
index 938a05ff4a7..a7af90c440f 100644
--- a/sql/discover.cc
+++ b/sql/discover.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -40,14 +39,13 @@
frmdata and len are set to 0 on error
*/
-int readfrm(const char *name,
- const void **frmdata, uint *len)
+int readfrm(const char *name, uchar **frmdata, size_t *len)
{
int error;
char index_file[FN_REFLEN];
File file;
- ulong read_len;
- char *read_data;
+ size_t read_len;
+ uchar *read_data;
MY_STAT state;
DBUG_ENTER("readfrm");
DBUG_PRINT("enter",("name: '%s'",name));
@@ -69,12 +67,12 @@ int readfrm(const char *name,
// Read whole frm file
error= 3;
- read_data= 0;
+ read_data= 0; // Nothing to free
if (read_string(file, &read_data, read_len))
goto err;
// Setup return data
- *frmdata= (void*) read_data;
+ *frmdata= (uchar*) read_data;
*len= read_len;
error= 0;
@@ -103,21 +101,20 @@ int readfrm(const char *name,
2 Could not write file
*/
-int writefrm(const char *name, const void *frmdata, uint len)
+int writefrm(const char *name, const uchar *frmdata, size_t len)
{
File file;
char index_file[FN_REFLEN];
int error;
DBUG_ENTER("writefrm");
- DBUG_PRINT("enter",("name: '%s' len: %d ",name,len));
- //DBUG_DUMP("frmdata", (char*)frmdata, len);
+ DBUG_PRINT("enter",("name: '%s' len: %lu ",name, (ulong) len));
error= 0;
if ((file=my_create(fn_format(index_file,name,"",reg_ext,
MY_UNPACK_FILENAME|MY_APPEND_EXT),
CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
{
- if (my_write(file,(byte*)frmdata,len,MYF(MY_WME | MY_NABP)))
+ if (my_write(file, frmdata, len,MYF(MY_WME | MY_NABP)))
error= 2;
VOID(my_close(file,MYF(0)));
}
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index ad7f0ab4e41..138752d5ce5 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,12 +23,45 @@
#define EVEX_MAX_INTERVAL_VALUE 1000000000L
-static bool
-event_change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
- LEX_STRING db, Security_context *backup);
+/*
+ Initiliazes dbname and name of an Event_queue_element_for_exec
+ object
+
+ SYNOPSIS
+ Event_queue_element_for_exec::init()
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error (OOM)
+*/
+
+bool
+Event_queue_element_for_exec::init(LEX_STRING db, LEX_STRING n)
+{
+ if (!(dbname.str= my_strndup(db.str, dbname.length= db.length, MYF(MY_WME))))
+ return TRUE;
+ if (!(name.str= my_strndup(n.str, name.length= n.length, MYF(MY_WME))))
+ {
+ my_free((uchar*) dbname.str, MYF(0));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ Destructor
+
+ SYNOPSIS
+ Event_queue_element_for_exec::~Event_queue_element_for_exec()
+*/
+
+Event_queue_element_for_exec::~Event_queue_element_for_exec()
+{
+ my_free((uchar*) dbname.str, MYF(0));
+ my_free((uchar*) name.str, MYF(0));
+}
-static void
-event_restore_security_context(THD *thd, Security_context *backup);
/*
Returns a new instance
@@ -39,7 +71,7 @@ event_restore_security_context(THD *thd, Security_context *backup);
RETURN VALUE
Address or NULL in case of error
-
+
NOTE
Created on THD's mem_root
*/
@@ -59,7 +91,9 @@ Event_parse_data::new_instance(THD *thd)
*/
Event_parse_data::Event_parse_data()
- :on_completion(ON_COMPLETION_DROP), status(ENABLED),
+ :on_completion(Event_basic::ON_COMPLETION_DROP),
+ status(Event_basic::ENABLED),
+ do_not_create(FALSE),
item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
item_expression(NULL), expression(0)
@@ -67,9 +101,7 @@ Event_parse_data::Event_parse_data()
DBUG_ENTER("Event_parse_data::Event_parse_data");
/* Actually in the parser STARTS is always set */
- set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
- set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
- set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+ starts= ends= execute_at= 0;
body.str= comment.str= NULL;
body.length= comment.length= 0;
@@ -124,17 +156,21 @@ void
Event_parse_data::init_body(THD *thd)
{
DBUG_ENTER("Event_parse_data::init_body");
+
+ /* This method is called from within the parser, from sql_yacc.yy */
+ DBUG_ASSERT(thd->m_lip != NULL);
+
DBUG_PRINT("info", ("body: '%s' body_begin: 0x%lx end: 0x%lx", body_begin,
- (long) body_begin, (long) thd->lex->ptr));
+ (long) body_begin, (long) thd->m_lip->ptr));
- body.length= thd->lex->ptr - body_begin;
- const uchar *body_end= body_begin + body.length - 1;
+ body.length= thd->m_lip->ptr - body_begin;
+ const char *body_end= body_begin + body.length - 1;
/* Trim nuls or close-comments ('*'+'/') or spaces at the end */
while (body_begin < body_end)
{
- if ((*body_end == '\0') ||
+ if ((*body_end == '\0') ||
(my_isspace(thd->variables.character_set_client, *body_end)))
{ /* consume NULs and meaningless whitespace */
--body.length;
@@ -146,7 +182,7 @@ Event_parse_data::init_body(THD *thd)
consume closing comments
This is arguably wrong, but it's the best we have until the parser is
- changed to be smarter. FIXME PARSER
+ changed to be smarter. FIXME PARSER
See also the sp_head code, where something like this is done also.
@@ -175,13 +211,62 @@ Event_parse_data::init_body(THD *thd)
++body_begin;
--body.length;
}
- body.str= thd->strmake((char *)body_begin, body.length);
+ body.str= thd->strmake(body_begin, body.length);
DBUG_VOID_RETURN;
}
/*
+ This function is called on CREATE EVENT or ALTER EVENT. When either
+ ENDS or AT is in the past, we are trying to create an event that
+ will never be executed. If it has ON COMPLETION NOT PRESERVE
+ (default), then it would normally be dropped already, so on CREATE
+ EVENT we give a warning, and do not create anyting. On ALTER EVENT
+ we give a error, and do not change the event.
+
+ If the event has ON COMPLETION PRESERVE, then we see if the event is
+ created or altered to the ENABLED (default) state. If so, then we
+ give a warning, and change the state to DISABLED.
+
+ Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
+ state.
+*/
+
+void
+Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
+{
+ if (ltime_utc >= (my_time_t) thd->query_start())
+ return;
+
+ if (on_completion == Event_basic::ON_COMPLETION_DROP)
+ {
+ switch (thd->lex->sql_command) {
+ case SQLCOM_CREATE_EVENT:
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
+ ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
+ break;
+ case SQLCOM_ALTER_EVENT:
+ my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ do_not_create= TRUE;
+ }
+ else if (status == Event_basic::ENABLED)
+ {
+ status= Event_basic::DISABLED;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_EVENT_EXEC_TIME_IN_THE_PAST,
+ ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
+ }
+}
+
+
+/*
Sets time for execution for one-time event.
SYNOPSIS
@@ -197,9 +282,8 @@ int
Event_parse_data::init_execute_at(THD *thd)
{
my_bool not_used;
- TIME ltime;
- my_time_t t;
- TIME time_tmp;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
DBUG_ENTER("Event_parse_data::init_execute_at");
@@ -208,41 +292,26 @@ Event_parse_data::init_execute_at(THD *thd)
if (item_execute_at->fix_fields(thd, &item_execute_at))
goto wrong_value;
-
+
/* no starts and/or ends in case of execute_at */
DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
(starts_null && ends_null)));
DBUG_ASSERT(starts_null && ends_null);
- /* let's check whether time is in the past */
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
- (my_time_t) thd->query_start());
-
if ((not_used= item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE)))
goto wrong_value;
- if (TIME_to_ulonglong_datetime(&ltime) <
- TIME_to_ulonglong_datetime(&time_tmp))
- {
- my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
- DBUG_RETURN(ER_WRONG_VALUE);
- }
-
- /*
- This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
- CONVERT_TZ has similar problem.
- mysql_priv.h currently lists
- #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
- */
- my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd,&ltime,&not_used));
- if (!t)
+ ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
+ if (!ltime_utc)
{
DBUG_PRINT("error", ("Execute AT after year 2037"));
goto wrong_value;
}
+ check_if_in_the_past(thd, ltime_utc);
+
execute_at_null= FALSE;
- execute_at= ltime;
+ execute_at= ltime_utc;
DBUG_RETURN(0);
wrong_value:
@@ -344,7 +413,8 @@ Event_parse_data::init_interval(THD *thd)
default:
;/* these are the microsec stuff */
}
- if (interval_tmp.neg || expression > EVEX_MAX_INTERVAL_VALUE)
+ if (interval_tmp.neg || expression == 0 ||
+ expression > EVEX_MAX_INTERVAL_VALUE)
{
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
DBUG_RETURN(EVEX_BAD_PARAMS);
@@ -382,8 +452,8 @@ int
Event_parse_data::init_starts(THD *thd)
{
my_bool not_used;
- TIME ltime, time_tmp;
- my_time_t t;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
DBUG_ENTER("Event_parse_data::init_starts");
if (!item_starts)
@@ -395,29 +465,15 @@ Event_parse_data::init_starts(THD *thd)
if ((not_used= item_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
goto wrong_value;
- /* Let's check whether time is in the past */
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
- (my_time_t) thd->query_start());
-
- DBUG_PRINT("info",("now: %ld starts: %ld",
- (long) TIME_to_ulonglong_datetime(&time_tmp),
- (long) TIME_to_ulonglong_datetime(&ltime)));
- if (TIME_to_ulonglong_datetime(&ltime) <
- TIME_to_ulonglong_datetime(&time_tmp))
+ ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+ if (!ltime_utc)
goto wrong_value;
- /*
- This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
- CONVERT_TZ has similar problem.
- mysql_priv.h currently lists
- #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
- */
- my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime, &not_used));
- if (!t)
- goto wrong_value;
+ DBUG_PRINT("info",("now: %ld starts: %ld",
+ (long) thd->query_start(), (long) ltime_utc));
- starts= ltime;
starts_null= FALSE;
+ starts= ltime_utc;
DBUG_RETURN(0);
wrong_value:
@@ -449,9 +505,9 @@ wrong_value:
int
Event_parse_data::init_ends(THD *thd)
{
- TIME ltime, ltime_now;
my_bool not_used;
- my_time_t t;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
DBUG_ENTER("Event_parse_data::init_ends");
if (!item_ends)
@@ -464,34 +520,19 @@ Event_parse_data::init_ends(THD *thd)
if ((not_used= item_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
goto error_bad_params;
- /*
- This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
- CONVERT_TZ has similar problem.
- mysql_priv.h currently lists
- #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
- */
- DBUG_PRINT("info", ("get the UTC time"));
- my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime, &not_used));
- if (!t)
+ ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+ if (!ltime_utc)
goto error_bad_params;
/* Check whether ends is after starts */
DBUG_PRINT("info", ("ENDS after STARTS?"));
- if (!starts_null && my_time_compare(&starts, &ltime) != -1)
+ if (!starts_null && starts >= ltime_utc)
goto error_bad_params;
- /*
- The parser forces starts to be provided but one day STARTS could be
- set before NOW() and in this case the following check should be done.
- Check whether ENDS is not in the past.
- */
- DBUG_PRINT("info", ("ENDS after NOW?"));
- my_tz_UTC->gmt_sec_to_TIME(&ltime_now, thd->query_start());
- if (my_time_compare(&ltime_now, &ltime) == 1)
- goto error_bad_params;
+ check_if_in_the_past(thd, ltime_utc);
- ends= ltime;
ends_null= FALSE;
+ ends= ltime_utc;
DBUG_RETURN(0);
error_bad_params:
@@ -547,6 +588,7 @@ Event_parse_data::check_parse_data(THD *thd)
ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
init_ends(thd);
+ check_originator_id(thd);
DBUG_RETURN(ret);
}
@@ -562,29 +604,30 @@ Event_parse_data::check_parse_data(THD *thd)
void
Event_parse_data::init_definer(THD *thd)
{
- int definer_user_len;
- int definer_host_len;
DBUG_ENTER("Event_parse_data::init_definer");
- DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
- "thd->sec_ctx->priv_user: 0x%lx", (long) thd->mem_root,
- (long) thd->security_ctx->priv_user));
+ DBUG_ASSERT(thd->lex->definer);
+
+ const char *definer_user= thd->lex->definer->user.str;
+ const char *definer_host= thd->lex->definer->host.str;
+ int definer_user_len= thd->lex->definer->user.length;
+ int definer_host_len= thd->lex->definer->host.length;
- definer_user_len= strlen(thd->security_ctx->priv_user);
- definer_host_len= strlen(thd->security_ctx->priv_host);
+ DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
+ "definer_user: 0x%lx", (long) thd->mem_root,
+ (long) definer_user));
/* + 1 for @ */
DBUG_PRINT("info",("init definer as whole"));
definer.length= definer_user_len + definer_host_len + 1;
- definer.str= thd->alloc(definer.length + 1);
+ definer.str= (char*) thd->alloc(definer.length + 1);
DBUG_PRINT("info",("copy the user"));
- memcpy(definer.str, thd->security_ctx->priv_user, definer_user_len);
+ memcpy(definer.str, definer_user, definer_user_len);
definer.str[definer_user_len]= '@';
DBUG_PRINT("info",("copy the host"));
- memcpy(definer.str + definer_user_len + 1, thd->security_ctx->priv_host,
- definer_host_len);
+ memcpy(definer.str + definer_user_len + 1, definer_host, definer_host_len);
definer.str[definer.length]= '\0';
DBUG_PRINT("info",("definer [%s] initted", definer.str));
@@ -592,6 +635,31 @@ Event_parse_data::init_definer(THD *thd)
}
+/**
+ Set the originator id of the event to the server_id if executing on
+ the master or set to the server_id of the master if executing on
+ the slave. If executing on slave, also set status to SLAVESIDE_DISABLED.
+
+ SYNOPSIS
+ Event_parse_data::check_originator_id()
+*/
+void Event_parse_data::check_originator_id(THD *thd)
+{
+ /* Disable replicated events on slave. */
+ if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) ||
+ (thd->system_thread == SYSTEM_THREAD_SLAVE_IO))
+ {
+ DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED."));
+ if ((status == Event_basic::ENABLED) ||
+ (status == Event_basic::DISABLED))
+ status = Event_basic::SLAVESIDE_DISABLED;
+ originator = thd->server_id;
+ }
+ else
+ originator = server_id;
+}
+
+
/*
Constructor
@@ -606,6 +674,7 @@ Event_basic::Event_basic()
init_alloc_root(&mem_root, 256, 512);
dbname.str= name.str= NULL;
dbname.length= name.length= 0;
+ time_zone= NULL;
DBUG_VOID_RETURN;
}
@@ -648,7 +717,7 @@ Event_basic::load_string_fields(Field **fields, ...)
va_start(args, fields);
field_name= (enum enum_events_table_field) va_arg(args, int);
- while (field_name != ET_FIELD_COUNT)
+ while (field_name < ET_FIELD_COUNT)
{
field_value= va_arg(args, LEX_STRING *);
if ((field_value->str= get_field(&mem_root, fields[field_name])) == NullS)
@@ -656,7 +725,7 @@ Event_basic::load_string_fields(Field **fields, ...)
ret= TRUE;
break;
}
- field_value->length= strlen(field_value->str);
+ field_value->length= strlen(field_value->str);
field_name= (enum enum_events_table_field) va_arg(args, int);
}
@@ -666,6 +735,16 @@ Event_basic::load_string_fields(Field **fields, ...)
}
+bool
+Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
+{
+ String str(tz_name.str, &my_charset_latin1);
+ time_zone= my_tz_find(thd, &str);
+
+ return (time_zone == NULL);
+}
+
+
/*
Constructor
@@ -680,10 +759,7 @@ Event_queue_element::Event_queue_element():
{
DBUG_ENTER("Event_queue_element::Event_queue_element");
- set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
- set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
- set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
- set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
+ starts= ends= execute_at= last_executed= 0;
starts_null= ends_null= execute_at_null= TRUE;
DBUG_VOID_RETURN;
@@ -725,7 +801,7 @@ Event_timed::Event_timed():
*/
Event_timed::~Event_timed()
-{
+{
}
@@ -737,27 +813,10 @@ Event_timed::~Event_timed()
*/
Event_job_data::Event_job_data()
- :thd(NULL), sphead(NULL), sql_mode(0)
-{
-}
-
-
-/*
- Destructor
-
- SYNOPSIS
- Event_timed::~Event_timed()
-*/
-
-Event_job_data::~Event_job_data()
+ :sql_mode(0)
{
- DBUG_ENTER("Event_job_data::~Event_job_data");
- delete sphead;
- sphead= NULL;
- DBUG_VOID_RETURN;
}
-
/*
Init all member variables
@@ -783,7 +842,7 @@ Event_timed::init()
Loads an event's body from a row from mysql.event
SYNOPSIS
- Event_job_data::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+ Event_job_data::load_from_row(THD *thd, TABLE *table)
RETURN VALUE
0 OK
@@ -796,7 +855,7 @@ Event_timed::init()
*/
int
-Event_job_data::load_from_row(TABLE *table)
+Event_job_data::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
uint len;
@@ -805,12 +864,21 @@ Event_job_data::load_from_row(TABLE *table)
if (!table)
goto error;
- if (table->s->fields != ET_FIELD_COUNT)
+ if (table->s->fields < ET_FIELD_COUNT)
goto error;
- load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
- ET_FIELD_BODY, &body, ET_FIELD_DEFINER, &definer,
- ET_FIELD_COUNT);
+ LEX_STRING tz_name;
+ if (load_string_fields(table->field,
+ ET_FIELD_DB, &dbname,
+ ET_FIELD_NAME, &name,
+ ET_FIELD_BODY, &body,
+ ET_FIELD_DEFINER, &definer,
+ ET_FIELD_TIME_ZONE, &tz_name,
+ ET_FIELD_COUNT))
+ goto error;
+
+ if (load_time_zone(thd, tz_name))
+ goto error;
ptr= strchr(definer.str, '@');
@@ -837,7 +905,7 @@ error:
Loads an event from a row from mysql.event
SYNOPSIS
- Event_queue_element::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+ Event_queue_element::load_from_row(THD *thd, TABLE *table)
RETURN VALUE
0 OK
@@ -850,42 +918,62 @@ error:
*/
int
-Event_queue_element::load_from_row(TABLE *table)
+Event_queue_element::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
- bool res1, res2;
+ MYSQL_TIME time;
+ LEX_STRING tz_name;
DBUG_ENTER("Event_queue_element::load_from_row");
if (!table)
goto error;
- if (table->s->fields != ET_FIELD_COUNT)
+ if (table->s->fields < ET_FIELD_COUNT)
goto error;
- load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
- ET_FIELD_DEFINER, &definer, ET_FIELD_COUNT);
+ if (load_string_fields(table->field,
+ ET_FIELD_DB, &dbname,
+ ET_FIELD_NAME, &name,
+ ET_FIELD_DEFINER, &definer,
+ ET_FIELD_TIME_ZONE, &tz_name,
+ ET_FIELD_COUNT))
+ goto error;
+
+ if (load_time_zone(thd, tz_name))
+ goto error;
starts_null= table->field[ET_FIELD_STARTS]->is_null();
- res1= table->field[ET_FIELD_STARTS]->get_date(&starts, TIME_NO_ZERO_DATE);
+ if (!starts_null)
+ {
+ table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
+ starts= sec_since_epoch_TIME(&time);
+ }
ends_null= table->field[ET_FIELD_ENDS]->is_null();
- res2= table->field[ET_FIELD_ENDS]->get_date(&ends, TIME_NO_ZERO_DATE);
+ if (!ends_null)
+ {
+ table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
+ ends= sec_since_epoch_TIME(&time);
+ }
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
else
expression= 0;
/*
- If res1 and res2 are TRUE then both fields are empty.
+ If neigher STARTS and ENDS is set, then both fields are empty.
Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
*/
execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
- if (!expression &&
- table->field[ET_FIELD_EXECUTE_AT]->get_date(&execute_at,
- TIME_NO_ZERO_DATE))
- goto error;
+ if (!expression && !execute_at_null)
+ {
+ if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
+ TIME_NO_ZERO_DATE))
+ goto error;
+ execute_at= sec_since_epoch_TIME(&time);
+ }
/*
We load the interval type from disk as string and then map it to
@@ -912,17 +1000,36 @@ Event_queue_element::load_from_row(TABLE *table)
interval= (interval_type) i;
}
- table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed,
- TIME_NO_ZERO_DATE);
+ if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null())
+ {
+ table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time,
+ TIME_NO_ZERO_DATE);
+ last_executed= sec_since_epoch_TIME(&time);
+ }
last_executed_changed= FALSE;
-
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
- status= (ptr[0]=='E'? Event_queue_element::ENABLED:
- Event_queue_element::DISABLED);
+
+ /* Set event status (ENABLED | SLAVESIDE_DISABLED | DISABLED) */
+ switch (ptr[0])
+ {
+ case 'E' :
+ status = Event_queue_element::ENABLED;
+ break;
+ case 'S' :
+ status = Event_queue_element::SLAVESIDE_DISABLED;
+ break;
+ case 'D' :
+ default:
+ status = Event_queue_element::DISABLED;
+ break;
+ }
+ if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
+ goto error;
+ originator = table->field[ET_FIELD_ORIGINATOR]->val_int();
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(&mem_root,
@@ -942,7 +1049,7 @@ error:
Loads an event from a row from mysql.event
SYNOPSIS
- Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+ Event_timed::load_from_row(THD *thd, TABLE *table)
RETURN VALUE
0 OK
@@ -955,17 +1062,21 @@ error:
*/
int
-Event_timed::load_from_row(TABLE *table)
+Event_timed::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
uint len;
DBUG_ENTER("Event_timed::load_from_row");
- if (Event_queue_element::load_from_row(table))
+ if (Event_queue_element::load_from_row(thd, table))
+ goto error;
+
+ if (load_string_fields(table->field,
+ ET_FIELD_BODY, &body,
+ ET_FIELD_COUNT))
goto error;
- load_string_fields(table->field, ET_FIELD_BODY, &body, ET_FIELD_COUNT);
ptr= strchr(definer.str, '@');
@@ -998,11 +1109,30 @@ error:
/*
- Computes the sum of a timestamp plus interval. Presumed is that at least one
- previous execution has occured.
+ add_interval() adds a specified interval to time 'ltime' in time
+ zone 'time_zone', and returns the result converted to the number of
+ seconds since epoch (aka Unix time; in UTC time zone). Zero result
+ means an error.
+*/
+static
+my_time_t
+add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
+ interval_type scale, INTERVAL interval)
+{
+ if (date_add_interval(ltime, scale, interval))
+ return 0;
+
+ my_bool not_used;
+ return time_zone->TIME_to_gmt_sec(ltime, &not_used);
+}
+
+
+/*
+ Computes the sum of a timestamp plus interval.
SYNOPSIS
- get_next_time(TIME *start, int interval_value, interval_type interval)
+ get_next_time()
+ time_zone event time zone
next the sum
start add interval_value to this time
time_now current time
@@ -1019,26 +1149,19 @@ error:
seconds as resolution for computation.
2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
and PERIOD_DIFF()'s implementation
- 3) We get the difference between time_now and `start`, then divide it
- by the months, respectively seconds and round up. Then we multiply
- monts/seconds by the rounded value and add it to `start` -> we get
- the next execution time.
*/
static
-bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
+bool get_next_time(const Time_zone *time_zone, my_time_t *next,
+ my_time_t start, my_time_t time_now,
int i_value, interval_type i_type)
{
- bool ret;
- INTERVAL interval;
- TIME tmp;
- longlong months=0, seconds=0;
DBUG_ENTER("get_next_time");
- DBUG_PRINT("enter", ("start: %lu now: %lu",
- (long) TIME_to_ulonglong_datetime(start),
- (long) TIME_to_ulonglong_datetime(time_now)));
+ DBUG_PRINT("enter", ("start: %lu now: %lu", (long) start, (long) time_now));
- bzero(&interval, sizeof(interval));
+ DBUG_ASSERT(start <= time_now);
+
+ longlong months=0, seconds=0;
switch (i_type) {
case INTERVAL_YEAR:
@@ -1085,84 +1208,151 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
DBUG_ASSERT(0);
}
DBUG_PRINT("info", ("seconds: %ld months: %ld", (long) seconds, (long) months));
+
+ MYSQL_TIME local_start;
+ MYSQL_TIME local_now;
+
+ /* Convert times from UTC to local. */
+ {
+ time_zone->gmt_sec_to_TIME(&local_start, start);
+ time_zone->gmt_sec_to_TIME(&local_now, time_now);
+ }
+
+ INTERVAL interval;
+ bzero(&interval, sizeof(interval));
+ my_time_t next_time= 0;
+
if (seconds)
{
longlong seconds_diff;
long microsec_diff;
+ bool negative= calc_time_diff(&local_now, &local_start, 1,
+ &seconds_diff, &microsec_diff);
+ if (!negative)
+ {
+ /*
+ The formula below returns the interval that, when added to
+ local_start, will always give the time in the future.
+ */
+ interval.second= seconds_diff - seconds_diff % seconds + seconds;
+ next_time= add_interval(&local_start, time_zone,
+ INTERVAL_SECOND, interval);
+ if (next_time == 0)
+ goto done;
+ }
- if (calc_time_diff(time_now, start, 1, &seconds_diff, &microsec_diff))
+ if (next_time <= time_now)
{
- DBUG_PRINT("error", ("negative difference"));
- DBUG_ASSERT(0);
+ /*
+ If 'negative' is true above, then 'next_time == 0', and
+ 'next_time <= time_now' is also true. If negative is false,
+ then next_time was set, but perhaps to the value that is less
+ then time_now. See below for elaboration.
+ */
+ DBUG_ASSERT(negative || next_time > 0);
+
+ /*
+ If local_now < local_start, i.e. STARTS time is in the future
+ according to the local time (it always in the past according
+ to UTC---this is a prerequisite of this function), then
+ STARTS is almost always in the past according to the local
+ time too. However, in the time zone that has backward
+ Daylight Saving Time shift, the following may happen: suppose
+ we have a backward DST shift at certain date after 2:59:59,
+ i.e. local time goes 1:59:59, 2:00:00, ... , 2:59:59, (shift
+ here) 2:00:00 (again), ... , 2:59:59 (again), 3:00:00, ... .
+ Now suppose the time has passed the first 2:59:59, has been
+ shifted backward, and now is (the second) 2:20:00. The user
+ does CREATE EVENT with STARTS 'current-date 2:40:00'. Local
+ time 2:40:00 from create statement is treated by time
+ functions as the first such time, so according to UTC it comes
+ before the second 2:20:00. But according to local time it is
+ obviously in the future, so we end up in this branch.
+
+ Since we are in the second pass through 2:00:00--2:59:59, and
+ any local time form this interval is treated by system
+ functions as the time from the first pass, we have to find the
+ time for the next execution that is past the DST-affected
+ interval (past the second 2:59:59 for our example,
+ i.e. starting from 3:00:00). We do this in the loop until the
+ local time is mapped onto future UTC time. 'start' time is in
+ the past, so we may use 'do { } while' here, and add the first
+ interval right away.
+
+ Alternatively, it could be that local_now >= local_start. Now
+ for the example above imagine we do CREATE EVENT with STARTS
+ 'current-date 2:10:00'. Local start 2:10 is in the past (now
+ is local 2:20), so we add an interval, and get next execution
+ time, say, 2:40. It is in the future according to local time,
+ but, again, since we are in the second pass through
+ 2:00:00--2:59:59, 2:40 will be converted into UTC time in the
+ past. So we will end up in this branch again, and may add
+ intervals in a 'do { } while' loop.
+
+ Note that for any given event we may end up here only if event
+ next execution time will map to the time interval that is
+ passed twice, and only if the server was started during the
+ second pass, or the event is being created during the second
+ pass. After that, we never will get here (unless we again
+ start the server during the second pass). In other words,
+ such a condition is extremely rare.
+ */
+ interval.second= seconds;
+ do
+ {
+ next_time= add_interval(&local_start, time_zone,
+ INTERVAL_SECOND, interval);
+ if (next_time == 0)
+ goto done;
+ }
+ while (next_time <= time_now);
}
- uint multiplier= (uint) (seconds_diff / seconds);
- /*
- Increase the multiplier is the modulus is not zero to make round up.
- Or if time_now==start then we should not execute the same
- event two times for the same time
- get the next exec if the modulus is not
- */
- DBUG_PRINT("info", ("multiplier: %d", multiplier));
- if (seconds_diff % seconds || (!seconds_diff && last_exec->year) ||
- TIME_to_ulonglong_datetime(time_now) ==
- TIME_to_ulonglong_datetime(last_exec))
- ++multiplier;
- interval.second= seconds * multiplier;
- DBUG_PRINT("info", ("multiplier: %lu interval.second: %lu", (ulong) multiplier,
- (ulong) interval.second));
- tmp= *start;
- if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval)))
- *next= tmp;
}
else
{
- /* PRESUMED is that at least one execution took already place */
- int diff_months= (time_now->year - start->year)*12 +
- (time_now->month - start->month);
+ long diff_months= (long) (local_now.year - local_start.year)*12 +
+ (local_now.month - local_start.month);
/*
- Note: If diff_months is 0 that means we are in the same month as the
- last execution which is also the first execution.
+ Unlike for seconds above, the formula below returns the interval
+ that, when added to the local_start, will give the time in the
+ past, or somewhere in the current month. We are interested in
+ the latter case, to see if this time has already passed, or is
+ yet to come this month.
+
+ Note that the time is guaranteed to be in the past unless
+ (diff_months % months == 0), but no good optimization is
+ possible here, because (diff_months % months == 0) is what will
+ happen most of the time, as get_next_time() will be called right
+ after the execution of the event. We could pass last_executed
+ time to this function, and see if the execution has already
+ happened this month, but for that we will have to convert
+ last_executed from seconds since epoch to local broken-down
+ time, and this will greatly reduce the effect of the
+ optimization. So instead we keep the code simple and clean.
*/
- /*
- First we try with the smaller if not then + 1, because if we try with
- directly with +1 we will be after the current date but it could be that
- we will be 1 month ahead, so 2 steps are necessary.
- */
- interval.month= (ulong) ((diff_months / months)*months);
- /*
- Check if the same month as last_exec (always set - prerequisite)
- An event happens at most once per month so there is no way to
- schedule it two times for the current month. This saves us from two
- calls to date_add_interval() if the event was just executed. But if
- the scheduler is started and there was at least 1 scheduled date
- skipped this one does not help and two calls to date_add_interval()
- will be done, which is a bit more expensive but compared to the
- rareness of the case is neglectable.
- */
- if (time_now->year == last_exec->year &&
- time_now->month == last_exec->month)
- interval.month+= (ulong) months;
-
- tmp= *start;
- if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+ interval.month= (ulong) (diff_months - diff_months % months);
+ next_time= add_interval(&local_start, time_zone,
+ INTERVAL_MONTH, interval);
+ if (next_time == 0)
goto done;
- /* If `tmp` is still before time_now just add one more time the interval */
- if (my_time_compare(&tmp, time_now) == -1)
- {
- interval.month+= (ulong) months;
- tmp= *start;
- if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+ if (next_time <= time_now)
+ {
+ interval.month= (ulong) months;
+ next_time= add_interval(&local_start, time_zone,
+ INTERVAL_MONTH, interval);
+ if (next_time == 0)
goto done;
}
- *next= tmp;
- /* assert on that the next is after now */
- DBUG_ASSERT(1==my_time_compare(next, time_now));
}
+ DBUG_ASSERT(time_now < next_time);
+
+ *next= next_time;
+
done:
- DBUG_PRINT("info", ("next: %lu", (long) TIME_to_ulonglong_datetime(next)));
- DBUG_RETURN(ret);
+ DBUG_PRINT("info", ("next_time: %ld", (long) next_time));
+ DBUG_RETURN(next_time == 0);
}
@@ -1177,23 +1367,20 @@ done:
TRUE Error
NOTES
- The time is set in execute_at, if no more executions the latter is set to
- 0000-00-00.
+ The time is set in execute_at, if no more executions the latter is
+ set to 0.
*/
bool
Event_queue_element::compute_next_execution_time()
{
- TIME time_now;
- int tmp;
+ my_time_t time_now;
DBUG_ENTER("Event_queue_element::compute_next_execution_time");
DBUG_PRINT("enter", ("starts: %lu ends: %lu last_executed: %lu this: 0x%lx",
- (long) TIME_to_ulonglong_datetime(&starts),
- (long) TIME_to_ulonglong_datetime(&ends),
- (long) TIME_to_ulonglong_datetime(&last_executed),
+ (long) starts, (long) ends, (long) last_executed,
(long) this));
- if (status == Event_queue_element::DISABLED)
+ if (status != Event_queue_element::ENABLED)
{
DBUG_PRINT("compute_next_execution_time",
("Event %s is DISABLED", name.str));
@@ -1203,7 +1390,7 @@ Event_queue_element::compute_next_execution_time()
if (!expression)
{
/* Let's check whether it was executed */
- if (last_executed.year)
+ if (last_executed)
{
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
dbname.str, name.str));
@@ -1216,17 +1403,16 @@ Event_queue_element::compute_next_execution_time()
goto ret;
}
- my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start());
+ time_now= (my_time_t) current_thd->query_start();
- DBUG_PRINT("info",("NOW: [%lu]",
- (ulong) TIME_to_ulonglong_datetime(&time_now)));
+ DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
/* if time_now is after ends don't execute anymore */
- if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1)
+ if (!ends_null && ends < time_now)
{
DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
/* time_now is after ends. don't execute anymore */
- set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+ execute_at= 0;
execute_at_null= TRUE;
if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
dropped= TRUE;
@@ -1242,12 +1428,11 @@ Event_queue_element::compute_next_execution_time()
Let's check whether time_now is before starts.
If so schedule for starts.
*/
- if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1)
+ if (!starts_null && time_now <= starts)
{
- if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0)
+ if (time_now == starts && starts == last_executed)
{
/*
- time_now = starts = last_executed
do nothing or we will schedule for second time execution at starts.
*/
}
@@ -1268,31 +1453,30 @@ Event_queue_element::compute_next_execution_time()
{
/*
Both starts and m_ends are set and time_now is between them (incl.)
- If last_executed is set then increase with m_expression. The new TIME is
+ If last_executed is set then increase with m_expression. The new MYSQL_TIME is
after m_ends set execute_at to 0. And check for on_completion
If not set then schedule for now.
*/
DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
- if (!last_executed.year)
+ if (!last_executed)
{
DBUG_PRINT("info", ("Not executed so far."));
}
{
- TIME next_exec;
+ my_time_t next_exec;
- if (get_next_time(&next_exec, &starts, &time_now,
- last_executed.year? &last_executed:&starts,
+ if (get_next_time(time_zone, &next_exec, starts, time_now,
(int) expression, interval))
goto err;
/* There was previous execution */
- if (my_time_compare(&ends, &next_exec) == -1)
+ if (ends < next_exec)
{
DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
name.str));
/* Next execution after ends. No more executions */
- set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+ execute_at= 0;
execute_at_null= TRUE;
if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
dropped= TRUE;
@@ -1301,8 +1485,7 @@ Event_queue_element::compute_next_execution_time()
}
else
{
- DBUG_PRINT("info",("Next[%lu]",
- (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+ DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
execute_at= next_exec;
execute_at_null= FALSE;
}
@@ -1317,15 +1500,14 @@ Event_queue_element::compute_next_execution_time()
Both starts and m_ends are not set, so we schedule for the next
based on last_executed.
*/
- if (last_executed.year)
+ if (last_executed)
{
- TIME next_exec;
- if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+ my_time_t next_exec;
+ if (get_next_time(time_zone, &next_exec, starts, time_now,
(int) expression, interval))
goto err;
execute_at= next_exec;
- DBUG_PRINT("info",("Next[%lu]",
- (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+ DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
}
else
{
@@ -1347,20 +1529,18 @@ Event_queue_element::compute_next_execution_time()
Hence schedule for starts + m_expression in case last_executed
is not set, otherwise to last_executed + m_expression
*/
- if (!last_executed.year)
+ if (!last_executed)
{
DBUG_PRINT("info", ("Not executed so far."));
}
{
- TIME next_exec;
- if (get_next_time(&next_exec, &starts, &time_now,
- last_executed.year? &last_executed:&starts,
+ my_time_t next_exec;
+ if (get_next_time(time_zone, &next_exec, starts, time_now,
(int) expression, interval))
goto err;
execute_at= next_exec;
- DBUG_PRINT("info",("Next[%lu]",
- (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+ DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
}
execute_at_null= FALSE;
}
@@ -1375,20 +1555,20 @@ Event_queue_element::compute_next_execution_time()
If last_executed is not set then schedule for now
*/
- if (!last_executed.year)
+ if (!last_executed)
execute_at= time_now;
else
{
- TIME next_exec;
+ my_time_t next_exec;
- if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+ if (get_next_time(time_zone, &next_exec, starts, time_now,
(int) expression, interval))
goto err;
- if (my_time_compare(&ends, &next_exec) == -1)
+ if (ends < next_exec)
{
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
- set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+ execute_at= 0;
execute_at_null= TRUE;
status= Event_queue_element::DISABLED;
status_changed= TRUE;
@@ -1397,8 +1577,7 @@ Event_queue_element::compute_next_execution_time()
}
else
{
- DBUG_PRINT("info", ("Next[%lu]",
- (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+ DBUG_PRINT("info", ("Next[%lu]", (ulong) next_exec));
execute_at= next_exec;
execute_at_null= FALSE;
}
@@ -1407,8 +1586,7 @@ Event_queue_element::compute_next_execution_time()
goto ret;
}
ret:
- DBUG_PRINT("info", ("ret: 0 execute_at: %lu",
- (long) TIME_to_ulonglong_datetime(&execute_at)));
+ DBUG_PRINT("info", ("ret: 0 execute_at: %lu", (long) execute_at));
DBUG_RETURN(FALSE);
err:
DBUG_PRINT("info", ("ret=1"));
@@ -1417,7 +1595,7 @@ err:
/*
- Set the internal last_executed TIME struct to now. NOW is the
+ Set the internal last_executed MYSQL_TIME struct to now. NOW is the
time according to thd->query_start(), so the THD's clock.
SYNOPSIS
@@ -1428,41 +1606,12 @@ err:
void
Event_queue_element::mark_last_executed(THD *thd)
{
- TIME time_now;
-
thd->end_time();
- my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
- last_executed= time_now; /* was execute_at */
+ last_executed= (my_time_t) thd->query_start();
last_executed_changed= TRUE;
-
- execution_count++;
-}
-
-
-/*
- Drops the event
-
- SYNOPSIS
- Event_queue_element::drop()
- thd thread context
-
- RETURN VALUE
- 0 OK
- -1 Cannot open mysql.event
- -2 Cannot find the event in mysql.event (already deleted?)
-
- others return code from SE in case deletion of the event row
- failed.
-*/
-
-int
-Event_queue_element::drop(THD *thd)
-{
- DBUG_ENTER("Event_queue_element::drop");
- DBUG_RETURN(Events::get_instance()->
- drop_event(thd, dbname, name, FALSE, TRUE));
+ execution_count++;
}
@@ -1482,57 +1631,45 @@ Event_queue_element::drop(THD *thd)
bool
Event_queue_element::update_timing_fields(THD *thd)
{
- TABLE *table;
- Field **fields;
- Open_tables_state backup;
- int ret= FALSE;
+ Event_db_repository *db_repository= Events::get_db_repository();
+ int ret;
DBUG_ENTER("Event_queue_element::update_timing_fields");
- DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
+ DBUG_PRINT("enter", ("name: %*s", (int) name.length, name.str));
/* No need to update if nothing has changed */
if (!(status_changed || last_executed_changed))
DBUG_RETURN(0);
- thd->reset_n_backup_open_tables_state(&backup);
-
- if (Events::get_instance()->open_event_table(thd, TL_WRITE, &table))
- {
- ret= TRUE;
- goto done;
- }
- fields= table->field;
- if ((ret= Events::get_instance()->db_repository->
- find_named_event(thd, dbname, name, table)))
- goto done;
-
- store_record(table,record[1]);
- /* Don't update create on row update. */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
- if (last_executed_changed)
- {
- fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
- fields[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
- MYSQL_TIMESTAMP_DATETIME);
- last_executed_changed= FALSE;
- }
- if (status_changed)
- {
- fields[ET_FIELD_STATUS]->set_notnull();
- fields[ET_FIELD_STATUS]->store((longlong)status, TRUE);
- status_changed= FALSE;
- }
-
- if ((table->file->ha_update_row(table->record[1], table->record[0])))
- ret= TRUE;
+ ret= db_repository->update_timing_fields_for_event(thd,
+ dbname, name,
+ last_executed_changed,
+ last_executed,
+ status_changed,
+ (ulonglong) status);
+ last_executed_changed= status_changed= FALSE;
+ DBUG_RETURN(ret);
+}
-done:
- close_thread_tables(thd);
- thd->restore_backup_open_tables_state(&backup);
- DBUG_RETURN(ret);
+static
+void
+append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
+ const char *name, uint len)
+{
+ char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
+ buf->append(STRING_WITH_LEN(" "));
+ buf->append(name, len);
+ buf->append(STRING_WITH_LEN(" '"));
+ /*
+ Pass the buffer and the second param tells fills the buffer and
+ returns the number of chars to copy.
+ */
+ MYSQL_TIME time;
+ time_zone->gmt_sec_to_TIME(&time, secs);
+ buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff));
+ buf->append(STRING_WITH_LEN("'"));
}
@@ -1554,13 +1691,13 @@ done:
int
Event_timed::get_create_event(THD *thd, String *buf)
{
- int multipl= 0;
char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE];
String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info);
expr_buf.length(0);
DBUG_ENTER("get_create_event");
- DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
+ DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]",
+ (int) body.length, body.str));
if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
expression))
@@ -1576,17 +1713,17 @@ Event_timed::get_create_event(THD *thd, String *buf)
buf->append(' ');
LEX_STRING *ival= &interval_type_to_name[interval];
buf->append(ival->str, ival->length);
+
+ if (!starts_null)
+ append_datetime(buf, time_zone, starts, STRING_WITH_LEN("STARTS"));
+
+ if (!ends_null)
+ append_datetime(buf, time_zone, ends, STRING_WITH_LEN("ENDS"));
}
else
{
- char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
- buf->append(STRING_WITH_LEN(" ON SCHEDULE AT '"));
- /*
- Pass the buffer and the second param tells fills the buffer and
- returns the number of chars to copy.
- */
- buf->append(dtime_buff, my_datetime_to_str(&execute_at, dtime_buff));
- buf->append(STRING_WITH_LEN("'"));
+ append_datetime(buf, time_zone, execute_at,
+ STRING_WITH_LEN("ON SCHEDULE AT"));
}
if (on_completion == Event_timed::ON_COMPLETION_DROP)
@@ -1596,6 +1733,8 @@ Event_timed::get_create_event(THD *thd, String *buf)
if (status == Event_timed::ENABLED)
buf->append(STRING_WITH_LEN("ENABLE"));
+ else if (status == Event_timed::SLAVESIDE_DISABLED)
+ buf->append(STRING_WITH_LEN("DISABLE ON SLAVE"));
else
buf->append(STRING_WITH_LEN("DISABLE"));
@@ -1611,223 +1750,257 @@ Event_timed::get_create_event(THD *thd, String *buf)
}
-/*
- Get SHOW CREATE EVENT as string
+/**
+ Get an artificial stored procedure to parse as an event definition.
+*/
- SYNOPSIS
- Event_job_data::get_create_event(THD *thd, String *buf)
- thd Thread
- buf String*, should be already allocated. CREATE EVENT goes inside.
+bool
+Event_job_data::construct_sp_sql(THD *thd, String *sp_sql)
+{
+ LEX_STRING buffer;
+ const uint STATIC_SQL_LENGTH= 44;
- RETURN VALUE
- 0 OK
- EVEX_MICROSECOND_UNSUP Error (for now if mysql.event has been
- tampered and MICROSECONDS interval or
- derivative has been put there.
+ DBUG_ENTER("Event_job_data::construct_sp_sql");
+
+ /*
+ Allocate a large enough buffer on the thread execution memory
+ root to avoid multiple [re]allocations on system heap
+ */
+ buffer.length= STATIC_SQL_LENGTH + name.length + body.length;
+ if (! (buffer.str= (char*) thd->alloc(buffer.length)))
+ DBUG_RETURN(TRUE);
+
+ sp_sql->set(buffer.str, buffer.length, system_charset_info);
+ sp_sql->length(0);
+
+
+ sp_sql->append(C_STRING_WITH_LEN("CREATE "));
+ sp_sql->append(C_STRING_WITH_LEN("PROCEDURE "));
+ /*
+ Let's use the same name as the event name to perhaps produce a
+ better error message in case it is a part of some parse error.
+ We're using append_identifier here to successfully parse
+ events with reserved names.
+ */
+ append_identifier(thd, sp_sql, name.str, name.length);
+
+ /*
+ The default SQL security of a stored procedure is DEFINER. We
+ have already activated the security context of the event, so
+ let's execute the procedure with the invoker rights to save on
+ resets of security contexts.
+ */
+ sp_sql->append(C_STRING_WITH_LEN("() SQL SECURITY INVOKER "));
+
+ sp_sql->append(body.str, body.length);
+
+ DBUG_RETURN(thd->is_fatal_error);
+}
+
+
+/**
+ Get DROP EVENT statement to binlog the drop of ON COMPLETION NOT
+ PRESERVE event.
*/
-int
-Event_job_data::get_fake_create_event(THD *thd, String *buf)
+bool
+Event_job_data::construct_drop_event_sql(THD *thd, String *sp_sql)
{
- DBUG_ENTER("Event_job_data::get_create_event");
- buf->append(STRING_WITH_LEN("CREATE EVENT anonymous ON SCHEDULE "
- "EVERY 3337 HOUR DO "));
- buf->append(body.str, body.length);
+ LEX_STRING buffer;
+ const uint STATIC_SQL_LENGTH= 14;
- DBUG_RETURN(0);
-}
+ DBUG_ENTER("Event_job_data::construct_drop_event_sql");
+ buffer.length= STATIC_SQL_LENGTH + name.length*2 + dbname.length*2;
+ if (! (buffer.str= (char*) thd->alloc(buffer.length)))
+ DBUG_RETURN(TRUE);
-/*
- Executes the event (the underlying sp_head object);
+ sp_sql->set(buffer.str, buffer.length, system_charset_info);
+ sp_sql->length(0);
- SYNOPSIS
- Event_job_data::execute()
- thd THD
+ sp_sql->append(C_STRING_WITH_LEN("DROP EVENT "));
+ append_identifier(thd, sp_sql, dbname.str, dbname.length);
+ sp_sql->append('.');
+ append_identifier(thd, sp_sql, name.str, name.length);
- RETURN VALUE
- 0 success
- -99 No rights on this.dbname.str
- others retcodes of sp_head::execute_procedure()
+ DBUG_RETURN(thd->is_fatal_error);
+}
+
+/**
+ Compiles and executes the event (the underlying sp_head object)
+
+ @retval TRUE error (reported to the error log)
+ @retval FALSE success
*/
-int
-Event_job_data::execute(THD *thd)
+bool
+Event_job_data::execute(THD *thd, bool drop)
{
- Security_context save_ctx;
- /* this one is local and not needed after exec */
- int ret= 0;
+ String sp_sql;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context event_sctx, *save_sctx= NULL;
+#endif
+ CHARSET_INFO *charset_connection;
+ List<Item> empty_item_list;
+ bool ret= TRUE;
DBUG_ENTER("Event_job_data::execute");
- DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
- if ((ret= compile(thd, NULL)))
- goto done;
+ mysql_reset_thd_for_next_command(thd);
- event_change_security_context(thd, definer_user, definer_host, dbname,
- &save_ctx);
/*
- THD::~THD will clean this or if there is DROP DATABASE in the
- SP then it will be free there. It should not point to our buffer
- which is allocated on a mem_root.
+ MySQL parser currently assumes that current database is either
+ present in THD or all names in all statements are fully specified.
+ And yet not fully specified names inside stored programs must be
+ be supported, even if the current database is not set:
+ CREATE PROCEDURE db1.p1() BEGIN CREATE TABLE t1; END//
+ -- in this example t1 should be always created in db1 and the statement
+ must parse even if there is no current database.
+
+ To support this feature and still address the parser limitation,
+ we need to set the current database here.
+ We don't have to call mysql_change_db, since the checks performed
+ in it are unnecessary for the purpose of parsing, and
+ mysql_change_db will be invoked anyway later, to activate the
+ procedure database before it's executed.
*/
- thd->db= my_strdup(dbname.str, MYF(0));
- thd->db_length= dbname.length;
- if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str)))
- {
- List<Item> empty_item_list;
- empty_item_list.empty();
- if (thd->enable_slow_log)
- sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
- sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
+ thd->set_db(dbname.str, dbname.length);
- ret= sphead->execute_procedure(thd, &empty_item_list);
- }
- else
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (event_sctx.change_security_context(thd,
+ &definer_user, &definer_host,
+ &dbname, &save_sctx))
{
- DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str,
- definer_host.str, dbname.str));
- ret= -99;
+ sql_print_error("Event Scheduler: "
+ "[%s].[%s.%s] execution failed, "
+ "failed to authenticate the user.",
+ definer.str, dbname.str, name.str);
+ goto end;
}
+#endif
- event_restore_security_context(thd, &save_ctx);
-done:
- thd->end_statement();
- thd->cleanup_after_query();
-
- DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
+ if (check_access(thd, EVENT_ACL, dbname.str,
+ 0, 0, 0, is_schema_db(dbname.str)))
+ {
+ /*
+ This aspect of behavior is defined in the worklog,
+ and this is how triggers work too: if TRIGGER
+ privilege is revoked from trigger definer,
+ triggers are not executed.
+ */
+ sql_print_error("Event Scheduler: "
+ "[%s].[%s.%s] execution failed, "
+ "user no longer has EVENT privilege.",
+ definer.str, dbname.str, name.str);
+ goto end;
+ }
- DBUG_RETURN(ret);
-}
+ if (construct_sp_sql(thd, &sp_sql))
+ goto end;
+ /*
+ Set up global thread attributes to reflect the properties of
+ this Event. We can simply reset these instead of usual
+ backup/restore employed in stored programs since we know that
+ this is a top level statement and the worker thread is
+ allocated exclusively to execute this event.
+ */
+ charset_connection= get_charset_by_csname("utf8",
+ MY_CS_PRIMARY, MYF(MY_WME));
+ thd->variables.character_set_client= charset_connection;
+ thd->variables.character_set_results= charset_connection;
+ thd->variables.collation_connection= charset_connection;
+ thd->update_charset();
-/*
- Compiles an event before it's execution. Compiles the anonymous
- sp_head object held by the event
+ thd->variables.sql_mode= sql_mode;
+ thd->variables.time_zone= time_zone;
- SYNOPSIS
- Event_job_data::compile()
- thd thread context, used for memory allocation mostly
- mem_root if != NULL then this memory root is used for allocs
- instead of thd->mem_root
+ /*
+ Peculiar initialization order is a crutch to avoid races in SHOW
+ PROCESSLIST which reads thd->{query/query_length} without a mutex.
+ */
+ thd->query_length= 0;
+ thd->query= sp_sql.c_ptr_safe();
+ thd->query_length= sp_sql.length();
- RETURN VALUE
- 0 success
- EVEX_COMPILE_ERROR error during compilation
- EVEX_MICROSECOND_UNSUP mysql.event was tampered
-*/
+ {
+ Lex_input_stream lip(thd, thd->query, thd->query_length);
+ thd->m_lip= &lip;
+ lex_start(thd);
+ int err= MYSQLparse(thd);
-int
-Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
-{
- int ret= 0;
- MEM_ROOT *tmp_mem_root= 0;
- LEX *old_lex= thd->lex, lex;
- char *old_db;
- int old_db_length;
- char *old_query;
- uint old_query_len;
- ulong old_sql_mode= thd->variables.sql_mode;
- char create_buf[15 * STRING_BUFFER_USUAL_SIZE];
- String show_create(create_buf, sizeof(create_buf), system_charset_info);
- CHARSET_INFO *old_character_set_client,
- *old_collation_connection,
- *old_character_set_results;
- Security_context save_ctx;
-
- DBUG_ENTER("Event_job_data::compile");
-
- show_create.length(0);
-
- switch (get_fake_create_event(thd, &show_create)) {
- case EVEX_MICROSECOND_UNSUP:
- DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
- case 0:
- break;
- default:
- DBUG_ASSERT(0);
+ if (err || thd->is_fatal_error)
+ {
+ sql_print_error("Event Scheduler: "
+ "%serror during compilation of %s.%s",
+ thd->is_fatal_error ? "fatal " : "",
+ (const char *) dbname.str, (const char *) name.str);
+ goto end;
+ }
}
- old_character_set_client= thd->variables.character_set_client;
- old_character_set_results= thd->variables.character_set_results;
- old_collation_connection= thd->variables.collation_connection;
+ {
+ sp_head *sphead= thd->lex->sphead;
- thd->variables.character_set_client=
- thd->variables.character_set_results=
- thd->variables.collation_connection=
- get_charset_by_csname("utf8", MY_CS_PRIMARY, MYF(MY_WME));
+ DBUG_ASSERT(sphead);
- thd->update_charset();
+ if (thd->enable_slow_log)
+ sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
+ sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
- DBUG_PRINT("info",("old_sql_mode: %lu new_sql_mode: %lu",old_sql_mode, sql_mode));
- thd->variables.sql_mode= this->sql_mode;
- /* Change the memory root for the execution time */
- if (mem_root)
- {
- tmp_mem_root= thd->mem_root;
- thd->mem_root= mem_root;
+ sphead->set_info(0, 0, &thd->lex->sp_chistics, sql_mode);
+ sphead->optimize();
+
+ ret= sphead->execute_procedure(thd, &empty_item_list);
+ /*
+ There is no pre-locking and therefore there should be no
+ tables open and locked left after execute_procedure.
+ */
}
- old_query_len= thd->query_length;
- old_query= thd->query;
- old_db= thd->db;
- old_db_length= thd->db_length;
- thd->db= dbname.str;
- thd->db_length= dbname.length;
-
- thd->query= show_create.c_ptr_safe();
- thd->query_length= show_create.length();
- DBUG_PRINT("info", ("query: %s",thd->query));
-
- event_change_security_context(thd, definer_user, definer_host, dbname,
- &save_ctx);
- thd->lex= &lex;
- mysql_init_query(thd, (uchar*) thd->query, thd->query_length);
- if (MYSQLparse((void *)thd) || thd->is_fatal_error)
+
+end:
+ if (drop && !thd->is_fatal_error)
{
- DBUG_PRINT("error", ("error during compile or thd->is_fatal_error: %d",
- thd->is_fatal_error));
/*
- Free lex associated resources
- QQ: Do we really need all this stuff here?
+ We must do it here since here we're under the right authentication
+ ID of the event definer.
*/
- sql_print_error("SCHEDULER: Error during compilation of %s.%s or "
- "thd->is_fatal_error: %d",
- dbname.str, name.str, thd->is_fatal_error);
-
- lex.unit.cleanup();
- delete lex.sphead;
- sphead= lex.sphead= NULL;
- ret= EVEX_COMPILE_ERROR;
- goto done;
+ sql_print_information("Event Scheduler: Dropping %s.%s",
+ (const char *) dbname.str, (const char *) name.str);
+ /*
+ Construct a query for the binary log, to ensure the event is dropped
+ on the slave
+ */
+ if (construct_drop_event_sql(thd, &sp_sql))
+ ret= 1;
+ else
+ {
+ /*
+ Peculiar initialization order is a crutch to avoid races in SHOW
+ PROCESSLIST which reads thd->{query/query_length} without a mutex.
+ */
+ thd->query_length= 0;
+ thd->query= sp_sql.c_ptr_safe();
+ thd->query_length= sp_sql.length();
+ if (Events::drop_event(thd, dbname, name, FALSE))
+ ret= 1;
+ }
}
- DBUG_PRINT("note", ("success compiling %s.%s", dbname.str, name.str));
-
- sphead= lex.sphead;
-
- sphead->set_definer(definer.str, definer.length);
- sphead->set_info(0, 0, &lex.sp_chistics, sql_mode);
- sphead->optimize();
- ret= 0;
-done:
-
- lex_end(&lex);
- event_restore_security_context(thd, &save_ctx);
- DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
-
- thd->lex= old_lex;
- thd->query= old_query;
- thd->query_length= old_query_len;
- thd->db= old_db;
-
- thd->variables.sql_mode= old_sql_mode;
- thd->variables.character_set_client= old_character_set_client;
- thd->variables.character_set_results= old_character_set_results;
- thd->variables.collation_connection= old_collation_connection;
- thd->update_charset();
+ if (thd->lex->sphead) /* NULL only if a parse error */
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (save_sctx)
+ event_sctx.restore_security_context(thd, save_sctx);
+#endif
+ lex_end(thd->lex);
+ thd->lex->unit.cleanup();
+ thd->end_statement();
+ thd->cleanup_after_query();
- /* Change the memory root for the execution time. */
- if (mem_root)
- thd->mem_root= tmp_mem_root;
+ DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
DBUG_RETURN(ret);
}
@@ -1873,64 +2046,3 @@ event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b)
return !sortcmp_lex_string(name, b->name, system_charset_info) &&
!sortcmp_lex_string(db, b->dbname, system_charset_info);
}
-
-
-/*
- Switches the security context.
-
- SYNOPSIS
- event_change_security_context()
- thd Thread
- user The user
- host The host of the user
- db The schema for which the security_ctx will be loaded
- backup Where to store the old context
-
- RETURN VALUE
- FALSE OK
- TRUE Error (generates error too)
-*/
-
-static bool
-event_change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
- LEX_STRING db, Security_context *backup)
-{
- DBUG_ENTER("event_change_security_context");
- DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
- *backup= thd->main_security_ctx;
- if (acl_getroot_no_password(&thd->main_security_ctx, user.str, host.str,
- host.str, db.str))
- {
- my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
- DBUG_RETURN(TRUE);
- }
- thd->security_ctx= &thd->main_security_ctx;
-#endif
- DBUG_RETURN(FALSE);
-}
-
-
-/*
- Restores the security context.
-
- SYNOPSIS
- event_restore_security_context()
- thd Thread
- backup Context to switch to
-*/
-
-static void
-event_restore_security_context(THD *thd, Security_context *backup)
-{
- DBUG_ENTER("event_restore_security_context");
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (backup)
- {
- thd->main_security_ctx= *backup;
- thd->security_ctx= &thd->main_security_ctx;
- }
-#endif
- DBUG_VOID_RETURN;
-}
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index 2da39c2158b..8e03ab19602 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -4,8 +4,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,15 +17,32 @@
#define EVEX_GET_FIELD_FAILED -2
-#define EVEX_COMPILE_ERROR -3
-#define EVEX_GENERAL_ERROR -4
#define EVEX_BAD_PARAMS -5
#define EVEX_MICROSECOND_UNSUP -6
-
class sp_head;
class Sql_alloc;
+class Event_queue_element_for_exec
+{
+public:
+ Event_queue_element_for_exec(){};
+ ~Event_queue_element_for_exec();
+
+ bool
+ init(LEX_STRING dbname, LEX_STRING name);
+
+ LEX_STRING dbname;
+ LEX_STRING name;
+ bool dropped;
+ THD *thd;
+
+private:
+ /* Prevent use of these */
+ Event_queue_element_for_exec(const Event_queue_element_for_exec &);
+ void operator=(Event_queue_element_for_exec &);
+};
+
class Event_basic
{
@@ -34,19 +50,42 @@ protected:
MEM_ROOT mem_root;
public:
+ /*
+ ENABLED = feature can function normally (is turned on)
+ SLAVESIDE_DISABLED = feature is turned off on slave
+ DISABLED = feature is turned off
+ */
+ enum enum_status
+ {
+ ENABLED = 1,
+ DISABLED,
+ SLAVESIDE_DISABLED
+ };
+
+ enum enum_on_completion
+ {
+ ON_COMPLETION_DROP = 1,
+ ON_COMPLETION_PRESERVE
+ };
+
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING definer;// combination of user and host
+ Time_zone *time_zone;
+
Event_basic();
virtual ~Event_basic();
virtual int
- load_from_row(TABLE *table) = 0;
+ load_from_row(THD *thd, TABLE *table) = 0;
protected:
bool
load_string_fields(Field **fields, ...);
+
+ bool
+ load_time_zone(THD *thd, const LEX_STRING tz_name);
};
@@ -58,25 +97,14 @@ protected:
bool last_executed_changed;
public:
- enum enum_status
- {
- ENABLED = 1,
- DISABLED
- };
-
- enum enum_on_completion
- {
- ON_COMPLETION_DROP = 1,
- ON_COMPLETION_PRESERVE
- };
-
- enum enum_on_completion on_completion;
- enum enum_status status;
- TIME last_executed;
-
- TIME execute_at;
- TIME starts;
- TIME ends;
+ int on_completion;
+ int status;
+ longlong originator;
+
+ my_time_t last_executed;
+ my_time_t execute_at;
+ my_time_t starts;
+ my_time_t ends;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
@@ -92,37 +120,16 @@ public:
virtual ~Event_queue_element();
virtual int
- load_from_row(TABLE *table);
+ load_from_row(THD *thd, TABLE *table);
bool
compute_next_execution_time();
- int
- drop(THD *thd);
-
void
mark_last_executed(THD *thd);
bool
update_timing_fields(THD *thd);
-
- static void *operator new(size_t size)
- {
- void *p;
- DBUG_ENTER("Event_queue_element::new(size)");
- p= my_malloc(size, MYF(0));
- DBUG_PRINT("info", ("alloc_ptr: 0x%lx", (long) p));
- DBUG_RETURN(p);
- }
-
- static void operator delete(void *ptr, size_t size)
- {
- DBUG_ENTER("Event_queue_element::delete(ptr,size)");
- DBUG_PRINT("enter", ("free_ptr: 0x%lx", (long) ptr));
- TRASH(ptr, size);
- my_free((gptr) ptr, MYF(0));
- DBUG_VOID_RETURN;
- }
};
@@ -151,7 +158,7 @@ public:
init();
virtual int
- load_from_row(TABLE *table);
+ load_from_row(THD *thd, TABLE *table);
int
get_create_event(THD *thd, String *buf);
@@ -161,31 +168,24 @@ public:
class Event_job_data : public Event_basic
{
public:
- THD *thd;
- sp_head *sphead;
-
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
ulong sql_mode;
- uint execution_count;
-
Event_job_data();
- virtual ~Event_job_data();
virtual int
- load_from_row(TABLE *table);
-
- int
- execute(THD *thd);
+ load_from_row(THD *thd, TABLE *table);
- int
- compile(THD *thd, MEM_ROOT *mem_root);
+ bool
+ execute(THD *thd, bool drop);
private:
- int
- get_fake_create_event(THD *thd, String *buf);
+ bool
+ construct_sp_sql(THD *thd, String *sp_sql);
+ bool
+ construct_drop_event_sql(THD *thd, String *sp_sql);
Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &);
@@ -195,21 +195,17 @@ private:
class Event_parse_data : public Sql_alloc
{
public:
- enum enum_status
- {
- ENABLED = 1,
- DISABLED
- };
- enum enum_on_completion
- {
- ON_COMPLETION_DROP = 1,
- ON_COMPLETION_PRESERVE
- };
- enum enum_on_completion on_completion;
- enum enum_status status;
+ int on_completion;
+ int status;
+ longlong originator;
+ /*
+ do_not_create will be set if STARTS time is in the past and
+ on_completion == ON_COMPLETION_DROP.
+ */
+ bool do_not_create;
- const uchar *body_begin;
+ const char *body_begin;
LEX_STRING dbname;
LEX_STRING name;
@@ -221,9 +217,9 @@ public:
Item* item_ends;
Item* item_execute_at;
- TIME starts;
- TIME ends;
- TIME execute_at;
+ my_time_t starts;
+ my_time_t ends;
+ my_time_t execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
@@ -268,7 +264,11 @@ private:
void
report_bad_value(const char *item_name, Item *bad_item);
+ void
+ check_if_in_the_past(THD *thd, my_time_t ltime_utc);
+
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
+ void check_originator_id(THD *thd);
void operator=(Event_parse_data &);
};
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 367c5bae579..fa17ee8a380 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,12 +18,6 @@
#include "event_data_objects.h"
#include "events.h"
#include "sql_show.h"
-#include "sp.h"
-#include "sp_head.h"
-
-
-static
-time_t mysql_event_last_create_time= 0L;
static
const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
@@ -95,7 +88,7 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
},
{
{ C_STRING_WITH_LEN("status") },
- { C_STRING_WITH_LEN("enum('ENABLED','DISABLED')") },
+ { C_STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')") },
{NULL, 0}
},
{
@@ -119,30 +112,35 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
{ C_STRING_WITH_LEN("comment") },
{ C_STRING_WITH_LEN("char(64)") },
{ C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("originator") },
+ { C_STRING_WITH_LEN("int(10)") },
+ {NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("time_zone") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { C_STRING_WITH_LEN("latin1") }
}
};
-/*
+/**
Puts some data common to CREATE and ALTER EVENT into a row.
- SYNOPSIS
- mysql_event_fill_row()
- thd THD
- table The row to fill out
- et Event's data
- is_update CREATE EVENT or ALTER EVENT
+ Used both when an event is created and when it is altered.
- RETURN VALUE
- 0 OK
- EVEX_GENERAL_ERROR Bad data
- EVEX_GET_FIELD_FAILED Field count does not match. table corrupted?
+ @param thd THD
+ @param table The row to fill out
+ @param et Event's data
+ @param is_update CREATE EVENT or ALTER EVENT
- DESCRIPTION
- Used both when an event is created and when it is altered.
+ @retval FALSE success
+ @retval TRUE error
*/
-static int
+static bool
mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
my_bool is_update)
{
@@ -156,6 +154,17 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
+ if (table->s->fields < ET_FIELD_COUNT)
+ {
+ /*
+ Safety: this can only happen if someone started the server
+ and then altered mysql.event.
+ */
+ my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, MYF(0), table->alias,
+ (int) ET_FIELD_COUNT, table->s->fields);
+ DBUG_RETURN(TRUE);
+ }
+
if (fields[f_num= ET_FIELD_DEFINER]->
store(et->definer.str, et->definer.length, scs))
goto err_truncate;
@@ -171,10 +180,13 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
+ fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE);
+
+
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
always during CREATE EVENT.
- */
+ */
if (et->body.str)
{
fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
@@ -184,6 +196,14 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
if (et->expression)
{
+ const String *tz_name= thd->variables.time_zone->get_name();
+ if (!is_update || !et->starts_null)
+ {
+ fields[ET_FIELD_TIME_ZONE]->set_notnull();
+ fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
+ tz_name->charset());
+ }
+
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
@@ -198,26 +218,40 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
if (!et->starts_null)
{
+ MYSQL_TIME time;
+ my_tz_UTC->gmt_sec_to_TIME(&time, et->starts);
+
fields[ET_FIELD_STARTS]->set_notnull();
- fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
+ MYSQL_TIME time;
+ my_tz_UTC->gmt_sec_to_TIME(&time, et->ends);
+
fields[ET_FIELD_ENDS]->set_notnull();
- fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
+ fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
}
- else if (et->execute_at.year)
+ else if (et->execute_at)
{
+ const String *tz_name= thd->variables.time_zone->get_name();
+ fields[ET_FIELD_TIME_ZONE]->set_notnull();
+ fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
+ tz_name->charset());
+
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
fields[ET_FIELD_STARTS]->set_null();
fields[ET_FIELD_ENDS]->set_null();
-
+
+ MYSQL_TIME time;
+ my_tz_UTC->gmt_sec_to_TIME(&time, et->execute_at);
+
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
fields[ET_FIELD_EXECUTE_AT]->
- store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
+ store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
else
{
@@ -227,7 +261,7 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
this is an error if the action is create. something is borked
*/
}
-
+
((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
if (et->comment.str)
@@ -237,11 +271,11 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
goto err_truncate;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err_truncate:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
- DBUG_RETURN(EVEX_GENERAL_ERROR);
+ DBUG_RETURN(TRUE);
}
@@ -269,45 +303,59 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
CHARSET_INFO *scs= system_charset_info;
KEY *key_info;
uint key_len;
- byte *key_buf= NULL;
+ uchar *key_buf= NULL;
LINT_INIT(key_buf);
DBUG_ENTER("Event_db_repository::index_read_for_db_for_i_s");
DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1);
- event_table->field[ET_FIELD_DB]->store(db, strlen(db), scs);
key_info= event_table->key_info;
- key_len= key_info->key_part[0].store_length;
- if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
+ if (key_info->key_parts == 0 ||
+ key_info->key_part[0].field != event_table->field[ET_FIELD_DB])
{
+ /* Corrupted table: no index or index on a wrong column */
+ my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
ret= 1;
+ goto end;
+ }
+
+ event_table->field[ET_FIELD_DB]->store(db, strlen(db), scs);
+ key_len= key_info->key_part[0].store_length;
+
+ if (!(key_buf= (uchar *)alloc_root(thd->mem_root, key_len)))
+ {
/* Don't send error, it would be done by sql_alloc_error_handler() */
+ ret= 1;
+ goto end;
}
- else
+
+ key_copy(key_buf, event_table->record[0], key_info, key_len);
+ if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
+ (key_part_map)1, HA_READ_PREFIX)))
{
- key_copy(key_buf, event_table->record[0], key_info, key_len);
- if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
- key_len, HA_READ_PREFIX)))
+ DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
+ do
{
- DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
- do
- {
- ret= copy_event_to_schema_table(thd, schema_table, event_table);
- if (ret == 0)
- ret= event_table->file->index_next_same(event_table->record[0],
- key_buf, key_len);
- } while (ret == 0);
- }
- DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
+ ret= copy_event_to_schema_table(thd, schema_table, event_table);
+ if (ret == 0)
+ ret= event_table->file->index_next_same(event_table->record[0],
+ key_buf, key_len);
+ } while (ret == 0);
}
- event_table->file->ha_index_end();
+ DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
+
/* ret is guaranteed to be != 0 */
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
- DBUG_RETURN(FALSE);
+ ret= 0;
+ else
+ event_table->file->print_error(ret, MYF(0));
- DBUG_RETURN(TRUE);
+end:
+ event_table->file->ha_index_end();
+
+ DBUG_RETURN(test(ret));
}
@@ -355,40 +403,33 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
}
-/*
+/**
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
SHOW EVENTS
- SYNOPSIS
- Event_db_repository::fill_schema_events()
- thd Thread
- tables The schema table
- db If not NULL then get events only from this schema
+ The reason we reset and backup open tables here is that this
+ function may be called from any query that accesses
+ INFORMATION_SCHEMA - including a query that is issued from
+ a pre-locked statement, one that already has open and locked
+ tables.
- RETURN VALUE
- FALSE OK
- TRUE Error
+ @retval FALSE success
+ @retval TRUE error
*/
-int
+bool
Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
const char *db)
{
TABLE *schema_table= tables->table;
TABLE *event_table= NULL;
- Open_tables_state backup;
int ret= 0;
DBUG_ENTER("Event_db_repository::fill_schema_events");
DBUG_PRINT("info",("db=%s", db? db:"(null)"));
- thd->reset_n_backup_open_tables_state(&backup);
if (open_event_table(thd, TL_READ, &event_table))
- {
- sql_print_error("Table mysql.event is damaged.");
- thd->restore_backup_open_tables_state(&backup);
- DBUG_RETURN(1);
- }
+ DBUG_RETURN(TRUE);
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
@@ -405,163 +446,100 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
ret= table_scan_all_for_i_s(thd, schema_table, event_table);
close_thread_tables(thd);
- thd->restore_backup_open_tables_state(&backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
-/*
- Open mysql.event table for read
+/**
+ Open mysql.event table for read.
- SYNOPSIS
- Events::open_event_table()
- thd [in] Thread context
- lock_type [in] How to lock the table
- table [out] We will store the open table here
+ It's assumed that the caller knows what they are doing:
+ - whether it was necessary to reset-and-backup the open tables state
+ - whether the requested lock does not lead to a deadlock
+ - whether this open mode would work under LOCK TABLES, or inside a
+ stored function or trigger.
- RETURN VALUE
- 1 Cannot lock table
- 2 The table is corrupted - different number of fields
- 0 OK
+ @param[in] thd Thread context
+ @param[in] lock_type How to lock the table
+ @param[out] table We will store the open table here
+
+ @retval TRUE open and lock failed - an error message is pushed into the
+ stack
+ @retval FALSE success
*/
-int
+bool
Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
TABLE **table)
{
TABLE_LIST tables;
DBUG_ENTER("Event_db_repository::open_event_table");
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "event";
- tables.lock_type= lock_type;
+ tables.init_one_table("mysql", "event", lock_type);
if (simple_open_n_lock_tables(thd, &tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
- if (table_check_intact(tables.table, ET_FIELD_COUNT,
- event_table_fields,
- &mysql_event_last_create_time,
- ER_CANNOT_LOAD_FROM_TABLE))
- {
- close_thread_tables(thd);
- DBUG_RETURN(2);
- }
*table= tables.table;
tables.table->use_all_columns();
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
-/*
- Checks parameters which we got from the parsing phase.
-
- SYNOPSIS
- check_parse_params()
- thd Thread context
- parse_data Event's data
-
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
-*/
-
-static int
-check_parse_params(THD *thd, Event_parse_data *parse_data)
-{
- DBUG_ENTER("check_parse_params");
-
- if (parse_data->check_parse_data(thd))
- DBUG_RETURN(EVEX_BAD_PARAMS);
-
- if (!parse_data->dbname.str ||
- (thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
- !thd->lex->spname->m_db.str))
- {
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- DBUG_RETURN(EVEX_BAD_PARAMS);
- }
-
- if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
- is_schema_db(parse_data->dbname.str)) ||
- (thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
- (check_access(thd, EVENT_ACL, thd->lex->spname->m_db.str, 0, 0, 0,
- is_schema_db(thd->lex->spname->m_db.str)))))
- DBUG_RETURN(EVEX_BAD_PARAMS);
-
- DBUG_RETURN(0);
-}
-
+/**
+ Creates an event record in mysql.event table.
-/*
- Creates an event in mysql.event
+ Creates an event. Relies on mysql_event_fill_row which is shared with
+ ::update_event.
- SYNOPSIS
- Event_db_repository::create_event()
- thd [in] THD
- parse_data [in] Object containing info about the event
- create_if_not [in] Whether to generate anwarning in case event exists
+ @pre All semantic checks must be performed outside. This function
+ only creates a record on disk.
+ @pre The thread handle has no open tables.
- RETURN VALUE
- 0 OK
- EVEX_GENERAL_ERROR Failure
+ @param[in,out] THD
+ @param[in] parse_data Parsed event definition
+ @param[in] create_if_not TRUE if IF NOT EXISTS clause was provided
+ to CREATE EVENT statement
- DESCRIPTION
- Creates an event. Relies on mysql_event_fill_row which is shared with
- ::update_event. The name of the event is inside "et".
+ @retval FALSE success
+ @retval TRUE error
*/
bool
Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
my_bool create_if_not)
{
- int ret= 0;
- CHARSET_INFO *scs= system_charset_info;
+ int ret= 1;
TABLE *table= NULL;
- char old_db_buf[NAME_LEN+1];
- LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
- bool dbchanged= FALSE;
DBUG_ENTER("Event_db_repository::create_event");
- if (check_parse_params(thd, parse_data))
- goto err;
-
DBUG_PRINT("info", ("open mysql.event for update"));
- if (open_event_table(thd, TL_WRITE, &table))
- {
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- goto err;
- }
+ if (open_event_table(thd, TL_WRITE, &table))
+ goto end;
- DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
+ DBUG_PRINT("info", ("name: %.*s", (int) parse_data->name.length,
parse_data->name.str));
DBUG_PRINT("info", ("check existance of an event with the same name"));
- if (!find_named_event(thd, parse_data->dbname, parse_data->name, table))
+ if (!find_named_event(parse_data->dbname, parse_data->name, table))
{
if (create_if_not)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
parse_data->name.str);
- goto ok;
+ ret= 0;
}
- my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
- goto err;
+ else
+ my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
+ goto end;
}
- DBUG_PRINT("info", ("non-existant, go forward"));
-
- if ((ret= sp_use_new_db(thd, parse_data->dbname, &old_db, 0, &dbchanged)))
- {
- my_error(ER_BAD_DB_ERROR, MYF(0));
- goto err;
- }
+ DBUG_PRINT("info", ("non-existent, go forward"));
restore_record(table, s->default_values); // Get default values for fields
@@ -571,7 +549,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
table->field[ET_FIELD_DB]->char_length())
{
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str);
- goto err;
+ goto end;
}
if (system_charset_info->cset->
@@ -580,20 +558,13 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
table->field[ET_FIELD_NAME]->char_length())
{
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str);
- goto err;
+ goto end;
}
if (parse_data->body.length > table->field[ET_FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
- goto err;
- }
-
- if (!(parse_data->expression) && !(parse_data->execute_at.year))
- {
- DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
- my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
- goto err;
+ goto end;
}
((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
@@ -602,93 +573,71 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
- if ((ret= mysql_event_fill_row(thd, table, parse_data, FALSE)))
- goto err;
+ if (mysql_event_fill_row(thd, table, parse_data, FALSE))
+ goto end;
- /* Close active transaction only if We are going to modify disk */
- if (end_active_trans(thd))
- goto err;
+ table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE);
- if (table->file->ha_write_row(table->record[0]))
+ if ((ret= table->file->ha_write_row(table->record[0])))
{
- my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, ret);
- goto err;
+ table->file->print_error(ret, MYF(0));
+ goto end;
}
+ ret= 0;
-ok:
- if (dbchanged)
- (void) mysql_change_db(thd, old_db.str, 1);
- /*
- This statement may cause a spooky valgrind warning at startup
- inside init_key_cache on my system (ahristov, 2006/08/10)
- */
- close_thread_tables(thd);
- DBUG_RETURN(FALSE);
-
-err:
- if (dbchanged)
- (void) mysql_change_db(thd, old_db.str, 1);
+end:
if (table)
close_thread_tables(thd);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(test(ret));
}
-/*
+/**
Used to execute ALTER EVENT. Pendant to Events::update_event().
- SYNOPSIS
- Event_db_repository::update_event()
- thd THD
- sp_name the name of the event to alter
- et event's data
+ @param[in,out] thd thread handle
+ @param[in] parse_data parsed event definition
+ @paran[in[ new_dbname not NULL if ALTER EVENT RENAME
+ points at a new database name
+ @param[in] new_name not NULL if ALTER EVENT RENAME
+ points at a new event name
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
+ @pre All semantic checks are performed outside this function,
+ it only updates the event definition on disk.
+ @pre We don't have any tables open in the given thread.
- NOTES
- sp_name is passed since this is the name of the event to
- alter in case of RENAME TO.
+ @retval FALSE success
+ @retval TRUE error (reported)
*/
bool
Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
- LEX_STRING *new_dbname, LEX_STRING *new_name)
+ LEX_STRING *new_dbname,
+ LEX_STRING *new_name)
{
CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
+ int ret= 1;
DBUG_ENTER("Event_db_repository::update_event");
- if (open_event_table(thd, TL_WRITE, &table))
- {
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- goto err;
- }
+ /* None or both must be set */
+ DBUG_ASSERT(new_dbname && new_name || new_dbname == new_name);
- if (check_parse_params(thd, parse_data))
- goto err;
+ if (open_event_table(thd, TL_WRITE, &table))
+ goto end;
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
DBUG_PRINT("info", ("name: %s", parse_data->name.str));
DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
- if (new_dbname)
- DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
/* first look whether we overwrite */
if (new_name)
{
- if (!sortcmp_lex_string(parse_data->name, *new_name, scs) &&
- !sortcmp_lex_string(parse_data->dbname, *new_dbname, scs))
- {
- my_error(ER_EVENT_SAME_NAME, MYF(0), parse_data->name.str);
- goto err;
- }
-
- if (!find_named_event(thd, *new_dbname, *new_name, table))
+ DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
+ if (!find_named_event(*new_dbname, *new_name, table))
{
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->str);
- goto err;
+ goto end;
}
}
/*
@@ -697,10 +646,10 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
overwrite the key and SE will tell us that it cannot find the already found
row (copied into record[1] later
*/
- if (find_named_event(thd, parse_data->dbname, parse_data->name, table))
+ if (find_named_event(parse_data->dbname, parse_data->name, table))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
- goto err;
+ goto end;
}
store_record(table,record[1]);
@@ -713,7 +662,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
handle it here
*/
if (mysql_event_fill_row(thd, table, parse_data, TRUE))
- goto err;
+ goto end;
if (new_dbname)
{
@@ -721,42 +670,32 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
table->field[ET_FIELD_NAME]->store(new_name->str, new_name->length, scs);
}
- /* Close active transaction only if We are going to modify disk */
- if (end_active_trans(thd))
- goto err;
-
- int res;
- if ((res= table->file->ha_update_row(table->record[1], table->record[0])))
+ if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
{
- my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, res);
- goto err;
+ table->file->print_error(ret, MYF(0));
+ goto end;
}
+ ret= 0;
- /* close mysql.event or we crash later when loading the event from disk */
- close_thread_tables(thd);
- DBUG_RETURN(FALSE);
-
-err:
+end:
if (table)
close_thread_tables(thd);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(test(ret));
}
-/*
- Drops an event
+/**
+ Delete event record from mysql.event table.
- SYNOPSIS
- Event_db_repository::drop_event()
- thd [in] THD
- db [in] Database name
- name [in] Event's name
- drop_if_exists [in] If set and the event not existing => warning
- onto the stack
+ @param[in,out] thd thread handle
+ @param[in] db Database name
+ @param[in] name Event name
+ @param[in] drop_if_exists DROP IF EXISTS clause was specified.
+ If set, and the event does not exist,
+ the error is downgraded to a warning.
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
+ @retval FALSE success
+ @retval TRUE error (reported)
*/
bool
@@ -764,70 +703,63 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
bool drop_if_exists)
{
TABLE *table= NULL;
- Open_tables_state backup;
- int ret;
+ int ret= 1;
DBUG_ENTER("Event_db_repository::drop_event");
DBUG_PRINT("enter", ("%s@%s", db.str, name.str));
- thd->reset_n_backup_open_tables_state(&backup);
- if ((ret= open_event_table(thd, TL_WRITE, &table)))
- {
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- goto done;
- }
+ if (open_event_table(thd, TL_WRITE, &table))
+ goto end;
- if (!(ret= find_named_event(thd, db, name, table)))
+ if (!find_named_event(db, name, table))
{
- /* Close active transaction only if we are actually going to modify disk */
- if (!(ret= end_active_trans(thd)) &&
- (ret= table->file->ha_delete_row(table->record[0])))
- my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
+ if ((ret= table->file->ha_delete_row(table->record[0])))
+ table->file->print_error(ret, MYF(0));
+ goto end;
}
- else
+
+ /* Event not found */
+ if (!drop_if_exists)
{
- if (drop_if_exists)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
- "Event", name.str);
- ret= 0;
- } else
- my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+ my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+ goto end;
}
-done:
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
+ "Event", name.str);
+ ret= 0;
+
+end:
if (table)
close_thread_tables(thd);
- thd->restore_backup_open_tables_state(&backup);
- DBUG_RETURN(ret);
+ DBUG_RETURN(test(ret));
}
-/*
+/**
Positions the internal pointer of `table` to the place where (db, name)
is stored.
- SYNOPSIS
- Event_db_repository::find_named_event()
- thd Thread
- db Schema
- name Event name
- table Opened mysql.event
+ In case search succeeded, the table cursor points at the found row.
- RETURN VALUE
- FALSE OK
- TRUE No such event
+ @param[in] db database name
+ @param[in] name event name
+ @param[in,out] table mysql.event table
+
+
+ @retval FALSE an event with such db/name key exists
+ @reval TRUE no record found or an error occured.
*/
bool
-Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name,
- TABLE *table)
+Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name,
+ TABLE *table)
{
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
DBUG_ENTER("Event_db_repository::find_named_event");
- DBUG_PRINT("enter", ("name: %.*s", name.length, name.str));
+ DBUG_PRINT("enter", ("name: %.*s", (int) name.length, name.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -845,8 +777,7 @@ Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name,
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0], 0, key,
- table->key_info->key_length,
+ if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
DBUG_PRINT("info", ("Row not found"));
@@ -876,39 +807,30 @@ Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
}
-/*
- Drops all events by field which has specific value of the field
+/**
+ Drops all events which have a specific value of a field.
- SYNOPSIS
- Event_db_repository::drop_events_by_field()
- thd Thread
- table mysql.event TABLE
- field Which field of the row to use for matching
- field_value The value that should match
+ @pre The thread handle has no open tables.
+
+ @param[in,out] thd Thread
+ @param[in,out] table mysql.event TABLE
+ @param[in] field Which field of the row to use for matching
+ @param[in] field_value The value that should match
*/
void
-Event_db_repository::drop_events_by_field(THD *thd,
+Event_db_repository::drop_events_by_field(THD *thd,
enum enum_events_table_field field,
LEX_STRING field_value)
{
int ret= 0;
TABLE *table= NULL;
READ_RECORD read_record_info;
- DBUG_ENTER("Event_db_repository::drop_events_by_field");
+ DBUG_ENTER("Event_db_repository::drop_events_by_field");
DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str));
if (open_event_table(thd, TL_WRITE, &table))
- {
- /*
- Currently being used only for DROP DATABASE - In this case we don't need
- error message since the OK packet has been sent. But for DROP USER we
- could need it.
-
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- */
DBUG_VOID_RETURN;
- }
/* only enabled events are in memory, so we go now and delete the rest */
init_read_record(&read_record_info, thd, table, NULL, 1, 0);
@@ -916,14 +838,20 @@ Event_db_repository::drop_events_by_field(THD *thd,
{
char *et_field= get_field(thd->mem_root, table->field[field]);
- LEX_STRING et_field_lex= { et_field, strlen(et_field) };
- DBUG_PRINT("info", ("Current event %s name=%s", et_field,
- get_field(thd->mem_root, table->field[ET_FIELD_NAME])));
-
- if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
+ /* et_field may be NULL if the table is corrupted or out of memory */
+ if (et_field)
{
- DBUG_PRINT("info", ("Dropping"));
- ret= table->file->ha_delete_row(table->record[0]);
+ LEX_STRING et_field_lex= { et_field, strlen(et_field) };
+ DBUG_PRINT("info", ("Current event %s name=%s", et_field,
+ get_field(thd->mem_root,
+ table->field[ET_FIELD_NAME])));
+
+ if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
+ {
+ DBUG_PRINT("info", ("Dropping"));
+ if ((ret= table->file->ha_delete_row(table->record[0])))
+ table->file->print_error(ret, MYF(0));
+ }
}
}
end_read_record(&read_record_info);
@@ -933,20 +861,14 @@ Event_db_repository::drop_events_by_field(THD *thd,
}
-/*
+/**
Looks for a named event in mysql.event and then loads it from
- the table, compiles and inserts it into the cache.
+ the table.
- SYNOPSIS
- Event_db_repository::load_named_event()
- thd [in] Thread context
- dbname [in] Event's db name
- name [in] Event's name
- etn [out] The loaded event
+ @pre The given thread does not have open tables.
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
+ @retval FALSE success
+ @retval TRUE error
*/
bool
@@ -954,26 +876,177 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
TABLE *table= NULL;
- int ret= 0;
- Open_tables_state backup;
+ bool ret;
DBUG_ENTER("Event_db_repository::load_named_event");
- DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd, name.length, name.str));
+ DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd,
+ (int) name.length, name.str));
- thd->reset_n_backup_open_tables_state(&backup);
+ if (!(ret= open_event_table(thd, TL_READ, &table)))
+ {
+ if ((ret= find_named_event(dbname, name, table)))
+ my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+ else if ((ret= etn->load_from_row(thd, table)))
+ my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
- if ((ret= open_event_table(thd, TL_READ, &table)))
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- else if ((ret= find_named_event(thd, dbname, name, table)))
- my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
- else if ((ret= etn->load_from_row(table)))
- my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
+ close_thread_tables(thd);
+ }
+
+
+ DBUG_RETURN(ret);
+}
+
+
+/**
+ Update the event record in mysql.event table with a changed status
+ and/or last execution time.
+
+ @pre The thread handle does not have open tables.
+*/
+
+bool
+Event_db_repository::
+update_timing_fields_for_event(THD *thd,
+ LEX_STRING event_db_name,
+ LEX_STRING event_name,
+ bool update_last_executed,
+ my_time_t last_executed,
+ bool update_status,
+ ulonglong status)
+{
+ TABLE *table= NULL;
+ Field **fields;
+ int ret= 1;
+
+ DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
+
+ /*
+ Turn off row binlogging of event timing updates. These are not used
+ for RBR of events replicated to the slave.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
+
+ if (open_event_table(thd, TL_WRITE, &table))
+ goto end;
+
+ fields= table->field;
+
+ if (find_named_event(event_db_name, event_name, table))
+ goto end;
+
+ store_record(table, record[1]);
+ /* Don't update create on row update. */
+ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+
+ if (update_last_executed)
+ {
+ MYSQL_TIME time;
+ my_tz_UTC->gmt_sec_to_TIME(&time, last_executed);
+
+ fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
+ fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
+ MYSQL_TIMESTAMP_DATETIME);
+ }
+ if (update_status)
+ {
+ fields[ET_FIELD_STATUS]->set_notnull();
+ fields[ET_FIELD_STATUS]->store(status, TRUE);
+ }
+
+ if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
+ {
+ table->file->print_error(ret, MYF(0));
+ goto end;
+ }
+ ret= 0;
+
+end:
if (table)
close_thread_tables(thd);
- thd->restore_backup_open_tables_state(&backup);
- /* In this case no memory was allocated so we don't need to clean */
+ DBUG_RETURN(test(ret));
+}
+
- DBUG_RETURN(ret);
+/**
+ Open mysql.db, mysql.user and mysql.event and check whether:
+ - mysql.db exists and is up to date (or from a newer version of MySQL),
+ - mysql.user has column Event_priv at an expected position,
+ - mysql.event exists and is up to date (or from a newer version of
+ MySQL)
+
+ This function is called only when the server is started.
+ @pre The passed in thread handle has no open tables.
+
+ @retval FALSE OK
+ @retval TRUE Error, an error message is output to the error log.
+*/
+
+bool
+Event_db_repository::check_system_tables(THD *thd)
+{
+ TABLE_LIST tables;
+ int ret= FALSE;
+ const unsigned int event_priv_column_position= 29;
+
+ DBUG_ENTER("Event_db_repository::check_system_tables");
+ DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
+
+
+ /* Check mysql.db */
+ tables.init_one_table("mysql", "db", TL_READ);
+
+ if (simple_open_n_lock_tables(thd, &tables))
+ {
+ ret= 1;
+ sql_print_error("Cannot open mysql.db");
+ }
+ else
+ {
+ if (table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT,
+ mysql_db_table_fields))
+ ret= 1;
+ /* in case of an error, the message is printed inside table_check_intact */
+
+ close_thread_tables(thd);
+ }
+ /* Check mysql.user */
+ tables.init_one_table("mysql", "user", TL_READ);
+
+ if (simple_open_n_lock_tables(thd, &tables))
+ {
+ ret= 1;
+ sql_print_error("Cannot open mysql.user");
+ }
+ else
+ {
+ if (tables.table->s->fields < event_priv_column_position ||
+ strncmp(tables.table->field[event_priv_column_position]->field_name,
+ STRING_WITH_LEN("Event_priv")))
+ {
+ sql_print_error("mysql.user has no `Event_priv` column at position %d",
+ event_priv_column_position);
+ ret= 1;
+ }
+ close_thread_tables(thd);
+ }
+ /* Check mysql.event */
+ tables.init_one_table("mysql", "event", TL_READ);
+
+ if (simple_open_n_lock_tables(thd, &tables))
+ {
+ ret= 1;
+ sql_print_error("Cannot open mysql.event");
+ }
+ else
+ {
+ if (table_check_intact(tables.table, ET_FIELD_COUNT, event_table_fields))
+ ret= 1;
+ /* in case of an error, the message is printed inside table_check_intact */
+ close_thread_tables(thd);
+ }
+
+ DBUG_RETURN(test(ret));
}
diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h
index ed74edd7e19..64e19854933 100644
--- a/sql/event_db_repository.h
+++ b/sql/event_db_repository.h
@@ -4,8 +4,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,11 +15,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define EVEX_OPEN_TABLE_FAILED -1
+/*
+ @file
+ This is a private header file of Events module. Please do not include it
+ directly. All public declarations of Events module should be stored in
+ events.h and event_data_objects.h.
+*/
enum enum_events_table_field
{
- ET_FIELD_DB = 0,
+ ET_FIELD_DB = 0,
ET_FIELD_NAME,
ET_FIELD_BODY,
ET_FIELD_DEFINER,
@@ -36,6 +40,8 @@ enum enum_events_table_field
ET_FIELD_ON_COMPLETION,
ET_FIELD_SQL_MODE,
ET_FIELD_COMMENT,
+ ET_FIELD_ORIGINATOR,
+ ET_FIELD_TIME_ZONE,
ET_FIELD_COUNT /* a cool trick to count the number of fields :) */
};
@@ -62,24 +68,35 @@ public:
update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname,
LEX_STRING *new_name);
- bool
+ bool
drop_event(THD *thd, LEX_STRING db, LEX_STRING name, bool drop_if_exists);
void
drop_schema_events(THD *thd, LEX_STRING schema);
bool
- find_named_event(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
+ find_named_event(LEX_STRING db, LEX_STRING name, TABLE *table);
bool
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
- int
+ bool
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
- int
+ bool
fill_schema_events(THD *thd, TABLE_LIST *tables, const char *db);
+ bool
+ update_timing_fields_for_event(THD *thd,
+ LEX_STRING event_db_name,
+ LEX_STRING event_name,
+ bool update_last_executed,
+ my_time_t last_executed,
+ bool update_status,
+ ulonglong status);
+public:
+ static bool
+ check_system_tables(THD *thd);
private:
void
drop_events_by_field(THD *thd, enum enum_events_table_field field,
@@ -91,12 +108,10 @@ private:
bool
table_scan_all_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table);
- static bool
- check_system_tables(THD *thd);
-
+private:
/* Prevent use of these */
Event_db_repository(const Event_db_repository &);
void operator=(Event_db_repository &);
};
-
+
#endif /* _EVENT_DB_REPOSITORY_H_ */
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 7ec665fcd5f..634cc764d74 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,7 +16,6 @@
#include "mysql_priv.h"
#include "event_queue.h"
#include "event_data_objects.h"
-#include "event_db_repository.h"
#define EVENT_QUEUE_INITIAL_SIZE 30
@@ -34,16 +32,6 @@
#define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__)
#define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__)
-struct event_queue_param
-{
- THD *thd;
- Event_queue *queue;
- pthread_mutex_t LOCK_loaded;
- pthread_cond_t COND_loaded;
- bool loading_finished;
-};
-
-
/*
Compares the execute_at members of two Event_queue_element instances.
Used as callback for the prioritized queue when shifting
@@ -64,11 +52,13 @@ struct event_queue_param
execute_at.second_part is not considered during comparison
*/
-static int
-event_queue_element_compare_q(void *vptr, byte* a, byte *b)
+static int
+event_queue_element_compare_q(void *vptr, uchar* a, uchar *b)
{
- return my_time_compare(&((Event_queue_element *)a)->execute_at,
- &((Event_queue_element *)b)->execute_at);
+ my_time_t lhs = ((Event_queue_element *)a)->execute_at;
+ my_time_t rhs = ((Event_queue_element *)b)->execute_at;
+
+ return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
}
@@ -80,41 +70,25 @@ event_queue_element_compare_q(void *vptr, byte* a, byte *b)
*/
Event_queue::Event_queue()
- :mutex_last_unlocked_at_line(0), mutex_last_locked_at_line(0),
+ :next_activation_at(0),
+ mutex_last_locked_at_line(0),
+ mutex_last_unlocked_at_line(0),
mutex_last_attempted_lock_at_line(0),
- mutex_queue_data_locked(FALSE), mutex_queue_data_attempting_lock(FALSE)
-{
- mutex_last_unlocked_in_func= mutex_last_locked_in_func=
- mutex_last_attempted_lock_in_func= "";
- set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
-}
-
-
-/*
- Inits mutexes.
-
- SYNOPSIS
- Event_queue::init_mutexes()
-*/
-
-void
-Event_queue::init_mutexes()
+ mutex_last_locked_in_func("n/a"),
+ mutex_last_unlocked_in_func("n/a"),
+ mutex_last_attempted_lock_in_func("n/a"),
+ mutex_queue_data_locked(FALSE),
+ mutex_queue_data_attempting_lock(FALSE),
+ waiting_on_cond(FALSE)
{
pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_queue_state, NULL);
}
-/*
- Destroys mutexes.
-
- SYNOPSIS
- Event_queue::deinit_mutexes()
-*/
-
-void
-Event_queue::deinit_mutexes()
+Event_queue::~Event_queue()
{
+ deinit_queue();
pthread_mutex_destroy(&LOCK_event_queue);
pthread_cond_destroy(&COND_queue_state);
}
@@ -137,39 +111,23 @@ Event_queue::deinit_mutexes()
*/
bool
-Event_queue::init_queue(THD *thd, Event_db_repository *db_repo)
+Event_queue::init_queue(THD *thd)
{
- bool res;
- struct event_queue_param *event_queue_param_value= NULL;
-
DBUG_ENTER("Event_queue::init_queue");
DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
LOCK_QUEUE_DATA();
- db_repository= db_repo;
if (init_queue_ex(&queue, EVENT_QUEUE_INITIAL_SIZE , 0 /*offset*/,
0 /*max_on_top*/, event_queue_element_compare_q,
NULL, EVENT_QUEUE_EXTENT))
{
- sql_print_error("SCHEDULER: Can't initialize the execution queue");
- goto err;
- }
-
- if (sizeof(my_time_t) != sizeof(time_t))
- {
- sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
- "The scheduler may not work correctly. Stopping");
- DBUG_ASSERT(0);
+ sql_print_error("Event Scheduler: Can't initialize the execution queue");
goto err;
}
- res= load_events_from_db(thd);
UNLOCK_QUEUE_DATA();
- if (res)
- deinit_queue();
-
- DBUG_RETURN(res);
+ DBUG_RETURN(FALSE);
err:
UNLOCK_QUEUE_DATA();
@@ -199,44 +157,50 @@ Event_queue::deinit_queue()
}
-/*
+/**
Adds an event to the queue.
- SYNOPSIS
- Event_queue::create_event()
- dbname The schema of the new event
- name The name of the new event
+ Compute the next execution time for an event, and if it is still
+ active, add it to the queue. Otherwise delete it.
+ The object is left intact in case of an error. Otherwise
+ the queue container assumes ownership of it.
- RETURN VALUE
- OP_OK OK or scheduler not working
- OP_LOAD_ERROR Error during loading from disk
+ @param[in] thd thread handle
+ @param[in] new_element a new element to add to the queue
+ @param[out] created set to TRUE if no error and the element is
+ added to the queue, FALSE otherwise
+
+ @retval TRUE an error occured. The value of created is undefined,
+ the element was not deleted.
+ @retval FALSE success
*/
-int
-Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
+bool
+Event_queue::create_event(THD *thd, Event_queue_element *new_element,
+ bool *created)
{
- int res;
- Event_queue_element *new_element;
DBUG_ENTER("Event_queue::create_event");
- DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd, dbname.str, name.str));
+ DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd,
+ new_element->dbname.str, new_element->name.str));
- new_element= new Event_queue_element();
- res= db_repository->load_named_event(thd, dbname, name, new_element);
- if (res || new_element->status == Event_queue_element::DISABLED)
- delete new_element;
- else
+ /* Will do nothing if the event is disabled */
+ new_element->compute_next_execution_time();
+ if (new_element->status != Event_queue_element::ENABLED)
{
- new_element->compute_next_execution_time();
-
- LOCK_QUEUE_DATA();
- DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
- queue_insert_safe(&queue, (byte *) new_element);
- dbug_dump_queue(thd->query_start());
- pthread_cond_broadcast(&COND_queue_state);
- UNLOCK_QUEUE_DATA();
+ delete new_element;
+ *created= FALSE;
+ DBUG_RETURN(FALSE);
}
- DBUG_RETURN(res);
+ DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
+
+ LOCK_QUEUE_DATA();
+ *created= (queue_insert_safe(&queue, (uchar *) new_element) == FALSE);
+ dbug_dump_queue(thd->query_start());
+ pthread_cond_broadcast(&COND_queue_state);
+ UNLOCK_QUEUE_DATA();
+
+ DBUG_RETURN(!*created);
}
@@ -250,32 +214,17 @@ Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
name Name of the event
new_schema New schema, in case of RENAME TO, otherwise NULL
new_name New name, in case of RENAME TO, otherwise NULL
-
- RETURN VALUE
- OP_OK OK or scheduler not working
- OP_LOAD_ERROR Error during loading from disk
*/
-int
+void
Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
- LEX_STRING *new_schema, LEX_STRING *new_name)
+ Event_queue_element *new_element)
{
- int res;
- Event_queue_element *new_element;
-
DBUG_ENTER("Event_queue::update_event");
DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str));
- new_element= new Event_queue_element();
-
- res= db_repository->load_named_event(thd, new_schema ? *new_schema:dbname,
- new_name ? *new_name:name, new_element);
- if (res)
- {
- delete new_element;
- goto end;
- }
- else if (new_element->status == Event_queue_element::DISABLED)
+ if ((new_element->status == Event_queue_element::DISABLED) ||
+ (new_element->status == Event_queue_element::SLAVESIDE_DISABLED))
{
DBUG_PRINT("info", ("The event is disabled."));
/*
@@ -295,16 +244,14 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
if (new_element)
{
DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
- queue_insert_safe(&queue, (byte *) new_element);
- pthread_cond_broadcast(&COND_queue_state);
+ queue_insert_safe(&queue, (uchar *) new_element);
+ pthread_cond_broadcast(&COND_queue_state);
}
dbug_dump_queue(thd->query_start());
UNLOCK_QUEUE_DATA();
-end:
- DBUG_PRINT("info", ("res=%d", res));
- DBUG_RETURN(res);
+ DBUG_VOID_RETURN;
}
@@ -329,7 +276,7 @@ Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
find_n_remove_event(dbname, name);
dbug_dump_queue(thd->query_start());
UNLOCK_QUEUE_DATA();
-
+
/*
We don't signal here because the scheduler will catch the change
next time it wakes up.
@@ -351,7 +298,7 @@ Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
RETURN VALUE
>=0 Number of dropped events
-
+
NOTE
Expected is the caller to acquire lock on LOCK_event_queue
*/
@@ -383,7 +330,7 @@ Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
i++;
}
/*
- We don't call pthread_cond_broadcast(&COND_queue_state);
+ We don't call pthread_cond_broadcast(&COND_queue_state);
If we remove the top event:
1. The queue is empty. The scheduler will wake up at some time and
realize that the queue is empty. If create_event() comes inbetween
@@ -456,133 +403,6 @@ Event_queue::find_n_remove_event(LEX_STRING db, LEX_STRING name)
/*
- Loads all ENABLED events from mysql.event into the prioritized
- queue. Called during scheduler main thread initialization. Compiles
- the events. Creates Event_queue_element instances for every ENABLED event
- from mysql.event.
-
- SYNOPSIS
- Event_queue::load_events_from_db()
- thd - Thread context. Used for memory allocation in some cases.
-
- RETURN VALUE
- 0 OK
- !0 Error (EVEX_OPEN_TABLE_FAILED, EVEX_MICROSECOND_UNSUP,
- EVEX_COMPILE_ERROR) - in all these cases mysql.event was
- tampered.
-
- NOTES
- Reports the error to the console
-*/
-
-int
-Event_queue::load_events_from_db(THD *thd)
-{
- TABLE *table;
- READ_RECORD read_record_info;
- int ret= -1;
- uint count= 0;
- bool clean_the_queue= TRUE;
-
- DBUG_ENTER("Event_queue::load_events_from_db");
- DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
-
- if ((ret= db_repository->open_event_table(thd, TL_READ, &table)))
- {
- sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open");
- DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
- }
-
- init_read_record(&read_record_info, thd, table ,NULL,1,0);
- while (!(read_record_info.read_record(&read_record_info)))
- {
- Event_queue_element *et;
- if (!(et= new Event_queue_element))
- {
- DBUG_PRINT("info", ("Out of memory"));
- break;
- }
- DBUG_PRINT("info", ("Loading event from row."));
-
- if ((ret= et->load_from_row(table)))
- {
- sql_print_error("SCHEDULER: Error while loading from mysql.event. "
- "Table probably corrupted");
- break;
- }
- if (et->status != Event_queue_element::ENABLED)
- {
- DBUG_PRINT("info",("%s is disabled",et->name.str));
- delete et;
- continue;
- }
-
- /* let's find when to be executed */
- if (et->compute_next_execution_time())
- {
- sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
- " Skipping", et->dbname.str, et->name.str);
- continue;
- }
-
- {
- Event_job_data temp_job_data;
- DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
-
- temp_job_data.load_from_row(table);
-
- /*
- We load only on scheduler root just to check whether the body
- compiles.
- */
- switch (ret= temp_job_data.compile(thd, thd->mem_root)) {
- case EVEX_MICROSECOND_UNSUP:
- sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
- "supported but found in mysql.event");
- break;
- case EVEX_COMPILE_ERROR:
- sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load",
- et->dbname.str, et->name.str);
- break;
- default:
- break;
- }
- thd->end_statement();
- thd->cleanup_after_query();
- }
- if (ret)
- {
- delete et;
- goto end;
- }
-
- queue_insert_safe(&queue, (byte *) et);
- count++;
- }
- clean_the_queue= FALSE;
-end:
- end_read_record(&read_record_info);
-
- if (clean_the_queue)
- {
- empty_queue();
- ret= -1;
- }
- else
- {
- ret= 0;
- sql_print_information("SCHEDULER: Loaded %d event%s", count,
- (count == 1)?"":"s");
- }
-
- close_thread_tables(thd);
-
- DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
- DBUG_RETURN(ret);
-}
-
-
-/*
Recalculates activation times in the queue. There is one reason for
that. Because the values (execute_at) by which the queue is ordered are
changed by calls to compute_next_execution_time() on a request from the
@@ -631,8 +451,9 @@ Event_queue::empty_queue()
{
uint i;
DBUG_ENTER("Event_queue::empty_queue");
- DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements));
- sql_print_information("SCHEDULER: Purging queue. %u events", queue.elements);
+ DBUG_PRINT("enter", ("Purging the queue. %u element(s)", queue.elements));
+ sql_print_information("Event Scheduler: Purging the queue. %u events",
+ queue.elements);
/* empty the queue */
for (i= 0; i < queue.elements; ++i)
{
@@ -668,15 +489,11 @@ Event_queue::dbug_dump_queue(time_t now)
DBUG_PRINT("info", ("exec_at: %lu starts: %lu ends: %lu execs_so_far: %u "
"expr: %ld et.exec_at: %ld now: %ld "
"(et.exec_at - now): %d if: %d",
- (long) TIME_to_ulonglong_datetime(&et->execute_at),
- (long) TIME_to_ulonglong_datetime(&et->starts),
- (long) TIME_to_ulonglong_datetime(&et->ends),
- et->execution_count,
- (long) et->expression,
- (long) (sec_since_epoch_TIME(&et->execute_at)),
- (long) now,
- (int) (sec_since_epoch_TIME(&et->execute_at) - now),
- sec_since_epoch_TIME(&et->execute_at) <= now));
+ (long) et->execute_at, (long) et->starts,
+ (long) et->ends, et->execution_count,
+ (long) et->expression, (long) et->execute_at,
+ (long) now, (int) (et->execute_at - now),
+ et->execute_at <= now));
}
DBUG_VOID_RETURN;
#endif
@@ -692,136 +509,104 @@ static const char *queue_wait_msg= "Waiting for next activation";
SYNOPSIS
Event_queue::get_top_for_execution_if_time()
- thd [in] Thread
- now [in] Current timestamp
- job_data [out] The object to execute
- abstime [out] Time to sleep
+ thd [in] Thread
+ event_name [out] The object to execute
RETURN VALUE
- FALSE No error. If *job_data==NULL then top not elligible for execution.
- Could be that there is no top. If abstime->tv_sec is set to value
- greater than zero then use abstime with pthread_cond_timedwait().
- If abstime->tv_sec is zero then sleep with pthread_cond_wait().
- abstime->tv_nsec is always zero.
- TRUE Error
-
+ FALSE No error. event_name != NULL
+ TRUE Serious error
*/
bool
-Event_queue::get_top_for_execution_if_time(THD *thd, Event_job_data **job_data)
+Event_queue::get_top_for_execution_if_time(THD *thd,
+ Event_queue_element_for_exec **event_name)
{
bool ret= FALSE;
- struct timespec top_time;
- struct timespec *abstime;
- Event_queue_element *top= NULL;
- bool to_free= FALSE;
- bool to_drop= FALSE;
- *job_data= NULL;
+ *event_name= NULL;
DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
- top_time.tv_nsec= 0;
LOCK_QUEUE_DATA();
for (;;)
{
- int res;
+ Event_queue_element *top= NULL;
- thd->end_time();
- time_t now= thd->query_start();
- abstime= NULL;
+ /* Break loop if thd has been killed */
+ if (thd->killed)
+ {
+ DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
+ goto end;
+ }
- if (queue.elements)
+ if (!queue.elements)
{
- top= ((Event_queue_element*) queue_element(&queue, 0));
- top_time.tv_sec= sec_since_epoch_TIME(&top->execute_at);
+ /* There are no events in the queue */
+ next_activation_at= 0;
- abstime= &top_time;
+ /* Wait on condition until signaled. Release LOCK_queue while waiting. */
+ cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
+
+ continue;
}
- if (!abstime || abstime->tv_sec > now)
+ top= ((Event_queue_element*) queue_element(&queue, 0));
+
+ thd->end_time(); /* Get current time */
+
+ next_activation_at= top->execute_at;
+ if (next_activation_at > thd->query_start())
{
- const char *msg;
- if (abstime)
- {
- next_activation_at= top->execute_at;
- msg= queue_wait_msg;
- }
- else
- {
- set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
- msg= queue_wait_msg;
- }
-
- cond_wait(thd, abstime, msg, SCHED_FUNC, __LINE__);
- if (thd->killed)
- {
- DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
- goto end;
- }
/*
- The queue could have been emptied. Therefore it's safe to start from
- the beginning. Moreover, this way we will get also the new top, if
- the element at the top has been changed.
+ Not yet time for top event, wait on condition with
+ time or until signaled. Release LOCK_queue while waiting.
*/
+ struct timespec top_time;
+ set_timespec(top_time, next_activation_at - thd->query_start());
+ cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
+
continue;
}
- DBUG_PRINT("info", ("Ready for execution"));
- if (!(*job_data= new Event_job_data()))
- {
- ret= TRUE;
- break;
- }
- if ((res= db_repository->load_named_event(thd, top->dbname, top->name,
- *job_data)))
+ if (!(*event_name= new Event_queue_element_for_exec()) ||
+ (*event_name)->init(top->dbname, top->name))
{
- DBUG_PRINT("error", ("Got %d from load_named_event", res));
- delete *job_data;
- *job_data= NULL;
ret= TRUE;
break;
}
+ DBUG_PRINT("info", ("Ready for execution"));
top->mark_last_executed(thd);
if (top->compute_next_execution_time())
top->status= Event_queue_element::DISABLED;
DBUG_PRINT("info", ("event %s status is %d", top->name.str, top->status));
- (*job_data)->execution_count= top->execution_count;
+ top->execution_count++;
+ (*event_name)->dropped= top->dropped;
top->update_timing_fields(thd);
- if (((top->execute_at.year && !top->expression) || top->execute_at_null) ||
- (top->status == Event_queue_element::DISABLED))
+ if (top->status == Event_queue_element::DISABLED)
{
DBUG_PRINT("info", ("removing from the queue"));
- sql_print_information("SCHEDULER: Last execution of %s.%s. %s",
+ sql_print_information("Event Scheduler: Last execution of %s.%s. %s",
top->dbname.str, top->name.str,
top->dropped? "Dropping.":"");
- to_free= TRUE;
- to_drop= top->dropped;
+ delete top;
queue_remove(&queue, 0);
}
else
queue_replaced(&queue);
- dbug_dump_queue(now);
+ dbug_dump_queue(thd->query_start());
break;
}
end:
UNLOCK_QUEUE_DATA();
- if (to_drop)
- {
- DBUG_PRINT("info", ("Dropping from disk"));
- top->drop(thd);
- }
- if (to_free)
- delete top;
- DBUG_PRINT("info", ("returning %d et_new: 0x%lx abstime.tv_sec: %ld ",
- ret, (long) *job_data, abstime ? abstime->tv_sec : 0));
+ DBUG_PRINT("info", ("returning %d et_new: 0x%lx ",
+ ret, (long) *event_name));
- if (*job_data)
- DBUG_PRINT("info", ("db: %s name: %s definer=%s", (*job_data)->dbname.str,
- (*job_data)->name.str, (*job_data)->definer.str));
+ if (*event_name)
+ DBUG_PRINT("info", ("db: %s name: %s",
+ (*event_name)->dbname.str, (*event_name)->name.str));
DBUG_RETURN(ret);
}
@@ -953,10 +738,14 @@ Event_queue::dump_internal_status()
printf("Last lock attempt at: %s:%u\n", mutex_last_attempted_lock_in_func,
mutex_last_attempted_lock_at_line);
printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
- printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
- next_activation_at.year, next_activation_at.month,
- next_activation_at.day, next_activation_at.hour,
- next_activation_at.minute, next_activation_at.second);
+
+ MYSQL_TIME time;
+ my_tz_UTC->gmt_sec_to_TIME(&time, next_activation_at);
+ if (time.year != 1970)
+ printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
+ time.year, time.month, time.day, time.hour, time.minute, time.second);
+ else
+ printf("Next activation : never");
DBUG_VOID_RETURN;
}
diff --git a/sql/event_queue.h b/sql/event_queue.h
index 5b70506d388..ac4a4f2bfd7 100644
--- a/sql/event_queue.h
+++ b/sql/event_queue.h
@@ -4,8 +4,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,38 +16,29 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class Event_basic;
-class Event_db_repository;
-class Event_job_data;
class Event_queue_element;
+class Event_queue_element_for_exec;
class THD;
-class Event_scheduler;
class Event_queue
{
public:
Event_queue();
-
- void
- init_mutexes();
-
- void
- deinit_mutexes();
+ ~Event_queue();
bool
- init_queue(THD *thd, Event_db_repository *db_repo);
-
- void
- deinit_queue();
+ init_queue(THD *thd);
/* Methods for queue management follow */
- int
- create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
+ bool
+ create_event(THD *thd, Event_queue_element *new_element,
+ bool *created);
- int
+ void
update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
- LEX_STRING *new_schema, LEX_STRING *new_name);
+ Event_queue_element *new_element);
void
drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
@@ -60,15 +50,30 @@ public:
recalculate_activation_times(THD *thd);
bool
- get_top_for_execution_if_time(THD *thd, Event_job_data **job_data);
+ get_top_for_execution_if_time(THD *thd,
+ Event_queue_element_for_exec **event_name);
+
void
dump_internal_status();
- int
- load_events_from_db(THD *thd);
+private:
+ void
+ empty_queue();
+
+ void
+ deinit_queue();
+ /* helper functions for working with mutexes & conditionals */
+ void
+ lock_data(const char *func, uint line);
+
+ void
+ unlock_data(const char *func, uint line);
+
+ void
+ cond_wait(THD *thd, struct timespec *abstime, const char* msg,
+ const char *func, uint line);
-protected:
void
find_n_remove_event(LEX_STRING db, LEX_STRING name);
@@ -77,8 +82,6 @@ protected:
drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*)(LEX_STRING, Event_basic *));
- void
- empty_queue();
void
dbug_dump_queue(time_t now);
@@ -87,14 +90,10 @@ protected:
pthread_mutex_t LOCK_event_queue;
pthread_cond_t COND_queue_state;
- Event_db_repository *db_repository;
-
- Event_scheduler *scheduler;
-
- /* The sorted queue with the Event_job_data objects */
+ /* The sorted queue with the Event_queue_element objects */
QUEUE queue;
- TIME next_activation_at;
+ my_time_t next_activation_at;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
@@ -105,17 +104,6 @@ protected:
bool mutex_queue_data_locked;
bool mutex_queue_data_attempting_lock;
bool waiting_on_cond;
-
- /* helper functions for working with mutexes & conditionals */
- void
- lock_data(const char *func, uint line);
-
- void
- unlock_data(const char *func, uint line);
-
- void
- cond_wait(THD *thd, struct timespec *abstime, const char* msg,
- const char *func, uint line);
};
#endif /* _EVENT_QUEUE_H_ */
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 1e9526b3364..478ae0098da 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,6 +18,7 @@
#include "event_data_objects.h"
#include "event_scheduler.h"
#include "event_queue.h"
+#include "event_db_repository.h"
#ifdef __GNUC__
#if __GNUC__ >= 2
@@ -35,10 +35,13 @@
extern pthread_attr_t connection_attrib;
+
+Event_db_repository *Event_worker_thread::db_repository;
+
+
static
const LEX_STRING scheduler_states_names[] =
{
- { C_STRING_WITH_LEN("UNINITIALIZED") },
{ C_STRING_WITH_LEN("INITIALIZED") },
{ C_STRING_WITH_LEN("RUNNING") },
{ C_STRING_WITH_LEN("STOPPING") }
@@ -61,8 +64,8 @@ struct scheduler_param {
et The event itself
*/
-static void
-evex_print_warnings(THD *thd, Event_job_data *et)
+void
+Event_worker_thread::print_warnings(THD *thd, Event_job_data *et)
{
MYSQL_ERROR *err;
DBUG_ENTER("evex_print_warnings");
@@ -73,13 +76,13 @@ evex_print_warnings(THD *thd, Event_job_data *et)
char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE];
String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
prefix.length(0);
- prefix.append("SCHEDULER: [");
+ prefix.append("Event Scheduler: [");
- append_identifier(thd, &prefix, et->definer.str, et->definer.length);
+ prefix.append(et->definer.str, et->definer.length, system_charset_info);
prefix.append("][", 2);
- append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
+ prefix.append(et->dbname.str, et->dbname.length, system_charset_info);
prefix.append('.');
- append_identifier(thd,&prefix, et->name.str, et->name.length);
+ prefix.append(et->name.str, et->name.length, system_charset_info);
prefix.append("] ", 2);
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
@@ -90,7 +93,6 @@ evex_print_warnings(THD *thd, Event_job_data *et)
err_msg.length(0);
err_msg.append(prefix);
err_msg.append(err->msg, strlen(err->msg), system_charset_info);
- err_msg.append("]");
DBUG_ASSERT(err->level < 3);
(sql_print_message_handlers[err->level])("%*s", err_msg.length(),
err_msg.c_ptr());
@@ -105,25 +107,22 @@ evex_print_warnings(THD *thd, Event_job_data *et)
SYNOPSIS
post_init_event_thread()
thd Thread
+
+ NOTES
+ Before this is called, one should not do any DBUG_XXX() calls.
+
*/
bool
post_init_event_thread(THD *thd)
{
- my_thread_init();
- pthread_detach_this_thread();
- thd->real_id= pthread_self();
+ (void) init_new_connection_handler_thread();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
return TRUE;
}
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd);
thread_count++;
@@ -154,8 +153,6 @@ deinit_event_thread(THD *thd)
thread_running--;
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
-
- my_thread_end();
}
@@ -188,7 +185,7 @@ pre_init_event_thread(THD* thd)
thd->options|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id= thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
/*
@@ -219,26 +216,25 @@ pthread_handler_t
event_scheduler_thread(void *arg)
{
/* needs to be first for thread_stack */
- THD *thd= (THD *)((struct scheduler_param *) arg)->thd;
+ THD *thd= (THD *) ((struct scheduler_param *) arg)->thd;
Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler;
-
- my_free((char*)arg, MYF(0));
+ bool res;
thd->thread_stack= (char *)&thd; // remember where our stack is
+ res= post_init_event_thread(thd);
DBUG_ENTER("event_scheduler_thread");
-
- if (!post_init_event_thread(thd))
+ my_free((char*)arg, MYF(0));
+ if (!res)
scheduler->run(thd);
- deinit_event_thread(thd);
-
+ my_thread_end();
DBUG_RETURN(0); // Against gcc warnings
}
-/*
- Function that executes an event in a child thread. Setups the
+/**
+ Function that executes an event in a child thread. Setups the
environment for the event execution and cleans after that.
SYNOPSIS
@@ -252,103 +248,107 @@ event_scheduler_thread(void *arg)
pthread_handler_t
event_worker_thread(void *arg)
{
- /* needs to be first for thread_stack */
- THD *thd;
- Event_job_data *event= (Event_job_data *)arg;
- int ret;
+ THD *thd;
+ Event_queue_element_for_exec *event= (Event_queue_element_for_exec *)arg;
thd= event->thd;
- thd->thread_stack= (char *) &thd; // remember where our stack is
- DBUG_ENTER("event_worker_thread");
+ Event_worker_thread worker_thread;
+ worker_thread.run(thd, event);
- if (!post_init_event_thread(thd))
- {
- DBUG_PRINT("info", ("Baikonur, time is %ld, BURAN reporting and operational."
- "THD: 0x%lx",
- (long) time(NULL), (long) thd));
-
- sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu. "
- "Execution %u",
- event->dbname.str, event->name.str,
- event->definer.str, thd->thread_id,
- event->execution_count);
-
- thd->enable_slow_log= TRUE;
-
- ret= event->execute(thd);
-
- evex_print_warnings(thd, event);
-
- sql_print_information("SCHEDULER: [%s.%s of %s] executed in thread %lu. "
- "RetCode=%d", event->dbname.str, event->name.str,
- event->definer.str, thd->thread_id, ret);
- if (ret == EVEX_COMPILE_ERROR)
- sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
- event->dbname.str, event->name.str,
- event->definer.str);
- else if (ret == EVEX_MICROSECOND_UNSUP)
- sql_print_information("SCHEDULER: MICROSECOND is not supported");
- }
- DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
- event->name.str));
- delete event;
-
- deinit_event_thread(thd);
-
- DBUG_RETURN(0); // Can't return anything here
+ my_thread_end();
+ return 0; // Can't return anything here
}
-/*
- Performs initialization of the scheduler data, outside of the
- threading primitives.
+/**
+ Function that executes an event in a child thread. Setups the
+ environment for the event execution and cleans after that.
SYNOPSIS
- Event_scheduler::init_scheduler()
+ Event_worker_thread::run()
+ thd Thread context
+ event The Event_queue_element_for_exec object to be processed
*/
void
-Event_scheduler::init_scheduler(Event_queue *q)
+Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
{
- LOCK_DATA();
- queue= q;
- started_events= 0;
- scheduler_thd= NULL;
- state= INITIALIZED;
- UNLOCK_DATA();
-}
+ /* needs to be first for thread_stack */
+ char my_stack;
+ Event_job_data job_data;
+ bool res;
+ thd->thread_stack= &my_stack; // remember where our stack is
+ res= post_init_event_thread(thd);
-void
-Event_scheduler::deinit_scheduler() {}
+ DBUG_ENTER("Event_worker_thread::run");
+ DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx",
+ (long) time(NULL), (long) thd));
+ if (res)
+ goto end;
-/*
- Inits scheduler's threading primitives.
+ if ((res= db_repository->load_named_event(thd, event->dbname, event->name,
+ &job_data)))
+ {
+ DBUG_PRINT("error", ("Got error from load_named_event"));
+ goto end;
+ }
- SYNOPSIS
- Event_scheduler::init_mutexes()
-*/
+ sql_print_information("Event Scheduler: "
+ "[%s].[%s.%s] started in thread %lu.",
+ job_data.definer.str,
+ job_data.dbname.str, job_data.name.str,
+ thd->thread_id);
-void
-Event_scheduler::init_mutexes()
+ thd->enable_slow_log= TRUE;
+
+ res= job_data.execute(thd, event->dropped);
+
+ print_warnings(thd, &job_data);
+
+ if (res)
+ sql_print_information("Event Scheduler: "
+ "[%s].[%s.%s] event execution failed.",
+ job_data.definer.str,
+ job_data.dbname.str, job_data.name.str);
+ else
+ sql_print_information("Event Scheduler: "
+ "[%s].[%s.%s] executed successfully in thread %lu.",
+ job_data.definer.str,
+ job_data.dbname.str, job_data.name.str,
+ thd->thread_id);
+
+end:
+ DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str,
+ event->name.str));
+
+ delete event;
+ deinit_event_thread(thd);
+}
+
+
+Event_scheduler::Event_scheduler(Event_queue *queue_arg)
+ :state(INITIALIZED),
+ scheduler_thd(NULL),
+ queue(queue_arg),
+ mutex_last_locked_at_line(0),
+ mutex_last_unlocked_at_line(0),
+ mutex_last_locked_in_func("n/a"),
+ mutex_last_unlocked_in_func("n/a"),
+ mutex_scheduler_data_locked(FALSE),
+ waiting_on_cond(FALSE),
+ started_events(0)
{
pthread_mutex_init(&LOCK_scheduler_state, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_state, NULL);
}
-/*
- Deinits scheduler's threading primitives.
-
- SYNOPSIS
- Event_scheduler::deinit_mutexes()
-*/
-
-void
-Event_scheduler::deinit_mutexes()
+Event_scheduler::~Event_scheduler()
{
+ stop(); /* does nothing if not running */
pthread_mutex_destroy(&LOCK_scheduler_state);
pthread_cond_destroy(&COND_state);
}
@@ -385,7 +385,7 @@ Event_scheduler::start()
if (!(new_thd= new THD))
{
- sql_print_error("SCHEDULER: Cannot init manager event thread");
+ sql_print_error("Event Scheduler: Cannot initialize the scheduler thread");
ret= TRUE;
goto end;
}
@@ -401,7 +401,7 @@ Event_scheduler::start()
scheduler_thd= new_thd;
DBUG_PRINT("info", ("Setting state go RUNNING"));
state= RUNNING;
- DBUG_PRINT("info", ("Forking new thread for scheduduler. THD: 0x%lx", (long) new_thd));
+ DBUG_PRINT("info", ("Forking new thread for scheduler. THD: 0x%lx", (long) new_thd));
if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
(void*)scheduler_param_value))
{
@@ -442,10 +442,9 @@ bool
Event_scheduler::run(THD *thd)
{
int res= FALSE;
- Event_job_data *job_data;
DBUG_ENTER("Event_scheduler::run");
- sql_print_information("SCHEDULER: Manager thread started with id %lu",
+ sql_print_information("Event Scheduler: scheduler thread started with id %lu",
thd->thread_id);
/*
Recalculate the values in the queue because there could have been stops
@@ -455,18 +454,22 @@ Event_scheduler::run(THD *thd)
while (is_running())
{
+ Event_queue_element_for_exec *event_name;
+
/* Gets a minimized version */
- if (queue->get_top_for_execution_if_time(thd, &job_data))
+ if (queue->get_top_for_execution_if_time(thd, &event_name))
{
- sql_print_information("SCHEDULER: Serious error during getting next "
+ sql_print_information("Event Scheduler: "
+ "Serious error during getting next "
"event to execute. Stopping");
break;
}
- DBUG_PRINT("info", ("get_top returned job_data: 0x%lx", (long) job_data));
- if (job_data)
+ DBUG_PRINT("info", ("get_top_for_execution_if_time returned "
+ "event_name=0x%lx", (long) event_name));
+ if (event_name)
{
- if ((res= execute_top(thd, job_data)))
+ if ((res= execute_top(event_name)))
break;
}
else
@@ -476,12 +479,14 @@ Event_scheduler::run(THD *thd)
}
DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
}
+
LOCK_DATA();
- DBUG_PRINT("info", ("Signalling back to the stopper COND_state"));
+ deinit_event_thread(thd);
+ scheduler_thd= NULL;
state= INITIALIZED;
+ DBUG_PRINT("info", ("Signalling back to the stopper COND_state"));
pthread_cond_signal(&COND_state);
UNLOCK_DATA();
- sql_print_information("SCHEDULER: Stopped");
DBUG_RETURN(res);
}
@@ -500,7 +505,7 @@ Event_scheduler::run(THD *thd)
*/
bool
-Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
+Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
{
THD *new_thd;
pthread_t th;
@@ -511,22 +516,30 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
- job_data->thd= new_thd;
- DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
- job_data->dbname.str, job_data->name.str));
+ event_name->thd= new_thd;
+ DBUG_PRINT("info", ("Event %s@%s ready for start",
+ event_name->dbname.str, event_name->name.str));
+ /*
+ TODO: should use thread pool here, preferably with an upper limit
+ on number of threads: if too many events are scheduled for the
+ same time, starting all of them at once won't help them run truly
+ in parallel (because of the great amount of synchronization), so
+ we may as well execute them in sequence, keeping concurrency at a
+ reasonable level.
+ */
/* Major failure */
if ((res= pthread_create(&th, &connection_attrib, event_worker_thread,
- job_data)))
+ event_name)))
goto error;
++started_events;
- DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD: 0x%lx", (long) new_thd));
+ DBUG_PRINT("info", ("Event is in THD: 0x%lx", (long) new_thd));
DBUG_RETURN(FALSE);
error:
- DBUG_PRINT("error", ("Baikonur, we have a problem! res: %d", res));
+ DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res));
if (new_thd)
{
new_thd->proc_info= "Clearing";
@@ -538,7 +551,7 @@ error:
delete new_thd;
pthread_mutex_unlock(&LOCK_thread_count);
}
- delete job_data;
+ delete event_name;
DBUG_RETURN(TRUE);
}
@@ -564,10 +577,13 @@ Event_scheduler::is_running()
}
-/*
+/**
Stops the scheduler (again). Waits for acknowledgement from the
scheduler that it has stopped - synchronous stopping.
+ Already running events will not be stopped. If the user needs
+ them stopped manual intervention is needed.
+
SYNOPSIS
Event_scheduler::stop()
@@ -590,8 +606,8 @@ Event_scheduler::stop()
/* Guarantee we don't catch spurious signals */
do {
- DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from the manager "
- "thread. Current value of state is %s . "
+ DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from "
+ "the scheduler thread. Current value of state is %s . "
"workers count=%d", scheduler_states_names[state].str,
workers_count()));
/*
@@ -605,31 +621,24 @@ Event_scheduler::stop()
*/
state= STOPPING;
- DBUG_PRINT("info", ("Manager thread has id %lu", scheduler_thd->thread_id));
+ DBUG_PRINT("info", ("Scheduler thread has id %lu",
+ scheduler_thd->thread_id));
/* Lock from delete */
pthread_mutex_lock(&scheduler_thd->LOCK_delete);
/* This will wake up the thread if it waits on Queue's conditional */
- sql_print_information("SCHEDULER: Killing manager thread %lu",
+ sql_print_information("Event Scheduler: Killing the scheduler thread, "
+ "thread id %lu",
scheduler_thd->thread_id);
scheduler_thd->awake(THD::KILL_CONNECTION);
pthread_mutex_unlock(&scheduler_thd->LOCK_delete);
/* thd could be 0x0, when shutting down */
- sql_print_information("SCHEDULER: Waiting the manager thread to reply");
+ sql_print_information("Event Scheduler: "
+ "Waiting for the scheduler thread to reply");
COND_STATE_WAIT(thd, NULL, "Waiting scheduler to stop");
} while (state == STOPPING);
- DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
- /*
- The rationale behind setting it to NULL here but not destructing it
- beforehand is because the THD will be deinited in event_scheduler_thread().
- It's more clear when the post_init and the deinit is done in one function.
- Here we just mark that the scheduler doesn't have a THD anymore. Though for
- milliseconds the old thread could exist we can't use it anymore. When we
- unlock the mutex in this function a little later the state will be
- INITIALIZED. Therefore, a connection thread could enter the critical section
- and will create a new THD object.
- */
- scheduler_thd= NULL;
+ DBUG_PRINT("info", ("Scheduler thread has cleaned up. Set state to INIT"));
+ sql_print_information("Event Scheduler: Stopped");
end:
UNLOCK_DATA();
DBUG_RETURN(FALSE);
@@ -648,7 +657,7 @@ Event_scheduler::workers_count()
{
THD *tmp;
uint count= 0;
-
+
DBUG_ENTER("Event_scheduler::workers_count");
pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
I_List_iterator<THD> it(threads);
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h
index dffaf8c056c..eba66c68d42 100644
--- a/sql/event_scheduler.h
+++ b/sql/event_scheduler.h
@@ -4,8 +4,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,8 +15,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/**
+ @file
+ This file is internal to Events module. Please do not include it directly.
+ All public declarations of Events module are in events.h and
+ event_data_objects.h.
+*/
+
+
class Event_queue;
class Event_job_data;
+class Event_db_repository;
+class Events;
void
pre_init_event_thread(THD* thd);
@@ -28,11 +37,33 @@ post_init_event_thread(THD* thd);
void
deinit_event_thread(THD *thd);
+
+class Event_worker_thread
+{
+public:
+ static void
+ init(Event_db_repository *db_repository_arg)
+ {
+ db_repository= db_repository_arg;
+ }
+
+ void
+ run(THD *thd, Event_queue_element_for_exec *event);
+
+private:
+ void
+ print_warnings(THD *thd, Event_job_data *et);
+
+ static Event_db_repository *db_repository;
+};
+
+
class Event_scheduler
{
public:
- Event_scheduler():state(UNINITIALIZED){}
- ~Event_scheduler(){}
+ Event_scheduler(Event_queue *event_queue_arg);
+ ~Event_scheduler();
+
/* State changing methods follow */
@@ -49,17 +80,6 @@ public:
bool
run(THD *thd);
- void
- init_scheduler(Event_queue *queue);
-
- void
- deinit_scheduler();
-
- void
- init_mutexes();
-
- void
- deinit_mutexes();
/* Information retrieving methods follow */
bool
@@ -72,10 +92,9 @@ private:
uint
workers_count();
-
/* helper functions */
bool
- execute_top(THD *thd, Event_job_data *job_data);
+ execute_top(Event_queue_element_for_exec *event_name);
/* helper functions for working with mutexes & conditionals */
void
@@ -92,8 +111,7 @@ private:
enum enum_state
{
- UNINITIALIZED = 0,
- INITIALIZED,
+ INITIALIZED = 0,
RUNNING,
STOPPING
};
diff --git a/sql/events.cc b/sql/events.cc
index 3dbc6fd27e1..7838972a5d6 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,7 +19,6 @@
#include "event_db_repository.h"
#include "event_queue.h"
#include "event_scheduler.h"
-#include "sp_head.h"
/*
TODO list :
@@ -50,7 +48,7 @@
counterpart.
1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
2. DROP EVENT the_name
-
+
In other words, the first one will create a row in mysql.event . In the
second step because there will be a line, disk based drop will pass and
the scheduler will remove the memory counterpart. The reason is that
@@ -67,7 +65,7 @@
static const char *opt_event_scheduler_state_names[]=
{ "OFF", "ON", "0", "1", "DISABLED", NullS };
-TYPELIB Events::opt_typelib=
+const TYPELIB Events::opt_typelib=
{
array_elements(opt_event_scheduler_state_names)-1,
"",
@@ -83,7 +81,7 @@ TYPELIB Events::opt_typelib=
*/
static const char *var_event_scheduler_state_names[]= { "OFF", "ON", NullS };
-TYPELIB Events::var_typelib=
+const TYPELIB Events::var_typelib=
{
array_elements(var_event_scheduler_state_names)-1,
"",
@@ -91,20 +89,13 @@ TYPELIB Events::var_typelib=
NULL
};
-
-static
-Event_queue events_event_queue;
-
-static
-Event_scheduler events_event_scheduler;
-
-static
-Event_db_repository events_event_db_repository;
-
-Events Events::singleton;
-
-enum Events::enum_opt_event_scheduler Events::opt_event_scheduler=
- Events::EVENTS_OFF;
+Event_queue *Events::event_queue;
+Event_scheduler *Events::scheduler;
+Event_db_repository *Events::db_repository;
+enum Events::enum_opt_event_scheduler
+Events::opt_event_scheduler= Events::EVENTS_OFF;
+pthread_mutex_t Events::LOCK_event_metadata;
+bool Events::check_system_tables_error= FALSE;
/*
@@ -129,25 +120,89 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
}
-/*
- Accessor for the singleton instance.
+/**
+ @brief Initialize the start up option of the Events scheduler.
- SYNOPSIS
- Events::get_instance()
+ Do not initialize the scheduler subsystem yet - the initialization
+ is split into steps as it has to fit into the common MySQL
+ initialization framework.
+ No locking as this is called only at start up.
- RETURN VALUE
- address
+ @param[in,out] argument The value of the argument. If this value
+ is found in the typelib, the argument is
+ updated.
+
+ @retval TRUE unknown option value
+ @retval FALSE success
*/
-Events *
-Events::get_instance()
+bool
+Events::set_opt_event_scheduler(char *argument)
{
- DBUG_ENTER("Events::get_instance");
- DBUG_RETURN(&singleton);
+ if (argument == NULL)
+ opt_event_scheduler= Events::EVENTS_DISABLED;
+ else
+ {
+ int type;
+ /*
+ type= 1 2 3 4 5
+ (OFF | ON) - (0 | 1) (DISABLE )
+ */
+ const static enum enum_opt_event_scheduler type2state[]=
+ { EVENTS_OFF, EVENTS_ON, EVENTS_OFF, EVENTS_ON, EVENTS_DISABLED };
+
+ type= find_type(argument, &opt_typelib, 1);
+
+ DBUG_ASSERT(type >= 0 && type <= 5); /* guaranteed by find_type */
+
+ if (type == 0)
+ {
+ fprintf(stderr, "Unknown option to event-scheduler: %s\n", argument);
+ return TRUE;
+ }
+ opt_event_scheduler= type2state[type-1];
+ }
+ return FALSE;
}
-/*
+/**
+ Return a string representation of the current scheduler mode.
+*/
+
+const char *
+Events::get_opt_event_scheduler_str()
+{
+ const char *str;
+
+ pthread_mutex_lock(&LOCK_event_metadata);
+ str= opt_typelib.type_names[(int) opt_event_scheduler];
+ pthread_mutex_unlock(&LOCK_event_metadata);
+
+ return str;
+}
+
+
+/**
+ Push an error into the error stack if the system tables are
+ not up to date.
+*/
+
+bool Events::check_if_system_tables_error()
+{
+ DBUG_ENTER("Events::check_if_system_tables_error");
+
+ if (check_system_tables_error)
+ {
+ my_error(ER_EVENTS_DB_ERROR, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
Reconstructs interval expression from interval type and expression
value that is in form of a value of the smalles entity:
For
@@ -279,84 +334,103 @@ common_1_lev_code:
return 0;
}
-/*
- Constructor of Events class. It's called when events.o
- is loaded. Assigning addressed of static variables in this
- object file.
-
- SYNOPSIS
- Events::Events()
-*/
-
-Events::Events()
-{
- scheduler= &events_event_scheduler;
- event_queue= &events_event_queue;
- db_repository= &events_event_db_repository;
-}
-
-/*
- Opens mysql.event table with specified lock
+/**
+ Create a new event.
- SYNOPSIS
- Events::open_event_table()
- thd Thread context
- lock_type How to lock the table
- table We will store the open table here
+ @param[in,out] thd THD
+ @param[in] parse_data Event's data from parsing stage
+ @param[in] if_not_exists Whether IF NOT EXISTS was
+ specified
+ In case there is an event with the same name (db) and
+ IF NOT EXISTS is specified, an warning is put into the stack.
+ @sa Events::drop_event for the notes about locking, pre-locking
+ and Events DDL.
- RETURN VALUE
- 1 Cannot lock table
- 2 The table is corrupted - different number of fields
- 0 OK
+ @retval FALSE OK
+ @retval TRUE Error (reported)
*/
-int
-Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
- TABLE **table)
+bool
+Events::create_event(THD *thd, Event_parse_data *parse_data,
+ bool if_not_exists)
{
- return db_repository->open_event_table(thd, lock_type, table);
-}
+ int ret;
+ DBUG_ENTER("Events::create_event");
+ /*
+ Let's commit the transaction first - MySQL manual specifies
+ that a DDL issues an implicit commit, and it doesn't say "successful
+ DDL", so that an implicit commit is a property of any successfully
+ parsed DDL statement.
+ */
+ if (end_active_trans(thd))
+ DBUG_RETURN(TRUE);
-/*
- The function exported to the world for creating of events.
+ if (check_if_system_tables_error())
+ DBUG_RETURN(TRUE);
- SYNOPSIS
- Events::create_event()
- thd [in] THD
- parse_data [in] Event's data from parsing stage
- if_not_exists [in] Whether IF NOT EXISTS was specified in the DDL
+ /*
+ Perform semantic checks outside of Event_db_repository:
+ once CREATE EVENT is supported in prepared statements, the
+ checks will be moved to PREPARE phase.
+ */
+ if (parse_data->check_parse_data(thd))
+ DBUG_RETURN(TRUE);
- RETURN VALUE
- FALSE OK
- TRUE Error (Reported)
+ /* At create, one of them must be set */
+ DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
- NOTES
- In case there is an event with the same name (db) and
- IF NOT EXISTS is specified, an warning is put into the stack.
-*/
+ if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
+ is_schema_db(parse_data->dbname.str)))
+ DBUG_RETURN(TRUE);
-bool
-Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists)
-{
- int ret;
- DBUG_ENTER("Events::create_event");
- if (unlikely(check_system_tables_error))
+ if (check_db_dir_existence(parse_data->dbname.str))
{
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
+ my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
DBUG_RETURN(TRUE);
}
+ if (parse_data->do_not_create)
+ DBUG_RETURN(FALSE);
+ /*
+ Turn off row binlogging of this statement and use statement-based
+ so that all supporting tables are updated for CREATE EVENT command.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
+
pthread_mutex_lock(&LOCK_event_metadata);
+
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)))
{
- if ((ret= event_queue->create_event(thd, parse_data->dbname,
- parse_data->name)))
+ Event_queue_element *new_element;
+
+ if (!(new_element= new Event_queue_element()))
+ ret= TRUE; // OOM
+ else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
+ parse_data->name,
+ new_element)))
{
- DBUG_ASSERT(ret == OP_LOAD_ERROR);
- my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
+ db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
+ TRUE);
+ delete new_element;
+ }
+ else
+ {
+ /* TODO: do not ignore the out parameter and a possible OOM error! */
+ bool created;
+ if (event_queue)
+ event_queue->create_event(thd, new_element, &created);
+ /* Binlog the create event. */
+ DBUG_ASSERT(thd->query && thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ thd->query, thd->query_length, FALSE, FALSE);
+ }
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
@@ -365,47 +439,124 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists)
}
-/*
- The function exported to the world for alteration of events.
+/**
+ Alter an event.
- SYNOPSIS
- Events::update_event()
- thd [in] THD
- parse_data [in] Event's data from parsing stage
- rename_to [in] Set in case of RENAME TO.
+ @param[in,out] thd THD
+ @param[in] parse_data Event's data from parsing stage
+ @param[in] new_dbname A new schema name for the event. Set in the case of
+ ALTER EVENT RENAME, otherwise is NULL.
+ @param[in] new_name A new name for the event. Set in the case of
+ ALTER EVENT RENAME
- RETURN VALUE
- FALSE OK
- TRUE Error
+ Parameter 'et' contains data about dbname and event name.
+ Parameter 'new_name' is the new name of the event, if not null
+ this means that RENAME TO was specified in the query
+ @sa Events::drop_event for the locking notes.
- NOTES
- et contains data about dbname and event name.
- new_name is the new name of the event, if not null this means
- that RENAME TO was specified in the query
+ @retval FALSE OK
+ @retval TRUE error (reported)
*/
bool
-Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to)
+Events::update_event(THD *thd, Event_parse_data *parse_data,
+ LEX_STRING *new_dbname, LEX_STRING *new_name)
{
int ret;
+ Event_queue_element *new_element;
+
DBUG_ENTER("Events::update_event");
- LEX_STRING *new_dbname= rename_to ? &rename_to->m_db : NULL;
- LEX_STRING *new_name= rename_to ? &rename_to->m_name : NULL;
- if (unlikely(check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
+
+ /*
+ For consistency, implicit COMMIT should be the first thing in the
+ execution chain.
+ */
+ if (end_active_trans(thd))
+ DBUG_RETURN(TRUE);
+
+ if (check_if_system_tables_error())
+ DBUG_RETURN(TRUE);
+
+ if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
DBUG_RETURN(TRUE);
+
+ if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
+ is_schema_db(parse_data->dbname.str)))
+ DBUG_RETURN(TRUE);
+
+ if (new_dbname) /* It's a rename */
+ {
+ /* Check that the new and the old names differ. */
+ if ( !sortcmp_lex_string(parse_data->dbname, *new_dbname,
+ system_charset_info) &&
+ !sortcmp_lex_string(parse_data->name, *new_name,
+ system_charset_info))
+ {
+ my_error(ER_EVENT_SAME_NAME, MYF(0), parse_data->name.str);
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ And the user has sufficient privileges to use the target database.
+ Do it before checking whether the database exists: we don't want
+ to tell the user that a database doesn't exist if they can not
+ access it.
+ */
+ if (check_access(thd, EVENT_ACL, new_dbname->str, 0, 0, 0,
+ is_schema_db(new_dbname->str)))
+ DBUG_RETURN(TRUE);
+
+ /* Check that the target database exists */
+ if (check_db_dir_existence(new_dbname->str))
+ {
+ my_error(ER_BAD_DB_ERROR, MYF(0), new_dbname->str);
+ DBUG_RETURN(TRUE);
+ }
}
+ /*
+ Turn off row binlogging of this statement and use statement-based
+ so that all supporting tables are updated for UPDATE EVENT command.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
+
pthread_mutex_lock(&LOCK_event_metadata);
+
/* On error conditions my_error() is called so no need to handle here */
- if (!(ret= db_repository->update_event(thd, parse_data, new_dbname, new_name)))
+ if (!(ret= db_repository->update_event(thd, parse_data,
+ new_dbname, new_name)))
{
- if ((ret= event_queue->update_event(thd, parse_data->dbname,
- parse_data->name, new_dbname, new_name)))
+ LEX_STRING dbname= new_dbname ? *new_dbname : parse_data->dbname;
+ LEX_STRING name= new_name ? *new_name : parse_data->name;
+
+ if (!(new_element= new Event_queue_element()))
+ ret= TRUE; // OOM
+ else if ((ret= db_repository->load_named_event(thd, dbname, name,
+ new_element)))
{
DBUG_ASSERT(ret == OP_LOAD_ERROR);
- my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
+ delete new_element;
+ }
+ else
+ {
+ /*
+ TODO: check if an update actually has inserted an entry
+ into the queue.
+ If not, and the element is ON COMPLETION NOT PRESERVE, delete
+ it right away.
+ */
+ if (event_queue)
+ event_queue->update_event(thd, parse_data->dbname, parse_data->name,
+ new_element);
+ /* Binlog the alter event. */
+ DBUG_ASSERT(thd->query && thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ thd->query, thd->query_length, FALSE, FALSE);
+ }
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
@@ -414,74 +565,111 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to)
}
-/*
+/**
Drops an event
- SYNOPSIS
- Events::drop_event()
- thd [in] THD
- dbname [in] Event's schema
- name [in] Event's name
- if_exists [in] When set and the event does not exist =>
- warning onto the stack
- only_from_disk [in] Whether to remove the event from the queue too.
- In case of Event_job_data::drop() it's needed to
- do only disk drop because Event_queue will handle
- removal from memory queue.
-
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
+ @param[in,out] thd THD
+ @param[in] dbname Event's schema
+ @param[in] name Event's name
+ @param[in] if_exists When this is set and the event does not exist
+ a warning is pushed into the warning stack.
+ Otherwise the operation produces an error.
+
+ @note Similarly to DROP PROCEDURE, we do not allow DROP EVENT
+ under LOCK TABLES mode, unless table mysql.event is locked. To
+ ensure that, we do not reset & backup the open tables state in
+ this function - if in LOCK TABLES or pre-locking mode, this will
+ lead to an error 'Table mysql.event is not locked with LOCK
+ TABLES' unless it _is_ locked. In pre-locked mode there is
+ another barrier - DROP EVENT commits the current transaction,
+ and COMMIT/ROLLBACK is not allowed in stored functions and
+ triggers.
+
+ @retval FALSE OK
+ @retval TRUE Error (reported)
*/
bool
-Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
- bool only_from_disk)
+Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
{
int ret;
DBUG_ENTER("Events::drop_event");
- if (unlikely(check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
+
+ /*
+ In MySQL, DDL must always commit: since mysql.* tables are
+ non-transactional, we must modify them outside a transaction
+ to not break atomicity.
+ But the second and more important reason to commit here
+ regardless whether we're actually changing mysql.event table
+ or not is replication: end_active_trans syncs the binary log,
+ and unless we run DDL in it's own transaction it may simply
+ never appear on the slave in case the outside transaction
+ rolls back.
+ */
+ if (end_active_trans(thd))
+ DBUG_RETURN(TRUE);
+
+ if (check_if_system_tables_error())
+ DBUG_RETURN(TRUE);
+
+ if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
+ is_schema_db(dbname.str)))
DBUG_RETURN(TRUE);
- }
+
+ /*
+ Turn off row binlogging of this statement and use statement-based so
+ that all supporting tables are updated for DROP EVENT command.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
{
- if (!only_from_disk)
+ if (event_queue)
event_queue->drop_event(thd, dbname, name);
+ /* Binlog the drop event. */
+ DBUG_ASSERT(thd->query && thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ thd->query, thd->query_length, FALSE, FALSE);
+ }
}
pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_RETURN(ret);
}
-/*
+/**
Drops all events from a schema
- SYNOPSIS
- Events::drop_schema_events()
- thd Thread
- db ASCIIZ schema name
+ @note We allow to drop all events in a schema even if the
+ scheduler is disabled. This is to not produce any warnings
+ in case of DROP DATABASE and a disabled scheduler.
+
+ @param[in,out] thd Thread
+ @param[in] db ASCIIZ schema name
*/
void
Events::drop_schema_events(THD *thd, char *db)
{
LEX_STRING const db_lex= { db, strlen(db) };
-
- DBUG_ENTER("Events::drop_schema_events");
+
+ DBUG_ENTER("Events::drop_schema_events");
DBUG_PRINT("enter", ("dropping events from %s", db));
- if (unlikely(check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
- DBUG_VOID_RETURN;
- }
+
+ /*
+ sic: no check if the scheduler is disabled or system tables
+ are damaged, as intended.
+ */
pthread_mutex_lock(&LOCK_event_metadata);
- event_queue->drop_schema_events(thd, db_lex);
+ if (event_queue)
+ event_queue->drop_schema_events(thd, db_lex);
db_repository->drop_schema_events(thd, db_lex);
pthread_mutex_unlock(&LOCK_event_metadata);
@@ -489,109 +677,137 @@ Events::drop_schema_events(THD *thd, char *db)
}
-/*
- SHOW CREATE EVENT
-
- SYNOPSIS
- Events::show_create_event()
- thd Thread context
- spn The name of the event (db, name)
-
- RETURN VALUE
- FALSE OK
- TRUE Error during writing to the wire
+/**
+ A helper function to generate SHOW CREATE EVENT output from
+ a named event
*/
-bool
-Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
+static bool
+send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
{
- CHARSET_INFO *scs= system_charset_info;
- int ret;
- Event_timed *et= new Event_timed();
+ char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
+ String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
+ List<Item> field_list;
+ LEX_STRING sql_mode;
+ const String *tz_name;
- DBUG_ENTER("Events::show_create_event");
- DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
- if (unlikely(check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
+ DBUG_ENTER("send_show_create_event");
+
+ show_str.length(0);
+ if (et->get_create_event(thd, &show_str))
DBUG_RETURN(TRUE);
- }
- ret= db_repository->load_named_event(thd, dbname, name, et);
+ field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
- if (!ret)
- {
- Protocol *protocol= thd->protocol;
- char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
- String show_str(show_str_buf, sizeof(show_str_buf), scs);
- List<Item> field_list;
- byte *sql_mode_str;
- ulong sql_mode_len=0;
+ if (sys_var_thd_sql_mode::symbolic_mode_representation(thd, et->sql_mode,
+ &sql_mode))
+ DBUG_RETURN(TRUE);
- show_str.length(0);
- show_str.set_charset(system_charset_info);
+ field_list.push_back(new Item_empty_string("sql_mode", sql_mode.length));
- if (et->get_create_event(thd, &show_str))
- goto err;
+ tz_name= et->time_zone->get_name();
- field_list.push_back(new Item_empty_string("Event", NAME_LEN));
+ field_list.push_back(new Item_empty_string("time_zone",
+ tz_name->length()));
- sql_mode_str=
- sys_var_thd_sql_mode::symbolic_mode_representation(thd, et->sql_mode,
- &sql_mode_len);
+ field_list.push_back(new Item_empty_string("Create Event",
+ show_str.length()));
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
- field_list.push_back(new Item_empty_string("Create Event",
- show_str.length()));
+ protocol->prepare_for_resend();
- if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
- Protocol::SEND_EOF))
- goto err;
+ protocol->store(et->name.str, et->name.length, system_charset_info);
+ protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
+ protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
+ protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
- protocol->prepare_for_resend();
- protocol->store(et->name.str, et->name.length, scs);
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
- protocol->store((char*) sql_mode_str, sql_mode_len, scs);
+ send_eof(thd);
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ Implement SHOW CREATE EVENT statement
+
+ thd Thread context
+ spn The name of the event (db, name)
+
+ @retval FALSE OK
+ @retval TRUE error (reported)
+*/
+
+bool
+Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
+{
+ Open_tables_state open_tables_backup;
+ Event_timed et;
+ bool ret;
+
+ DBUG_ENTER("Events::show_create_event");
+ DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
+
+ if (check_if_system_tables_error())
+ DBUG_RETURN(TRUE);
+
+ if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
+ is_schema_db(dbname.str)))
+ DBUG_RETURN(TRUE);
+
+ /*
+ We would like to allow SHOW CREATE EVENT under LOCK TABLES and
+ in pre-locked mode. mysql.event table is marked as a system table.
+ This flag reduces the set of its participation scenarios in LOCK TABLES
+ operation, and therefore an out-of-bound open of this table
+ for reading like the one below (sic, only for reading) is
+ more or less deadlock-free. For additional information about when a
+ deadlock can occur please refer to the description of 'system table'
+ flag.
+ */
+ thd->reset_n_backup_open_tables_state(&open_tables_backup);
+ ret= db_repository->load_named_event(thd, dbname, name, &et);
+ thd->restore_backup_open_tables_state(&open_tables_backup);
+
+ if (!ret)
+ ret= send_show_create_event(thd, &et, thd->protocol);
- protocol->store(show_str.c_ptr(), show_str.length(), scs);
- ret= protocol->write();
- send_eof(thd);
- }
- delete et;
DBUG_RETURN(ret);
-err:
- delete et;
- DBUG_RETURN(TRUE);
}
-/*
- Proxy for Event_db_repository::fill_schema_events.
- Callback for I_S from sql_show.cc
+/**
+ Check access rights and fill INFORMATION_SCHEMA.events table.
- SYNOPSIS
- Events::fill_schema_events()
- thd Thread context
- tables The schema table
+ @param[in,out] thd Thread context
+ @param[in] table The temporary table to fill.
cond Unused
- RETURN VALUE
- 0 OK
- !0 Error
+ In MySQL INFORMATION_SCHEMA tables are temporary tables that are
+ created and filled on demand. In this function, we fill
+ INFORMATION_SCHEMA.events. It is a callback for I_S module, invoked from
+ sql_show.cc
+
+ @return Has to be integer, as such is the requirement of the I_S API
+ @retval 0 success
+ @retval 1 an error, pushed into the error stack
*/
int
Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
{
char *db= NULL;
+ int ret;
+ Open_tables_state open_tables_backup;
DBUG_ENTER("Events::fill_schema_events");
- Events *myself= get_instance();
- if (unlikely(myself->check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
- }
+
+ if (check_if_system_tables_error())
+ DBUG_RETURN(1);
/*
If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
@@ -605,7 +821,17 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
DBUG_RETURN(1);
db= thd->lex->select_lex.db;
}
- DBUG_RETURN(myself->db_repository->fill_schema_events(thd, tables, db));
+ /*
+ Reset and backup of the currently open tables in this thread
+ is a way to allow SELECTs from INFORMATION_SCHEMA.events under
+ LOCK TABLES and in pre-locked mode. See also
+ Events::show_create_event for additional comments.
+ */
+ thd->reset_n_backup_open_tables_state(&open_tables_backup);
+ ret= db_repository->fill_schema_events(thd, tables, db);
+ thd->restore_backup_open_tables_state(&open_tables_backup);
+
+ DBUG_RETURN(ret);
}
@@ -624,14 +850,17 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
*/
bool
-Events::init()
+Events::init(my_bool opt_noacl)
{
THD *thd;
bool res= FALSE;
+
DBUG_ENTER("Events::init");
- if (opt_event_scheduler == Events::EVENTS_DISABLED)
- DBUG_RETURN(FALSE);
+ /* Disable the scheduler if running with --skip-grant-tables */
+ if (opt_noacl)
+ opt_event_scheduler= EVENTS_DISABLED;
+
/* We need a temporary THD during boot */
if (!(thd= new THD()))
@@ -647,28 +876,67 @@ Events::init()
thd->thread_stack= (char*) &thd;
thd->store_globals();
- if (check_system_tables(thd))
+ /*
+ We will need Event_db_repository anyway, even if the scheduler is
+ disabled - to perform events DDL.
+ */
+ if (!(db_repository= new Event_db_repository))
{
- check_system_tables_error= TRUE;
- sql_print_error("SCHEDULER: The system tables are damaged. "
- "The scheduler subsystem will be unusable during this run.");
+ res= TRUE; /* fatal error: request unireg_abort */
goto end;
}
- check_system_tables_error= FALSE;
- if (event_queue->init_queue(thd, db_repository))
+ /*
+ Since we allow event DDL even if the scheduler is disabled,
+ check the system tables, as we might need them.
+ */
+ if (Event_db_repository::check_system_tables(thd))
{
- sql_print_error("SCHEDULER: Error while loading from disk.");
+ sql_print_error("Event Scheduler: An error occurred when initializing "
+ "system tables.%s",
+ opt_event_scheduler == EVENTS_DISABLED ?
+ "" : " Disabling the Event Scheduler.");
+
+ /* Disable the scheduler since the system tables are not up to date */
+ opt_event_scheduler= EVENTS_DISABLED;
+ check_system_tables_error= TRUE;
goto end;
}
- scheduler->init_scheduler(event_queue);
+
+ /*
+ Was disabled explicitly from the command line, or because we're running
+ with --skip-grant-tables, or because we have no system tables.
+ */
+ if (opt_event_scheduler == Events::EVENTS_DISABLED)
+ goto end;
+
DBUG_ASSERT(opt_event_scheduler == Events::EVENTS_ON ||
opt_event_scheduler == Events::EVENTS_OFF);
- if (opt_event_scheduler == Events::EVENTS_ON)
- res= scheduler->start();
+
+ if (!(event_queue= new Event_queue) ||
+ !(scheduler= new Event_scheduler(event_queue)))
+ {
+ res= TRUE; /* fatal error: request unireg_abort */
+ goto end;
+ }
+
+ if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
+ opt_event_scheduler == EVENTS_ON && scheduler->start())
+ {
+ sql_print_error("Event Scheduler: Error while loading from disk.");
+ res= TRUE; /* fatal error: request unireg_abort */
+ goto end;
+ }
+ Event_worker_thread::init(db_repository);
end:
+ if (res)
+ {
+ delete db_repository;
+ delete event_queue;
+ delete scheduler;
+ }
delete thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, NULL);
@@ -691,19 +959,23 @@ void
Events::deinit()
{
DBUG_ENTER("Events::deinit");
- if (likely(!check_system_tables_error))
- {
- scheduler->stop();
- scheduler->deinit_scheduler();
- event_queue->deinit_queue();
+ if (opt_event_scheduler != EVENTS_DISABLED)
+ {
+ delete scheduler;
+ scheduler= NULL; /* safety */
+ delete event_queue;
+ event_queue= NULL; /* safety */
}
+ delete db_repository;
+ db_repository= NULL; /* safety */
+
DBUG_VOID_RETURN;
}
-/*
+/**
Inits Events mutexes
SYNOPSIS
@@ -715,8 +987,6 @@ void
Events::init_mutexes()
{
pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
- event_queue->init_mutexes();
- scheduler->init_mutexes();
}
@@ -730,8 +1000,6 @@ Events::init_mutexes()
void
Events::destroy_mutexes()
{
- event_queue->deinit_mutexes();
- scheduler->deinit_mutexes();
pthread_mutex_destroy(&LOCK_event_metadata);
}
@@ -754,153 +1022,163 @@ Events::dump_internal_status()
puts("LLA = Last Locked At LUA = Last Unlocked At");
puts("WOC = Waiting On Condition DL = Data Locked");
- scheduler->dump_internal_status();
- event_queue->dump_internal_status();
+ pthread_mutex_lock(&LOCK_event_metadata);
+ if (opt_event_scheduler == EVENTS_DISABLED)
+ puts("The Event Scheduler is disabled");
+ else
+ {
+ scheduler->dump_internal_status();
+ event_queue->dump_internal_status();
+ }
+ pthread_mutex_unlock(&LOCK_event_metadata);
DBUG_VOID_RETURN;
}
-/*
- Starts execution of events by the scheduler
-
- SYNOPSIS
- Events::start_execution_of_events()
+/**
+ Starts or stops the event scheduler thread.
- RETURN VALUE
- FALSE OK
- TRUE Error
+ @retval FALSE success
+ @retval TRUE error
*/
bool
-Events::start_execution_of_events()
+Events::switch_event_scheduler_state(enum_opt_event_scheduler new_state)
{
- DBUG_ENTER("Events::start_execution_of_events");
- if (unlikely(check_system_tables_error))
- {
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
- }
- DBUG_RETURN(scheduler->start());
-}
+ bool ret= FALSE;
+ DBUG_ENTER("Events::switch_event_scheduler_state");
-/*
- Stops execution of events by the scheduler.
- Already running events will not be stopped. If the user needs
- them stopped manual intervention is needed.
+ DBUG_ASSERT(new_state == Events::EVENTS_ON ||
+ new_state == Events::EVENTS_OFF);
- SYNOPSIS
- Events::stop_execution_of_events()
+ /*
+ If the scheduler was disabled because there are no/bad
+ system tables, produce a more meaningful error message
+ than ER_OPTION_PREVENTS_STATEMENT
+ */
+ if (check_if_system_tables_error())
+ DBUG_RETURN(TRUE);
- RETURN VALUE
- FALSE OK
- TRUE Error
-*/
+ pthread_mutex_lock(&LOCK_event_metadata);
-bool
-Events::stop_execution_of_events()
-{
- DBUG_ENTER("Events::stop_execution_of_events");
- if (unlikely(check_system_tables_error))
+ if (opt_event_scheduler == EVENTS_DISABLED)
{
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
- DBUG_RETURN(TRUE);
+ my_error(ER_OPTION_PREVENTS_STATEMENT,
+ MYF(0), "--event-scheduler=DISABLED or --skip-grant-tables");
+ ret= TRUE;
+ goto end;
}
- DBUG_RETURN(scheduler->stop());
-}
-
-
-/*
- Checks whether the scheduler is running or not.
- SYNOPSIS
- Events::is_started()
-
- RETURN VALUE
- TRUE Yes
- FALSE No
-*/
+ if (new_state == EVENTS_ON)
+ ret= scheduler->start();
+ else
+ ret= scheduler->stop();
-bool
-Events::is_execution_of_events_started()
-{
- DBUG_ENTER("Events::is_execution_of_events_started");
- if (unlikely(check_system_tables_error))
+ if (ret)
{
- my_error(ER_EVENTS_DB_ERROR, MYF(0));
- DBUG_RETURN(FALSE);
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
+ goto end;
}
- DBUG_RETURN(scheduler->is_running());
+
+ opt_event_scheduler= new_state;
+
+end:
+ pthread_mutex_unlock(&LOCK_event_metadata);
+ DBUG_RETURN(ret);
}
+/**
+ Loads all ENABLED events from mysql.event into a prioritized
+ queue.
-/*
- Opens mysql.db and mysql.user and checks whether:
- 1. mysql.db has column Event_priv at column 20 (0 based);
- 2. mysql.user has column Event_priv at column 29 (0 based);
+ This function is called during the server start up. It reads
+ every event, computes the next execution time, and if the event
+ needs execution, adds it to a prioritized queue. Otherwise, if
+ ON COMPLETION DROP is specified, the event is automatically
+ removed from the table.
- SYNOPSIS
- Events::check_system_tables()
- thd Thread
+ @param[in,out] thd Thread context. Used for memory allocation in some cases.
- RETURN VALUE
- FALSE OK
- TRUE Error
+ @retval FALSE success
+ @retval TRUE error, the load is aborted
+
+ @note Reports the error to the console
*/
bool
-Events::check_system_tables(THD *thd)
+Events::load_events_from_db(THD *thd)
{
- TABLE_LIST tables;
- Open_tables_state backup;
- bool ret= FALSE;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ bool ret= TRUE;
+ uint count= 0;
- DBUG_ENTER("Events::check_system_tables");
+ DBUG_ENTER("Events::load_events_from_db");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
- thd->reset_n_backup_open_tables_state(&backup);
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "db";
- tables.lock_type= TL_READ;
-
- if ((ret= simple_open_n_lock_tables(thd, &tables)))
+ if (db_repository->open_event_table(thd, TL_WRITE, &table))
{
- sql_print_error("SCHEDULER: Cannot open mysql.db");
- ret= TRUE;
+ sql_print_error("Event Scheduler: Failed to open table mysql.event");
+ DBUG_RETURN(TRUE);
}
- ret= table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT,
- mysql_db_table_fields, &mysql_db_table_last_check,
- ER_CANNOT_LOAD_FROM_TABLE);
- close_thread_tables(thd);
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "user";
- tables.lock_type= TL_READ;
- if (simple_open_n_lock_tables(thd, &tables))
- {
- sql_print_error("SCHEDULER: Cannot open mysql.user");
- ret= TRUE;
- }
- else
+ init_read_record(&read_record_info, thd, table, NULL, 0, 1);
+ while (!(read_record_info.read_record(&read_record_info)))
{
- if (tables.table->s->fields < 29 ||
- strncmp(tables.table->field[29]->field_name,
- STRING_WITH_LEN("Event_priv")))
+ Event_queue_element *et;
+ bool created;
+ bool drop_on_completion;
+
+ if (!(et= new Event_queue_element))
+ goto end;
+
+ DBUG_PRINT("info", ("Loading event from row."));
+
+ if (et->load_from_row(thd, table))
{
- sql_print_error("mysql.user has no `Event_priv` column at position %d",
- 29);
- ret= TRUE;
+ sql_print_error("Event Scheduler: "
+ "Error while loading events from mysql.event. "
+ "The table probably contains bad data or is corrupted");
+ delete et;
+ goto end;
+ }
+ drop_on_completion= (et->on_completion ==
+ Event_queue_element::ON_COMPLETION_DROP);
+
+
+ if (event_queue->create_event(thd, et, &created))
+ {
+ /* Out of memory */
+ delete et;
+ goto end;
+ }
+ if (created)
+ count++;
+ else if (drop_on_completion)
+ {
+ /*
+ If not created, a stale event - drop if immediately if
+ ON COMPLETION NOT PRESERVE
+ */
+ int rc= table->file->ha_delete_row(table->record[0]);
+ if (rc)
+ {
+ table->file->print_error(rc, MYF(0));
+ goto end;
+ }
}
- close_thread_tables(thd);
}
+ sql_print_information("Event Scheduler: Loaded %d event%s",
+ count, (count == 1) ? "" : "s");
+ ret= FALSE;
+
+end:
+ end_read_record(&read_record_info);
- thd->restore_backup_open_tables_state(&backup);
+ close_thread_tables(thd);
DBUG_RETURN(ret);
}
diff --git a/sql/events.h b/sql/events.h
index 79c4a419388..1b99b072fd7 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -4,8 +4,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,11 +15,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-class sp_name;
+/*
+ @file
+ A public interface of Events Scheduler module.
+*/
+
class Event_parse_data;
class Event_db_repository;
class Event_queue;
-class Event_queue_element;
class Event_scheduler;
/* Return codes */
@@ -39,17 +41,30 @@ enum enum_events_error_code
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
+/**
+ @class Events -- a facade to the functionality of the Event Scheduler.
+
+ Every public operation against the scheduler has to be executed via the
+ interface provided by a static method of this class. No instance of this
+ class is ever created and it has no non-static data members.
+
+ The life cycle of the Events module is the following:
+
+ At server start up:
+ set_opt_event_scheduler() -> init_mutexes() -> init()
+ When the server is running:
+ create_event(), drop_event(), start_or_stop_event_scheduler(), etc
+ At shutdown:
+ deinit(), destroy_mutexes().
+
+ The peculiar initialization and shutdown cycle is an adaptation to the
+ outside server startup/shutdown framework and mimics the rest of MySQL
+ subsystems (ACL, time zone tables, etc).
+*/
class Events
{
public:
- /*
- Quite NOT the best practice and will be removed once
- Event_timed::drop() and Event_timed is fixed not do drop directly
- or other scheme will be found.
- */
- friend class Event_queue_element;
-
/* The order should match the order in opt_typelib */
enum enum_opt_event_scheduler
{
@@ -58,51 +73,48 @@ public:
EVENTS_DISABLED= 4
};
- static enum_opt_event_scheduler opt_event_scheduler;
- static TYPELIB opt_typelib;
- static TYPELIB var_typelib;
+ /* Possible values of @@event_scheduler variable */
+ static const TYPELIB var_typelib;
- bool
- init();
+ static bool
+ set_opt_event_scheduler(char *argument);
- void
- deinit();
+ static const char *
+ get_opt_event_scheduler_str();
- void
- init_mutexes();
+ /* A hack needed for Event_queue_element */
+ static Event_db_repository *
+ get_db_repository() { return db_repository; }
- void
- destroy_mutexes();
+ static bool
+ init(my_bool opt_noacl);
- bool
- start_execution_of_events();
+ static void
+ deinit();
- bool
- stop_execution_of_events();
+ static void
+ init_mutexes();
- bool
- is_execution_of_events_started();
+ static void
+ destroy_mutexes();
- static Events *
- get_instance();
+ static bool
+ switch_event_scheduler_state(enum enum_opt_event_scheduler new_state);
- bool
+ static bool
create_event(THD *thd, Event_parse_data *parse_data, bool if_exists);
- bool
- update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to);
+ static bool
+ update_event(THD *thd, Event_parse_data *parse_data,
+ LEX_STRING *new_dbname, LEX_STRING *new_name);
- bool
- drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists,
- bool only_from_disk);
+ static bool
+ drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists);
- void
+ static void
drop_schema_events(THD *thd, char *db);
- int
- open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
-
- bool
+ static bool
show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
@@ -113,28 +125,28 @@ public:
static int
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
- void
+ static void
dump_internal_status();
private:
- bool
- check_system_tables(THD *thd);
-
- /* Singleton DP is used */
- Events();
- ~Events(){}
+ static bool check_if_system_tables_error();
- /* Singleton instance */
- static Events singleton;
+ static bool
+ load_events_from_db(THD *thd);
- Event_queue *event_queue;
- Event_scheduler *scheduler;
- Event_db_repository *db_repository;
-
- pthread_mutex_t LOCK_event_metadata;
-
- bool check_system_tables_error;
+private:
+ /* Command line option names */
+ static const TYPELIB opt_typelib;
+ static pthread_mutex_t LOCK_event_metadata;
+ static Event_queue *event_queue;
+ static Event_scheduler *scheduler;
+ static Event_db_repository *db_repository;
+ /* Current state of Event Scheduler */
+ static enum enum_opt_event_scheduler opt_event_scheduler;
+ /* Set to TRUE if an error at start up */
+ static bool check_system_tables_error;
+private:
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);
diff --git a/sql/examples/CMakeLists.txt b/sql/examples/CMakeLists.txt
index d3cc430ef40..1a22e9a3efd 100755
--- a/sql/examples/CMakeLists.txt
+++ b/sql/examples/CMakeLists.txt
@@ -1,3 +1,18 @@
+# Copyright (C) 2006 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; version 2 of the License.
+#
+# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
diff --git a/sql/field.cc b/sql/field.cc
index bda58172c63..322d3e2ca80 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -969,6 +968,31 @@ static Item_result field_types_result_type [FIELDTYPE_NUM]=
/*
+ Test if the given string contains important data:
+ not spaces for character string,
+ or any data for binary string.
+
+ SYNOPSIS
+ test_if_important_data()
+ cs Character set
+ str String to test
+ strend String end
+
+ RETURN
+ FALSE - If string does not have important data
+ TRUE - If string has some important data
+*/
+
+static bool
+test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
+{
+ if (cs != &my_charset_bin)
+ str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
+ return (str < strend);
+}
+
+
+/*
Detect Item_result by given field type of UNION merge result
SYNOPSIS
@@ -1016,6 +1040,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_GEOMETRY:
return TRUE;
default:
return FALSE;
@@ -1026,7 +1051,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
/*
Numeric fields base class constructor
*/
-Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+Field_num::Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg)
@@ -1046,73 +1071,125 @@ void Field_num::prepend_zeros(String *value)
int diff;
if ((diff= (int) (field_length - value->length())) > 0)
{
- bmove_upp((char*) value->ptr()+field_length,value->ptr()+value->length(),
+ bmove_upp((uchar*) value->ptr()+field_length,
+ (uchar*) value->ptr()+value->length(),
value->length());
- bfill((char*) value->ptr(),diff,'0');
+ bfill((uchar*) value->ptr(),diff,'0');
value->length(field_length);
(void) value->c_ptr_quick(); // Avoid warnings in purify
}
}
/*
- Test if given number is a int (or a fixed format float with .000)
+ Test if given number is a int.
SYNOPSIS
- test_if_int()
+ Field_num::check_int
+ cs Character set
str String to test
end Pointer to char after last used digit
- cs Character set
+ length String length
+ error Error returned by strntoull10rnd()
- NOTES
- This is called after one has called my_strntol() or similar function.
- This is only used to give warnings in ALTER TABLE or LOAD DATA...
-
- TODO
- Make this multi-byte-character safe
+ NOTE
+ This is called after one has called strntoull10rnd() function.
RETURN
- 0 OK
- 1 error. A warning is pushed if field_name != 0
+ 0 ok
+ 1 error: empty string or wrong integer.
+ 2 error: garbage at the end of string.
*/
-bool Field::check_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs)
+int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length,
+ const char *int_end, int error)
{
- const char *end;
- if (str == int_end)
+ /* Test if we get an empty string or wrong integer */
+ if (str == int_end || error == MY_ERRNO_EDOM)
{
char buff[128];
- String tmp(buff,(uint32) sizeof(buff), system_charset_info);
+ String tmp(buff, (uint32) sizeof(buff), system_charset_info);
tmp.copy(str, length, system_charset_info);
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"integer", tmp.c_ptr(), field_name,
(ulong) table->in_use->row_count);
- return 1; // Empty string
+ return 1;
}
- end= str+length;
- if ((str= int_end) == end)
- return 0; // OK; All digits was used
+ /* Test if we have garbage at the end of the given string. */
+ if (test_if_important_data(cs, int_end, str + length))
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
+ return 2;
+ }
+ return 0;
+}
- /* Allow end .0000 */
- if (*str == '.')
+
+/*
+ Conver a string to an integer then check bounds.
+
+ SYNOPSIS
+ Field_num::get_int
+ cs Character set
+ from String to convert
+ len Length of the string
+ rnd OUT longlong value
+ unsigned_max max unsigned value
+ signed_min min signed value
+ signed_max max signed value
+
+ DESCRIPTION
+ The function calls strntoull10rnd() to get an integer value then
+ check bounds and errors returned. In case of any error a warning
+ is raised.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
+ longlong *rnd, ulonglong unsigned_max,
+ longlong signed_min, longlong signed_max)
+{
+ char *end;
+ int error;
+
+ *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len,
+ unsigned_flag, &end,
+ &error);
+ if (unsigned_flag)
{
- for (str++ ; str != end && *str == '0'; str++)
- ;
+
+ if (((ulonglong) *rnd > unsigned_max) && (*rnd= (longlong) unsigned_max) ||
+ error == MY_ERRNO_ERANGE)
+ {
+ goto out_of_range;
+ }
}
- /* Allow end space */
- for ( ; str != end ; str++)
+ else
{
- if (!my_isspace(cs,*str))
+ if (*rnd < signed_min)
{
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
- return 1;
+ *rnd= signed_min;
+ goto out_of_range;
+ }
+ else if (*rnd > signed_max)
+ {
+ *rnd= signed_max;
+ goto out_of_range;
}
}
+ if (table->in_use->count_cuted_fields &&
+ check_int(cs, from, len, end, error))
+ return 1;
return 0;
-}
+out_of_range:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+}
/*
Process decimal library return codes and issue warnings for overflow and
@@ -1208,13 +1285,13 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_READ;
CHARSET_INFO *cs= &my_charset_bin;
- uint length= 21;
+ uint length;
longlong value= val_int();
- if (val_buffer->alloc(length))
+ if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
return 0;
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
- length,
+ MY_INT64_NUM_DECIMAL_DIGITS,
unsigned_val ? 10 : -10,
value);
val_buffer->length(length);
@@ -1222,7 +1299,7 @@ String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
}
-Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
+Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg)
:ptr(ptr_arg), null_ptr(null_ptr_arg),
@@ -1249,18 +1326,17 @@ void Field::hash(ulong *nr, ulong *nr2)
{
uint len= pack_length();
CHARSET_INFO *cs= charset();
- cs->coll->hash_sort(cs, (uchar*) ptr, len, nr, nr2);
+ cs->coll->hash_sort(cs, ptr, len, nr, nr2);
}
}
-my_size_t
+size_t
Field::do_last_null_byte() const
{
- DBUG_ASSERT(null_ptr == NULL || (byte*) null_ptr >= table->record[0]);
+ DBUG_ASSERT(null_ptr == NULL || null_ptr >= table->record[0]);
if (null_ptr)
- return (byte*) null_ptr - table->record[0] + 1;
- else
- return LAST_NULL_BYTE_UNDEF;
+ return (size_t) (null_ptr - table->record[0]) + 1;
+ return LAST_NULL_BYTE_UNDEF;
}
@@ -1414,14 +1490,14 @@ my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
}
-Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset)
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{
- field_charset=charset;
- if (charset->state & MY_CS_BINSORT)
+ field_charset= charset_arg;
+ if (charset_arg->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
field_derivation= DERIVATION_IMPLICIT;
}
@@ -1500,7 +1576,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
}
-bool Field::get_date(TIME *ltime,uint fuzzydate)
+bool Field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
@@ -1511,7 +1587,7 @@ bool Field::get_date(TIME *ltime,uint fuzzydate)
return 0;
}
-bool Field::get_time(TIME *ltime)
+bool Field::get_time(MYSQL_TIME *ltime)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
@@ -1528,7 +1604,7 @@ bool Field::get_time(TIME *ltime)
Needs to be changed if/when we want to support different time formats
*/
-int Field::store_time(TIME *ltime, timestamp_type type)
+int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
@@ -1565,7 +1641,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field *tmp;
@@ -1609,16 +1685,17 @@ void Field_null::sql_type(String &res) const
This is an number stored as a pre-space (or pre-zero) string
****************************************************************************/
-void
+int
Field_decimal::reset(void)
{
Field_decimal::store(STRING_WITH_LEN("0"),&my_charset_bin);
+ return 0;
}
void Field_decimal::overflow(bool negative)
{
uint len=field_length;
- char *to=ptr, filler= '9';
+ uchar *to=ptr, filler= '9';
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
if (negative)
@@ -1654,36 +1731,37 @@ void Field_decimal::overflow(bool negative)
}
-int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
+int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
+ const uchar *from= (uchar*) from_arg;
- /* Convert character set if the old one is multi byte */
+ /* Convert character set if the old one is multi uchar */
if (cs->mbmaxlen > 1)
{
uint dummy_errors;
- tmp.copy(from, len, cs, &my_charset_bin, &dummy_errors);
- from= tmp.ptr();
+ tmp.copy((char*) from, len, cs, &my_charset_bin, &dummy_errors);
+ from= (uchar*) tmp.ptr();
len= tmp.length();
}
- const char *end= from+len;
+ const uchar *end= from+len;
/* The pointer where the field value starts (i.e., "where to write") */
- char *to=ptr;
+ uchar *to= ptr;
uint tmp_dec, tmp_uint;
/*
The sign of the number : will be 0 (means positive but sign not
specified), '+' or '-'
*/
- char sign_char=0;
+ uchar sign_char=0;
/* The pointers where prezeros start and stop */
- const char *pre_zeros_from, *pre_zeros_end;
+ const uchar *pre_zeros_from, *pre_zeros_end;
/* The pointers where digits at the left of '.' start and stop */
- const char *int_digits_from, *int_digits_end;
+ const uchar *int_digits_from, *int_digits_end;
/* The pointers where digits at the right of '.' start and stop */
- const char *frac_digits_from, *frac_digits_end;
+ const uchar *frac_digits_from, *frac_digits_end;
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
uint exponent=0; // value of the exponent
@@ -1691,20 +1769,20 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
Pointers used when digits move from the left of the '.' to the
right of the '.' (explained below)
*/
- const char *int_digits_tail_from;
+ const uchar *int_digits_tail_from;
/* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
uint int_digits_added_zeros;
/*
Pointer used when digits move from the right of the '.' to the left
of the '.'
*/
- const char *frac_digits_head_end;
+ const uchar *frac_digits_head_end;
/* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
uint frac_digits_added_zeros;
- char *pos,*tmp_left_pos,*tmp_right_pos;
+ uchar *pos,*tmp_left_pos,*tmp_right_pos;
/* Pointers that are used as limits (begin and end of the field buffer) */
- char *left_wall,*right_wall;
- char tmp_char;
+ uchar *left_wall,*right_wall;
+ uchar tmp_char;
/*
To remember if table->in_use->cuted_fields has already been incremented,
to do that only once
@@ -2041,17 +2119,18 @@ int Field_decimal::store(double nr)
}
#endif
- reg4 uint i,length;
- char fyllchar,*to;
+ reg4 uint i;
+ size_t length;
+ uchar fyllchar,*to;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
fyllchar = zerofill ? (char) '0' : (char) ' ';
#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
- length=(uint) strlen(buff);
+ length= strlen(buff);
#else
- length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr));
+ length= my_sprintf(buff,(buff,"%.*f",dec,nr));
#endif
if (length > field_length)
@@ -2075,7 +2154,8 @@ int Field_decimal::store(longlong nr, bool unsigned_val)
ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[22];
uint length, int_part;
- char fyllchar, *to;
+ char fyllchar;
+ uchar *to;
if (nr < 0 && unsigned_flag && !unsigned_val)
{
@@ -2110,7 +2190,7 @@ double Field_decimal::val_real(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used,
+ return my_strntod(&my_charset_bin, (char*) ptr, field_length, &end_not_used,
&not_used);
}
@@ -2119,11 +2199,10 @@ longlong Field_decimal::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
if (unsigned_flag)
- return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
- &not_used);
- else
- return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL,
+ return my_strntoull(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
&not_used);
+ return my_strntoll(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
+ &not_used);
}
@@ -2131,10 +2210,12 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- char *str;
+ uchar *str;
+ size_t tmp_length;
+
for (str=ptr ; *str == ' ' ; str++) ;
- uint tmp_length=(uint) (str-ptr);
val_ptr->set_charset(&my_charset_bin);
+ tmp_length= (size_t) (str-ptr);
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
else
@@ -2147,9 +2228,9 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
** 5.00 , -1.0, 05, -05, +5 with optional pre/end space
*/
-int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
+int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr)
{
- const char *end;
+ const uchar *end;
int swap=0;
/* First remove prefixes '0', ' ', and '-' */
for (end=a_ptr+field_length;
@@ -2180,9 +2261,9 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
}
-void Field_decimal::sort_string(char *to,uint length)
+void Field_decimal::sort_string(uchar *to,uint length)
{
- char *str,*end;
+ uchar *str,*end;
for (str=ptr,end=ptr+length;
str != end &&
((my_isspace(&my_charset_bin,*str) || *str == '+' ||
@@ -2224,7 +2305,7 @@ void Field_decimal::sql_type(String &res) const
** Field_new_decimal
****************************************************************************/
-Field_new_decimal::Field_new_decimal(char *ptr_arg,
+Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg,
@@ -2242,12 +2323,12 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg,
Field_new_decimal::Field_new_decimal(uint32 len_arg,
- bool maybe_null,
+ bool maybe_null_arg,
const char *name,
uint8 dec_arg,
bool unsigned_arg)
- :Field_num((char*) 0, len_arg,
- maybe_null ? (uchar*) "": 0, 0,
+ :Field_num((uchar*) 0, len_arg,
+ maybe_null_arg ? (uchar*) "": 0, 0,
NONE, name, dec_arg, 0, unsigned_arg)
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
@@ -2257,9 +2338,10 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
}
-void Field_new_decimal::reset(void)
+int Field_new_decimal::reset(void)
{
store_value(&decimal_zero);
+ return 0;
}
@@ -2343,14 +2425,14 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
error= 1;
}
- DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
bin_size););
DBUG_RETURN(error);
}
int Field_new_decimal::store(const char *from, uint length,
- CHARSET_INFO *charset)
+ CHARSET_INFO *charset_arg)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
int err;
@@ -2358,8 +2440,9 @@ int Field_new_decimal::store(const char *from, uint length,
DBUG_ENTER("Field_new_decimal::store(char*)");
if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
- ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
- from, length, charset, &decimal_value)) &&
+ ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
+ from, length, charset_arg,
+ &decimal_value)) &&
table->in_use->abort_on_warning)
{
/* Because "from" is not NUL-terminated and we use %s in the ER() */
@@ -2474,7 +2557,7 @@ int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
}
-int Field_new_decimal::store_time(TIME *ltime, timestamp_type t_type)
+int Field_new_decimal::store_time(MYSQL_TIME *ltime, timestamp_type t_type)
{
my_decimal decimal_value;
return store_value(date2my_decimal(ltime, &decimal_value));
@@ -2508,7 +2591,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
DBUG_ENTER("Field_new_decimal::val_decimal");
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
precision, dec);
- DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
bin_size););
DBUG_RETURN(decimal_value);
}
@@ -2526,13 +2609,13 @@ String *Field_new_decimal::val_str(String *val_buffer,
}
-int Field_new_decimal::cmp(const char *a,const char*b)
+int Field_new_decimal::cmp(const uchar *a,const uchar*b)
{
return memcmp(a, b, bin_size);
}
-void Field_new_decimal::sort_string(char *buff,
+void Field_new_decimal::sort_string(uchar *buff,
uint length __attribute__((unused)))
{
memcpy(buff, ptr, bin_size);
@@ -2555,7 +2638,7 @@ uint Field_new_decimal::is_equal(create_field *new_field)
(uint) (flags & UNSIGNED_FLAG)) &&
((new_field->flags & AUTO_INCREMENT_FLAG) ==
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
- (new_field->length == max_length()) &&
+ (new_field->length == max_display_length()) &&
(new_field->decimals == dec));
}
@@ -2567,45 +2650,11 @@ uint Field_new_decimal::is_equal(create_field *new_field)
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- char *end;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > 255)
- {
- set_if_smaller(tmp, 255);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- ptr[0]= (char) tmp;
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < -128)
- {
- tmp= -128;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp >= 128)
- {
- tmp= 127;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- ptr[0]= (char) tmp;
- }
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, 255, -128, 127);
+ ptr[0]= unsigned_flag ? (char) (ulonglong) rnd : (char) rnd;
return error;
}
@@ -2701,7 +2750,7 @@ int Field_tiny::store(longlong nr, bool unsigned_val)
double Field_tiny::val_real(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ int tmp= unsigned_flag ? (int) ptr[0] :
(int) ((signed char*) ptr)[0];
return (double) tmp;
}
@@ -2710,7 +2759,7 @@ double Field_tiny::val_real(void)
longlong Field_tiny::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int tmp= unsigned_flag ? (int) ((uchar*) ptr)[0] :
+ int tmp= unsigned_flag ? (int) ptr[0] :
(int) ((signed char*) ptr)[0];
return (longlong) tmp;
}
@@ -2728,7 +2777,7 @@ String *Field_tiny::val_str(String *val_buffer,
if (unsigned_flag)
length= (uint) cs->cset->long10_to_str(cs,to,mlength, 10,
- (long) *((uchar*) ptr));
+ (long) *ptr);
else
length= (uint) cs->cset->long10_to_str(cs,to,mlength,-10,
(long) *((signed char*) ptr));
@@ -2744,7 +2793,7 @@ bool Field_tiny::send_binary(Protocol *protocol)
return protocol->store_tiny((longlong) (int8) ptr[0]);
}
-int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
+int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
signed char a,b;
a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
@@ -2753,12 +2802,12 @@ int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
+void Field_tiny::sort_string(uchar *to,uint length __attribute__((unused)))
{
if (unsigned_flag)
*to= *ptr;
else
- to[0] = (char) ((uchar) ptr[0] ^ (uchar) 128); /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ (uchar) 128); /* Revers signbit */
}
void Field_tiny::sql_type(String &res) const
@@ -2776,59 +2825,20 @@ void Field_tiny::sql_type(String &res) const
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- char *end;
+ int store_tmp;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > UINT_MAX16)
- {
- set_if_smaller(tmp, UINT_MAX16);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX16, INT_MIN16, INT_MAX16);
+ store_tmp= unsigned_flag ? (int) (ulonglong) rnd : (int) rnd;
#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,tmp);
- }
- else
-#endif
- shortstore(ptr,(short) tmp);
+ if (table->s->db_low_byte_first)
+ {
+ int2store(ptr, store_tmp);
}
else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN16)
- {
- tmp= INT_MIN16;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX16)
- {
- tmp=INT_MAX16;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int2store(ptr,tmp);
- }
- else
#endif
- shortstore(ptr,(short) tmp);
- }
+ shortstore(ptr, (short) store_tmp);
return error;
}
@@ -3002,7 +3012,7 @@ bool Field_short::send_binary(Protocol *protocol)
}
-int Field_short::cmp(const char *a_ptr, const char *b_ptr)
+int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
short a,b;
#ifdef WORDS_BIGENDIAN
@@ -3024,7 +3034,7 @@ int Field_short::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_short::sort_string(char *to,uint length __attribute__((unused)))
+void Field_short::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -3062,45 +3072,13 @@ void Field_short::sql_type(String &res) const
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- char *end;
+ int store_tmp;
int error;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > UINT_MAX24)
- {
- set_if_smaller(tmp, UINT_MAX24);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- int3store(ptr,tmp);
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN24)
- {
- tmp= INT_MIN24;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX24)
- {
- tmp=INT_MAX24;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- int3store(ptr,tmp);
- }
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX24, INT_MIN24, INT_MAX24);
+ store_tmp= unsigned_flag ? (int) (ulonglong) rnd : (int) rnd;
+ int3store(ptr, store_tmp);
return error;
}
@@ -3242,7 +3220,7 @@ bool Field_medium::send_binary(Protocol *protocol)
}
-int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
+int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
long a,b;
if (unsigned_flag)
@@ -3258,7 +3236,7 @@ int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
+void Field_medium::sort_string(uchar *to,uint length __attribute__((unused)))
{
if (unsigned_flag)
to[0] = ptr[2];
@@ -3281,69 +3259,15 @@ void Field_medium::sql_type(String &res) const
** long int
****************************************************************************/
-/*
- A helper function to check whether the next character
- in the string "s" is MINUS SIGN.
-*/
-#ifdef HAVE_CHARSET_ucs2
-static bool test_if_minus(CHARSET_INFO *cs,
- const char *s, const char *e)
-{
- my_wc_t wc;
- return cs->cset->mb_wc(cs, &wc, (uchar*) s, (uchar*) e) > 0 && wc == '-';
-}
-#else
-/*
- If not UCS2 support is compiled then it is easier
-*/
-#define test_if_minus(cs, s, e) (*s == '-')
-#endif
-
-
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
long store_tmp;
int error;
- char *end;
-
- if (unsigned_flag)
- {
- ulonglong tmp= cs->cset->strntoull10rnd(cs, from, len, 1, &end, &error);
- if (error == MY_ERRNO_ERANGE || tmp > (ulonglong) UINT_MAX32)
- {
- set_if_smaller(tmp, (ulonglong) UINT_MAX32);
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- store_tmp= (long) tmp;
- }
- else
- {
- longlong tmp= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (tmp < INT_MIN32)
- {
- tmp= INT_MIN32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (tmp > INT_MAX32)
- {
- tmp=INT_MAX32;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
- error= 1;
- }
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
- error= 1;
- else
- error= 0;
- store_tmp= (long) tmp;
- }
-
+ longlong rnd;
+
+ error= get_int(cs, from, len, &rnd, UINT_MAX32, INT_MIN32, INT_MAX32);
+ store_tmp= unsigned_flag ? (long) (ulonglong) rnd : (long) rnd;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
@@ -3523,7 +3447,7 @@ bool Field_long::send_binary(Protocol *protocol)
return protocol->store_long(Field_long::val_int());
}
-int Field_long::cmp(const char *a_ptr, const char *b_ptr)
+int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -3543,7 +3467,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_long::sort_string(char *to,uint length __attribute__((unused)))
+void Field_long::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -3595,7 +3519,8 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
+ else if (table->in_use->count_cuted_fields &&
+ check_int(cs, from, len, end, error))
error= 1;
else
error= 0;
@@ -3762,7 +3687,7 @@ bool Field_longlong::send_binary(Protocol *protocol)
}
-int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
+int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
@@ -3783,7 +3708,7 @@ int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
+void Field_longlong::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table->s->db_low_byte_first)
@@ -3908,7 +3833,7 @@ int Field_float::store(double nr)
}
else
#endif
- memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ memcpy_fixed(ptr,(uchar*) &j,sizeof(j));
return error;
}
@@ -3931,7 +3856,7 @@ double Field_float::val_real(void)
}
else
#endif
- memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return ((double) j);
}
@@ -3945,7 +3870,7 @@ longlong Field_float::val_int(void)
}
else
#endif
- memcpy_fixed((byte*) &j,ptr,sizeof(j));
+ memcpy_fixed((uchar*) &j,ptr,sizeof(j));
return (longlong) rint(j);
}
@@ -3962,7 +3887,7 @@ String *Field_float::val_str(String *val_buffer,
}
else
#endif
- memcpy_fixed((byte*) &nr,ptr,sizeof(nr));
+ memcpy_fixed((uchar*) &nr,ptr,sizeof(nr));
uint to_length=max(field_length,70);
val_buffer->alloc(to_length);
@@ -4034,7 +3959,7 @@ String *Field_float::val_str(String *val_buffer,
}
-int Field_float::cmp(const char *a_ptr, const char *b_ptr)
+int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
float a,b;
#ifdef WORDS_BIGENDIAN
@@ -4054,7 +3979,7 @@ int Field_float::cmp(const char *a_ptr, const char *b_ptr)
#define FLT_EXP_DIG (sizeof(float)*8-FLT_MANT_DIG)
-void Field_float::sort_string(char *to,uint length __attribute__((unused)))
+void Field_float::sort_string(uchar *to,uint length __attribute__((unused)))
{
float nr;
#ifdef WORDS_BIGENDIAN
@@ -4066,7 +3991,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
#endif
memcpy_fixed(&nr,ptr,sizeof(float));
- uchar *tmp= (uchar*) to;
+ uchar *tmp= to;
if (nr == (float) 0.0)
{ /* Change to zero string */
tmp[0]=(uchar) 128;
@@ -4162,7 +4087,7 @@ int Field_double::store(double nr)
else
{
double max_value;
- if (dec >= NOT_FIXED_DEC)
+ if (not_fixed)
{
max_value= DBL_MAX;
}
@@ -4366,7 +4291,7 @@ bool Field_double::send_binary(Protocol *protocol)
}
-int Field_double::cmp(const char *a_ptr, const char *b_ptr)
+int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double a,b;
@@ -4390,7 +4315,7 @@ int Field_double::cmp(const char *a_ptr, const char *b_ptr)
/* The following should work for IEEE */
-void Field_double::sort_string(char *to,uint length __attribute__((unused)))
+void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
{
double nr;
#ifdef WORDS_BIGENDIAN
@@ -4401,7 +4326,7 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused)))
else
#endif
doubleget(nr,ptr);
- change_double_for_sort(nr, (byte*) to);
+ change_double_for_sort(nr, to);
}
@@ -4466,7 +4391,7 @@ void Field_double::sql_type(String &res) const
exception is different behavior of old/new timestamps during ALTER TABLE.
*/
-Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
+Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg,
const char *field_name_arg,
@@ -4489,7 +4414,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
Field_timestamp::Field_timestamp(bool maybe_null_arg,
const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str((char*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_str((uchar*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
@@ -4539,7 +4464,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME l_time;
+ MYSQL_TIME l_time;
my_time_t tmp= 0;
int error;
bool have_smth_to_conv;
@@ -4610,7 +4535,7 @@ int Field_timestamp::store(double nr)
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME l_time;
+ MYSQL_TIME l_time;
my_time_t timestamp= 0;
int error;
my_bool in_dst_time_gap;
@@ -4669,7 +4594,7 @@ longlong Field_timestamp::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp;
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
THD *thd= table ? table->in_use : current_thd;
#ifdef WORDS_BIGENDIAN
@@ -4695,7 +4620,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
ASSERT_COLUMN_MARKED_FOR_READ;
uint32 temp, temp2;
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
THD *thd= table ? table->in_use : current_thd;
char *to;
@@ -4764,7 +4689,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
}
-bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
+bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
long temp;
THD *thd= table ? table->in_use : current_thd;
@@ -4788,7 +4713,7 @@ bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
return 0;
}
-bool Field_timestamp::get_time(TIME *ltime)
+bool Field_timestamp::get_time(MYSQL_TIME *ltime)
{
return Field_timestamp::get_date(ltime,0);
}
@@ -4796,13 +4721,13 @@ bool Field_timestamp::get_time(TIME *ltime)
bool Field_timestamp::send_binary(Protocol *protocol)
{
- TIME tm;
+ MYSQL_TIME tm;
Field_timestamp::get_date(&tm, 0);
return protocol->store(&tm);
}
-int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
+int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -4821,7 +4746,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
+void Field_timestamp::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -4872,7 +4797,7 @@ void Field_timestamp::set_time()
int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
- TIME ltime;
+ MYSQL_TIME ltime;
long tmp;
int error= 0;
int warning;
@@ -4887,9 +4812,12 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
else
{
if (warning & MYSQL_TIME_WARN_TRUNCATED)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ {
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_TIME, 1);
+ error= 1;
+ }
if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE)
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -4900,8 +4828,6 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
if (ltime.month)
ltime.day=0;
tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second);
- if (error > 1)
- error= 2;
}
if (ltime.neg)
@@ -4911,7 +4837,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
}
-int Field_time::store_time(TIME *ltime, timestamp_type type)
+int Field_time::store_time(MYSQL_TIME *ltime, timestamp_type time_type)
{
long tmp= ((ltime->month ? 0 : ltime->day * 24L) + ltime->hour) * 10000L +
(ltime->minute * 100 + ltime->second);
@@ -5020,7 +4946,7 @@ String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- TIME ltime;
+ MYSQL_TIME ltime;
val_buffer->alloc(19);
long tmp=(long) sint3korr(ptr);
ltime.neg= 0;
@@ -5044,7 +4970,7 @@ String *Field_time::val_str(String *val_buffer,
DATE_FORMAT(time, "%l.%i %p")
*/
-bool Field_time::get_date(TIME *ltime, uint fuzzydate)
+bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
long tmp;
THD *thd= table ? table->in_use : current_thd;
@@ -5072,7 +4998,7 @@ bool Field_time::get_date(TIME *ltime, uint fuzzydate)
}
-bool Field_time::get_time(TIME *ltime)
+bool Field_time::get_time(MYSQL_TIME *ltime)
{
long tmp=(long) sint3korr(ptr);
ltime->neg=0;
@@ -5094,7 +5020,7 @@ bool Field_time::get_time(TIME *ltime)
bool Field_time::send_binary(Protocol *protocol)
{
- TIME tm;
+ MYSQL_TIME tm;
Field_time::get_time(&tm);
tm.day= tm.hour/24; // Move hours to days
tm.hour-= tm.day*24;
@@ -5102,7 +5028,7 @@ bool Field_time::send_binary(Protocol *protocol)
}
-int Field_time::cmp(const char *a_ptr, const char *b_ptr)
+int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
a=(int32) sint3korr(a_ptr);
@@ -5110,7 +5036,7 @@ int Field_time::cmp(const char *a_ptr, const char *b_ptr)
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_time::sort_string(char *to,uint length __attribute__((unused)))
+void Field_time::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = (uchar) (ptr[2] ^ 128);
to[1] = ptr[1];
@@ -5133,16 +5059,25 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
ASSERT_COLUMN_MARKED_FOR_WRITE;
char *end;
int error;
- long nr= my_strntol(cs, from, len, 10, &end, &error);
+ longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 || error)
+ if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 ||
+ error == MY_ERRNO_ERANGE)
{
*ptr=0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
- if (table->in_use->count_cuted_fields && check_int(from,len,end,cs))
+ if (table->in_use->count_cuted_fields &&
+ (error= check_int(cs, from, len, end, error)))
+ {
+ if (error == 1) /* empty or incorrect string */
+ {
+ *ptr= 0;
+ return 1;
+ }
error= 1;
+ }
if (nr != 0 || len != 4)
{
@@ -5205,7 +5140,7 @@ double Field_year::val_real(void)
longlong Field_year::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int tmp= (int) ((uchar*) ptr)[0];
+ int tmp= (int) ptr[0];
if (field_length != 4)
tmp%=100; // Return last 2 char
else if (tmp)
@@ -5243,7 +5178,7 @@ void Field_year::sql_type(String &res) const
int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME l_time;
+ MYSQL_TIME l_time;
uint32 tmp;
int error;
THD *thd= table ? table->in_use : current_thd;
@@ -5300,7 +5235,7 @@ int Field_date::store(double nr)
int Field_date::store(longlong nr, bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME not_used;
+ MYSQL_TIME not_used;
int error;
longlong initial_nr= nr;
THD *thd= table ? table->in_use : current_thd;
@@ -5341,7 +5276,7 @@ int Field_date::store(longlong nr, bool unsigned_val)
bool Field_date::send_binary(Protocol *protocol)
{
longlong tmp= Field_date::val_int();
- TIME tm;
+ MYSQL_TIME tm;
tm.year= (uint32) tmp/10000L % 10000;
tm.month= (uint32) tmp/100 % 100;
tm.day= (uint32) tmp % 100;
@@ -5381,7 +5316,7 @@ String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
ASSERT_COLUMN_MARKED_FOR_READ;
- TIME ltime;
+ MYSQL_TIME ltime;
val_buffer->alloc(field_length);
int32 tmp;
#ifdef WORDS_BIGENDIAN
@@ -5399,7 +5334,7 @@ String *Field_date::val_str(String *val_buffer,
}
-int Field_date::cmp(const char *a_ptr, const char *b_ptr)
+int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
int32 a,b;
#ifdef WORDS_BIGENDIAN
@@ -5418,7 +5353,7 @@ int Field_date::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_date::sort_string(char *to,uint length __attribute__((unused)))
+void Field_date::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -5450,31 +5385,54 @@ void Field_date::sql_type(String &res) const
** In number context: YYYYMMDD
****************************************************************************/
+/*
+ Store string into a date field
+
+ SYNOPSIS
+ Field_newdate::store()
+ from Date string
+ len Length of date field
+ cs Character set (not used)
+
+ RETURN
+ 0 ok
+ 1 Value was cut during conversion
+ 2 Wrong date string
+ 3 Datetime value that was cut (warning level NOTE)
+*/
+
int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME l_time;
long tmp;
+ MYSQL_TIME l_time;
int error;
THD *thd= table ? table->in_use : current_thd;
- if (str_to_datetime(from, len, &l_time,
- (TIME_FUZZY_DATE |
- (thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))),
- &error) <= MYSQL_TIMESTAMP_ERROR)
+ enum enum_mysql_timestamp_type ret;
+ if ((ret= str_to_datetime(from, len, &l_time,
+ (TIME_FUZZY_DATE |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error)) <= MYSQL_TIMESTAMP_ERROR)
{
- tmp= 0L;
+ tmp= 0;
error= 2;
}
else
+ {
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
+ if (!error && (ret != MYSQL_TIMESTAMP_DATE))
+ error= 3; // Datetime was cut (note)
+ }
if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
+ set_datetime_warning(error == 3 ? MYSQL_ERROR::WARN_LEVEL_NOTE :
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_DATE, 1);
- int3store(ptr,tmp);
+ int3store(ptr, tmp);
return error;
}
@@ -5495,7 +5453,7 @@ int Field_newdate::store(double nr)
int Field_newdate::store(longlong nr, bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME l_time;
+ MYSQL_TIME l_time;
longlong tmp;
int error;
THD *thd= table ? table->in_use : current_thd;
@@ -5522,12 +5480,13 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
}
-int Field_newdate::store_time(TIME *ltime,timestamp_type type)
+int Field_newdate::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
long tmp;
int error= 0;
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
tmp=ltime->year*16*32+ltime->month*32+ltime->day;
if (check_date(ltime, tmp != 0,
@@ -5556,7 +5515,7 @@ int Field_newdate::store_time(TIME *ltime,timestamp_type type)
bool Field_newdate::send_binary(Protocol *protocol)
{
- TIME tm;
+ MYSQL_TIME tm;
Field_newdate::get_date(&tm,0);
return protocol->store_date(&tm);
}
@@ -5607,7 +5566,7 @@ String *Field_newdate::val_str(String *val_buffer,
}
-bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
+bool Field_newdate::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
uint32 tmp=(uint32) uint3korr(ptr);
ltime->day= tmp & 31;
@@ -5620,13 +5579,13 @@ bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
}
-bool Field_newdate::get_time(TIME *ltime)
+bool Field_newdate::get_time(MYSQL_TIME *ltime)
{
return Field_newdate::get_date(ltime,0);
}
-int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
+int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
uint32 a,b;
a=(uint32) uint3korr(a_ptr);
@@ -5635,7 +5594,7 @@ int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
}
-void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
+void Field_newdate::sort_string(uchar *to,uint length __attribute__((unused)))
{
to[0] = ptr[2];
to[1] = ptr[1];
@@ -5659,7 +5618,7 @@ void Field_newdate::sql_type(String &res) const
int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
int error;
ulonglong tmp= 0;
enum enum_mysql_timestamp_type func_res;
@@ -5712,7 +5671,7 @@ int Field_datetime::store(double nr)
int Field_datetime::store(longlong nr, bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- TIME not_used;
+ MYSQL_TIME not_used;
int error;
longlong initial_nr= nr;
THD *thd= table ? table->in_use : current_thd;
@@ -5747,7 +5706,7 @@ int Field_datetime::store(longlong nr, bool unsigned_val)
}
-int Field_datetime::store_time(TIME *ltime,timestamp_type type)
+int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
longlong tmp;
@@ -5756,7 +5715,8 @@ int Field_datetime::store_time(TIME *ltime,timestamp_type type)
We don't perform range checking here since values stored in TIME
structure always fit into DATETIME range.
*/
- if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
+ if (time_type == MYSQL_TIMESTAMP_DATE ||
+ time_type == MYSQL_TIMESTAMP_DATETIME)
{
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
(ltime->hour*10000L+ltime->minute*100+ltime->second));
@@ -5792,7 +5752,7 @@ int Field_datetime::store_time(TIME *ltime,timestamp_type type)
bool Field_datetime::send_binary(Protocol *protocol)
{
- TIME tm;
+ MYSQL_TIME tm;
Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
return protocol->store(&tm);
}
@@ -5866,7 +5826,7 @@ String *Field_datetime::val_str(String *val_buffer,
return val_buffer;
}
-bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
+bool Field_datetime::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
longlong tmp=Field_datetime::val_int();
uint32 part1,part2;
@@ -5885,12 +5845,12 @@ bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
return (!(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day)) ? 1 : 0;
}
-bool Field_datetime::get_time(TIME *ltime)
+bool Field_datetime::get_time(MYSQL_TIME *ltime)
{
return Field_datetime::get_date(ltime,0);
}
-int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
+int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
longlong a,b;
#ifdef WORDS_BIGENDIAN
@@ -5909,7 +5869,7 @@ int Field_datetime::cmp(const char *a_ptr, const char *b_ptr)
((ulonglong) a > (ulonglong) b) ? 1 : 0;
}
-void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
+void Field_datetime::sort_string(uchar *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
if (!table || !table->s->db_low_byte_first)
@@ -5958,6 +5918,7 @@ void Field_datetime::sql_type(String &res) const
well_formed_error_pos - where not well formed data was first met
cannot_convert_error_pos - where a not-convertable character was first met
end - end of the string
+ cs - character set of the string
NOTES
As of version 5.0 both cases return the same error:
@@ -5977,7 +5938,8 @@ static bool
check_string_copy_error(Field_str *field,
const char *well_formed_error_pos,
const char *cannot_convert_error_pos,
- const char *end)
+ const char *end,
+ CHARSET_INFO *cs)
{
const char *pos, *end_orig;
char tmp[64], *t;
@@ -5991,8 +5953,18 @@ check_string_copy_error(Field_str *field,
for (t= tmp; pos < end; pos++)
{
+ /*
+ If the source string is ASCII compatible (mbminlen==1)
+ and the source character is in ASCII printable range (0x20..0x7F),
+ then display the character as is.
+
+ Otherwise, if the source string is not ASCII compatible (e.g. UCS2),
+ or the source character is not in the printable range,
+ then print the character using HEX notation.
+ */
if (((unsigned char) *pos) >= 0x20 &&
- ((unsigned char) *pos) <= 0x7F)
+ ((unsigned char) *pos) <= 0x7F &&
+ cs->mbminlen == 1)
{
*t++= *pos;
}
@@ -6046,31 +6018,6 @@ report_data_too_long(Field_str *field)
}
-/*
- Test if the given string contains important data:
- not spaces for character string,
- or any data for binary string.
-
- SYNOPSIS
- test_if_important_data()
- cs Character set
- str String to test
- strend String end
-
- RETURN
- FALSE - If string does not have important data
- TRUE - If string has some important data
-*/
-
-static bool
-test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend)
-{
- if (cs != &my_charset_bin)
- str+= cs->cset->scan(cs, str, strend, MY_SEQ_SPACES);
- return (str < strend);
-}
-
-
/* Copy a string and fill with space */
int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
@@ -6085,7 +6032,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
DBUG_ASSERT(table->in_use == current_thd);
copy_length= well_formed_copy_nchars(field_charset,
- ptr, field_length,
+ (char*) ptr, field_length,
cs, from, length,
field_length / field_charset->mbmaxlen,
&well_formed_error_pos,
@@ -6094,12 +6041,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
- field_charset->cset->fill(field_charset,ptr+copy_length,
+ field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
field_length-copy_length,
field_charset->pad_char);
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
/*
@@ -6135,33 +6082,33 @@ int Field_str::store(double nr)
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint length;
bool use_scientific_notation= TRUE;
- uint char_length= field_length / charset()->mbmaxlen;
+ uint local_char_length= field_length / charset()->mbmaxlen;
/*
Check fabs(nr) against longest value that can be stored in field,
which depends on whether the value is < 1 or not, and negative or not
*/
double anr= fabs(nr);
int neg= (nr < 0.0) ? 1 : 0;
- if (char_length > 4 && char_length < 32 &&
- (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */
- : anr < log_10[char_length-neg]-1))
+ if (local_char_length > 4 && local_char_length < 32 &&
+ (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */
+ : anr < log_10[local_char_length-neg]-1))
use_scientific_notation= FALSE;
length= (uint) my_sprintf(buff, (buff, "%-.*g",
(use_scientific_notation ?
- max(0, (int)char_length-neg-5) :
- char_length),
+ max(0, (int)local_char_length-neg-5) :
+ local_char_length),
nr));
/*
+1 below is because "precision" in %g above means the
max. number of significant digits, not the output width.
Thus the width can be larger than number of significant digits by 1
(for decimal point)
- the test for char_length < 5 is for extreme cases,
+ the test for local_char_length < 5 is for extreme cases,
like inserting 500.0 in char(1)
*/
- DBUG_ASSERT(char_length < 5 || length <= char_length+1);
- return store((const char *) buff, length, charset());
+ DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1);
+ return store(buff, length, charset());
}
@@ -6171,17 +6118,25 @@ uint Field::is_equal(create_field *new_field)
}
+/* If one of the fields is binary and the other one isn't return 1 else 0 */
+
+bool Field_str::compare_str_field_flags(create_field *new_field, uint32 flags)
+{
+ return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
+ !(flags & (BINCMP_FLAG | BINARY_FLAG))) ||
+ (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
+ (flags & (BINCMP_FLAG | BINARY_FLAG))));
+}
+
+
uint Field_str::is_equal(create_field *new_field)
{
- if (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
- !(flags & (BINCMP_FLAG | BINARY_FLAG))) ||
- (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
- (flags & (BINCMP_FLAG | BINARY_FLAG))))
- return 0; /* One of the fields is binary and the other one isn't */
+ if (compare_str_field_flags(new_field, flags))
+ return 0;
return ((new_field->sql_type == real_type()) &&
new_field->charset == field_charset &&
- new_field->length == max_length());
+ new_field->length == max_display_length());
}
@@ -6213,14 +6168,15 @@ double Field_string::val_real(void)
CHARSET_INFO *cs= charset();
double result;
- result= my_strntod(cs,ptr,field_length,&end,&error);
+ result= my_strntod(cs,(char*) ptr,field_length,&end,&error);
if (!table->in_use->no_errors &&
- (error || (field_length != (uint32)(end - ptr) &&
- !check_if_only_end_space(cs, end, ptr + field_length))))
+ (error || (field_length != (uint32)(end - (char*) ptr) &&
+ !check_if_only_end_space(cs, end,
+ (char*) ptr + field_length))))
{
char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -6238,14 +6194,15 @@ longlong Field_string::val_int(void)
CHARSET_INFO *cs= charset();
longlong result;
- result= my_strntoll(cs,ptr,field_length,10,&end,&error);
+ result= my_strntoll(cs, (char*) ptr,field_length,10,&end,&error);
if (!table->in_use->no_errors &&
- (error || (field_length != (uint32)(end - ptr) &&
- !check_if_only_end_space(cs, end, ptr + field_length))))
+ (error || (field_length != (uint32)(end - (char*) ptr) &&
+ !check_if_only_end_space(cs, end,
+ (char*) ptr + field_length))))
{
char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE];
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -6259,9 +6216,15 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
+ uint length;
+ if (table->in_use->variables.sql_mode &
+ MODE_PAD_CHAR_TO_FULL_LENGTH)
+ length= my_charpos(field_charset, ptr, ptr + field_length, field_length);
+ else
+ length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
+ field_length);
val_ptr->set((const char*) ptr, length, field_charset);
return val_ptr;
}
@@ -6270,14 +6233,14 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- int err= str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
- decimal_value);
+ int err= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr, field_length,
+ charset(), decimal_value);
if (!table->in_use->no_errors && err)
{
char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE];
CHARSET_INFO *cs= charset();
String tmp(buf, sizeof(buf), cs);
- tmp.copy(ptr, field_length, cs);
+ tmp.copy((char*) ptr, field_length, cs);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE),
@@ -6288,7 +6251,7 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
}
-int Field_string::cmp(const char *a_ptr, const char *b_ptr)
+int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
uint a_len, b_len;
@@ -6305,17 +6268,17 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
like in latin_de 'ae' and 0xe4
*/
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a_ptr, a_len,
- (const uchar*) b_ptr, b_len,
+ a_ptr, a_len,
+ b_ptr, b_len,
0);
}
-void Field_string::sort_string(char *to,uint length)
+void Field_string::sort_string(uchar *to,uint length)
{
- uint tmp= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr, field_length);
+ IF_DBUG(uint tmp=) my_strnxfrm(field_charset,
+ to, length,
+ ptr, field_length);
DBUG_ASSERT(tmp == length);
}
@@ -6340,24 +6303,25 @@ void Field_string::sql_type(String &res) const
}
-char *Field_string::pack(char *to, const char *from, uint max_length)
+uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
uint length= min(field_length,max_length);
- uint char_length= max_length/field_charset->mbmaxlen;
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
+ uint local_char_length= max_length/field_charset->mbmaxlen;
+ if (length > local_char_length)
+ local_char_length= my_charpos(field_charset, from, from+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
while (length && from[length-1] == ' ')
length--;
- *to++= (char) (uchar) length;
+ *to++= (uchar) length;
if (field_length > 255)
- *to++= (char) (uchar) (length >> 8);
+ *to++= (uchar) (length >> 8);
memcpy(to, from, length);
return to+length;
}
-const char *Field_string::unpack(char *to, const char *from)
+const uchar *Field_string::unpack(uchar *to, const uchar *from)
{
uint length;
if (field_length > 255)
@@ -6366,7 +6330,7 @@ const char *Field_string::unpack(char *to, const char *from)
from+= 2;
}
else
- length= (uint) (uchar) *from++;
+ length= (uint) *from++;
memcpy(to, from, (int) length);
bfill(to+length, field_length - length, ' ');
return from+length;
@@ -6389,7 +6353,7 @@ const char *Field_string::unpack(char *to, const char *from)
> 0 a > b
*/
-int Field_string::pack_cmp(const char *a, const char *b, uint length,
+int Field_string::pack_cmp(const uchar *a, const uchar *b, uint length,
my_bool insert_or_update)
{
uint a_length, b_length;
@@ -6402,12 +6366,12 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length,
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
@@ -6427,18 +6391,18 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length,
> 0 row > key
*/
-int Field_string::pack_cmp(const char *key, uint length,
+int Field_string::pack_cmp(const uchar *key, uint length,
my_bool insert_or_update)
{
- uint row_length, key_length;
- char *end;
+ uint row_length, local_key_length;
+ uchar *end;
if (length > 255)
{
- key_length= uint2korr(key);
+ local_key_length= uint2korr(key);
key+= 2;
}
else
- key_length= (uint) (uchar) *key++;
+ local_key_length= (uint) *key++;
/* Only use 'length' of key, not field_length */
end= ptr + length;
@@ -6447,17 +6411,17 @@ int Field_string::pack_cmp(const char *key, uint length,
row_length= (uint) (end - ptr);
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) ptr, row_length,
- (const uchar*) key, key_length,
+ ptr, row_length,
+ key, local_key_length,
insert_or_update);
}
-uint Field_string::packed_col_length(const char *data_ptr, uint length)
+uint Field_string::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -6467,6 +6431,18 @@ uint Field_string::max_packed_col_length(uint max_length)
}
+uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
+{
+ uint bytes = my_charpos(field_charset, (char*) ptr,
+ (char*) ptr + field_length,
+ length / field_charset->mbmaxlen);
+ memcpy(buff, ptr, bytes);
+ if (bytes < length)
+ bzero(buff + bytes, length - bytes);
+ return bytes;
+}
+
+
Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
bool keep_type)
{
@@ -6520,7 +6496,8 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
const char *from_end_pos;
copy_length= well_formed_copy_nchars(field_charset,
- ptr + length_bytes, field_length,
+ (char*) ptr + length_bytes,
+ field_length,
cs, from, length,
field_length / field_charset->mbmaxlen,
&well_formed_error_pos,
@@ -6533,7 +6510,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
int2store(ptr, copy_length);
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
// Check if we lost something other than just trailing spaces
@@ -6568,9 +6545,9 @@ double Field_varstring::val_real(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntod(field_charset, ptr+length_bytes, length, &end_not_used,
- &not_used);
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ return my_strntod(field_charset, (char*) ptr+length_bytes, length,
+ &end_not_used, &not_used);
}
@@ -6579,8 +6556,8 @@ longlong Field_varstring::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
int not_used;
char *end_not_used;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntoll(field_charset, ptr+length_bytes, length, 10,
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ return my_strntoll(field_charset, (char*) ptr+length_bytes, length, 10,
&end_not_used, &not_used);
}
@@ -6588,7 +6565,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
val_ptr->set((const char*) ptr+length_bytes, length, field_charset);
return val_ptr;
}
@@ -6597,14 +6574,14 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- str2my_decimal(E_DEC_FATAL_ERROR, ptr+length_bytes, length, charset(),
- decimal_value);
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length,
+ charset(), decimal_value);
return decimal_value;
}
-int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr,
+int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_len)
{
uint a_length, b_length;
@@ -6612,8 +6589,8 @@ int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr,
if (length_bytes == 1)
{
- a_length= (uint) (uchar) *a_ptr;
- b_length= (uint) (uchar) *b_ptr;
+ a_length= (uint) *a_ptr;
+ b_length= (uint) *b_ptr;
}
else
{
@@ -6623,10 +6600,10 @@ int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr,
set_if_smaller(a_length, max_len);
set_if_smaller(b_length, max_len);
diff= field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a_ptr+
+ a_ptr+
length_bytes,
a_length,
- (const uchar*) b_ptr+
+ b_ptr+
length_bytes,
b_length,0);
return diff;
@@ -6637,18 +6614,18 @@ int Field_varstring::cmp_max(const char *a_ptr, const char *b_ptr,
NOTE: varstring and blob keys are ALWAYS stored with a 2 byte length prefix
*/
-int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
+int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- uint char_length= max_key_length / field_charset->mbmaxlen;
+ uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ uint local_char_length= max_key_length / field_charset->mbmaxlen;
- char_length= my_charpos(field_charset, ptr + length_bytes,
- ptr + length_bytes + length, char_length);
- set_if_smaller(length, char_length);
+ local_char_length= my_charpos(field_charset, ptr + length_bytes,
+ ptr + length_bytes + length, local_char_length);
+ set_if_smaller(length, local_char_length);
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) ptr + length_bytes,
+ ptr + length_bytes,
length,
- (const uchar*) key_ptr+
+ key_ptr+
HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr), 0);
}
@@ -6662,22 +6639,20 @@ int Field_varstring::key_cmp(const byte *key_ptr, uint max_key_length)
(keys are created and compared in key.cc)
*/
-int Field_varstring::key_cmp(const byte *a,const byte *b)
+int Field_varstring::key_cmp(const uchar *a,const uchar *b)
{
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a +
- HA_KEY_BLOB_LENGTH,
+ a + HA_KEY_BLOB_LENGTH,
uint2korr(a),
- (const uchar*) b +
- HA_KEY_BLOB_LENGTH,
+ b + HA_KEY_BLOB_LENGTH,
uint2korr(b),
0);
}
-void Field_varstring::sort_string(char *to,uint length)
+void Field_varstring::sort_string(uchar *to,uint length)
{
- uint tot_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint tot_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
if (field_charset == &my_charset_bin)
{
@@ -6690,8 +6665,7 @@ void Field_varstring::sort_string(char *to,uint length)
}
tot_length= my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) ptr + length_bytes,
+ to, length, ptr + length_bytes,
tot_length);
DBUG_ASSERT(tot_length == length);
}
@@ -6728,7 +6702,7 @@ void Field_varstring::sql_type(String &res) const
uint32 Field_varstring::data_length()
{
- return length_bytes == 1 ? (uint32) (uchar) *ptr : uint2korr(ptr);
+ return length_bytes == 1 ? (uint32) *ptr : uint2korr(ptr);
}
/*
@@ -6736,9 +6710,9 @@ uint32 Field_varstring::data_length()
Here the number of length bytes are depending on the given max_length
*/
-char *Field_varstring::pack(char *to, const char *from, uint max_length)
+uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *from : uint2korr(from);
+ uint length= length_bytes == 1 ? (uint) *from : uint2korr(from);
set_if_smaller(max_length, field_length);
if (length > max_length)
length=max_length;
@@ -6751,16 +6725,17 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
}
-char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
+uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
{
- uint length= length_bytes == 1 ? (uint) (uchar) *key : uint2korr(key);
- uint char_length= ((field_charset->mbmaxlen > 1) ?
+ uint length= length_bytes == 1 ? (uint) *key : uint2korr(key);
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
max_length/field_charset->mbmaxlen : max_length);
key+= length_bytes;
- if (length > char_length)
+ if (length > local_char_length)
{
- char_length= my_charpos(field_charset, key, key+length, char_length);
- set_if_smaller(length, char_length);
+ local_char_length= my_charpos(field_charset, key, key+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
}
*to++= (char) (length & 255);
if (max_length > 255)
@@ -6789,13 +6764,13 @@ char *Field_varstring::pack_key(char *to, const char *key, uint max_length)
Pointer to end of 'key' (To the next key part if multi-segment key)
*/
-const char *Field_varstring::unpack_key(char *to, const char *key,
- uint max_length)
+const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key,
+ uint max_length)
{
/* get length of the blob key */
- uint32 length= *((uchar*) key++);
+ uint32 length= *key++;
if (max_length > 255)
- length+= (*((uchar*) key++)) << 8;
+ length+= (*key++) << 8;
/* put the length into the record buffer */
if (length_bytes == 1)
@@ -6819,8 +6794,8 @@ const char *Field_varstring::unpack_key(char *to, const char *key,
end of key storage
*/
-char *Field_varstring::pack_key_from_key_image(char *to, const char *from,
- uint max_length)
+uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
+ uint max_length)
{
/* Key length is always stored as 2 bytes */
uint length= uint2korr(from);
@@ -6839,11 +6814,11 @@ char *Field_varstring::pack_key_from_key_image(char *to, const char *from,
unpack field packed with Field_varstring::pack()
*/
-const char *Field_varstring::unpack(char *to, const char *from)
+const uchar *Field_varstring::unpack(uchar *to, const uchar *from)
{
uint length;
if (length_bytes == 1)
- length= (uint) (uchar) (*to= *from++);
+ length= (uint) (*to= *from++);
else
{
length= uint2korr(from);
@@ -6856,62 +6831,64 @@ const char *Field_varstring::unpack(char *to, const char *from)
}
-int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length,
+int Field_varstring::pack_cmp(const uchar *a, const uchar *b,
+ uint key_length_arg,
my_bool insert_or_update)
{
uint a_length, b_length;
- if (key_length > 255)
+ if (key_length_arg > 255)
{
a_length=uint2korr(a); a+= 2;
b_length=uint2korr(b); b+= 2;
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-int Field_varstring::pack_cmp(const char *b, uint key_length,
+int Field_varstring::pack_cmp(const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
- char *a= ptr+ length_bytes;
- uint a_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uchar *a= ptr+ length_bytes;
+ uint a_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
uint b_length;
- uint char_length= ((field_charset->mbmaxlen > 1) ?
- key_length / field_charset->mbmaxlen : key_length);
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
+ key_length_arg / field_charset->mbmaxlen :
+ key_length_arg);
- if (key_length > 255)
+ if (key_length_arg > 255)
{
b_length=uint2korr(b); b+= HA_KEY_BLOB_LENGTH;
}
else
- b_length= (uint) (uchar) *b++;
+ b_length= (uint) *b++;
- if (a_length > char_length)
+ if (a_length > local_char_length)
{
- char_length= my_charpos(field_charset, a, a+a_length, char_length);
- set_if_smaller(a_length, char_length);
+ local_char_length= my_charpos(field_charset, a, a+a_length,
+ local_char_length);
+ set_if_smaller(a_length, local_char_length);
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a,
- a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
+uint Field_varstring::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -6920,14 +6897,14 @@ uint Field_varstring::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
-
-void Field_varstring::get_key_image(char *buff, uint length, imagetype type)
+uint Field_varstring::get_key_image(uchar *buff, uint length, imagetype type)
{
- uint f_length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- uint char_length= length / field_charset->mbmaxlen;
- char *pos= ptr+length_bytes;
- char_length= my_charpos(field_charset, pos, pos + f_length, char_length);
- set_if_smaller(f_length, char_length);
+ uint f_length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
+ uint local_char_length= length / field_charset->mbmaxlen;
+ uchar *pos= ptr+length_bytes;
+ local_char_length= my_charpos(field_charset, pos, pos + f_length,
+ local_char_length);
+ set_if_smaller(f_length, local_char_length);
/* Key is always stored with 2 bytes */
int2store(buff,f_length);
memcpy(buff+HA_KEY_BLOB_LENGTH, pos, f_length);
@@ -6939,26 +6916,27 @@ void Field_varstring::get_key_image(char *buff, uint length, imagetype type)
*/
bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length));
}
+ return HA_KEY_BLOB_LENGTH+f_length;
}
-void Field_varstring::set_key_image(char *buff,uint length)
+void Field_varstring::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff); // Real length is here
- (void) Field_varstring::store(buff+HA_KEY_BLOB_LENGTH, length,
+ (void) Field_varstring::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
field_charset);
}
-int Field_varstring::cmp_binary(const char *a_ptr, const char *b_ptr,
+int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
uint32 max_length)
{
uint32 a_length,b_length;
if (length_bytes == 1)
{
- a_length= (uint) (uchar) *a_ptr;
- b_length= (uint) (uchar) *b_ptr;
+ a_length= (uint) *a_ptr;
+ b_length= (uint) *b_ptr;
}
else
{
@@ -6986,7 +6964,7 @@ Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *Field_varstring::new_key_field(MEM_ROOT *root,
struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field_varstring *res;
@@ -7008,11 +6986,11 @@ uint Field_varstring::is_equal(create_field *new_field)
if (new_field->sql_type == real_type() &&
new_field->charset == field_charset)
{
- if (new_field->length == max_length())
+ if (new_field->length == max_display_length())
return IS_EQUAL_YES;
- if (new_field->length > max_length() &&
- ((new_field->length <= 255 && max_length() <= 255) ||
- (new_field->length > 255 && max_length() > 255)))
+ if (new_field->length > max_display_length() &&
+ ((new_field->length <= 255 && max_display_length() <= 255) ||
+ (new_field->length > 255 && max_display_length() > 255)))
return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length
}
return IS_EQUAL_NO;
@@ -7027,9 +7005,9 @@ void Field_varstring::hash(ulong *nr, ulong *nr2)
}
else
{
- uint len= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
+ uint len= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
CHARSET_INFO *cs= charset();
- cs->coll->hash_sort(cs, (uchar*) ptr + length_bytes, len, nr, nr2);
+ cs->coll->hash_sort(cs, ptr + length_bytes, len, nr, nr2);
}
}
@@ -7040,7 +7018,7 @@ void Field_varstring::hash(ulong *nr, ulong *nr2)
** packlength slot and may be from 1-4.
****************************************************************************/
-Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
TABLE_SHARE *share, uint blob_pack_length,
CHARSET_INFO *cs)
@@ -7055,43 +7033,43 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
}
-void Field_blob::store_length(uint32 number)
+void Field_blob::store_length(uchar *i_ptr, uint i_packlength, uint32 i_number)
{
- switch (packlength) {
+ switch (i_packlength) {
case 1:
- ptr[0]= (uchar) number;
+ i_ptr[0]= (uchar) i_number;
break;
case 2:
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
- int2store(ptr,(unsigned short) number);
+ int2store(i_ptr,(unsigned short) i_number);
}
else
#endif
- shortstore(ptr,(unsigned short) number);
+ shortstore(i_ptr,(unsigned short) i_number);
break;
case 3:
- int3store(ptr,number);
+ int3store(i_ptr,i_number);
break;
case 4:
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
- int4store(ptr,number);
+ int4store(i_ptr,i_number);
}
else
#endif
- longstore(ptr,number);
+ longstore(i_ptr,i_number);
}
}
-uint32 Field_blob::get_length(const char *pos)
+uint32 Field_blob::get_length(const uchar *pos)
{
switch (packlength) {
case 1:
- return (uint32) (uchar) pos[0];
+ return (uint32) pos[0];
case 2:
{
uint16 tmp;
@@ -7138,7 +7116,7 @@ uint32 Field_blob::get_length(const char *pos)
nothing
*/
-void Field_blob::put_length(char *pos, uint32 length)
+void Field_blob::put_length(uchar *pos, uint32 length)
{
switch (packlength) {
case 1:
@@ -7206,13 +7184,13 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
Field_blob::store_length(copy_length);
tmp= value.ptr();
- bmove(ptr+packlength,(char*) &tmp,sizeof(char*));
+ bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*));
if (check_string_copy_error(this, well_formed_error_pos,
- cannot_convert_error_pos, from + length))
+ cannot_convert_error_pos, from + length, cs))
return 2;
- if (copy_length < length)
+ if (from_end_pos < from + length)
{
report_data_too_long(this);
return 2;
@@ -7290,29 +7268,35 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
const char *blob;
- memcpy_fixed(&blob, ptr+packlength, sizeof(const char*));
+ size_t length;
+ memcpy_fixed(&blob, ptr+packlength, sizeof(const uchar*));
if (!blob)
+ {
blob= "";
- str2my_decimal(E_DEC_FATAL_ERROR, blob, get_length(ptr), charset(),
+ length= 0;
+ }
+ else
+ length= get_length(ptr);
+
+ str2my_decimal(E_DEC_FATAL_ERROR, blob, length, charset(),
decimal_value);
return decimal_value;
}
-int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
+int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b,
uint32 b_length)
{
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*)a, a_length,
- (const uchar*)b, b_length,
+ a, a_length, b, b_length,
0);
}
-int Field_blob::cmp_max(const char *a_ptr, const char *b_ptr,
+int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_length)
{
- char *blob1,*blob2;
+ uchar *blob1,*blob2;
memcpy_fixed(&blob1,a_ptr+packlength,sizeof(char*));
memcpy_fixed(&blob2,b_ptr+packlength,sizeof(char*));
uint a_len= get_length(a_ptr), b_len= get_length(b_ptr);
@@ -7322,7 +7306,7 @@ int Field_blob::cmp_max(const char *a_ptr, const char *b_ptr,
}
-int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
+int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
uint32 max_length)
{
char *a,*b;
@@ -7343,28 +7327,29 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff, uint length, imagetype type)
+uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
{
uint32 blob_length= get_length(ptr);
- char *blob;
+ uchar *blob;
#ifdef HAVE_SPATIAL
- if (type == itMBR)
+ if (type_arg == itMBR)
{
const char *dummy;
MBR mbr;
Geometry_buffer buffer;
Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
if (blob_length < SRID_SIZE)
{
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
+ bzero(buff, image_length);
+ return image_length;
}
get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
+ gobj= Geometry::construct(&buffer, (char*) blob, blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
+ bzero(buff, image_length);
else
{
float8store(buff, mbr.xmin);
@@ -7372,15 +7357,15 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type)
float8store(buff+16, mbr.ymin);
float8store(buff+24, mbr.ymax);
}
- return;
+ return image_length;
}
#endif /*HAVE_SPATIAL*/
get_ptr(&blob);
- uint char_length= length / field_charset->mbmaxlen;
- char_length= my_charpos(field_charset, blob, blob + blob_length,
- char_length);
- set_if_smaller(blob_length, char_length);
+ uint local_char_length= length / field_charset->mbmaxlen;
+ local_char_length= my_charpos(field_charset, blob, blob + blob_length,
+ local_char_length);
+ set_if_smaller(blob_length, local_char_length);
if ((uint32) length > blob_length)
{
@@ -7393,34 +7378,37 @@ void Field_blob::get_key_image(char *buff, uint length, imagetype type)
}
int2store(buff,length);
memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
+ return HA_KEY_BLOB_LENGTH+length;
}
-void Field_blob::set_key_image(char *buff,uint length)
+void Field_blob::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff);
- (void) Field_blob::store(buff+HA_KEY_BLOB_LENGTH, length, field_charset);
+ (void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
+ field_charset);
}
-int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
+int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
{
- char *blob1;
+ uchar *blob1;
uint blob_length=get_length(ptr);
memcpy_fixed(&blob1,ptr+packlength,sizeof(char*));
CHARSET_INFO *cs= charset();
- uint char_length= max_key_length / cs->mbmaxlen;
- char_length= my_charpos(cs, blob1, blob1+blob_length, char_length);
- set_if_smaller(blob_length, char_length);
+ uint local_char_length= max_key_length / cs->mbmaxlen;
+ local_char_length= my_charpos(cs, blob1, blob1+blob_length,
+ local_char_length);
+ set_if_smaller(blob_length, local_char_length);
return Field_blob::cmp(blob1, blob_length,
- (char*) key_ptr+HA_KEY_BLOB_LENGTH,
+ key_ptr+HA_KEY_BLOB_LENGTH,
uint2korr(key_ptr));
}
-int Field_blob::key_cmp(const byte *a,const byte *b)
+int Field_blob::key_cmp(const uchar *a,const uchar *b)
{
- return Field_blob::cmp((char*) a+HA_KEY_BLOB_LENGTH, uint2korr(a),
- (char*) b+HA_KEY_BLOB_LENGTH, uint2korr(b));
+ return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
+ b+HA_KEY_BLOB_LENGTH, uint2korr(b));
}
@@ -7431,9 +7419,9 @@ uint32 Field_blob::sort_length() const
}
-void Field_blob::sort_string(char *to,uint length)
+void Field_blob::sort_string(uchar *to,uint length)
{
- char *blob;
+ uchar *blob;
uint blob_length=get_length();
if (!blob_length)
@@ -7442,7 +7430,7 @@ void Field_blob::sort_string(char *to,uint length)
{
if (field_charset == &my_charset_bin)
{
- char *pos;
+ uchar *pos;
/*
Store length of blob last in blob to shorter blobs before longer blobs
@@ -7468,8 +7456,7 @@ void Field_blob::sort_string(char *to,uint length)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
blob_length=my_strnxfrm(field_charset,
- (uchar*) to, length,
- (uchar*) blob, blob_length);
+ to, length, blob, blob_length);
DBUG_ASSERT(blob_length == length);
}
}
@@ -7495,23 +7482,23 @@ void Field_blob::sql_type(String &res) const
}
-char *Field_blob::pack(char *to, const char *from, uint max_length)
+uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
{
- char *save=ptr;
- ptr=(char*) from;
+ uchar *save= ptr;
+ ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
if (length > max_length)
{
ptr=to;
length=max_length;
store_length(length); // Store max length
- ptr=(char*) from;
+ ptr= (uchar*) from;
}
else
memcpy(to,from,packlength); // Copy length
if (length)
{
- get_ptr((char**) &from);
+ get_ptr((uchar**) &from);
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
@@ -7519,7 +7506,7 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
}
-const char *Field_blob::unpack(char *to, const char *from)
+const uchar *Field_blob::unpack(uchar *to, const uchar *from)
{
memcpy(to,from,packlength);
uint32 length=get_length(from);
@@ -7533,63 +7520,64 @@ const char *Field_blob::unpack(char *to, const char *from)
/* Keys for blobs are like keys on varchars */
-int Field_blob::pack_cmp(const char *a, const char *b, uint key_length,
+int Field_blob::pack_cmp(const uchar *a, const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
uint a_length, b_length;
- if (key_length > 255)
+ if (key_length_arg > 255)
{
a_length=uint2korr(a); a+=2;
b_length=uint2korr(b); b+=2;
}
else
{
- a_length= (uint) (uchar) *a++;
- b_length= (uint) (uchar) *b++;
+ a_length= (uint) *a++;
+ b_length= (uint) *b++;
}
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
-int Field_blob::pack_cmp(const char *b, uint key_length,
+int Field_blob::pack_cmp(const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{
- char *a;
+ uchar *a;
+ uint a_length, b_length;
memcpy_fixed(&a,ptr+packlength,sizeof(char*));
if (!a)
- return key_length > 0 ? -1 : 0;
- uint a_length=get_length(ptr);
- uint b_length;
+ return key_length_arg > 0 ? -1 : 0;
- if (key_length > 255)
+ a_length= get_length(ptr);
+ if (key_length_arg > 255)
{
- b_length=uint2korr(b); b+=2;
+ b_length= uint2korr(b); b+=2;
}
else
- b_length= (uint) (uchar) *b++;
+ b_length= (uint) *b++;
return field_charset->coll->strnncollsp(field_charset,
- (const uchar*) a, a_length,
- (const uchar*) b, b_length,
+ a, a_length,
+ b, b_length,
insert_or_update);
}
/* Create a packed key that will be used for storage from a MySQL row */
-char *Field_blob::pack_key(char *to, const char *from, uint max_length)
+uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
{
- char *save=ptr;
- ptr=(char*) from;
+ uchar *save= ptr;
+ ptr= (uchar*) from;
uint32 length=get_length(); // Length of from string
- uint char_length= ((field_charset->mbmaxlen > 1) ?
- max_length/field_charset->mbmaxlen : max_length);
+ uint local_char_length= ((field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length);
if (length)
- get_ptr((char**) &from);
- if (length > char_length)
- char_length= my_charpos(field_charset, from, from+length, char_length);
- set_if_smaller(length, char_length);
+ get_ptr((uchar**) &from);
+ if (length > local_char_length)
+ local_char_length= my_charpos(field_charset, from, from+length,
+ local_char_length);
+ set_if_smaller(length, local_char_length);
*to++= (uchar) length;
if (max_length > 255) // 2 byte length
*to++= (uchar) (length >> 8);
@@ -7622,12 +7610,13 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
Pointer into 'from' past the last byte copied from packed key.
*/
-const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
+const uchar *Field_blob::unpack_key(uchar *to, const uchar *from,
+ uint max_length)
{
/* get length of the blob key */
- uint32 length= *((uchar*) from++);
+ uint32 length= *from++;
if (max_length > 255)
- length+= (*((uchar*) from++)) << 8;
+ length+= *from++ << 8;
/* put the length into the record buffer */
put_length(to, length);
@@ -7645,8 +7634,8 @@ const char *Field_blob::unpack_key(char *to, const char *from, uint max_length)
/* Create a packed key that will be used for storage from a MySQL key */
-char *Field_blob::pack_key_from_key_image(char *to, const char *from,
- uint max_length)
+uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from,
+ uint max_length)
{
uint length=uint2korr(from);
if (length > max_length)
@@ -7660,11 +7649,11 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
}
-uint Field_blob::packed_col_length(const char *data_ptr, uint length)
+uint Field_blob::packed_col_length(const uchar *data_ptr, uint length)
{
if (length > 255)
return uint2korr(data_ptr)+2;
- return (uint) ((uchar) *data_ptr)+1;
+ return (uint) *data_ptr + 1;
}
@@ -7674,26 +7663,39 @@ uint Field_blob::max_packed_col_length(uint max_length)
}
+uint Field_blob::is_equal(create_field *new_field)
+{
+ if (compare_str_field_flags(new_field, flags))
+ return 0;
+
+ return ((new_field->sql_type == get_blob_type_from_length(max_data_length()))
+ && new_field->charset == field_charset &&
+ ((Field_blob *)new_field->field)->max_data_length() ==
+ max_data_length());
+}
+
+
#ifdef HAVE_SPATIAL
-void Field_geom::get_key_image(char *buff, uint length, imagetype type)
+uint Field_geom::get_key_image(uchar *buff, uint length, imagetype type)
{
- char *blob;
+ uchar *blob;
const char *dummy;
MBR mbr;
ulong blob_length= get_length(ptr);
Geometry_buffer buffer;
Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
if (blob_length < SRID_SIZE)
{
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
+ bzero(buff, image_length);
+ return image_length;
}
get_ptr(&blob);
- gobj= Geometry::construct(&buffer, blob, blob_length);
+ gobj= Geometry::construct(&buffer, (char*) blob, blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
+ bzero(buff, image_length);
else
{
float8store(buff, mbr.xmin);
@@ -7701,6 +7703,7 @@ void Field_geom::get_key_image(char *buff, uint length, imagetype type)
float8store(buff + 16, mbr.ymin);
float8store(buff + 24, mbr.ymax);
}
+ return image_length;
}
@@ -7774,7 +7777,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
goto err;
wkb_type= uint4korr(from + SRID_SIZE + 1);
if (wkb_type < (uint32) Geometry::wkb_point ||
- wkb_type > (uint32) Geometry::wkb_end)
+ wkb_type > (uint32) Geometry::wkb_last)
goto err;
Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
@@ -7887,6 +7890,8 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
tmp=0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
}
+ if (!table->in_use->count_cuted_fields)
+ err= 0;
}
else
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
@@ -7928,7 +7933,7 @@ longlong Field_enum::val_int(void)
ASSERT_COLUMN_MARKED_FOR_READ;
switch (packlength) {
case 1:
- return (longlong) (uchar) ptr[0];
+ return (longlong) ptr[0];
case 2:
{
uint16 tmp;
@@ -7982,18 +7987,18 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
return val_ptr;
}
-int Field_enum::cmp(const char *a_ptr, const char *b_ptr)
+int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
- char *old=ptr;
- ptr=(char*) a_ptr;
+ uchar *old= ptr;
+ ptr= (uchar*) a_ptr;
ulonglong a=Field_enum::val_int();
- ptr=(char*) b_ptr;
+ ptr= (uchar*) b_ptr;
ulonglong b=Field_enum::val_int();
- ptr=old;
+ ptr= old;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
-void Field_enum::sort_string(char *to,uint length __attribute__((unused)))
+void Field_enum::sort_string(uchar *to,uint length __attribute__((unused)))
{
ulonglong value=Field_enum::val_int();
to+=packlength-1;
@@ -8029,6 +8034,16 @@ void Field_enum::sql_type(String &res) const
}
+Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table,
+ bool keep_type)
+{
+ Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type);
+ if (res)
+ res->typelib= copy_typelib(root, typelib);
+ return res;
+}
+
+
/*
set type.
This is a string which can have a collection of different values.
@@ -8165,9 +8180,9 @@ bool Field_enum::eq_def(Field *field)
for (uint i=0 ; i < from_lib->count ; i++)
if (my_strnncoll(field_charset,
(const uchar*)typelib->type_names[i],
- (uint) strlen(typelib->type_names[i]),
+ strlen(typelib->type_names[i]),
(const uchar*)from_lib->type_names[i],
- (uint) strlen(from_lib->type_names[i])))
+ strlen(from_lib->type_names[i])))
return 0;
return 1;
}
@@ -8193,7 +8208,7 @@ uint Field_num::is_equal(create_field *new_field)
UNSIGNED_FLAG)) &&
((new_field->flags & AUTO_INCREMENT_FLAG) ==
(uint) (flags & AUTO_INCREMENT_FLAG)) &&
- (new_field->length <= max_length()));
+ (new_field->length <= max_display_length()));
}
@@ -8226,7 +8241,7 @@ uint Field_num::is_equal(create_field *new_field)
11 one byte for 'd'
*/
-Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
enum utype unireg_check_arg, const char *field_name_arg)
: Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -8234,6 +8249,7 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
bytes_in_rec(len_arg / 8)
{
+ flags|= UNSIGNED_FLAG;
/*
Ensure that Field::eq() can distinguish between two different bit fields.
(two bit fields that are not null, may have same ptr and null_ptr)
@@ -8243,7 +8259,7 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
}
-my_size_t
+size_t
Field_bit::do_last_null_byte() const
{
/*
@@ -8265,14 +8281,14 @@ Field_bit::do_last_null_byte() const
result= bit_ptr;
if (result)
- return (byte*) result - table->record[0] + 1;
- else
- return LAST_NULL_BYTE_UNDEF;
+ return (size_t) (result - table->record[0]) + 1;
+ return LAST_NULL_BYTE_UNDEF;
}
+
Field *Field_bit::new_key_field(MEM_ROOT *root,
struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit)
{
Field_bit *res;
@@ -8281,7 +8297,7 @@ Field *Field_bit::new_key_field(MEM_ROOT *root,
new_null_bit)))
{
/* Move bits normally stored in null_pointer to new_ptr */
- res->bit_ptr= (uchar*) new_ptr;
+ res->bit_ptr= new_ptr;
res->bit_ofs= 0;
if (bit_len)
res->ptr++; // Store rest of data here
@@ -8378,7 +8394,7 @@ longlong Field_bit::val_int(void)
switch (bytes_in_rec) {
case 0: return bits;
- case 1: return bits | (ulonglong) (uchar) ptr[0];
+ case 1: return bits | (ulonglong) ptr[0];
case 2: return bits | mi_uint2korr(ptr);
case 3: return bits | mi_uint3korr(ptr);
case 4: return bits | mi_uint4korr(ptr);
@@ -8428,7 +8444,7 @@ my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
The a and b pointer must be pointers to the field in a record
(not the table->record[0] necessarily)
*/
-int Field_bit::cmp_max(const char *a, const char *b, uint max_len)
+int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
{
my_ptrdiff_t a_diff= a - ptr;
my_ptrdiff_t b_diff= b - ptr;
@@ -8444,13 +8460,13 @@ int Field_bit::cmp_max(const char *a, const char *b, uint max_len)
}
-int Field_bit::key_cmp(const byte *str, uint length)
+int Field_bit::key_cmp(const uchar *str, uint length)
{
if (bit_len)
{
int flag;
uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
- if ((flag= (int) (bits - *(uchar*) str)))
+ if ((flag= (int) (bits - *str)))
return flag;
str++;
length--;
@@ -8473,7 +8489,7 @@ int Field_bit::cmp_offset(uint row_offset)
}
-void Field_bit::get_key_image(char *buff, uint length, imagetype type)
+uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
if (bit_len)
{
@@ -8481,7 +8497,9 @@ void Field_bit::get_key_image(char *buff, uint length, imagetype type)
*buff++= bits;
length--;
}
- memcpy(buff, ptr, min(length, bytes_in_rec));
+ uint data_length = min(length, bytes_in_rec);
+ memcpy(buff, ptr, data_length);
+ return data_length + 1;
}
@@ -8494,13 +8512,32 @@ void Field_bit::sql_type(String &res) const
}
-char *Field_bit::pack(char *to, const char *from, uint max_length)
+uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length)
{
DBUG_ASSERT(max_length);
uint length;
- if (bit_len)
+ if (bit_len > 0)
{
- uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
+ /*
+ We have the following:
+
+ ptr Points into a field in record R1
+ from Points to a field in a record R2
+ bit_ptr Points to the byte (in the null bytes) that holds the
+ odd bits of R1
+ from_bitp Points to the byte that holds the odd bits of R2
+
+ We have the following:
+
+ ptr - bit_ptr = from - from_bitp
+
+ We want to isolate 'from_bitp', so this gives:
+
+ ptr - bit_ptr - from = - from_bitp
+ - ptr + bit_ptr + from = from_bitp
+ bit_ptr + from - ptr = from_bitp
+ */
+ uchar bits= get_rec_bits(bit_ptr + (from - ptr), bit_ofs, bit_len);
*to++= bits;
}
length= min(bytes_in_rec, max_length - (bit_len > 0));
@@ -8509,11 +8546,18 @@ char *Field_bit::pack(char *to, const char *from, uint max_length)
}
-const char *Field_bit::unpack(char *to, const char *from)
+const uchar *Field_bit::unpack(uchar *to, const uchar *from)
{
- if (bit_len)
+ if (bit_len > 0)
{
- set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
+ /*
+ set_rec_bits is a macro, don't put the post-increment in the
+ argument since that might cause strange side-effects.
+
+ For the choice of the second argument, see the explanation for
+ Field_bit::pack().
+ */
+ set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len);
from++;
}
memcpy(to, from, bytes_in_rec);
@@ -8536,13 +8580,14 @@ void Field_bit::set_default()
Bit field support for non-MyISAM tables.
*/
-Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
+Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg,
const char *field_name_arg)
:Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0,
unireg_check_arg, field_name_arg)
{
+ flags|= UNSIGNED_FLAG;
bit_len= 0;
bytes_in_rec= (len_arg + 7) / 8;
}
@@ -8562,7 +8607,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
{
memset(ptr, 0xff, bytes_in_rec);
if (bits)
- *ptr&= ((1 << bits) - 1); /* set first byte */
+ *ptr&= ((1 << bits) - 1); /* set first uchar */
if (table->in_use->really_abort_on_warning())
set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
else
@@ -8646,7 +8691,7 @@ void create_field::create_length_to_internal_length(void)
void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
- uint32 length_arg, uint32 decimals,
+ uint32 length_arg, uint32 decimals_arg,
bool maybe_null, bool is_unsigned)
{
field_name= "";
@@ -8657,7 +8702,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
charset= &my_charset_bin;
geom_type= Field::GEOM_GEOMETRY;
pack_flag= (FIELDFLAG_NUMBER |
- ((decimals & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
+ ((decimals_arg & FIELDFLAG_MAX_DEC) << FIELDFLAG_DEC_SHIFT) |
(maybe_null ? FIELDFLAG_MAYBE_NULL : 0) |
(is_unsigned ? 0 : FIELDFLAG_DECIMAL));
}
@@ -8727,7 +8772,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
it is NOT NULL, not an AUTO_INCREMENT field and not a TIMESTAMP.
*/
if (!fld_default_value && !(fld_type_modifier & AUTO_INCREMENT_FLAG) &&
- (fld_type_modifier & NOT_NULL_FLAG) && fld_type != FIELD_TYPE_TIMESTAMP)
+ (fld_type_modifier & NOT_NULL_FLAG) && fld_type != MYSQL_TYPE_TIMESTAMP)
flags|= NO_DEFAULT_VALUE_FLAG;
if (fld_length && !(length= (uint) atoi(fld_length)))
@@ -8735,36 +8780,35 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;
switch (fld_type) {
- case FIELD_TYPE_TINY:
+ case MYSQL_TYPE_TINY:
if (!fld_length)
length= MAX_TINYINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_SHORT:
+ case MYSQL_TYPE_SHORT:
if (!fld_length)
length= MAX_SMALLINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_INT24:
+ case MYSQL_TYPE_INT24:
if (!fld_length)
length= MAX_MEDIUMINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_LONG:
+ case MYSQL_TYPE_LONG:
if (!fld_length)
length= MAX_INT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_LONGLONG:
+ case MYSQL_TYPE_LONGLONG:
if (!fld_length)
length= MAX_BIGINT_WIDTH;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_NULL:
+ case MYSQL_TYPE_NULL:
break;
- case FIELD_TYPE_NEWDECIMAL:
- if (!fld_length && !decimals)
- length= 10;
+ case MYSQL_TYPE_NEWDECIMAL:
+ my_decimal_trim(&length, &decimals);
if (length > DECIMAL_MAX_PRECISION)
{
my_error(ER_TOO_BIG_PRECISION, MYF(0), length, fld_name,
@@ -8791,11 +8835,11 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
break;
case MYSQL_TYPE_STRING:
break;
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_GEOMETRY:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
if (fld_default_value)
{
/* Allow empty as default value. */
@@ -8827,12 +8871,12 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
flags|= BLOB_FLAG;
break;
- case FIELD_TYPE_YEAR:
+ case MYSQL_TYPE_YEAR:
if (!fld_length || length != 2)
length= 4; /* Default length */
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
break;
- case FIELD_TYPE_FLOAT:
+ case MYSQL_TYPE_FLOAT:
/* change FLOAT(precision) to FLOAT or DOUBLE */
allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (fld_length && !fld_decimals)
@@ -8845,7 +8889,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
else if (tmp_length > PRECISION_FOR_FLOAT)
{
- sql_type= FIELD_TYPE_DOUBLE;
+ sql_type= MYSQL_TYPE_DOUBLE;
length= DBL_DIG+7; /* -[digits].E+### */
}
else
@@ -8865,7 +8909,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
DBUG_RETURN(TRUE);
}
break;
- case FIELD_TYPE_DOUBLE:
+ case MYSQL_TYPE_DOUBLE:
allowed_type_modifier= AUTO_INCREMENT_FLAG;
if (!fld_length && !fld_decimals)
{
@@ -8879,7 +8923,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
DBUG_RETURN(TRUE);
}
break;
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
if (!fld_length)
length= 14; /* Full date YYYYMMDDHHMMSS */
else if (length != 19)
@@ -8930,27 +8974,22 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
Field::NONE));
}
break;
- case FIELD_TYPE_DATE:
+ case MYSQL_TYPE_DATE:
/* Old date type. */
if (protocol_version != PROTOCOL_VERSION-1)
- sql_type= FIELD_TYPE_NEWDATE;
+ sql_type= MYSQL_TYPE_NEWDATE;
/* fall trough */
- case FIELD_TYPE_NEWDATE:
+ case MYSQL_TYPE_NEWDATE:
length= 10;
break;
- case FIELD_TYPE_TIME:
+ case MYSQL_TYPE_TIME:
length= 10;
break;
- case FIELD_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME:
length= 19;
break;
- case FIELD_TYPE_SET:
+ case MYSQL_TYPE_SET:
{
- if (fld_interval_list->elements > sizeof(longlong)*8)
- {
- my_error(ER_TOO_BIG_SET, MYF(0), fld_name); /* purecov: inspected */
- DBUG_RETURN(TRUE);
- }
pack_length= get_set_pack_length(fld_interval_list->elements);
List_iterator<String> it(*fld_interval_list);
@@ -8965,7 +9004,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
length= 1;
break;
}
- case FIELD_TYPE_ENUM:
+ case MYSQL_TYPE_ENUM:
{
/* Should be safe. */
pack_length= get_enum_pack_length(fld_interval_list->elements);
@@ -8974,7 +9013,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
String *tmp;
while ((tmp= it++))
interval_list.push_back(tmp);
- length= 1; /* See comment for FIELD_TYPE_SET above. */
+ length= 1; /* See comment for MYSQL_TYPE_SET above. */
break;
}
case MYSQL_TYPE_VAR_STRING:
@@ -8993,19 +9032,19 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
pack_length= (length + 7) / 8;
break;
}
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
DBUG_ASSERT(0); /* Was obsolete */
}
/* Remember the value of length */
char_length= length;
if (!(flags & BLOB_FLAG) &&
- ((length > max_field_charlength && fld_type != FIELD_TYPE_SET &&
- fld_type != FIELD_TYPE_ENUM &&
+ ((length > max_field_charlength && fld_type != MYSQL_TYPE_SET &&
+ fld_type != MYSQL_TYPE_ENUM &&
(fld_type != MYSQL_TYPE_VARCHAR || fld_default_value)) ||
(!length &&
fld_type != MYSQL_TYPE_STRING &&
- fld_type != MYSQL_TYPE_VARCHAR && fld_type != FIELD_TYPE_GEOMETRY)))
+ fld_type != MYSQL_TYPE_VARCHAR && fld_type != MYSQL_TYPE_GEOMETRY)))
{
my_error((fld_type == MYSQL_TYPE_VAR_STRING ||
fld_type == MYSQL_TYPE_VARCHAR ||
@@ -9030,13 +9069,13 @@ enum_field_types get_blob_type_from_length(ulong length)
{
enum_field_types type;
if (length < 256)
- type= FIELD_TYPE_TINY_BLOB;
+ type= MYSQL_TYPE_TINY_BLOB;
else if (length < 65536)
- type= FIELD_TYPE_BLOB;
+ type= MYSQL_TYPE_BLOB;
else if (length < 256L*256L*256L)
- type= FIELD_TYPE_MEDIUM_BLOB;
+ type= MYSQL_TYPE_MEDIUM_BLOB;
else
- type= FIELD_TYPE_LONG_BLOB;
+ type= MYSQL_TYPE_LONG_BLOB;
return type;
}
@@ -9050,32 +9089,32 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
switch (type) {
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
- case FIELD_TYPE_DECIMAL: return (length);
+ case MYSQL_TYPE_DECIMAL: return (length);
case MYSQL_TYPE_VARCHAR: return (length + (length < 256 ? 1: 2));
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_TINY : return 1;
- case FIELD_TYPE_SHORT : return 2;
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME: return 3;
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_LONG : return 4;
- case FIELD_TYPE_FLOAT : return sizeof(float);
- case FIELD_TYPE_DOUBLE: return sizeof(double);
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
- case FIELD_TYPE_NULL : return 0;
- case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
- case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
- case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
- case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
- case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
- case FIELD_TYPE_SET:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_TINY : return 1;
+ case MYSQL_TYPE_SHORT : return 2;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME: return 3;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_LONG : return 4;
+ case MYSQL_TYPE_FLOAT : return sizeof(float);
+ case MYSQL_TYPE_DOUBLE: return sizeof(double);
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
+ case MYSQL_TYPE_NULL : return 0;
+ case MYSQL_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_NEWDECIMAL:
abort(); return 0; // This shouldn't happen
- case FIELD_TYPE_BIT: return length / 8;
+ case MYSQL_TYPE_BIT: return length / 8;
default:
return 0;
}
@@ -9085,17 +9124,17 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
uint pack_length_to_packflag(uint type)
{
switch (type) {
- case 1: return f_settype((uint) FIELD_TYPE_TINY);
- case 2: return f_settype((uint) FIELD_TYPE_SHORT);
- case 3: return f_settype((uint) FIELD_TYPE_INT24);
- case 4: return f_settype((uint) FIELD_TYPE_LONG);
- case 8: return f_settype((uint) FIELD_TYPE_LONGLONG);
+ case 1: return f_settype((uint) MYSQL_TYPE_TINY);
+ case 2: return f_settype((uint) MYSQL_TYPE_SHORT);
+ case 3: return f_settype((uint) MYSQL_TYPE_INT24);
+ case 4: return f_settype((uint) MYSQL_TYPE_LONG);
+ case 8: return f_settype((uint) MYSQL_TYPE_LONGLONG);
}
return 0; // This shouldn't happen
}
-Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
+Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag,
enum_field_types field_type,
@@ -9109,7 +9148,7 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
uchar bit_offset;
LINT_INIT(bit_ptr);
LINT_INIT(bit_offset);
- if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
+ if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
{
bit_ptr= null_pos;
bit_offset= null_bit;
@@ -9131,11 +9170,11 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
}
switch (field_type) {
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
field_charset= &my_charset_bin;
default: break;
}
@@ -9145,7 +9184,7 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
if (!f_is_packed(pack_flag))
{
if (field_type == MYSQL_TYPE_STRING ||
- field_type == FIELD_TYPE_DECIMAL || // 3.23 or 4.0 string
+ field_type == MYSQL_TYPE_DECIMAL || // 3.23 or 4.0 string
field_type == MYSQL_TYPE_VAR_STRING)
return new Field_string(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
@@ -9188,78 +9227,78 @@ Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
}
switch (field_type) {
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
return new Field_decimal(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
return new Field_new_decimal(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_FLOAT:
+ case MYSQL_TYPE_FLOAT:
return new Field_float(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_DOUBLE:
+ case MYSQL_TYPE_DOUBLE:
return new Field_double(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag)== 0);
- case FIELD_TYPE_TINY:
+ case MYSQL_TYPE_TINY:
return new Field_tiny(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_SHORT:
+ case MYSQL_TYPE_SHORT:
return new Field_short(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_INT24:
+ case MYSQL_TYPE_INT24:
return new Field_medium(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONG:
+ case MYSQL_TYPE_LONG:
return new Field_long(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_LONGLONG:
+ case MYSQL_TYPE_LONGLONG:
return new Field_longlong(ptr,field_length,null_pos,null_bit,
unireg_check, field_name,
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
return new Field_timestamp(ptr,field_length, null_pos, null_bit,
unireg_check, field_name, share,
field_charset);
- case FIELD_TYPE_YEAR:
+ case MYSQL_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
unireg_check, field_name);
- case FIELD_TYPE_DATE:
+ case MYSQL_TYPE_DATE:
return new Field_date(ptr,null_pos,null_bit,
unireg_check, field_name, field_charset);
- case FIELD_TYPE_NEWDATE:
+ case MYSQL_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
unireg_check, field_name, field_charset);
- case FIELD_TYPE_TIME:
+ case MYSQL_TYPE_TIME:
return new Field_time(ptr,null_pos,null_bit,
unireg_check, field_name, field_charset);
- case FIELD_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME:
return new Field_datetime(ptr,null_pos,null_bit,
unireg_check, field_name, field_charset);
- case FIELD_TYPE_NULL:
+ case MYSQL_TYPE_NULL:
return new Field_null(ptr, field_length, unireg_check, field_name,
field_charset);
- case FIELD_TYPE_BIT:
+ case MYSQL_TYPE_BIT:
return f_bit_as_char(pack_flag) ?
new Field_bit_as_char(ptr, field_length, null_pos, null_bit,
unireg_check, field_name) :
@@ -9295,12 +9334,12 @@ create_field::create_field(Field *old_field,Field *orig_field)
portable_sizeof_char_ptr);
switch (sql_type) {
- case FIELD_TYPE_BLOB:
+ case MYSQL_TYPE_BLOB:
switch (pack_length - portable_sizeof_char_ptr) {
- case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
- case 2: sql_type= FIELD_TYPE_BLOB; break;
- case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
- default: sql_type= FIELD_TYPE_LONG_BLOB; break;
+ case 1: sql_type= MYSQL_TYPE_TINY_BLOB; break;
+ case 2: sql_type= MYSQL_TYPE_BLOB; break;
+ case 3: sql_type= MYSQL_TYPE_MEDIUM_BLOB; break;
+ default: sql_type= MYSQL_TYPE_LONG_BLOB; break;
}
length/= charset->mbmaxlen;
key_length/= charset->mbmaxlen;
@@ -9319,7 +9358,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
length= (length+charset->mbmaxlen-1) / charset->mbmaxlen;
break;
#ifdef HAVE_SPATIAL
- case FIELD_TYPE_GEOMETRY:
+ case MYSQL_TYPE_GEOMETRY:
geom_type= ((Field_geom*)old_field)->geom_type;
break;
#endif
@@ -9336,7 +9375,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
old_field->ptr && orig_field &&
- (sql_type != FIELD_TYPE_TIMESTAMP || /* set def only if */
+ (sql_type != MYSQL_TYPE_TIMESTAMP || /* set def only if */
old_field->table->timestamp_field != old_field || /* timestamp field */
unireg_check == Field::TIMESTAMP_UN_FIELD)) /* has default val */
{
@@ -9365,12 +9404,13 @@ create_field::create_field(Field *old_field,Field *orig_field)
maximum possible display length for blob
SYNOPSIS
- Field_blob::max_length()
+ Field_blob::max_display_length()
RETURN
length
*/
-uint32 Field_blob::max_length()
+
+uint32 Field_blob::max_display_length()
{
switch (packlength)
{
@@ -9404,10 +9444,13 @@ uint32 Field_blob::max_length()
NOTE
This function won't produce warning and increase cut fields counter
- if count_cuted_fields == FIELD_CHECK_IGNORE for current thread.
+ if count_cuted_fields == CHECK_FIELD_IGNORE for current thread.
+
+ if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
+ This allows us to avoid notes in optimisation, like convert_constant_item().
RETURN VALUE
- 1 if count_cuted_fields == FIELD_CHECK_IGNORE
+ 1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE
0 otherwise
*/
@@ -9427,7 +9470,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
thd->row_count);
return 0;
}
- return 1;
+ return level >= MYSQL_ERROR::WARN_LEVEL_WARN;
}
@@ -9455,9 +9498,10 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
timestamp_type ts_type, int cuted_increment)
{
THD *thd= table ? table->in_use : current_thd;
- if (thd->really_abort_on_warning() ||
+ if ((thd->really_abort_on_warning() &&
+ level >= MYSQL_ERROR::WARN_LEVEL_WARN) ||
set_warning(level, code, cuted_increment))
- make_truncated_value_warning(thd, str, str_length, ts_type,
+ make_truncated_value_warning(thd, level, str, str_length, ts_type,
field_name);
}
@@ -9490,7 +9534,7 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
char str_nr[22];
char *str_end= longlong10_to_str(nr, str_nr, -10);
- make_truncated_value_warning(thd, str_nr, (uint) (str_end - str_nr),
+ make_truncated_value_warning(thd, level, str_nr, (uint) (str_end - str_nr),
ts_type, field_name);
}
}
@@ -9523,7 +9567,7 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
/* DBL_DIG is enough to print '-[digits].E+###' */
char str_nr[DBL_DIG + 8];
uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr));
- make_truncated_value_warning(thd, str_nr, str_len, ts_type,
+ make_truncated_value_warning(thd, level, str_nr, str_len, ts_type,
field_name);
}
}
diff --git a/sql/field.h b/sql/field.h
index 70c27e92f01..6c77eded2d1 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -31,7 +30,7 @@ class Send_field;
class Protocol;
class create_field;
struct st_cache_field;
-void field_conv(Field *to,Field *from);
+int field_conv(Field *to,Field *from);
inline uint get_enum_pack_length(int elements)
{
@@ -49,10 +48,10 @@ class Field
Field(const Item &); /* Prevent use of these */
void operator=(Field &);
public:
- static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size) {return sql_alloc(size); }
static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); }
- char *ptr; // Position to field in record
+ uchar *ptr; // Position to field in record
uchar *null_ptr; // Byte where null_bit is
/*
Note that you can use table->in_use as replacement for current_thd member
@@ -91,15 +90,16 @@ public:
uint16 field_index; // field number in fields array
uchar null_bit; // Bit used to test null bit
- Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
- utype unireg_check_arg, const char *field_name_arg);
+ Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg);
virtual ~Field() {}
/* Store functions returns 1 on overflow and -1 on fatal error */
- virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0;
+ virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0;
virtual int store(double nr)=0;
virtual int store(longlong nr, bool unsigned_val)=0;
virtual int store_decimal(const my_decimal *d)=0;
- virtual int store_time(TIME *ltime, timestamp_type t_type);
+ virtual int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
virtual double val_real(void)=0;
virtual longlong val_int(void)=0;
virtual my_decimal *val_decimal(my_decimal *);
@@ -155,16 +155,16 @@ public:
*/
virtual uint32 data_length() { return pack_length(); }
virtual uint32 sort_length() const { return pack_length(); }
- virtual void reset(void) { bzero(ptr,pack_length()); }
+ virtual int reset(void) { bzero(ptr,pack_length()); return 0; }
virtual void reset_fields() {}
virtual void set_default()
{
- my_ptrdiff_t offset = (my_ptrdiff_t) (table->s->default_values -
+ my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
table->record[0]);
- memcpy(ptr, ptr + offset, pack_length());
+ memcpy(ptr, ptr + l_offset, pack_length());
if (null_ptr)
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
- null_ptr[offset] & null_bit);
+ null_ptr[l_offset] & null_bit);
}
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
@@ -172,20 +172,20 @@ public:
virtual uint32 key_length() const { return pack_length(); }
virtual enum_field_types type() const =0;
virtual enum_field_types real_type() const { return type(); }
- inline int cmp(const char *str) { return cmp(ptr,str); }
- virtual int cmp_max(const char *a, const char *b, uint max_len)
+ inline int cmp(const uchar *str) { return cmp(ptr,str); }
+ virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
{ return cmp(a, b); }
- virtual int cmp(const char *,const char *)=0;
- virtual int cmp_binary(const char *a,const char *b, uint32 max_length=~0L)
+ virtual int cmp(const uchar *,const uchar *)=0;
+ virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L)
{ return memcmp(a,b,pack_length()); }
virtual int cmp_offset(uint row_offset)
{ return cmp(ptr,ptr+row_offset); }
virtual int cmp_binary_offset(uint row_offset)
{ return cmp_binary(ptr, ptr+row_offset); };
- virtual int key_cmp(const byte *a,const byte *b)
- { return cmp((char*) a,(char*) b); }
- virtual int key_cmp(const byte *str, uint length)
- { return cmp(ptr,(char*) str); }
+ virtual int key_cmp(const uchar *a,const uchar *b)
+ { return cmp(a, b); }
+ virtual int key_cmp(const uchar *str, uint length)
+ { return cmp(ptr,str); }
virtual uint decimals() const { return 0; }
/*
Caller beware: sql_type can change str.Ptr, so check
@@ -194,15 +194,15 @@ public:
*/
virtual void sql_type(String &str) const =0;
virtual uint size_of() const =0; // For new field
- inline bool is_null(uint row_offset=0)
+ inline bool is_null(my_ptrdiff_t row_offset= 0)
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
- inline bool is_real_null(uint row_offset=0)
+ inline bool is_real_null(my_ptrdiff_t row_offset= 0)
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; }
inline bool is_null_in_record(const uchar *record)
{
if (!null_ptr)
return 0;
- return test(record[(uint) (null_ptr - (uchar*) table->record[0])] &
+ return test(record[(uint) (null_ptr -table->record[0])] &
null_bit);
}
inline bool is_null_in_record_with_offset(my_ptrdiff_t offset)
@@ -211,9 +211,9 @@ public:
return 0;
return test(null_ptr[offset] & null_bit);
}
- inline void set_null(int row_offset=0)
+ inline void set_null(my_ptrdiff_t row_offset= 0)
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
- inline void set_notnull(int row_offset=0)
+ inline void set_notnull(my_ptrdiff_t row_offset= 0)
{ if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
inline bool real_maybe_null(void) { return null_ptr != 0; }
@@ -237,15 +237,15 @@ public:
the record. If the field does not use any bits of the null
bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned.
*/
- my_size_t last_null_byte() const {
- my_size_t bytes= do_last_null_byte();
+ size_t last_null_byte() const {
+ size_t bytes= do_last_null_byte();
DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes));
DBUG_ASSERT(bytes <= table->s->null_bytes);
return bytes;
}
virtual void make_field(Send_field *);
- virtual void sort_string(char *buff,uint length)=0;
+ virtual void sort_string(uchar *buff,uint length)=0;
virtual bool optimize_range(uint idx, uint part);
/*
This should be true for fields which, when compared with constant
@@ -259,27 +259,58 @@ public:
virtual Field *new_field(MEM_ROOT *root, struct st_table *new_table,
bool keep_type);
virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
Field *clone(MEM_ROOT *mem_root, struct st_table *new_table);
- inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
+ inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
{
ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
}
- inline void move_field(char *ptr_arg) { ptr=ptr_arg; }
+ inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; }
virtual void move_field_offset(my_ptrdiff_t ptr_diff)
{
- ptr=ADD_TO_PTR(ptr,ptr_diff,char*);
+ ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*);
if (null_ptr)
null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*);
}
- inline void get_image(char *buff,uint length, CHARSET_INFO *cs)
+ inline void get_image(uchar *buff,uint length, CHARSET_INFO *cs)
{ memcpy(buff,ptr,length); }
- inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
+ inline void set_image(const uchar *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff, uint length, imagetype type)
- { get_image(buff,length, &my_charset_bin); }
- virtual void set_key_image(char *buff,uint length)
+
+
+ /*
+ Copy a field part into an output buffer.
+
+ SYNOPSIS
+ Field::get_key_image()
+ buff [out] output buffer
+ length output buffer size
+ type itMBR for geometry blobs, otherwise itRAW
+
+ DESCRIPTION
+ This function makes a copy of field part of size equal to or
+ less than "length" parameter value.
+ For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer
+ is padded by zero byte.
+
+ NOTES
+ For variable length character fields (i.e. UTF-8) the "length"
+ parameter means a number of output buffer bytes as if all field
+ characters have maximal possible size (mbmaxlen). In the other words,
+ "length" parameter is a number of characters multiplied by
+ field_charset->mbmaxlen.
+
+ RETURN
+ Number of copied bytes (excluding padded zero bytes -- see above).
+ */
+
+ virtual uint get_key_image(uchar *buff, uint length, imagetype type)
+ {
+ get_image(buff, length, &my_charset_bin);
+ return length;
+ }
+ virtual void set_key_image(const uchar *buff,uint length)
{ set_image(buff,length, &my_charset_bin); }
inline longlong val_int_offset(uint row_offset)
{
@@ -288,79 +319,78 @@ public:
ptr-=row_offset;
return tmp;
}
- inline longlong val_int(char *new_ptr)
+ inline longlong val_int(const uchar *new_ptr)
{
- char *old_ptr= ptr;
+ uchar *old_ptr= ptr;
longlong return_value;
- ptr= new_ptr;
+ ptr= (uchar*) new_ptr;
return_value= val_int();
ptr= old_ptr;
return return_value;
}
- inline String *val_str(String *str, char *new_ptr)
+ inline String *val_str(String *str, const uchar *new_ptr)
{
- char *old_ptr= ptr;
- ptr= new_ptr;
+ uchar *old_ptr= ptr;
+ ptr= (uchar*) new_ptr;
val_str(str);
ptr= old_ptr;
return str;
}
virtual bool send_binary(Protocol *protocol);
- virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
+ virtual uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0)
{
uint32 length=pack_length();
memcpy(to,from,length);
return to+length;
}
- virtual const char *unpack(char* to, const char *from)
+ virtual const uchar *unpack(uchar* to, const uchar *from)
{
uint length=pack_length();
memcpy(to,from,length);
return from+length;
}
- virtual char *pack_key(char* to, const char *from, uint max_length)
+ virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length)
{
return pack(to,from,max_length);
}
- virtual char *pack_key_from_key_image(char* to, const char *from,
+ virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from,
uint max_length)
{
return pack(to,from,max_length);
}
- virtual const char *unpack_key(char* to, const char *from, uint max_length)
+ virtual const uchar *unpack_key(uchar* to, const uchar *from,
+ uint max_length)
{
return unpack(to,from);
}
- virtual uint packed_col_length(const char *to, uint length)
+ virtual uint packed_col_length(const uchar *to, uint length)
{ return length;}
virtual uint max_packed_col_length(uint max_length)
{ return max_length;}
- virtual int pack_cmp(const char *a,const char *b, uint key_length_arg,
+ virtual int pack_cmp(const uchar *a,const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{ return cmp(a,b); }
- virtual int pack_cmp(const char *b, uint key_length_arg,
+ virtual int pack_cmp(const uchar *b, uint key_length_arg,
my_bool insert_or_update)
{ return cmp(ptr,b); }
- uint offset(byte *record)
+ uint offset(uchar *record)
{
- return (uint) (ptr - (char*) record);
+ return (uint) (ptr - record);
}
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
- virtual bool get_date(TIME *ltime,uint fuzzydate);
- virtual bool get_time(TIME *ltime);
+ virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ virtual bool get_time(MYSQL_TIME *ltime);
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
- virtual void set_charset(CHARSET_INFO *charset) { }
+ virtual void set_charset(CHARSET_INFO *charset_arg) { }
virtual enum Derivation derivation(void) const
{ return DERIVATION_IMPLICIT; }
- virtual void set_derivation(enum Derivation derivation) { }
+ virtual void set_derivation(enum Derivation derivation_arg) { }
bool set_warning(MYSQL_ERROR::enum_warning_level, unsigned int code,
int cuted_increment);
- bool check_int(const char *str, int length, const char *int_end,
- CHARSET_INFO *cs);
void set_datetime_warning(MYSQL_ERROR::enum_warning_level, uint code,
const char *str, uint str_len,
timestamp_type ts_type, int cuted_increment);
@@ -381,7 +411,7 @@ public:
}
/* maximum possible display length */
- virtual uint32 max_length()= 0;
+ virtual uint32 max_display_length()= 0;
virtual uint is_equal(create_field *new_field);
/* convert decimal to longlong with overflow check */
@@ -396,7 +426,7 @@ public:
/* Hash value */
virtual void hash(ulong *nr, ulong *nr2);
friend bool reopen_table(THD *,struct st_table *,bool);
- friend int cre_myisam(my_string name, register TABLE *form, uint options,
+ friend int cre_myisam(char * name, register TABLE *form, uint options,
ulonglong auto_increment_value);
friend class Copy_field;
friend class Item_avg_field;
@@ -423,7 +453,7 @@ private:
function. This represents the inheritance interface and can be
overridden by subclasses.
*/
- virtual my_size_t do_last_null_byte() const;
+ virtual size_t do_last_null_byte() const;
};
@@ -431,7 +461,7 @@ class Field_num :public Field {
public:
const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
- Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
@@ -446,6 +476,11 @@ public:
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
uint is_equal(create_field *new_field);
+ int check_int(CHARSET_INFO *cs, const char *str, int length,
+ const char *int_end, int error);
+ bool get_int(CHARSET_INFO *cs, const char *from, uint len,
+ longlong *rnd, ulonglong unsigned_max,
+ longlong signed_min, longlong signed_max);
};
@@ -454,7 +489,7 @@ protected:
CHARSET_INFO *field_charset;
enum Derivation field_derivation;
public:
- Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg, CHARSET_INFO *charset);
Item_result result_type () const { return STRING_RESULT; }
@@ -465,15 +500,16 @@ public:
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
- void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
+ void set_charset(CHARSET_INFO *charset_arg) { field_charset= charset_arg; }
enum Derivation derivation(void) const { return field_derivation; }
virtual void set_derivation(enum Derivation derivation_arg)
{ field_derivation= derivation_arg; }
bool binary() const { return field_charset == &my_charset_bin; }
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
friend class create_field;
my_decimal *val_decimal(my_decimal *);
virtual bool str_needs_quotes() { return TRUE; }
+ bool compare_str_field_flags(create_field *new_field, uint32 flags);
uint is_equal(create_field *new_field);
};
@@ -483,11 +519,11 @@ public:
class Field_longstr :public Field_str
{
public:
- Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
- const char *field_name_arg, CHARSET_INFO *charset)
+ const char *field_name_arg, CHARSET_INFO *charset_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, charset)
+ field_name_arg, charset_arg)
{}
int store_decimal(const my_decimal *d);
@@ -496,7 +532,7 @@ public:
/* base class for float and double and decimal (old one) */
class Field_real :public Field_num {
public:
- Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg)
@@ -505,12 +541,13 @@ public:
{}
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
+ uint32 max_display_length() { return field_length; }
};
class Field_decimal :public Field_real {
public:
- Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
@@ -518,22 +555,21 @@ public:
unireg_check_arg, field_name_arg,
dec_arg, zero_arg, unsigned_arg)
{}
- enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
+ enum_field_types type() const { return MYSQL_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
- void reset(void);
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
+ int reset(void);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
void overflow(bool negative);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
- uint32 max_length() { return field_length; }
};
@@ -549,33 +585,33 @@ public:
So for example we need to count length from precision handling
CREATE TABLE ( DECIMAL(x,y))
*/
- Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
const char *field_name_arg, uint8 dec_arg,
bool unsigned_arg);
- enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;}
+ enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; }
- void reset(void);
+ int reset(void);
bool store_value(const my_decimal *decimal_value);
void set_value_on_overflow(my_decimal *decimal_value, bool sign);
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(TIME *ltime, timestamp_type t_type);
+ int store_time(MYSQL_TIME *ltime, timestamp_type t_type);
int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
my_decimal *val_decimal(my_decimal *);
String *val_str(String*, String *);
- int cmp(const char *, const char*);
- void sort_string(char *buff, uint length);
+ int cmp(const uchar *, const uchar *);
+ void sort_string(uchar *buff, uint length);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
uint is_equal(create_field *new_field);
@@ -584,7 +620,7 @@ public:
class Field_tiny :public Field_num {
public:
- Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
bool zero_arg, bool unsigned_arg)
@@ -593,28 +629,28 @@ public:
0, zero_arg,unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return FIELD_TYPE_TINY;}
+ enum_field_types type() const { return MYSQL_TYPE_TINY;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=0; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { ptr[0]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
- uint32 max_length() { return 4; }
+ uint32 max_display_length() { return 4; }
};
class Field_short :public Field_num {
public:
- Field_short(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
bool zero_arg, bool unsigned_arg)
@@ -624,32 +660,32 @@ public:
{}
Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
bool unsigned_arg)
- :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, 0, unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return FIELD_TYPE_SHORT;}
+ enum_field_types type() const { return MYSQL_TYPE_SHORT;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=0; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { ptr[0]=ptr[1]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
- uint32 max_length() { return 6; }
+ uint32 max_display_length() { return 6; }
};
class Field_medium :public Field_num {
public:
- Field_medium(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
bool zero_arg, bool unsigned_arg)
@@ -658,28 +694,28 @@ public:
0, zero_arg,unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return FIELD_TYPE_INT24;}
+ enum_field_types type() const { return MYSQL_TYPE_INT24;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- uint32 max_length() { return 8; }
+ uint32 max_display_length() { return 8; }
};
class Field_long :public Field_num {
public:
- Field_long(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
bool zero_arg, bool unsigned_arg)
@@ -689,33 +725,33 @@ public:
{}
Field_long(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
bool unsigned_arg)
- :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg,0,0,unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return FIELD_TYPE_LONG;}
+ enum_field_types type() const { return MYSQL_TYPE_LONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
double val_real(void);
longlong val_int(void);
bool send_binary(Protocol *protocol);
String *val_str(String*,String *);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
- uint32 max_length() { return 11; }
+ uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; }
};
#ifdef HAVE_LONG_LONG
class Field_longlong :public Field_num {
public:
- Field_longlong(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
bool zero_arg, bool unsigned_arg)
@@ -726,34 +762,38 @@ public:
Field_longlong(uint32 len_arg,bool maybe_null_arg,
const char *field_name_arg,
bool unsigned_arg)
- :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg,0,0,unsigned_arg)
{}
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types type() const { return FIELD_TYPE_LONGLONG;}
+ enum_field_types type() const { return MYSQL_TYPE_LONGLONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void)
+ {
+ ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
+ return 0;
+ }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
- uint32 max_length() { return 20; }
+ uint32 max_display_length() { return 20; }
};
#endif
class Field_float :public Field_real {
public:
- Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
@@ -763,57 +803,65 @@ public:
{}
Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
uint8 dec_arg)
- :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
+ :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
NONE, field_name_arg, dec_arg, 0, 0)
{}
- enum_field_types type() const { return FIELD_TYPE_FLOAT;}
+ enum_field_types type() const { return MYSQL_TYPE_FLOAT;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { bzero(ptr,sizeof(float)); }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { bzero(ptr,sizeof(float)); return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(float); }
void sql_type(String &str) const;
- uint32 max_length() { return 24; }
};
class Field_double :public Field_real {
public:
- Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ my_bool not_fixed;
+ Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
- dec_arg, zero_arg, unsigned_arg)
+ dec_arg, zero_arg, unsigned_arg),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
uint8 dec_arg)
- :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, dec_arg, 0, 0)
+ :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, dec_arg, 0, 0),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
- enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
+ Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
+ uint8 dec_arg, my_bool not_fixed_srg)
+ :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, dec_arg, 0, 0),
+ not_fixed(not_fixed_srg)
+ {}
+ enum_field_types type() const { return MYSQL_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- void reset(void) { bzero(ptr,sizeof(double)); }
+ int reset(void) { bzero(ptr,sizeof(double)); return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(double); }
void sql_type(String &str) const;
- uint32 max_length() { return 53; }
+ uint size_of() const { return sizeof(*this); }
};
@@ -822,54 +870,54 @@ public:
class Field_null :public Field_str {
static uchar null[1];
public:
- Field_null(char *ptr_arg, uint32 len_arg,
+ Field_null(uchar *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str(ptr_arg, len_arg, null, 1,
unireg_check_arg, field_name_arg, cs)
{}
- enum_field_types type() const { return FIELD_TYPE_NULL;}
+ enum_field_types type() const { return MYSQL_TYPE_NULL;}
int store(const char *to, uint length, CHARSET_INFO *cs)
{ null[0]=1; return 0; }
- int store(double nr) { null[0]=1; return 0; }
- int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; }
- int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
- void reset(void) {}
+ int store(double nr) { null[0]=1; return 0; }
+ int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; }
+ int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
+ int reset(void) { return 0; }
double val_real(void) { return 0.0;}
longlong val_int(void) { return 0;}
my_decimal *val_decimal(my_decimal *) { return 0; }
String *val_str(String *value,String *value2)
{ value2->length(0); return value2;}
- int cmp(const char *a, const char *b) { return 0;}
- void sort_string(char *buff, uint length) {}
+ int cmp(const uchar *a, const uchar *b) { return 0;}
+ void sort_string(uchar *buff, uint length) {}
uint32 pack_length() const { return 0; }
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
- uint32 max_length() { return 4; }
+ uint32 max_display_length() { return 4; }
};
class Field_timestamp :public Field_str {
public:
- Field_timestamp(char *ptr_arg, uint32 len_arg,
+ Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
TABLE_SHARE *share, CHARSET_INFO *cs);
Field_timestamp(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs);
- enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;}
+ enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
@@ -896,21 +944,21 @@ public:
longget(tmp,ptr);
return tmp;
}
- bool get_date(TIME *ltime,uint fuzzydate);
- bool get_time(TIME *ltime);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ bool get_time(MYSQL_TIME *ltime);
timestamp_auto_set_type get_auto_set_type() const;
};
class Field_year :public Field_tiny {
public:
- Field_year(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg)
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, 1, 1)
{}
- enum_field_types type() const { return FIELD_TYPE_YEAR;}
+ enum_field_types type() const { return MYSQL_TYPE_YEAR;}
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -925,7 +973,7 @@ public:
class Field_date :public Field_str {
public:
- Field_date(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
@@ -933,21 +981,21 @@ public:
{}
Field_date(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, cs) {}
- enum_field_types type() const { return FIELD_TYPE_DATE;}
+ enum_field_types type() const { return MYSQL_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
@@ -957,39 +1005,39 @@ public:
class Field_newdate :public Field_str {
public:
- Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
{}
- enum_field_types type() const { return FIELD_TYPE_DATE;}
- enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; }
+ enum_field_types type() const { return MYSQL_TYPE_DATE;}
+ enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(TIME *ltime, timestamp_type type);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
+ int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
- bool get_date(TIME *ltime,uint fuzzydate);
- bool get_time(TIME *ltime);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ bool get_time(MYSQL_TIME *ltime);
};
class Field_time :public Field_str {
public:
- Field_time(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ Field_time(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
@@ -997,24 +1045,24 @@ public:
{}
Field_time(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, cs) {}
- enum_field_types type() const { return FIELD_TYPE_TIME;}
+ enum_field_types type() const { return MYSQL_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
- int store_time(TIME *ltime, timestamp_type type);
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
+ int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_date(TIME *ltime, uint fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
bool send_binary(Protocol *protocol);
- bool get_time(TIME *ltime);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ bool get_time(MYSQL_TIME *ltime);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
@@ -1024,7 +1072,7 @@ public:
class Field_datetime :public Field_str {
public:
- Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
:Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
@@ -1032,9 +1080,9 @@ public:
{}
Field_datetime(bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
+ :Field_str((uchar*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, cs) {}
- enum_field_types type() const { return FIELD_TYPE_DATETIME;}
+ enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
#endif
@@ -1043,27 +1091,31 @@ public:
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
- int store_time(TIME *ltime, timestamp_type type);
- void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; }
+ int store_time(MYSQL_TIME *ltime, timestamp_type type);
+ int reset(void)
+ {
+ ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0;
+ return 0;
+ }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
- bool get_date(TIME *ltime,uint fuzzydate);
- bool get_time(TIME *ltime);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ bool get_time(MYSQL_TIME *ltime);
};
class Field_string :public Field_longstr {
public:
bool can_alter_field_type;
- Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
+ Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
CHARSET_INFO *cs)
@@ -1072,7 +1124,7 @@ public:
can_alter_field_type(1) {};
Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs),
can_alter_field_type(1) {};
@@ -1087,37 +1139,48 @@ 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()->cset->fill(charset(),ptr,field_length,' '); }
- int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(longlong nr, bool unsigned_val);
+ int reset(void)
+ {
+ charset()->cset->fill(charset(),(char*) ptr, field_length,
+ (has_charset() ? ' ' : 0));
+ return 0;
+ }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(longlong nr, bool unsigned_val);
int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
void sql_type(String &str) const;
- char *pack(char *to, const char *from, uint max_length=~(uint) 0);
- const char *unpack(char* to, const char *from);
- int pack_cmp(const char *a,const char *b,uint key_length,
+ uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
+ const uchar *unpack(uchar* to, const uchar *from);
+ int pack_cmp(const uchar *a,const uchar *b,uint key_length,
my_bool insert_or_update);
- int pack_cmp(const char *b,uint key_length,my_bool insert_or_update);
- uint packed_col_length(const char *to, uint length);
+ int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update);
+ uint packed_col_length(const uchar *to, uint length);
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; }
+ enum_field_types real_type() const { return MYSQL_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+ virtual uint get_key_image(uchar *buff,uint length, imagetype type);
};
class Field_varstring :public Field_longstr {
public:
+ /*
+ The maximum space available in a Field_varstring, in bytes. See
+ length_bytes.
+ */
+ static const uint MAX_SIZE= UINT_MAX16;
/* Store number of bytes used to store length (1 or 2) */
uint32 length_bytes;
- Field_varstring(char *ptr_arg,
+ Field_varstring(uchar *ptr_arg,
uint32 len_arg, uint length_bytes_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
@@ -1131,7 +1194,7 @@ public:
Field_varstring(uint32 len_arg,bool maybe_null_arg,
const char *field_name_arg,
TABLE_SHARE *share, CHARSET_INFO *cs)
- :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs),
length_bytes(len_arg < 256 ? 1 :2)
{
@@ -1141,7 +1204,7 @@ public:
enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
enum ha_base_keytype key_type() const;
bool zero_pack() const { return 0; }
- void reset(void) { bzero(ptr,field_length+length_bytes); }
+ int reset(void) { bzero(ptr,field_length+length_bytes); return 0; }
uint32 pack_length() const { return (uint32) field_length+length_bytes; }
uint32 key_length() const { return (uint32) field_length; }
uint32 sort_length() const
@@ -1156,27 +1219,28 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp_max(const char *, const char *, uint max_length);
- int cmp(const char *a,const char*b)
+ int cmp_max(const uchar *, const uchar *, uint max_length);
+ int cmp(const uchar *a,const uchar *b)
{
return cmp_max(a, b, ~0L);
}
- void sort_string(char *buff,uint length);
- void get_key_image(char *buff,uint length, imagetype type);
- void set_key_image(char *buff,uint length);
+ void sort_string(uchar *buff,uint length);
+ uint get_key_image(uchar *buff,uint length, imagetype type);
+ void set_key_image(const uchar *buff,uint length);
void sql_type(String &str) const;
- char *pack(char *to, const char *from, uint max_length=~(uint) 0);
- char *pack_key(char *to, const char *from, uint max_length);
- char *pack_key_from_key_image(char* to, const char *from, uint max_length);
- const char *unpack(char* to, const char *from);
- const char *unpack_key(char* to, const char *from, uint max_length);
- int pack_cmp(const char *a, const char *b, uint key_length,
+ uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
+ uchar *pack_key(uchar *to, const uchar *from, uint max_length);
+ uchar *pack_key_from_key_image(uchar* to, const uchar *from,
+ uint max_length);
+ const uchar *unpack(uchar* to, const uchar *from);
+ const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
+ int pack_cmp(const uchar *a, const uchar *b, uint key_length,
my_bool insert_or_update);
- int pack_cmp(const char *b, uint key_length,my_bool insert_or_update);
- int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
- int key_cmp(const byte *,const byte*);
- int key_cmp(const byte *str, uint length);
- uint packed_col_length(const char *to, uint length);
+ int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L);
+ int key_cmp(const uchar *,const uchar*);
+ int key_cmp(const uchar *str, uint length);
+ uint packed_col_length(const uchar *to, uint length);
uint max_packed_col_length(uint max_length);
uint32 data_length();
uint size_of() const { return sizeof(*this); }
@@ -1185,7 +1249,7 @@ public:
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
uint is_equal(create_field *new_field);
void hash(ulong *nr, ulong *nr2);
@@ -1197,12 +1261,12 @@ protected:
uint packlength;
String value; // For temporaries
public:
- Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs);
Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs),
packlength(4)
{
@@ -1210,20 +1274,20 @@ public:
}
Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
CHARSET_INFO *cs, bool set_packlength)
- :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs)
{
flags|= BLOB_FLAG;
packlength= 4;
if (set_packlength)
{
- uint32 char_length= len_arg/cs->mbmaxlen;
- packlength= char_length <= 255 ? 1 :
- char_length <= 65535 ? 2 :
- char_length <= 16777215 ? 3 : 4;
+ uint32 l_char_length= len_arg/cs->mbmaxlen;
+ packlength= l_char_length <= 255 ? 1 :
+ l_char_length <= 65535 ? 2 :
+ l_char_length <= 16777215 ? 3 : 4;
}
}
- enum_field_types type() const { return FIELD_TYPE_BLOB;}
+ enum_field_types type() const { return MYSQL_TYPE_BLOB;}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -1233,15 +1297,15 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp_max(const char *, const char *, uint max_length);
- int cmp(const char *a,const char*b)
+ int cmp_max(const uchar *, const uchar *, uint max_length);
+ int cmp(const uchar *a,const uchar *b)
{ return cmp_max(a, b, ~0L); }
- int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length);
- int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
- int key_cmp(const byte *,const byte*);
- int key_cmp(const byte *str, uint length);
+ int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length);
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L);
+ int key_cmp(const uchar *,const uchar*);
+ int key_cmp(const uchar *str, uint length);
uint32 key_length() const { return 0; }
- void sort_string(char *buff,uint length);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const
{ return (uint32) (packlength+table->s->blob_ptr_size); }
uint32 sort_length() const;
@@ -1249,62 +1313,79 @@ public:
{
return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
}
- void reset(void) { bzero(ptr, packlength+sizeof(char*)); }
- void reset_fields() { bzero((char*) &value,sizeof(value)); }
- void store_length(uint32 number);
+ int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
+ void reset_fields() { bzero((uchar*) &value,sizeof(value)); }
+#ifndef WORDS_BIGENDIAN
+ static
+#endif
+ void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number);
+ inline void store_length(uint32 number)
+ {
+ store_length(ptr, packlength, number);
+ }
+
inline uint32 get_length(uint row_offset=0)
{ return get_length(ptr+row_offset); }
- uint32 get_length(const char *ptr);
- void put_length(char *pos, uint32 length);
- inline void get_ptr(char **str)
+ uint32 get_length(const uchar *ptr);
+ void put_length(uchar *pos, uint32 length);
+ inline void get_ptr(uchar **str)
{
- memcpy_fixed(str,ptr+packlength,sizeof(char*));
+ memcpy_fixed((uchar*) str,ptr+packlength,sizeof(uchar*));
}
- inline void get_ptr(char **str, uint row_offset)
+ inline void get_ptr(uchar **str, uint row_offset)
{
- memcpy_fixed(str,ptr+packlength+row_offset,sizeof(char*));
+ memcpy_fixed((uchar*) str,ptr+packlength+row_offset,sizeof(char*));
}
- inline void set_ptr(char *length,char *data)
+ inline void set_ptr(uchar *length, uchar *data)
{
memcpy(ptr,length,packlength);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- inline void set_ptr(uint32 length,char *data)
+ void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data)
{
- store_length(length);
- memcpy_fixed(ptr+packlength,&data,sizeof(char*));
+ uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*);
+ store_length(ptr_ofs, packlength, length);
+ memcpy_fixed(ptr_ofs+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length, imagetype type);
- void set_key_image(char *buff,uint length);
+ inline void set_ptr(uint32 length, uchar *data)
+ {
+ set_ptr_offset(0, length, data);
+ }
+ uint get_key_image(uchar *buff,uint length, imagetype type);
+ void set_key_image(const uchar *buff,uint length);
void sql_type(String &str) const;
inline bool copy()
- { char *tmp;
+ {
+ uchar *tmp;
get_ptr(&tmp);
- if (value.copy(tmp,get_length(),charset()))
+ if (value.copy((char*) tmp, get_length(),charset()))
{
Field_blob::reset();
return 1;
}
- tmp=(char*) value.ptr(); memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
+ tmp=(uchar*) value.ptr();
+ memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
return 0;
}
- char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
- char *pack_key(char *to, const char *from, uint max_length);
- char *pack_key_from_key_image(char* to, const char *from, uint max_length);
- const char *unpack(char *to, const char *from);
- const char *unpack_key(char* to, const char *from, uint max_length);
- int pack_cmp(const char *a, const char *b, uint key_length,
+ uchar *pack(uchar *to, const uchar *from, uint max_length= ~(uint) 0);
+ uchar *pack_key(uchar *to, const uchar *from, uint max_length);
+ uchar *pack_key_from_key_image(uchar* to, const uchar *from,
+ uint max_length);
+ const uchar *unpack(uchar *to, const uchar *from);
+ const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
+ int pack_cmp(const uchar *a, const uchar *b, uint key_length,
my_bool insert_or_update);
- int pack_cmp(const char *b, uint key_length,my_bool insert_or_update);
- uint packed_col_length(const char *col_ptr, uint length);
+ int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update);
+ uint packed_col_length(const uchar *col_ptr, uint length);
uint max_packed_col_length(uint max_length);
void free() { value.free(); }
- inline void clear_temporary() { bzero((char*) &value,sizeof(value)); }
- friend void field_conv(Field *to,Field *from);
+ inline void clear_temporary() { bzero((uchar*) &value,sizeof(value)); }
+ friend int 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; }
- uint32 max_length();
+ uint32 max_display_length();
+ uint is_equal(create_field *new_field);
};
@@ -1313,7 +1394,7 @@ class Field_geom :public Field_blob {
public:
enum geometry_type geom_type;
- Field_geom(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
TABLE_SHARE *share, uint blob_pack_length,
enum geometry_type geom_type_arg)
@@ -1325,14 +1406,15 @@ public:
:Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin)
{ geom_type= geom_type_arg; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
- enum_field_types type() const { return FIELD_TYPE_GEOMETRY; }
+ enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
void sql_type(String &str) const;
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
int store_decimal(const my_decimal *);
- void get_key_image(char *buff,uint length,imagetype type);
+ uint get_key_image(uchar *buff,uint length,imagetype type);
uint size_of() const { return sizeof(*this); }
+ int reset(void) { return !maybe_null() || Field_blob::reset(); }
};
#endif /*HAVE_SPATIAL*/
@@ -1342,7 +1424,7 @@ protected:
uint packlength;
public:
TYPELIB *typelib;
- Field_enum(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint packlength_arg,
@@ -1354,7 +1436,8 @@ public:
{
flags|=ENUM_FLAG;
}
- enum_field_types type() const { return FIELD_TYPE_STRING; }
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type);
+ enum_field_types type() const { return MYSQL_TYPE_STRING; }
enum Item_result cmp_type () const { return INT_RESULT; }
enum Item_result cast_to_int_type () const { return INT_RESULT; }
enum ha_base_keytype key_type() const;
@@ -1364,13 +1447,13 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- int cmp(const char *,const char*);
- void sort_string(char *buff,uint length);
+ int cmp(const uchar *,const uchar *);
+ void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return (uint32) packlength; }
void store_type(ulonglong value);
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
- enum_field_types real_type() const { return FIELD_TYPE_ENUM; }
+ enum_field_types real_type() const { return MYSQL_TYPE_ENUM; }
virtual bool zero_pack() const { return 0; }
bool optimize_range(uint idx, uint part) { return 0; }
bool eq_def(Field *field);
@@ -1382,7 +1465,7 @@ public:
class Field_set :public Field_enum {
public:
- Field_set(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
uint32 packlength_arg,
@@ -1400,7 +1483,7 @@ public:
virtual bool zero_pack() const { return 1; }
String *val_str(String*,String *);
void sql_type(String &str) const;
- enum_field_types real_type() const { return FIELD_TYPE_SET; }
+ enum_field_types real_type() const { return MYSQL_TYPE_SET; }
bool has_charset(void) const { return TRUE; }
};
@@ -1425,16 +1508,16 @@ public:
uchar bit_ofs; // offset to 'uneven' high bits
uint bit_len; // number of 'uneven' high bits
uint bytes_in_rec;
- Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
enum utype unireg_check_arg, const char *field_name_arg);
- enum_field_types type() const { return FIELD_TYPE_BIT; }
+ enum_field_types type() const { return MYSQL_TYPE_BIT; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
- uint32 max_length() { return field_length; }
+ uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
- void reset(void) { bzero(ptr, bytes_in_rec); }
+ int reset(void) { bzero(ptr, bytes_in_rec); return 0; }
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1444,29 +1527,29 @@ public:
String *val_str(String*, String *);
virtual bool str_needs_quotes() { return TRUE; }
my_decimal *val_decimal(my_decimal *);
- int cmp(const char *a, const char *b)
+ int cmp(const uchar *a, const uchar *b)
{ return cmp_binary(a, b); }
int cmp_binary_offset(uint row_offset)
{ return cmp_offset(row_offset); }
- int cmp_max(const char *a, const char *b, uint max_length);
- int key_cmp(const byte *a, const byte *b)
- { return cmp_binary((char *) a, (char *) b); }
- int key_cmp(const byte *str, uint length);
+ int cmp_max(const uchar *a, const uchar *b, uint max_length);
+ int key_cmp(const uchar *a, const uchar *b)
+ { return cmp_binary((uchar *) a, (uchar *) b); }
+ int key_cmp(const uchar *str, uint length);
int cmp_offset(uint row_offset);
- void get_key_image(char *buff, uint length, imagetype type);
- void set_key_image(char *buff, uint length)
- { Field_bit::store(buff, length, &my_charset_bin); }
- void sort_string(char *buff, uint length)
+ uint get_key_image(uchar *buff, uint length, imagetype type);
+ void set_key_image(const uchar *buff, uint length)
+ { Field_bit::store((char*) buff, length, &my_charset_bin); }
+ void sort_string(uchar *buff, uint length)
{ get_key_image(buff, length, itRAW); }
uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
uint32 pack_length_in_rec() const { return bytes_in_rec; }
void sql_type(String &str) const;
- char *pack(char *to, const char *from, uint max_length=~(uint) 0);
- const char *unpack(char* to, const char *from);
+ uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0);
+ const uchar *unpack(uchar* to, const uchar *from);
virtual void set_default();
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
- char *new_ptr, uchar *new_null_ptr,
+ uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
{
@@ -1487,7 +1570,7 @@ public:
}
private:
- virtual my_size_t do_last_null_byte() const;
+ virtual size_t do_last_null_byte() const;
};
@@ -1500,7 +1583,7 @@ private:
*/
class Field_bit_as_char: public Field_bit {
public:
- Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg);
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
@@ -1550,6 +1633,9 @@ public:
uint offset,pack_flag;
create_field() :after(0) {}
create_field(Field *field, Field *orig_field);
+ /* Used to make a clone of this object for ALTER/CREATE TABLE */
+ create_field *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) create_field(*this); }
void create_length_to_internal_length(void);
/* Init for a tmp table field. To be extended if need be. */
@@ -1588,7 +1674,7 @@ class Send_field {
class Copy_field :public Sql_alloc {
void (*get_copy_func(Field *to,Field *from))(Copy_field *);
public:
- char *from_ptr,*to_ptr;
+ uchar *from_ptr,*to_ptr;
uchar *from_null_ptr,*to_null_ptr;
my_bool *null_row;
uint from_bit,to_bit;
@@ -1599,13 +1685,13 @@ public:
Copy_field() {}
~Copy_field() {}
void set(Field *to,Field *from,bool save); // Field to field
- void set(char *to,Field *from); // Field to string
+ void set(uchar *to,Field *from); // Field to string
void (*do_copy)(Copy_field *);
void (*do_copy2)(Copy_field *); // Used to handle null values
};
-Field *make_field(TABLE_SHARE *share, char *ptr, uint32 field_length,
+Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag, enum_field_types field_type,
CHARSET_INFO *cs,
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 5fde5ecb2e8..63810c8b113 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -165,7 +164,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
when set to NULL (TIMESTAMP fields which allow setting to NULL
are handled by first check).
*/
- if (field->type() == FIELD_TYPE_TIMESTAMP)
+ if (field->type() == MYSQL_TYPE_TIMESTAMP)
{
((Field_timestamp*) field)->set_time();
return 0; // Ok to set time to NULL
@@ -174,7 +173,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
if (field == field->table->next_number_field)
{
field->table->auto_increment_field_not_null= FALSE;
- return 0; // field is set in handler.cc
+ return 0; // field is set in fill_record()
}
if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN)
{
@@ -337,6 +336,13 @@ static void do_field_real(Copy_field *copy)
}
+static void do_field_decimal(Copy_field *copy)
+{
+ my_decimal value;
+ copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
+}
+
+
/*
string copy for single byte characters set when to string is shorter than
from string
@@ -349,8 +355,8 @@ static void do_cut_string(Copy_field *copy)
/* Check if we loosed any important characters */
if (cs->cset->scan(cs,
- copy->from_ptr + copy->to_length,
- copy->from_ptr + copy->from_length,
+ (char*) copy->from_ptr + copy->to_length,
+ (char*) copy->from_ptr + copy->from_length,
MY_SEQ_SPACES) < copy->from_length - copy->to_length)
{
copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -368,8 +374,10 @@ static void do_cut_string_complex(Copy_field *copy)
{ // Shorter string field
int well_formed_error;
CHARSET_INFO *cs= copy->from_field->charset();
- const char *from_end= copy->from_ptr + copy->from_length;
- uint copy_length= cs->cset->well_formed_len(cs, copy->from_ptr, from_end,
+ const uchar *from_end= copy->from_ptr + copy->from_length;
+ uint copy_length= cs->cset->well_formed_len(cs,
+ (char*) copy->from_ptr,
+ (char*) from_end,
copy->to_length / cs->mbmaxlen,
&well_formed_error);
if (copy->to_length < copy_length)
@@ -378,7 +386,8 @@ static void do_cut_string_complex(Copy_field *copy)
/* Check if we lost any important characters */
if (well_formed_error ||
- cs->cset->scan(cs, copy->from_ptr + copy_length, from_end,
+ cs->cset->scan(cs, (char*) copy->from_ptr + copy_length,
+ (char*) from_end,
MY_SEQ_SPACES) < (copy->from_length - copy_length))
{
copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -386,7 +395,7 @@ static void do_cut_string_complex(Copy_field *copy)
}
if (copy_length < copy->to_length)
- cs->cset->fill(cs, copy->to_ptr + copy_length,
+ cs->cset->fill(cs, (char*) copy->to_ptr + copy_length,
copy->to_length - copy_length, ' ');
}
@@ -397,7 +406,7 @@ static void do_expand_binary(Copy_field *copy)
{
CHARSET_INFO *cs= copy->from_field->charset();
memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
- cs->cset->fill(cs, copy->to_ptr+copy->from_length,
+ cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
copy->to_length-copy->from_length, '\0');
}
@@ -407,7 +416,7 @@ static void do_expand_string(Copy_field *copy)
{
CHARSET_INFO *cs= copy->from_field->charset();
memcpy(copy->to_ptr,copy->from_ptr,copy->from_length);
- cs->cset->fill(cs, copy->to_ptr+copy->from_length,
+ cs->cset->fill(cs, (char*) copy->to_ptr+copy->from_length,
copy->to_length-copy->from_length, ' ');
}
@@ -427,6 +436,27 @@ static void do_varstring1(Copy_field *copy)
}
+static void do_varstring1_mb(Copy_field *copy)
+{
+ int well_formed_error;
+ CHARSET_INFO *cs= copy->from_field->charset();
+ uint from_length= (uint) *(uchar*) copy->from_ptr;
+ const uchar *from_ptr= copy->from_ptr + 1;
+ uint to_char_length= (copy->to_length - 1) / cs->mbmaxlen;
+ uint length= cs->cset->well_formed_len(cs, (char*) from_ptr,
+ (char*) from_ptr + from_length,
+ to_char_length, &well_formed_error);
+ if (length < from_length)
+ {
+ if (current_thd->count_cuted_fields)
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
+ *copy->to_ptr= (uchar) length;
+ memcpy(copy->to_ptr + 1, from_ptr, length);
+}
+
+
static void do_varstring2(Copy_field *copy)
{
uint length=uint2korr(copy->from_ptr);
@@ -449,9 +479,16 @@ static void do_varstring2_mb(Copy_field *copy)
CHARSET_INFO *cs= copy->from_field->charset();
uint char_length= (copy->to_length - HA_KEY_BLOB_LENGTH) / cs->mbmaxlen;
uint from_length= uint2korr(copy->from_ptr);
- const char *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
- uint length= cs->cset->well_formed_len(cs, from_beg, from_beg + from_length,
+ const uchar *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
+ uint length= cs->cset->well_formed_len(cs, (char*) from_beg,
+ (char*) from_beg + from_length,
char_length, &well_formed_error);
+ if (length < from_length)
+ {
+ if (current_thd->count_cuted_fields)
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
int2store(copy->to_ptr, length);
memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, length);
}
@@ -469,7 +506,7 @@ static void do_varstring2_mb(Copy_field *copy)
The 'to' buffer should have a size of field->pack_length()+1
*/
-void Copy_field::set(char *to,Field *from)
+void Copy_field::set(uchar *to,Field *from)
{
from_ptr=from->ptr;
to_ptr=to;
@@ -497,10 +534,24 @@ void Copy_field::set(char *to,Field *from)
}
+/*
+ To do:
+
+ If 'save\ is set to true and the 'from' is a blob field, do_copy is set to
+ do_save_blob rather than do_conv_blob. The only differences between them
+ appears to be:
+
+ - do_save_blob allocates and uses an intermediate buffer before calling
+ Field_blob::store. Is this in order to trigger the call to
+ well_formed_copy_nchars, by changing the pointer copy->tmp.ptr()?
+ That call will take place anyway in all known cases.
+ - The above causes a truncation to MAX_FIELD_WIDTH. Is this the intended
+ effect? Truncation is handled by well_formed_copy_nchars anyway.
+ */
void Copy_field::set(Field *to,Field *from,bool save)
{
- if (to->type() == FIELD_TYPE_NULL)
+ if (to->type() == MYSQL_TYPE_NULL)
{
to_null_ptr=0; // For easy debugging
to_ptr=0;
@@ -534,7 +585,7 @@ void Copy_field::set(Field *to,Field *from,bool save)
}
else
{
- if (to_field->type() == FIELD_TYPE_TIMESTAMP)
+ if (to_field->type() == MYSQL_TYPE_TIMESTAMP)
do_copy= do_copy_timestamp; // Automatic timestamp
else if (to_field == to_field->table->next_number_field)
do_copy= do_copy_next_number;
@@ -578,9 +629,11 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
}
else
{
- if (to->real_type() == FIELD_TYPE_BIT ||
- from->real_type() == FIELD_TYPE_BIT)
+ if (to->real_type() == MYSQL_TYPE_BIT ||
+ from->real_type() == MYSQL_TYPE_BIT)
return do_field_int;
+ if (to->result_type() == DECIMAL_RESULT)
+ return do_field_decimal;
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
@@ -601,17 +654,17 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
!compatible_db_low_byte_first ||
((to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) &&
- to->type() == FIELD_TYPE_DATE ||
- to->type() == FIELD_TYPE_DATETIME))
+ to->type() == MYSQL_TYPE_DATE ||
+ to->type() == MYSQL_TYPE_DATETIME))
{
- if (from->real_type() == FIELD_TYPE_ENUM ||
- from->real_type() == FIELD_TYPE_SET)
+ if (from->real_type() == MYSQL_TYPE_ENUM ||
+ from->real_type() == MYSQL_TYPE_SET)
if (to->result_type() != STRING_RESULT)
return do_field_int; // Convert SET to number
return do_field_string;
}
- if (to->real_type() == FIELD_TYPE_ENUM ||
- to->real_type() == FIELD_TYPE_SET)
+ if (to->real_type() == MYSQL_TYPE_ENUM ||
+ to->real_type() == MYSQL_TYPE_SET)
{
if (!to->eq_def(from))
return do_field_string;
@@ -625,8 +678,10 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
return do_field_string;
if (to_length != from_length)
return (((Field_varstring*) to)->length_bytes == 1 ?
- do_varstring1 : (from->charset()->mbmaxlen == 1 ?
- do_varstring2 : do_varstring2_mb));
+ (from->charset()->mbmaxlen == 1 ? do_varstring1 :
+ do_varstring1_mb) :
+ (from->charset()->mbmaxlen == 1 ? do_varstring2 :
+ do_varstring2_mb));
}
else if (to_length < from_length)
return (from->charset()->mbmaxlen == 1 ?
@@ -644,7 +699,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
to_length != from_length ||
!compatible_db_low_byte_first)
{
- if (to->real_type() == FIELD_TYPE_DECIMAL ||
+ if (to->real_type() == MYSQL_TYPE_DECIMAL ||
to->result_type() == STRING_RESULT)
return do_field_string;
if (to->result_type() == INT_RESULT)
@@ -655,7 +710,7 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
{
if (!to->eq_def(from) || !compatible_db_low_byte_first)
{
- if (to->real_type() == FIELD_TYPE_DECIMAL)
+ if (to->real_type() == MYSQL_TYPE_DECIMAL)
return do_field_string;
if (to->result_type() == INT_RESULT)
return do_field_int;
@@ -679,25 +734,25 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
/* Simple quick field convert that is called on insert */
-void field_conv(Field *to,Field *from)
+int field_conv(Field *to,Field *from)
{
if (to->real_type() == from->real_type() &&
- !(to->type() == FIELD_TYPE_BLOB && to->table->copy_blobs))
+ !(to->type() == MYSQL_TYPE_BLOB && to->table->copy_blobs))
{
if (to->pack_length() == from->pack_length() &&
!(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
- to->real_type() != FIELD_TYPE_ENUM &&
- to->real_type() != FIELD_TYPE_SET &&
- to->real_type() != FIELD_TYPE_BIT &&
- (to->real_type() != FIELD_TYPE_NEWDECIMAL ||
+ to->real_type() != MYSQL_TYPE_ENUM &&
+ to->real_type() != MYSQL_TYPE_SET &&
+ to->real_type() != MYSQL_TYPE_BIT &&
+ (to->real_type() != MYSQL_TYPE_NEWDECIMAL ||
(to->field_length == from->field_length &&
(((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
from->charset() == to->charset() &&
to->table->s->db_low_byte_first == from->table->s->db_low_byte_first &&
(!(to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
- to->type() != FIELD_TYPE_DATE &&
- to->type() != FIELD_TYPE_DATETIME) &&
+ to->type() != MYSQL_TYPE_DATE &&
+ to->type() != MYSQL_TYPE_DATETIME) &&
(from->real_type() != MYSQL_TYPE_VARCHAR ||
((Field_varstring*)from)->length_bytes ==
((Field_varstring*)to)->length_bytes))
@@ -707,10 +762,10 @@ void field_conv(Field *to,Field *from)
if (to->ptr != from->ptr)
#endif
memcpy(to->ptr,from->ptr,to->pack_length());
- return;
+ return 0;
}
}
- if (to->type() == FIELD_TYPE_BLOB)
+ if (to->type() == MYSQL_TYPE_BLOB)
{ // Be sure the value is stored
Field_blob *blob=(Field_blob*) to;
from->val_str(&blob->value);
@@ -723,14 +778,13 @@ void field_conv(Field *to,Field *from)
from->real_type() != MYSQL_TYPE_STRING &&
from->real_type() != MYSQL_TYPE_VARCHAR))
blob->value.copy();
- blob->store(blob->value.ptr(),blob->value.length(),from->charset());
- return;
+ return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
}
if ((from->result_type() == STRING_RESULT &&
(to->result_type() == STRING_RESULT ||
- (from->real_type() != FIELD_TYPE_ENUM &&
- from->real_type() != FIELD_TYPE_SET))) ||
- to->type() == FIELD_TYPE_DECIMAL)
+ (from->real_type() != MYSQL_TYPE_ENUM &&
+ from->real_type() != MYSQL_TYPE_SET))) ||
+ to->type() == MYSQL_TYPE_DECIMAL)
{
char buff[MAX_FIELD_WIDTH];
String result(buff,sizeof(buff),from->charset());
@@ -741,15 +795,15 @@ void field_conv(Field *to,Field *from)
end with \0. Can be replaced with .ptr() when we have our own
string->double conversion.
*/
- to->store(result.c_ptr_quick(),result.length(),from->charset());
+ return to->store(result.c_ptr_quick(),result.length(),from->charset());
}
else if (from->result_type() == REAL_RESULT)
- to->store(from->val_real());
+ return to->store(from->val_real());
else if (from->result_type() == DECIMAL_RESULT)
{
my_decimal buff;
- to->store_decimal(from->val_decimal(&buff));
+ return to->store_decimal(from->val_decimal(&buff));
}
else
- to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
+ return to->store(from->val_int(), test(from->flags & UNSIGNED_FLAG));
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 5f8153e64e7..1d443e85327 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -31,7 +30,7 @@
/* How to write record_ref. */
#define WRITE_REF(file,from) \
-if (my_b_write((file),(byte*) (from),param->ref_length)) \
+if (my_b_write((file),(uchar*) (from),param->ref_length)) \
DBUG_RETURN(1);
/* functions defined in this file */
@@ -43,7 +42,7 @@ static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
IO_CACHE *tempfile,IO_CACHE *indexfile);
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
-static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos);
+static void make_sortkey(SORTPARAM *param,uchar *to, uchar *ref_pos);
static void register_used_fields(SORTPARAM *param);
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek,
@@ -57,7 +56,7 @@ static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
uint sortlength, uint *plength);
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
- byte *buff);
+ uchar *buff);
/*
Sort a table
@@ -105,7 +104,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
uint maxbuffer;
BUFFPEK *buffpek;
ha_rows records= HA_POS_ERROR;
- uchar **sort_keys;
+ uchar **sort_keys= 0;
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
bool multi_byte_charset;
@@ -154,7 +153,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (param.addon_field)
{
param.res_length= param.addon_length;
- if (!(table_sort.addon_buf= (byte *) my_malloc(param.addon_length,
+ if (!(table_sort.addon_buf= (uchar *) my_malloc(param.addon_length,
MYF(MY_WME))))
goto err;
}
@@ -172,11 +171,11 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick)
{
- statistic_increment(thd->status_var.filesort_range_count, &LOCK_status);
+ status_var_increment(thd->status_var.filesort_range_count);
}
else
{
- statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status);
+ status_var_increment(thd->status_var.filesort_scan_count);
}
#ifdef CAN_TRUST_RANGE
if (select && select->quick && select->quick->records > 0L)
@@ -199,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
}
if (multi_byte_charset &&
- !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME))))
+ !(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
goto err;
memavl= thd->variables.sortbuff_size;
@@ -246,7 +245,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
{
if (!table_sort.buffpek && table_sort.buffpek_len < maxbuffer &&
!(table_sort.buffpek=
- (byte *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
+ (uchar *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
goto err;
buffpek= (BUFFPEK *) table_sort.buffpek;
table_sort.buffpek_len= maxbuffer;
@@ -256,7 +255,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
MYF(MY_WME)))
goto err;
- reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
+ if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
+ goto err;
/*
Use also the space previously used by string pointers in sort_buffer
@@ -284,9 +284,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
x_free(param.tmp_buffer);
if (!subselect || !subselect->is_uncacheable())
{
- x_free((gptr) sort_keys);
+ x_free((uchar*) sort_keys);
table_sort.sort_keys= 0;
- x_free((gptr) buffpek);
+ x_free((uchar*) buffpek);
table_sort.buffpek= 0;
table_sort.buffpek_len= 0;
}
@@ -324,19 +324,19 @@ void filesort_free_buffers(TABLE *table, bool full)
{
if (table->sort.record_pointers)
{
- my_free((gptr) table->sort.record_pointers,MYF(0));
+ my_free((uchar*) table->sort.record_pointers,MYF(0));
table->sort.record_pointers=0;
}
if (full)
{
if (table->sort.sort_keys )
{
- x_free((gptr) table->sort.sort_keys);
+ x_free((uchar*) table->sort.sort_keys);
table->sort.sort_keys= 0;
}
if (table->sort.buffpek)
{
- x_free((gptr) table->sort.buffpek);
+ x_free((uchar*) table->sort.buffpek);
table->sort.buffpek= 0;
table->sort.buffpek_len= 0;
}
@@ -376,11 +376,13 @@ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count)
ulong length;
BUFFPEK *tmp;
DBUG_ENTER("read_buffpek_from_file");
+ if (count > UINT_MAX/sizeof(BUFFPEK))
+ return 0; /* sizeof(BUFFPEK)*count will overflow */
tmp=(BUFFPEK*) my_malloc(length=sizeof(BUFFPEK)*count, MYF(MY_WME));
if (tmp)
{
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
- my_b_read(buffpek_pointers, (byte*) tmp, length))
+ my_b_read(buffpek_pointers, (uchar*) tmp, length))
{
my_free((char*) tmp, MYF(0));
tmp=0;
@@ -432,10 +434,11 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
int error,flag,quick_select;
uint idx,indexpos,ref_length;
- byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
+ uchar *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
- volatile THD::killed_state *killed= &current_thd->killed;
+ THD *thd= current_thd;
+ volatile THD::killed_state *killed= &thd->killed;
handler *file;
MY_BITMAP *save_read_set, *save_write_set;
DBUG_ENTER("find_all_keys");
@@ -458,7 +461,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
next_pos=ref_pos;
if (! indexfile && ! quick_select)
{
- next_pos=(byte*) 0; /* Find records in sequence */
+ next_pos=(uchar*) 0; /* Find records in sequence */
file->ha_rnd_init(1);
file->extra_opt(HA_EXTRA_CACHE,
current_thd->variables.read_buff_size);
@@ -483,7 +486,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
register_used_fields(param);
if (select && select->cond)
select->cond->walk(&Item::register_field_in_read_map, 1,
- (byte*) sort_form);
+ (uchar*) sort_form);
sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
for (;;)
@@ -501,7 +504,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
if (indexfile)
{
- if (my_b_read(indexfile,(byte*) ref_pos,ref_length)) /* purecov: deadcode */
+ if (my_b_read(indexfile,(uchar*) ref_pos,ref_length)) /* purecov: deadcode */
{
error= my_errno ? my_errno : -1; /* Abort */
break;
@@ -548,6 +551,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
}
else
file->unlock_row();
+ /* It does not make sense to read more keys in case of a fatal error */
+ if (thd->net.report_error)
+ DBUG_RETURN(HA_POS_ERROR);
}
if (quick_select)
{
@@ -606,7 +612,7 @@ static int
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
- uint sort_length, rec_length;
+ size_t sort_length, rec_length;
uchar **end;
BUFFPEK buffpek;
DBUG_ENTER("write_keys");
@@ -616,20 +622,23 @@ write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
#ifdef MC68000
quicksort(sort_keys,count,sort_length);
#else
- my_string_ptr_sort((gptr) sort_keys, (uint) count, sort_length);
+ my_string_ptr_sort((uchar*) sort_keys, (uint) count, sort_length);
#endif
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
goto err; /* purecov: inspected */
+ /* check we won't have more buffpeks than we can possibly keep in memory */
+ if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (ulonglong)UINT_MAX)
+ goto err;
buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
- if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
+ if (my_b_write(tempfile, (uchar*) *sort_keys, (uint) rec_length))
goto err;
- if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
+ if (my_b_write(buffpek_pointers, (uchar*) &buffpek, sizeof(buffpek)))
goto err;
DBUG_RETURN(0);
@@ -664,7 +673,7 @@ static inline void store_length(uchar *to, uint length, uint pack_length)
/* makes a sort-key from record */
static void make_sortkey(register SORTPARAM *param,
- register uchar *to, byte *ref_pos)
+ register uchar *to, uchar *ref_pos)
{
reg3 Field *field;
reg1 SORT_FIELD *sort_field;
@@ -691,7 +700,7 @@ static void make_sortkey(register SORTPARAM *param,
else
*to++=1;
}
- field->sort_string((char*) to,sort_field->length);
+ field->sort_string(to, sort_field->length);
}
else
{ // Item
@@ -820,7 +829,7 @@ static void make_sortkey(register SORTPARAM *param,
}
*to++=1;
}
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (char*)to,
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,
item->max_length - (item->decimals ? 1:0),
item->decimals);
break;
@@ -838,7 +847,7 @@ static void make_sortkey(register SORTPARAM *param,
}
*to++=1;
}
- change_double_for_sort(value,(byte*) to);
+ change_double_for_sort(value,(uchar*) to);
break;
}
case ROW_RESULT:
@@ -887,12 +896,14 @@ static void make_sortkey(register SORTPARAM *param,
}
else
{
- uchar *end= (uchar*) field->pack((char *) to, field->ptr);
#ifdef HAVE_purify
+ uchar *end= field->pack(to, field->ptr);
uint length= (uint) ((to + addonf->length) - end);
DBUG_ASSERT((int) length >= 0);
if (length)
bzero(end, length);
+#else
+ (void) field->pack(to, field->ptr);
#endif
}
to+= addonf->length;
@@ -901,7 +912,7 @@ static void make_sortkey(register SORTPARAM *param,
else
{
/* Save filepos last */
- memcpy((byte*) to, ref_pos, (size_s) param->ref_length);
+ memcpy((uchar*) to, ref_pos, (size_t) param->ref_length);
}
return;
}
@@ -930,7 +941,7 @@ static void register_used_fields(SORTPARAM *param)
else
{ // Item
sort_field->item->walk(&Item::register_field_in_read_map, 1,
- (byte *) table);
+ (uchar *) table);
}
}
@@ -953,16 +964,16 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
FILESORT_INFO *table_sort)
{
uint offset,res_length;
- byte *to;
+ uchar *to;
DBUG_ENTER("save_index");
- my_string_ptr_sort((gptr) sort_keys, (uint) count, param->sort_length);
+ my_string_ptr_sort((uchar*) sort_keys, (uint) count, param->sort_length);
res_length= param->res_length;
offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows;
if (!(to= table_sort->record_pointers=
- (byte*) my_malloc(res_length*count, MYF(MY_WME))))
+ (uchar*) my_malloc(res_length*count, MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
{
@@ -978,7 +989,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
{
- register int i;
+ register uint i;
IO_CACHE t_file2,*from_file,*to_file,*temp;
BUFFPEK *lastbuff;
DBUG_ENTER("merge_many_buff");
@@ -993,14 +1004,16 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
from_file= t_file ; to_file= &t_file2;
while (*maxbuffer >= MERGEBUFF2)
{
- reinit_io_cache(from_file,READ_CACHE,0L,0,0);
- reinit_io_cache(to_file,WRITE_CACHE,0L,0,0);
+ if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
+ goto cleanup;
+ if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
+ goto cleanup;
lastbuff=buffpek;
- for (i=0 ; i <= (int) *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
{
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+i+MERGEBUFF-1,0))
- break; /* purecov: inspected */
+ goto cleanup;
}
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+ *maxbuffer,0))
@@ -1012,6 +1025,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
setup_io_cache(to_file);
*maxbuffer= (uint) (lastbuff-buffpek)-1;
}
+cleanup:
close_cached_file(to_file); // This holds old result
if (to_file == t_file)
{
@@ -1034,7 +1048,7 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{
- if (my_pread(fromfile->file,(byte*) buffpek->base,
+ if (my_pread(fromfile->file,(uchar*) buffpek->base,
(length= rec_length*count),buffpek->file_pos,MYF_RW))
return((uint) -1); /* purecov: inspected */
buffpek->key=buffpek->base;
@@ -1115,8 +1129,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
- statistic_increment(current_thd->status_var.filesort_merge_passes,
- &LOCK_status);
+ status_var_increment(current_thd->status_var.filesort_merge_passes);
if (param->not_killable)
{
killed= &not_killable;
@@ -1149,7 +1162,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (error == -1)
goto err; /* purecov: inspected */
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
- queue_insert(&queue, (byte*) buffpek);
+ queue_insert(&queue, (uchar*) buffpek);
}
if (param->unique_buff)
@@ -1164,7 +1177,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
*/
buffpek= (BUFFPEK*) queue_top(&queue);
memcpy(param->unique_buff, buffpek->key, rec_length);
- if (my_b_write(to_file, (byte*) buffpek->key, rec_length))
+ if (my_b_write(to_file, (uchar*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
}
@@ -1198,14 +1211,14 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
}
if (flag == 0)
{
- if (my_b_write(to_file,(byte*) buffpek->key, rec_length))
+ if (my_b_write(to_file,(uchar*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
}
}
else
{
- if (my_b_write(to_file, (byte*) buffpek->key+offset, res_length))
+ if (my_b_write(to_file, (uchar*) buffpek->key+offset, res_length))
{
error=1; goto err; /* purecov: inspected */
}
@@ -1260,7 +1273,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
max_rows-= buffpek->mem_count;
if (flag == 0)
{
- if (my_b_write(to_file,(byte*) buffpek->key,
+ if (my_b_write(to_file,(uchar*) buffpek->key,
(rec_length*buffpek->mem_count)))
{
error= 1; goto err; /* purecov: inspected */
@@ -1274,7 +1287,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
strpos != end ;
strpos+= rec_length)
{
- if (my_b_write(to_file, (byte *) strpos, res_length))
+ if (my_b_write(to_file, (uchar *) strpos, res_length))
{
error=1; goto err;
}
@@ -1369,7 +1382,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
- switch ((sortorder->result_type=sortorder->item->result_type())) {
+ sortorder->result_type= sortorder->item->result_type();
+ if (sortorder->item->result_as_longlong())
+ sortorder->result_type= INT_RESULT;
+ switch (sortorder->result_type) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
@@ -1540,7 +1556,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
*/
static void
-unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
+unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff)
{
Field *field;
SORT_ADDON_FIELD *addonf= addon_field;
@@ -1553,7 +1569,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
continue;
}
field->set_notnull();
- field->unpack(field->ptr, (char *) buff+addonf->offset);
+ field->unpack(field->ptr, buff + addonf->offset);
}
}
@@ -1564,7 +1580,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
-void change_double_for_sort(double nr,byte *to)
+void change_double_for_sort(double nr,uchar *to)
{
uchar *tmp=(uchar*) to;
if (nr == 0.0)
diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc
index 8dd70900648..590205e83ab 100644
--- a/sql/frm_crypt.cc
+++ b/sql/frm_crypt.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 2674b2e65f7..36b7f30dc64 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -91,8 +90,8 @@ struct my_option my_long_options[] =
{"debug", '#', "This is a non-debug version. Catch this and exit",
0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
#else
- {"debug", '#', "Output debug log", (gptr*) &default_dbug_option,
- (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug", '#', "Output debug log", (uchar**) &default_dbug_option,
+ (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"help", '?', "Display help and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -446,10 +445,24 @@ int main(int argc,char **argv)
/* Broken up to indicate that it's not advice to you, gentle reader. */
printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
- printf("/* Copyright (C) 2001-2004 MySQL AB\n\
- This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
- and you are welcome to modify and redistribute it under the GPL license\n\
- \n*/\n\n");
+ printf("\
+/* Copyright (C) 2001-2004 MySQL AB\n\
+\n\
+ This program is free software; you can redistribute it and/or modify\n\
+ it under the terms of the GNU General Public License as published by\n\
+ the Free Software Foundation; version 2 of the License.\n\
+\n\
+ This program is distributed in the hope that it will be useful,\n\
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
+ GNU General Public License for more details.\n\
+\n\
+ You should have received a copy of the GNU General Public License\n\
+ along with this program; see the file COPYING. If not, write to the\n\
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston\n\
+ MA 02110-1301 USA. */\n\
+\n\
+");
/* Broken up to indicate that it's not advice to you, gentle reader. */
printf("/* Do " "not " "edit " "this " "file! This is generated by "
diff --git a/sql/gstream.cc b/sql/gstream.cc
index 4083cb2fe71..46e12b6ef3b 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/gstream.h b/sql/gstream.h
index bfbf28851ce..1ef90ad5bf0 100644
--- a/sql/gstream.h
+++ b/sql/gstream.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,7 +35,7 @@ public:
{}
~Gis_read_stream()
{
- my_free(m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
}
enum enum_tok_types get_next_toc_type();
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 0362b8bf215..aeaea90feb6 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,12 +24,13 @@
#endif
#include "mysql_priv.h"
+#include "rpl_mi.h"
#include <my_dir.h>
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
#include "ha_ndbcluster.h"
#include <ndbapi/NdbApi.hpp>
-#include <ndbapi/NdbScanFilter.hpp>
+#include "ha_ndbcluster_cond.h"
#include <../util/Bitmask.hpp>
#include <ndbapi/NdbIndexStat.hpp>
@@ -134,7 +134,7 @@ static uint ndbcluster_alter_table_flags(uint flags)
}
static int ndbcluster_inited= 0;
-int ndbcluster_util_inited= 0;
+int ndbcluster_terminating= 0;
static Ndb* g_ndb= NULL;
Ndb_cluster_connection* g_ndb_cluster_connection= NULL;
@@ -146,20 +146,21 @@ pthread_mutex_t ndbcluster_mutex;
// Table lock handling
HASH ndbcluster_open_tables;
-static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
+static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
my_bool not_used __attribute__((unused)));
#ifdef HAVE_NDB_BINLOG
static int rename_share(NDB_SHARE *share, const char *new_key);
#endif
-static void ndb_set_fragmentation(NDBTAB &tab, TABLE *table, uint pk_len);
static int ndb_get_table_statistics(ha_ndbcluster*, bool, Ndb*, const NDBTAB *,
struct Ndb_statistics *);
// Util thread variables
pthread_t ndb_util_thread;
+int ndb_util_thread_running= 0;
pthread_mutex_t LOCK_ndb_util_thread;
pthread_cond_t COND_ndb_util_thread;
+pthread_cond_t COND_ndb_util_ready;
pthread_handler_t ndb_util_thread_func(void *arg);
ulong ndb_cache_check_time;
@@ -259,16 +260,16 @@ static int ndb_to_mysql_error(const NdbError *ndberr)
int execute_no_commit_ignore_no_key(ha_ndbcluster *h, NdbTransaction *trans)
{
- int res= trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AO_IgnoreError,
- h->m_force_send);
- if (res == 0)
- return 0;
+ if (trans->execute(NdbTransaction::NoCommit,
+ NdbOperation::AO_IgnoreError,
+ h->m_force_send) == -1)
+ return -1;
const NdbError &err= trans->getNdbError();
- if (err.classification != NdbError::ConstraintViolation &&
+ if (err.classification != NdbError::NoError &&
+ err.classification != NdbError::ConstraintViolation &&
err.classification != NdbError::NoDataFound)
- return res;
+ return -1;
return 0;
}
@@ -286,7 +287,7 @@ int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans,
return h->m_ignore_no_key ?
execute_no_commit_ignore_no_key(h,trans) :
trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
h->m_force_send);
}
@@ -299,7 +300,7 @@ int execute_commit(ha_ndbcluster *h, NdbTransaction *trans)
return 0;
#endif
return trans->execute(NdbTransaction::Commit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
h->m_force_send);
}
@@ -312,7 +313,7 @@ int execute_commit(THD *thd, NdbTransaction *trans)
return 0;
#endif
return trans->execute(NdbTransaction::Commit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
thd->variables.ndb_force_send);
}
@@ -327,7 +328,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans,
#endif
h->release_completed_operations(trans, force_release);
return trans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AO_IgnoreError,
+ NdbOperation::AO_IgnoreError,
h->m_force_send);
}
@@ -335,11 +336,11 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans,
Place holder for ha_ndbcluster thread specific data
*/
static
-byte *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, uint *length,
+uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length= sizeof(thd_ndb_share->key);
- return (byte*) &thd_ndb_share->key;
+ return (uchar*) &thd_ndb_share->key;
}
Thd_ndb::Thd_ndb()
@@ -349,7 +350,7 @@ Thd_ndb::Thd_ndb()
count= 0;
all= NULL;
stmt= NULL;
- error= 0;
+ m_error= FALSE;
query_state&= NDB_QUERY_NORMAL;
options= 0;
(void) hash_init(&open_tables, &my_charset_bin, 5, 0, 0,
@@ -384,7 +385,7 @@ void
Thd_ndb::init_open_tables()
{
count= 0;
- error= 0;
+ m_error= FALSE;
my_hash_reset(&open_tables);
}
@@ -394,9 +395,9 @@ Thd_ndb::get_open_table(THD *thd, const void *key)
DBUG_ENTER("Thd_ndb::get_open_table");
HASH_SEARCH_STATE state;
THD_NDB_SHARE *thd_ndb_share=
- (THD_NDB_SHARE*)hash_first(&open_tables, (byte *)&key, sizeof(key), &state);
+ (THD_NDB_SHARE*)hash_first(&open_tables, (uchar *)&key, sizeof(key), &state);
while (thd_ndb_share && thd_ndb_share->key != key)
- thd_ndb_share= (THD_NDB_SHARE*)hash_next(&open_tables, (byte *)&key, sizeof(key), &state);
+ thd_ndb_share= (THD_NDB_SHARE*)hash_next(&open_tables, (uchar *)&key, sizeof(key), &state);
if (thd_ndb_share == 0)
{
thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
@@ -405,7 +406,7 @@ Thd_ndb::get_open_table(THD *thd, const void *key)
thd_ndb_share->stat.last_count= count;
thd_ndb_share->stat.no_uncommitted_rows_count= 0;
thd_ndb_share->stat.records= ~(ha_rows)0;
- my_hash_insert(&open_tables, (byte *)thd_ndb_share);
+ my_hash_insert(&open_tables, (uchar *)thd_ndb_share);
}
else if (thd_ndb_share->stat.last_count != count)
{
@@ -442,15 +443,15 @@ ha_rows ha_ndbcluster::records()
{
ha_rows retval;
DBUG_ENTER("ha_ndbcluster::records");
- struct Ndb_local_table_statistics *info= m_table_info;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ local_info->no_uncommitted_rows_count));
Ndb *ndb= get_ndb();
ndb->setDatabaseName(m_dbname);
struct Ndb_statistics stat;
- if (ndb_get_table_statistics(this, true, ndb, m_table, &stat) == 0)
+ if (ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat) == 0)
{
retval= stat.row_count;
}
@@ -460,10 +461,10 @@ ha_rows ha_ndbcluster::records()
}
THD *thd= current_thd;
- if (get_thd_ndb(thd)->error)
- info->no_uncommitted_rows_count= 0;
+ if (get_thd_ndb(thd)->m_error)
+ local_info->no_uncommitted_rows_count= 0;
- DBUG_RETURN(retval + info->no_uncommitted_rows_count);
+ DBUG_RETURN(retval + local_info->no_uncommitted_rows_count);
}
int ha_ndbcluster::records_update()
@@ -473,30 +474,32 @@ int ha_ndbcluster::records_update()
DBUG_ENTER("ha_ndbcluster::records_update");
int result= 0;
- struct Ndb_local_table_statistics *info= m_table_info;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
- // if (info->records == ~(ha_rows)0)
+ local_info->no_uncommitted_rows_count));
{
Ndb *ndb= get_ndb();
struct Ndb_statistics stat;
- ndb->setDatabaseName(m_dbname);
- result= ndb_get_table_statistics(this, true, ndb, m_table, &stat);
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ return my_errno= HA_ERR_OUT_OF_MEM;
+ }
+ result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat);
if (result == 0)
{
stats.mean_rec_length= stat.row_size;
stats.data_file_length= stat.fragment_memory;
- info->records= stat.row_count;
+ local_info->records= stat.row_count;
}
}
{
THD *thd= current_thd;
- if (get_thd_ndb(thd)->error)
- info->no_uncommitted_rows_count= 0;
+ if (get_thd_ndb(thd)->m_error)
+ local_info->no_uncommitted_rows_count= 0;
}
- if(result==0)
- stats.records= info->records+ info->no_uncommitted_rows_count;
+ if (result == 0)
+ stats.records= local_info->records+ local_info->no_uncommitted_rows_count;
DBUG_RETURN(result);
}
@@ -505,7 +508,7 @@ void ha_ndbcluster::no_uncommitted_rows_execute_failure()
if (m_ha_not_exact_count)
return;
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_execute_failure");
- get_thd_ndb(current_thd)->error= 1;
+ get_thd_ndb(current_thd)->m_error= TRUE;
DBUG_VOID_RETURN;
}
@@ -514,11 +517,11 @@ void ha_ndbcluster::no_uncommitted_rows_update(int c)
if (m_ha_not_exact_count)
return;
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update");
- struct Ndb_local_table_statistics *info= m_table_info;
- info->no_uncommitted_rows_count+= c;
+ struct Ndb_local_table_statistics *local_info= m_table_info;
+ local_info->no_uncommitted_rows_count+= c;
DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
((const NDBTAB *)m_table)->getTableId(),
- info->no_uncommitted_rows_count));
+ local_info->no_uncommitted_rows_count));
DBUG_VOID_RETURN;
}
@@ -529,7 +532,7 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd)
DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset");
Thd_ndb *thd_ndb= get_thd_ndb(thd);
thd_ndb->count++;
- thd_ndb->error= 0;
+ thd_ndb->m_error= FALSE;
DBUG_VOID_RETURN;
}
@@ -647,11 +650,31 @@ static bool ndb_supported_type(enum_field_types type)
/*
+ Check if MySQL field type forces var part in ndb storage
+*/
+static bool field_type_forces_var_part(enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_VARCHAR:
+ return TRUE;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ return FALSE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
Instruct NDB to set the value of the hidden primary key
*/
bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op,
- uint fieldnr, const byte *field_ptr)
+ uint fieldnr, const uchar *field_ptr)
{
DBUG_ENTER("set_hidden_key");
DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0);
@@ -663,14 +686,14 @@ bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op,
*/
int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
- uint fieldnr, const byte *field_ptr)
+ uint fieldnr, const uchar *field_ptr)
{
uint32 pack_len= field->pack_length();
DBUG_ENTER("set_ndb_key");
DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d",
fieldnr, field->field_name, field->type(),
pack_len));
- DBUG_DUMP("key", (char*)field_ptr, pack_len);
+ DBUG_DUMP("key", field_ptr, pack_len);
DBUG_ASSERT(ndb_supported_type(field->type()));
DBUG_ASSERT(! (field->flags & BLOB_FLAG));
@@ -687,13 +710,13 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
uint fieldnr, int row_offset,
bool *set_blob_value)
{
- const byte* field_ptr= field->ptr + row_offset;
+ const uchar* field_ptr= field->ptr + row_offset;
uint32 pack_len= field->pack_length();
DBUG_ENTER("set_ndb_value");
DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s",
fieldnr, field->field_name, field->type(),
pack_len, field->is_null(row_offset) ? "Y" : "N"));
- DBUG_DUMP("value", (char*) field_ptr, pack_len);
+ DBUG_DUMP("value", field_ptr, pack_len);
DBUG_ASSERT(ndb_supported_type(field->type()));
{
@@ -702,7 +725,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
if (pack_len == 0)
{
pack_len= sizeof(empty_field);
- field_ptr= (byte *)&empty_field;
+ field_ptr= (uchar *)&empty_field;
if (field->is_null(row_offset))
empty_field= 0;
else
@@ -732,12 +755,11 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
// Set value to NULL
DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL) != 0));
DBUG_PRINT("info", ("bit field"));
- DBUG_DUMP("value", (char*)&bits, pack_len);
+ DBUG_DUMP("value", (uchar*)&bits, pack_len);
#ifdef WORDS_BIGENDIAN
- if (pack_len < 5)
- {
- DBUG_RETURN(ndb_op->setValue(fieldnr, ((char*)&bits)+4) != 0);
- }
+ /* store lsw first */
+ bits = ((bits >> 32) & 0x00000000FFFFFFFFLL)
+ | ((bits << 32) & 0xFFFFFFFF00000000LL);
#endif
DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)&bits) != 0);
}
@@ -753,18 +775,18 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
// Get length and pointer to data
uint32 blob_len= field_blob->get_length(field_ptr);
- char* blob_ptr= NULL;
+ uchar* blob_ptr= NULL;
field_blob->get_ptr(&blob_ptr);
// Looks like NULL ptr signals length 0 blob
if (blob_ptr == NULL) {
DBUG_ASSERT(blob_len == 0);
- blob_ptr= (char*)"";
+ blob_ptr= (uchar*)"";
}
DBUG_PRINT("value", ("set blob ptr: 0x%lx len: %u",
(long) blob_ptr, blob_len));
- DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26));
+ DBUG_DUMP("value", blob_ptr, min(blob_len, 26));
if (set_blob_value)
*set_blob_value= TRUE;
@@ -808,7 +830,7 @@ int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
passes a record pointer diff.
*/
int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
- byte*& buffer, uint& buffer_size,
+ uchar*& buffer, uint& buffer_size,
my_ptrdiff_t ptrdiff)
{
DBUG_ENTER("get_ndb_blobs_value");
@@ -844,7 +866,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
size+= 8 - size % 8;
if (loop == 1)
{
- char *buf= buffer + offset;
+ uchar *buf= buffer + offset;
uint32 len= 0xffffffff; // Max uint32
if (ndb_blob->readData(buf, len) != 0)
ERR_RETURN(ndb_blob->getNdbError());
@@ -852,20 +874,16 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
i, offset, (long) buf, len, (int)ptrdiff));
DBUG_ASSERT(len == len64);
// Ugly hack assumes only ptr needs to be changed
- field_blob->ptr+= ptrdiff;
- field_blob->set_ptr(len, buf);
- field_blob->ptr-= ptrdiff;
+ field_blob->set_ptr_offset(ptrdiff, len, buf);
}
offset+= size;
}
else if (loop == 1) // undefined or null
{
// have to set length even in this case
- char *buf= buffer + offset; // or maybe NULL
+ uchar *buf= buffer + offset; // or maybe NULL
uint32 len= 0;
- field_blob->ptr+= ptrdiff;
- field_blob->set_ptr(len, buf);
- field_blob->ptr-= ptrdiff;
+ field_blob->set_ptr_offset(ptrdiff, len, buf);
DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull));
}
}
@@ -874,9 +892,13 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
buffer_size= 0;
DBUG_PRINT("info", ("allocate blobs buffer size %u", offset));
- buffer= my_malloc(offset, MYF(MY_WME));
+ buffer= (uchar*) my_malloc(offset, MYF(MY_WME));
if (buffer == NULL)
+ {
+ sql_print_error("ha_ndbcluster::get_ndb_blobs_value: "
+ "my_malloc(%u) failed", offset);
DBUG_RETURN(-1);
+ }
buffer_size= offset;
}
}
@@ -891,7 +913,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
*/
int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
- uint fieldnr, byte* buf)
+ uint fieldnr, uchar* buf)
{
DBUG_ENTER("get_ndb_value");
DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr,
@@ -906,13 +928,13 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
{
if (field->type() != MYSQL_TYPE_BIT)
{
- byte *field_buf;
+ uchar *field_buf;
if (field->pack_length() != 0)
field_buf= buf + (field->ptr - table->record[0]);
else
- field_buf= (byte *)&dummy_buf;
+ field_buf= (uchar *)&dummy_buf;
m_value[fieldnr].rec= ndb_op->getValue(fieldnr,
- field_buf);
+ (char*) field_buf);
}
else // if (field->type() == MYSQL_TYPE_BIT)
{
@@ -927,7 +949,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
if (ndb_blob != NULL)
{
// Set callback
- m_blobs_offset= buf - (byte*) table->record[0];
+ m_blobs_offset= buf - (uchar*) table->record[0];
void *arg= (void *)this;
DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0);
}
@@ -935,7 +957,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
}
// Used for hidden key only
- m_value[fieldnr].rec= ndb_op->getValue(fieldnr, m_ref);
+ m_value[fieldnr].rec= ndb_op->getValue(fieldnr, (char*) m_ref);
DBUG_RETURN(m_value[fieldnr].rec == NULL);
}
@@ -955,7 +977,6 @@ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
bool ha_ndbcluster::uses_blob_value()
{
- uint blob_fields;
MY_BITMAP *bitmap;
uint *blob_index, *blob_index_end;
if (table_share->blob_fields == 0)
@@ -1010,8 +1031,8 @@ int ha_ndbcluster::get_metadata(const char *path)
DBUG_ASSERT(m_table == NULL);
DBUG_ASSERT(m_table_info == NULL);
- const void *data, *pack_data;
- uint length, pack_length;
+ uchar *data= NULL, *pack_data= NULL;
+ size_t length, pack_length;
/*
Compare FrmData in NDB with frm file from disk.
@@ -1020,8 +1041,8 @@ int ha_ndbcluster::get_metadata(const char *path)
if (readfrm(path, &data, &length) ||
packfrm(data, length, &pack_data, &pack_length))
{
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(pack_data, MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(1);
}
@@ -1033,11 +1054,11 @@ int ha_ndbcluster::get_metadata(const char *path)
&& cmp_frm(tab, pack_data, pack_length))
{
DBUG_PRINT("error",
- ("metadata, pack_length: %d getFrmLength: %d memcmp: %d",
- pack_length, tab->getFrmLength(),
+ ("metadata, pack_length: %lu getFrmLength: %d memcmp: %d",
+ (ulong) pack_length, tab->getFrmLength(),
memcmp(pack_data, tab->getFrmData(), pack_length)));
- DBUG_DUMP("pack_data", (char*)pack_data, pack_length);
- DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength());
+ DBUG_DUMP("pack_data", (uchar*) pack_data, pack_length);
+ DBUG_DUMP("frm", (uchar*) tab->getFrmData(), tab->getFrmLength());
error= HA_ERR_TABLE_DEF_CHANGED;
}
my_free((char*)data, MYF(0));
@@ -1069,6 +1090,12 @@ static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
if (data.unique_index_attrid_map)
my_free((char*)data.unique_index_attrid_map, MYF(0));
data.unique_index_attrid_map= (uchar*)my_malloc(sz,MYF(MY_WME));
+ if (data.unique_index_attrid_map == 0)
+ {
+ sql_print_error("fix_unique_index_attr_order: my_malloc(%u) failure",
+ (unsigned int)sz);
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
@@ -1105,9 +1132,8 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab)
const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
- NDBDICT *dict= ndb->getDictionary();
DBUG_ENTER("ha_ndbcluster::create_indexes");
-
+
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
{
index_name= *key_name;
@@ -1243,7 +1269,6 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error)
int error= 0;
THD *thd=current_thd;
NDBDICT *dict= ndb->getDictionary();
- const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
DBUG_ENTER("ha_ndbcluster::open_indexes");
@@ -1255,9 +1280,9 @@ int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error)
m_index[i].index= m_index[i].unique_index= NULL;
else
break;
- m_index[i].null_in_unique_index= false;
+ m_index[i].null_in_unique_index= FALSE;
if (check_index_fields_not_null(key_info))
- m_index[i].null_in_unique_index= true;
+ m_index[i].null_in_unique_index= TRUE;
}
if (error && !ignore_error)
@@ -1293,7 +1318,6 @@ void ha_ndbcluster::renumber_indexes(Ndb *ndb, TABLE *tab)
const char *index_name;
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
- NDBDICT *dict= ndb->getDictionary();
DBUG_ENTER("ha_ndbcluster::renumber_indexes");
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
@@ -1410,10 +1434,10 @@ bool ha_ndbcluster::check_index_fields_not_null(KEY* key_info)
{
Field* field= key_part->field;
if (field->maybe_null())
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb)
@@ -1537,7 +1561,7 @@ inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part,
HA_KEY_SCAN_NOT_ROR);
}
-static void shrink_varchar(Field* field, const byte* & ptr, char* buf)
+static void shrink_varchar(Field* field, const uchar* & ptr, uchar* buf)
{
if (field->type() == MYSQL_TYPE_VARCHAR && ptr != NULL) {
Field_varstring* f= (Field_varstring*)field;
@@ -1556,7 +1580,7 @@ static void shrink_varchar(Field* field, const byte* & ptr, char* buf)
}
}
-int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
+int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key)
{
KEY* key_info= table->key_info + table_share->primary_key;
KEY_PART_INFO* key_part= key_info->key_part;
@@ -1566,8 +1590,8 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
for (; key_part != end; key_part++)
{
Field* field= key_part->field;
- const byte* ptr= key;
- char buf[256];
+ const uchar* ptr= key;
+ uchar buf[256];
shrink_varchar(field, ptr, buf);
if (set_ndb_key(op, field,
key_part->fieldnr-1, ptr))
@@ -1578,7 +1602,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key)
}
-int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const byte *record)
+int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *record)
{
KEY* key_info= table->key_info + table_share->primary_key;
KEY_PART_INFO* key_part= key_info->key_part;
@@ -1596,7 +1620,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const byte *rec
}
int ha_ndbcluster::set_index_key_from_record(NdbOperation *op,
- const byte *record, uint keyno)
+ const uchar *record, uint keyno)
{
KEY* key_info= table->key_info + keyno;
KEY_PART_INFO* key_part= key_info->key_part;
@@ -1617,7 +1641,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op,
int
ha_ndbcluster::set_index_key(NdbOperation *op,
const KEY *key_info,
- const byte * key_ptr)
+ const uchar * key_ptr)
{
DBUG_ENTER("ha_ndbcluster::set_index_key");
uint i;
@@ -1627,8 +1651,8 @@ ha_ndbcluster::set_index_key(NdbOperation *op,
for (i= 0; key_part != end; key_part++, i++)
{
Field* field= key_part->field;
- const byte* ptr= key_part->null_bit ? key_ptr + 1 : key_ptr;
- char buf[256];
+ const uchar* ptr= key_part->null_bit ? key_ptr + 1 : key_ptr;
+ uchar buf[256];
shrink_varchar(field, ptr, buf);
if (set_ndb_key(op, field, m_index[active_index].unique_index_attrid_map[i], ptr))
ERR_RETURN(m_active_trans->getNdbError());
@@ -1638,7 +1662,7 @@ ha_ndbcluster::set_index_key(NdbOperation *op,
}
inline
-int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
+int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op)
{
uint i;
DBUG_ENTER("define_read_attrs");
@@ -1680,7 +1704,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
Read one record from NDB using primary key
*/
-int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
+int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf,
uint32 part_id)
{
uint no_fields= table_share->fields;
@@ -1690,7 +1714,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
int res;
DBUG_ENTER("pk_read");
DBUG_PRINT("enter", ("key_len: %u", key_len));
- DBUG_DUMP("key", (char*)key, key_len);
+ DBUG_DUMP("key", key, key_len);
m_write_op= FALSE;
NdbOperation::LockMode lm=
@@ -1703,7 +1727,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
{
// This table has no primary key, use "hidden" primary key
DBUG_PRINT("info", ("Using hidden key"));
- DBUG_DUMP("key", (char*)key, 8);
+ DBUG_DUMP("key", key, 8);
if (set_hidden_key(op, no_fields, key))
ERR_RETURN(trans->getNdbError());
@@ -1731,7 +1755,8 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
ERR_RETURN(trans->getNdbError());
}
- if (execute_no_commit_ie(this,trans,false) != 0)
+ if ((res = execute_no_commit_ie(this,trans,FALSE)) != 0 ||
+ op->getNdbError().code)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -1748,7 +1773,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf,
or hidden key
*/
-int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
+int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data,
uint32 old_part_id)
{
uint no_fields= table_share->fields, i;
@@ -1796,7 +1821,7 @@ int ha_ndbcluster::complemented_read(const byte *old_data, byte *new_data,
}
}
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -1842,7 +1867,7 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
if (err.status != NdbError::Success)
{
if (ndb_to_mysql_error(&err) != (int) errcode)
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
if (op == last) break;
op= trans->getNextCompletedOperation(op);
}
@@ -1873,19 +1898,46 @@ bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
if (errcode == HA_ERR_KEY_NOT_FOUND)
m_dupkey= table->s->primary_key;
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
}
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
}
+/**
+ * Check if record contains any null valued columns that are part of a key
+ */
+static
+int
+check_null_in_record(const KEY* key_info, const uchar *record)
+{
+ KEY_PART_INFO *curr_part, *end_part;
+ curr_part= key_info->key_part;
+ end_part= curr_part + key_info->key_parts;
+
+ while (curr_part != end_part)
+ {
+ if (curr_part->null_bit &&
+ (record[curr_part->null_offset] & curr_part->null_bit))
+ return 1;
+ curr_part++;
+ }
+ return 0;
+ /*
+ We could instead pre-compute a bitmask in table_share with one bit for
+ every null-bit in the key, and so check this just by OR'ing the bitmask
+ with the null bitmap in the record.
+ But not sure it's worth it.
+ */
+}
+
/*
* Peek to check if any rows already exist with conflicting
* primary key or unique index values
*/
-int ha_ndbcluster::peek_indexed_rows(const byte *record,
+int ha_ndbcluster::peek_indexed_rows(const uchar *record,
bool check_pk)
{
NdbTransaction *trans= m_active_trans;
@@ -1937,7 +1989,17 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record,
if (i != table->s->primary_key &&
key_info->flags & HA_NOSAME)
{
- // A unique index is defined on table
+ /*
+ A unique index is defined on table.
+ We cannot look up a NULL field value in a unique index. But since
+ keys with NULLs are not indexed, such rows cannot conflict anyway, so
+ we just skip the index in this case.
+ */
+ if (check_null_in_record(key_info, record))
+ {
+ DBUG_PRINT("info", ("skipping check for key with NULL"));
+ continue;
+ }
NdbIndexOperation *iop;
const NDBINDEX *unique_index = m_index[i].unique_index;
key_part= key_info->key_part;
@@ -1954,7 +2016,7 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record,
}
last= trans->getLastDefinedOperation();
if (first)
- res= execute_no_commit_ie(this,trans,false);
+ res= execute_no_commit_ie(this,trans,FALSE);
else
{
// Table has no keys
@@ -1979,15 +2041,15 @@ int ha_ndbcluster::peek_indexed_rows(const byte *record,
Read one record from NDB using unique secondary index
*/
-int ha_ndbcluster::unique_index_read(const byte *key,
- uint key_len, byte *buf)
+int ha_ndbcluster::unique_index_read(const uchar *key,
+ uint key_len, uchar *buf)
{
int res;
NdbTransaction *trans= m_active_trans;
NdbIndexOperation *op;
DBUG_ENTER("ha_ndbcluster::unique_index_read");
DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index));
- DBUG_DUMP("key", (char*)key, key_len);
+ DBUG_DUMP("key", key, key_len);
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
@@ -2003,7 +2065,8 @@ int ha_ndbcluster::unique_index_read(const byte *key,
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit_ie(this,trans,false) != 0)
+ if (execute_no_commit_ie(this,trans,FALSE) != 0 ||
+ op->getNdbError().code)
{
table->status= STATUS_NOT_FOUND;
DBUG_RETURN(ndb_err(trans));
@@ -2017,7 +2080,7 @@ int ha_ndbcluster::unique_index_read(const byte *key,
inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
DBUG_ENTER("fetch_next");
- int check;
+ int local_check;
NdbTransaction *trans= m_active_trans;
if (m_lock_tuple)
@@ -2028,19 +2091,21 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
LOCK WITH SHARE MODE) and row was not explictly unlocked
with unlock_row() call
*/
- NdbConnection *trans= m_active_trans;
+ NdbConnection *con_trans= m_active_trans;
NdbOperation *op;
// Lock row
DBUG_PRINT("info", ("Keeping lock on scanned row"));
if (!(op= m_active_cursor->lockCurrentTuple()))
{
- m_lock_tuple= false;
- ERR_RETURN(trans->getNdbError());
+ /* purecov: begin inspected */
+ m_lock_tuple= FALSE;
+ ERR_RETURN(con_trans->getNdbError());
+ /* purecov: end */
}
m_ops_pending++;
}
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE &&
m_lock.type != TL_READ_WITH_SHARED_LOCKS;;
@@ -2051,13 +2116,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
*/
if (m_ops_pending && m_blobs_pending)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
m_ops_pending= 0;
m_blobs_pending= FALSE;
}
- if ((check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
+ if ((local_check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
{
/*
Explicitly lock tuple if "select for update" or
@@ -2068,7 +2133,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
m_lock.type == TL_READ_WITH_SHARED_LOCKS);
DBUG_RETURN(0);
}
- else if (check == 1 || check == 2)
+ else if (local_check == 1 || local_check == 2)
{
// 1: No more records
// 2: No more cached records
@@ -2083,7 +2148,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
{
if (m_transaction_on)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(-1);
}
else
@@ -2098,13 +2163,13 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
}
m_ops_pending= 0;
}
- contact_ndb= (check == 2);
+ contact_ndb= (local_check == 2);
}
else
{
DBUG_RETURN(-1);
}
- } while (check == 2);
+ } while (local_check == 2);
DBUG_RETURN(1);
}
@@ -2120,7 +2185,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
*/
-inline int ha_ndbcluster::next_result(byte *buf)
+inline int ha_ndbcluster::next_result(uchar *buf)
{
int res;
DBUG_ENTER("next_result");
@@ -2199,10 +2264,10 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
struct part_st {
bool part_last;
const key_range *key;
- const byte *part_ptr;
+ const uchar *part_ptr;
bool part_null;
int bound_type;
- const char* bound_ptr;
+ const uchar* bound_ptr;
};
struct part_st part[2];
@@ -2281,8 +2346,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag));
DBUG_ASSERT(FALSE);
// Stop setting bounds but continue with what we have
- op->end_of_bound(range_no);
- DBUG_RETURN(0);
+ DBUG_RETURN(op->end_of_bound(range_no));
}
}
}
@@ -2313,13 +2377,13 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
{
DBUG_PRINT("info", ("key %d:%d offset: %d length: %d last: %d bound: %d",
j, i, tot_len, part_len, p.part_last, p.bound_type));
- DBUG_DUMP("info", (const char*)p.part_ptr, part_store_len);
+ DBUG_DUMP("info", p.part_ptr, part_store_len);
// Set bound if not cancelled via type -1
if (p.bound_type != -1)
{
- const char* ptr= p.bound_ptr;
- char buf[256];
+ const uchar* ptr= p.bound_ptr;
+ uchar buf[256];
shrink_varchar(field, ptr, buf);
if (op->setBound(i, p.bound_type, ptr))
ERR_RETURN(op->getNdbError());
@@ -2329,8 +2393,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
tot_len+= part_store_len;
}
- op->end_of_bound(range_no);
- DBUG_RETURN(0);
+ DBUG_RETURN(op->end_of_bound(range_no));
}
/*
@@ -2340,7 +2403,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
const key_range *end_key,
bool sorted, bool descending,
- byte* buf, part_id_range *part_spec)
+ uchar* buf, part_id_range *part_spec)
{
int res;
bool restart;
@@ -2364,7 +2427,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
bool need_pk = (lm == NdbOperation::LM_Read);
if (!(op= trans->getNdbIndexScanOperation(m_index[active_index].index,
m_table)) ||
- op->readTuples(lm, 0, parallelism, sorted, descending, false, need_pk))
+ op->readTuples(lm, 0, parallelism, sorted, descending, FALSE, need_pk))
ERR_RETURN(trans->getNdbError());
if (m_use_partition_function && part_spec != NULL &&
part_spec->start_part == part_spec->end_part)
@@ -2386,14 +2449,14 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
{
const key_range *keys[2]= { start_key, end_key };
- res= set_bounds(op, active_index, false, keys);
+ res= set_bounds(op, active_index, FALSE, keys);
if (res)
DBUG_RETURN(res);
}
if (!restart)
{
- if (generate_scan_filter(m_cond_stack, op))
+ if (m_cond && m_cond->generate_scan_filter(op))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
@@ -2410,7 +2473,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
ERR_RETURN(trans->getNdbError());
}
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_RETURN(next_result(buf));
@@ -2446,9 +2509,9 @@ guess_scan_flags(NdbOperation::LockMode lm,
*/
int ha_ndbcluster::unique_index_scan(const KEY* key_info,
- const byte *key,
+ const uchar *key,
uint key_len,
- byte *buf)
+ uchar *buf)
{
int res;
NdbScanOperation *op;
@@ -2499,13 +2562,19 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
(get_ndb_partition_id(op)))
ERR_RETURN(trans->getNdbError());
}
-
- if (generate_scan_filter_from_key(op, key_info, key, key_len, buf))
+ if (!m_cond)
+ m_cond= new ha_ndbcluster_cond;
+ if (!m_cond)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(my_errno);
+ }
+ if (m_cond->generate_scan_filter_from_key(op, key_info, key, key_len, buf))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_PRINT("exit", ("Scan started successfully"));
DBUG_RETURN(next_result(buf));
@@ -2516,7 +2585,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
Start full table scan in NDB
*/
-int ha_ndbcluster::full_table_scan(byte *buf)
+int ha_ndbcluster::full_table_scan(uchar *buf)
{
int res;
NdbScanOperation *op;
@@ -2569,12 +2638,12 @@ int ha_ndbcluster::full_table_scan(byte *buf)
ERR_RETURN(trans->getNdbError());
}
- if (generate_scan_filter(m_cond_stack, op))
+ if (m_cond && m_cond->generate_scan_filter(op))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
DBUG_RETURN(ndb_err(trans));
DBUG_PRINT("exit", ("Scan started successfully"));
DBUG_RETURN(next_result(buf));
@@ -2583,14 +2652,14 @@ int ha_ndbcluster::full_table_scan(byte *buf)
/*
Insert one record into NDB
*/
-int ha_ndbcluster::write_row(byte *record)
+int ha_ndbcluster::write_row(uchar *record)
{
bool has_auto_increment;
uint i;
NdbTransaction *trans= m_active_trans;
NdbOperation *op;
int res;
- THD *thd= current_thd;
+ THD *thd= table->in_use;
longlong func_value= 0;
DBUG_ENTER("ha_ndbcluster::write_row");
@@ -2603,7 +2672,6 @@ int ha_ndbcluster::write_row(byte *record)
*/
if (has_auto_increment)
{
- THD *thd= table->in_use;
int error;
m_skip_auto_increment= FALSE;
@@ -2623,7 +2691,7 @@ int ha_ndbcluster::write_row(byte *record)
start_bulk_insert will set parameters to ensure that each
write_row is committed individually
*/
- int peek_res= peek_indexed_rows(record, true);
+ int peek_res= peek_indexed_rows(record, TRUE);
if (!peek_res)
{
@@ -2633,7 +2701,7 @@ int ha_ndbcluster::write_row(byte *record)
DBUG_RETURN(peek_res);
}
- statistic_increment(thd->status_var.ha_write_count, &LOCK_status);
+ ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
@@ -2663,18 +2731,25 @@ int ha_ndbcluster::write_row(byte *record)
{
// Table has hidden primary key
Ndb *ndb= get_ndb();
- int ret;
Uint64 auto_value;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
- do {
+ int retry_sleep= 30; /* 30 milliseconds, transaction */
+ for (;;)
+ {
Ndb_tuple_id_range_guard g(m_share);
- ret= ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1);
- } while (ret == -1 &&
- --retries &&
- ndb->getNdbError().status == NdbError::TemporaryError);
- if (ret == -1)
- ERR_RETURN(ndb->getNdbError());
- if (set_hidden_key(op, table_share->fields, (const byte*)&auto_value))
+ if (ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1) == -1)
+ {
+ if (--retries &&
+ ndb->getNdbError().status == NdbError::TemporaryError);
+ {
+ my_sleep(retry_sleep);
+ continue;
+ }
+ ERR_RETURN(ndb->getNdbError());
+ }
+ break;
+ }
+ if (set_hidden_key(op, table_share->fields, (const uchar*)&auto_value))
ERR_RETURN(op->getNdbError());
}
else
@@ -2717,6 +2792,13 @@ int ha_ndbcluster::write_row(byte *record)
op->setValue(no_fields, part_func_value);
}
+ if (unlikely(m_slow_path))
+ {
+ if (!(thd->options & OPTION_BIN_LOG))
+ op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
+ else if (thd->slave_thread)
+ op->setAnyValue(thd->server_id);
+ }
m_rows_changed++;
/*
@@ -2742,7 +2824,7 @@ int ha_ndbcluster::write_row(byte *record)
m_bulk_insert_not_flushed= FALSE;
if (m_transaction_on)
{
- if (execute_no_commit(this,trans,false) != 0)
+ if (execute_no_commit(this,trans,FALSE) != 0)
{
m_skip_auto_increment= TRUE;
no_uncommitted_rows_execute_failure();
@@ -2768,10 +2850,12 @@ int ha_ndbcluster::write_row(byte *record)
{
Ndb *ndb= get_ndb();
Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
+#ifndef DBUG_OFF
char buff[22];
DBUG_PRINT("info",
("Trying to set next auto increment value to %s",
llstr(next_val, buff)));
+#endif
Ndb_tuple_id_range_guard g(m_share);
if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE)
== -1)
@@ -2786,8 +2870,8 @@ int ha_ndbcluster::write_row(byte *record)
/* Compare if a key in a row has changed */
-int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
- const byte * new_row)
+int ha_ndbcluster::key_cmp(uint keynr, const uchar * old_row,
+ const uchar * new_row)
{
KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
@@ -2803,8 +2887,8 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
{
- if (key_part->field->cmp_binary((char*) (old_row + key_part->offset),
- (char*) (new_row + key_part->offset),
+ if (key_part->field->cmp_binary((old_row + key_part->offset),
+ (new_row + key_part->offset),
(ulong) key_part->length))
return 1;
}
@@ -2822,9 +2906,9 @@ int ha_ndbcluster::key_cmp(uint keynr, const byte * old_row,
Update one record in NDB using primary key
*/
-int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
+int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data)
{
- THD *thd= current_thd;
+ THD *thd= table->in_use;
NdbTransaction *trans= m_active_trans;
NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
@@ -2853,7 +2937,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_RETURN(peek_res);
}
- statistic_increment(thd->status_var.ha_update_count, &LOCK_status);
+ ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
{
table->timestamp_field->set_time();
@@ -2907,7 +2991,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
{
// Undo delete_row(old_data)
m_primary_key_update= TRUE;
- undo_res= write_row((byte *)old_data);
+ undo_res= write_row((uchar *)old_data);
if (undo_res)
push_warning(current_thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -2933,7 +3017,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_PRINT("info", ("Calling updateTuple on cursor"));
if (!(op= cursor->updateCurrentTuple()))
ERR_RETURN(trans->getNdbError());
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
m_ops_pending++;
if (uses_blob_value())
m_blobs_pending= TRUE;
@@ -2995,8 +3079,21 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
no_fields++;
op->setValue(no_fields, part_func_value);
}
- // Execute update operation
- if (!cursor && execute_no_commit(this,trans,false) != 0) {
+
+ if (unlikely(m_slow_path))
+ {
+ if (!(thd->options & OPTION_BIN_LOG))
+ op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
+ else if (thd->slave_thread)
+ op->setAnyValue(thd->server_id);
+ }
+ /*
+ Execute update operation if we are not doing a scan for update
+ and there exist UPDATE AFTER triggers
+ */
+
+ if ((!cursor || m_update_cannot_batch) &&
+ execute_no_commit(this,trans,false) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3009,9 +3106,9 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
Delete one record from NDB, using primary key
*/
-int ha_ndbcluster::delete_row(const byte *record)
+int ha_ndbcluster::delete_row(const uchar *record)
{
- THD *thd= current_thd;
+ THD *thd= table->in_use;
NdbTransaction *trans= m_active_trans;
NdbScanOperation* cursor= m_active_cursor;
NdbOperation *op;
@@ -3020,7 +3117,7 @@ int ha_ndbcluster::delete_row(const byte *record)
DBUG_ENTER("delete_row");
m_write_op= TRUE;
- statistic_increment(thd->status_var.ha_delete_count,&LOCK_status);
+ ha_statistic_increment(&SSV::ha_delete_count);
m_rows_changed++;
if (m_use_partition_function &&
@@ -3042,7 +3139,7 @@ int ha_ndbcluster::delete_row(const byte *record)
DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
if (cursor->deleteCurrentTuple() != 0)
ERR_RETURN(trans->getNdbError());
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
m_ops_pending++;
if (m_use_partition_function)
@@ -3050,7 +3147,16 @@ int ha_ndbcluster::delete_row(const byte *record)
no_uncommitted_rows_update(-1);
- if (!m_primary_key_update)
+ if (unlikely(m_slow_path))
+ {
+ if (!(thd->options & OPTION_BIN_LOG))
+ ((NdbOperation *)trans->getLastDefinedOperation())->
+ setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
+ else if (thd->slave_thread)
+ ((NdbOperation *)trans->getLastDefinedOperation())->
+ setAnyValue(thd->server_id);
+ }
+ if (!(m_primary_key_update || m_delete_cannot_batch))
// If deleting from cursor, NoCommit will be handled in next_result
DBUG_RETURN(0);
}
@@ -3079,10 +3185,18 @@ int ha_ndbcluster::delete_row(const byte *record)
if ((error= set_primary_key_from_record(op, record)))
DBUG_RETURN(error);
}
+
+ if (unlikely(m_slow_path))
+ {
+ if (!(thd->options & OPTION_BIN_LOG))
+ op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
+ else if (thd->slave_thread)
+ op->setAnyValue(thd->server_id);
+ }
}
// Execute delete operation
- if (execute_no_commit(this,trans,false) != 0) {
+ if (execute_no_commit(this,trans,FALSE) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3104,18 +3218,29 @@ int ha_ndbcluster::delete_row(const byte *record)
*/
void ndb_unpack_record(TABLE *table, NdbValue *value,
- MY_BITMAP *defined, byte *buf)
+ MY_BITMAP *defined, uchar *buf)
{
Field **p_field= table->field, *field= *p_field;
my_ptrdiff_t row_offset= (my_ptrdiff_t) (buf - table->record[0]);
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
DBUG_ENTER("ndb_unpack_record");
- // Set null flag(s)
- bzero(buf, table->s->null_bytes);
+ /*
+ Set the filler bits of the null byte, since they are
+ not touched in the code below.
+
+ The filler bits are the MSBs in the last null byte
+ */
+ if (table->s->null_bytes > 0)
+ buf[table->s->null_bytes - 1]|= 256U - (1U <<
+ table->s->last_null_bit_pos);
+ /*
+ Set null flag(s)
+ */
for ( ; field;
p_field++, value++, field= *p_field)
{
+ field->set_notnull(row_offset);
if ((*value).ptr)
{
if (!(field->flags & BLOB_FLAG))
@@ -3125,7 +3250,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
{
if (is_null > 0)
{
- DBUG_PRINT("info",("[%u] NULL",
+ DBUG_PRINT("info",("[%u] NULL",
(*value).rec->getColumn()->getColumnNo()));
field->set_null(row_offset);
}
@@ -3157,10 +3282,21 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
else
{
DBUG_PRINT("info", ("bit field H'%.8X%.8X",
- *(Uint32*) (*value).rec->aRef(),
- *((Uint32*) (*value).rec->aRef()+1)));
- field_bit->Field_bit::store((longlong) (*value).rec->u_64_value(),
+ *(Uint32 *)(*value).rec->aRef(),
+ *((Uint32 *)(*value).rec->aRef()+1)));
+#ifdef WORDS_BIGENDIAN
+ /* lsw is stored first */
+ Uint32 *buf= (Uint32 *)(*value).rec->aRef();
+ field_bit->Field_bit::store((((longlong)*buf)
+ & 0x000000000FFFFFFFFLL)
+ |
+ ((((longlong)*(buf+1)) << 32)
+ & 0xFFFFFFFF00000000LL),
TRUE);
+#else
+ field_bit->Field_bit::store((longlong)
+ (*value).rec->u_64_value(), TRUE);
+#endif
}
/*
Move back internal field pointer to point to original
@@ -3169,13 +3305,13 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
field_bit->Field_bit::move_field_offset(-row_offset);
DBUG_PRINT("info",("[%u] SET",
(*value).rec->getColumn()->getColumnNo()));
- DBUG_DUMP("info", (const char*) field->ptr, field->pack_length());
+ DBUG_DUMP("info", field->ptr, field->pack_length());
}
else
{
DBUG_PRINT("info",("[%u] SET",
(*value).rec->getColumn()->getColumnNo()));
- DBUG_DUMP("info", (const char*) field->ptr, field->pack_length());
+ DBUG_DUMP("info", field->ptr, field->pack_length());
}
}
else
@@ -3199,7 +3335,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
#ifndef DBUG_OFF
// pointer vas set in get_ndb_blobs_value
Field_blob *field_blob= (Field_blob*)field;
- char* ptr;
+ uchar *ptr;
field_blob->get_ptr(&ptr, row_offset);
uint32 len= field_blob->get_length(row_offset);
DBUG_PRINT("info",("[%u] SET ptr: 0x%lx len: %u",
@@ -3213,7 +3349,7 @@ void ndb_unpack_record(TABLE *table, NdbValue *value,
DBUG_VOID_RETURN;
}
-void ha_ndbcluster::unpack_record(byte *buf)
+void ha_ndbcluster::unpack_record(uchar *buf)
{
ndb_unpack_record(table, m_value, 0, buf);
#ifndef DBUG_OFF
@@ -3310,8 +3446,7 @@ int ha_ndbcluster::index_init(uint index, bool sorted)
unless m_lock.type == TL_READ_HIGH_PRIORITY
and no sub-sequent call to unlock_row()
*/
- m_lock_tuple= false;
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
DBUG_RETURN(0);
}
@@ -3327,13 +3462,12 @@ int ha_ndbcluster::index_end()
*/
static
int
-check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
+check_null_in_key(const KEY* key_info, const uchar *key, uint key_len)
{
KEY_PART_INFO *curr_part, *end_part;
- const byte* end_ptr= key + key_len;
+ const uchar* end_ptr= key + key_len;
curr_part= key_info->key_part;
end_part= curr_part + key_info->key_parts;
-
for (; curr_part != end_part && key < end_ptr; curr_part++)
{
@@ -3345,8 +3479,8 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len)
return 0;
}
-int ha_ndbcluster::index_read(byte *buf,
- const byte *key, uint key_len,
+int ha_ndbcluster::index_read(uchar *buf,
+ const uchar *key, uint key_len,
enum ha_rkey_function find_flag)
{
key_range start_key;
@@ -3374,42 +3508,26 @@ int ha_ndbcluster::index_read(byte *buf,
}
-int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
- const byte *key, uint key_len,
- enum ha_rkey_function find_flag)
-{
- statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
- DBUG_ENTER("ha_ndbcluster::index_read_idx");
- DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
- close_scan();
- index_init(index_no, 0);
- DBUG_RETURN(index_read(buf, key, key_len, find_flag));
-}
-
-
-int ha_ndbcluster::index_next(byte *buf)
+int ha_ndbcluster::index_next(uchar *buf)
{
DBUG_ENTER("ha_ndbcluster::index_next");
- statistic_increment(current_thd->status_var.ha_read_next_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_next_count);
DBUG_RETURN(next_result(buf));
}
-int ha_ndbcluster::index_prev(byte *buf)
+int ha_ndbcluster::index_prev(uchar *buf)
{
DBUG_ENTER("ha_ndbcluster::index_prev");
- statistic_increment(current_thd->status_var.ha_read_prev_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_prev_count);
DBUG_RETURN(next_result(buf));
}
-int ha_ndbcluster::index_first(byte *buf)
+int ha_ndbcluster::index_first(uchar *buf)
{
DBUG_ENTER("ha_ndbcluster::index_first");
- statistic_increment(current_thd->status_var.ha_read_first_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_first_count);
// Start the ordered index scan and fetch the first row
// Only HA_READ_ORDER indexes get called by index_first
@@ -3417,14 +3535,14 @@ int ha_ndbcluster::index_first(byte *buf)
}
-int ha_ndbcluster::index_last(byte *buf)
+int ha_ndbcluster::index_last(uchar *buf)
{
DBUG_ENTER("ha_ndbcluster::index_last");
- statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_last_count);
DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL));
}
-int ha_ndbcluster::index_read_last(byte * buf, const byte * key, uint key_len)
+int ha_ndbcluster::index_read_last(uchar * buf, const uchar * key, uint key_len)
{
DBUG_ENTER("ha_ndbcluster::index_read_last");
DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
@@ -3433,7 +3551,7 @@ int ha_ndbcluster::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
const key_range *end_key,
bool desc, bool sorted,
- byte* buf)
+ uchar* buf)
{
part_id_range part_spec;
ndb_index_type type= get_index_type(active_index);
@@ -3478,8 +3596,9 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
{
if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
- DBUG_RETURN(pk_read(start_key->key, start_key->length, buf,
- part_spec.start_part));
+ error= pk_read(start_key->key, start_key->length, buf,
+ part_spec.start_part);
+ DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
}
break;
case UNIQUE_ORDERED_INDEX:
@@ -3490,7 +3609,9 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
{
if (m_active_cursor && (error= close_scan()))
DBUG_RETURN(error);
- DBUG_RETURN(unique_index_read(start_key->key, start_key->length, buf));
+
+ error= unique_index_read(start_key->key, start_key->length, buf);
+ DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
}
else if (type == UNIQUE_INDEX)
DBUG_RETURN(unique_index_scan(key_info,
@@ -3510,7 +3631,7 @@ int ha_ndbcluster::read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_r, bool sorted)
{
- byte* buf= table->record[0];
+ uchar* buf= table->record[0];
DBUG_ENTER("ha_ndbcluster::read_range_first");
DBUG_RETURN(read_range_first_to_buf(start_key, end_key, FALSE,
sorted, buf));
@@ -3550,10 +3671,10 @@ int ha_ndbcluster::close_scan()
m_multi_cursor= 0;
if (!m_active_cursor && !m_multi_cursor)
- DBUG_RETURN(1);
+ DBUG_RETURN(0);
NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor;
-
+
if (m_lock_tuple)
{
/*
@@ -3568,12 +3689,12 @@ int ha_ndbcluster::close_scan()
if (!(op= cursor->lockCurrentTuple()))
{
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
ERR_RETURN(trans->getNdbError());
}
m_ops_pending++;
}
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
if (m_ops_pending)
{
/*
@@ -3581,7 +3702,7 @@ int ha_ndbcluster::close_scan()
deleteing/updating transaction before closing the scan
*/
DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending));
- if (execute_no_commit(this,trans,false) != 0) {
+ if (execute_no_commit(this,trans,FALSE) != 0) {
no_uncommitted_rows_execute_failure();
DBUG_RETURN(ndb_err(trans));
}
@@ -3600,11 +3721,10 @@ int ha_ndbcluster::rnd_end()
}
-int ha_ndbcluster::rnd_next(byte *buf)
+int ha_ndbcluster::rnd_next(uchar *buf)
{
DBUG_ENTER("rnd_next");
- statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_rnd_next_count);
if (!m_active_cursor)
DBUG_RETURN(full_table_scan(buf));
@@ -3619,11 +3739,10 @@ int ha_ndbcluster::rnd_next(byte *buf)
again
*/
-int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
+int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
{
DBUG_ENTER("rnd_pos");
- statistic_increment(current_thd->status_var.ha_read_rnd_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_rnd_count);
// The primary key for the record is stored in pos
// Perform a pk_read using primary key "index"
{
@@ -3637,7 +3756,7 @@ int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
The partition id has been fetched from ndb
and has been stored directly after the hidden key
*/
- DBUG_DUMP("key+part", (char *)pos, key_length);
+ DBUG_DUMP("key+part", pos, key_length);
key_length= ref_length - sizeof(m_part_id);
part_spec.start_part= part_spec.end_part= *(uint32 *)(pos + key_length);
}
@@ -3654,7 +3773,7 @@ int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
}
DBUG_PRINT("info", ("partition id %u", part_spec.start_part));
}
- DBUG_DUMP("key", (char *)pos, key_length);
+ DBUG_DUMP("key", pos, key_length);
DBUG_RETURN(pk_read(pos, key_length, buf, part_spec.start_part));
}
}
@@ -3666,12 +3785,12 @@ int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
using "reference" in rnd_pos
*/
-void ha_ndbcluster::position(const byte *record)
+void ha_ndbcluster::position(const uchar *record)
{
KEY *key_info;
KEY_PART_INFO *key_part;
KEY_PART_INFO *end;
- byte *buff;
+ uchar *buff;
uint key_length;
DBUG_ENTER("position");
@@ -3697,22 +3816,28 @@ void ha_ndbcluster::position(const byte *record)
}
size_t len = key_part->length;
- const byte * ptr = record + key_part->offset;
+ const uchar * ptr = record + key_part->offset;
Field *field = key_part->field;
- if ((field->type() == MYSQL_TYPE_VARCHAR) &&
- ((Field_varstring*)field)->length_bytes == 1)
+ if (field->type() == MYSQL_TYPE_VARCHAR)
{
- /**
- * Keys always use 2 bytes length
- */
- buff[0] = ptr[0];
- buff[1] = 0;
- memcpy(buff+2, ptr + 1, len);
- len += 2;
+ if (((Field_varstring*)field)->length_bytes == 1)
+ {
+ /**
+ * Keys always use 2 bytes length
+ */
+ buff[0] = ptr[0];
+ buff[1] = 0;
+ memcpy(buff+2, ptr + 1, len);
+ }
+ else
+ {
+ memcpy(buff, ptr, len + 2);
+ }
+ len += 2;
}
else
{
- memcpy(buff, ptr, len);
+ memcpy(buff, ptr, len);
}
buff += len;
}
@@ -3742,9 +3867,9 @@ void ha_ndbcluster::position(const byte *record)
}
#ifndef DBUG_OFF
if (table_share->primary_key == MAX_KEY && m_use_partition_function)
- DBUG_DUMP("key+part", (char*)ref, key_length+sizeof(m_part_id));
+ DBUG_DUMP("key+part", ref, key_length+sizeof(m_part_id));
#endif
- DBUG_DUMP("ref", (char*)ref, key_length);
+ DBUG_DUMP("ref", ref, key_length);
DBUG_VOID_RETURN;
}
@@ -3778,9 +3903,12 @@ int ha_ndbcluster::info(uint flag)
Ndb *ndb= get_ndb();
ndb->setDatabaseName(m_dbname);
struct Ndb_statistics stat;
- ndb->setDatabaseName(m_dbname);
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
+ }
if (current_thd->variables.ndb_use_exact_count &&
- (result= ndb_get_table_statistics(this, true, ndb, m_table, &stat))
+ (result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))
== 0)
{
stats.mean_rec_length= stat.row_size;
@@ -3807,7 +3935,7 @@ int ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_AUTO)
{
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
- if (m_table)
+ if (m_table && table->found_next_number_field)
{
Ndb *ndb= get_ndb();
Ndb_tuple_id_range_guard g(m_share);
@@ -3871,7 +3999,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
break;
case HA_EXTRA_WRITE_CAN_REPLACE:
DBUG_PRINT("info", ("HA_EXTRA_WRITE_CAN_REPLACE"));
- if (!m_has_unique_index)
+ if (!m_has_unique_index ||
+ current_thd->slave_thread) /* always set if slave, quick fix for bug 27378 */
{
DBUG_PRINT("info", ("Turning ON use of write instead of insert"));
m_use_write= TRUE;
@@ -3882,6 +4011,14 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
DBUG_PRINT("info", ("Turning OFF use of write instead of insert"));
m_use_write= FALSE;
break;
+ case HA_EXTRA_DELETE_CANNOT_BATCH:
+ DBUG_PRINT("info", ("HA_EXTRA_DELETE_CANNOT_BATCH"));
+ m_delete_cannot_batch= TRUE;
+ break;
+ case HA_EXTRA_UPDATE_CANNOT_BATCH:
+ DBUG_PRINT("info", ("HA_EXTRA_UPDATE_CANNOT_BATCH"));
+ m_update_cannot_batch= TRUE;
+ break;
default:
break;
}
@@ -3893,7 +4030,11 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
int ha_ndbcluster::reset()
{
DBUG_ENTER("ha_ndbcluster::reset");
- cond_clear();
+ if (m_cond)
+ {
+ m_cond->cond_clear();
+ }
+
/*
Regular partition pruning will set the bitmap appropriately.
Some queries like ALTER TABLE doesn't use partition pruning and
@@ -3901,6 +4042,14 @@ int ha_ndbcluster::reset()
*/
if (m_part_info)
bitmap_set_all(&m_part_info->used_partitions);
+
+ /* reset flags set by extra calls */
+ m_ignore_dup_key= FALSE;
+ m_use_write= FALSE;
+ m_ignore_no_key= FALSE;
+ m_delete_cannot_batch= FALSE;
+ m_update_cannot_batch= FALSE;
+
DBUG_RETURN(0);
}
@@ -3981,7 +4130,7 @@ int ha_ndbcluster::end_bulk_insert()
m_bulk_insert_not_flushed= FALSE;
if (m_transaction_on)
{
- if (execute_no_commit(this, trans,false) != 0)
+ if (execute_no_commit(this, trans,FALSE) != 0)
{
no_uncommitted_rows_execute_failure();
my_errno= error= ndb_err(trans);
@@ -3996,7 +4145,7 @@ int ha_ndbcluster::end_bulk_insert()
}
else
{
- int res= trans->restart();
+ IF_DBUG(int res=) trans->restart();
DBUG_ASSERT(res == 0);
}
}
@@ -4114,6 +4263,60 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
- refresh list of the indexes for the table if needed (if altered)
*/
+#ifdef HAVE_NDB_BINLOG
+extern MASTER_INFO *active_mi;
+static int ndbcluster_update_apply_status(THD *thd, int do_update)
+{
+ return 0;
+
+ Thd_ndb *thd_ndb= get_thd_ndb(thd);
+ Ndb *ndb= thd_ndb->ndb;
+ NDBDICT *dict= ndb->getDictionary();
+ const NDBTAB *ndbtab;
+ NdbTransaction *trans= thd_ndb->all ? thd_ndb->all : thd_ndb->stmt;
+ ndb->setDatabaseName(NDB_REP_DB);
+ Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE);
+ if (!(ndbtab= ndbtab_g.get_table()))
+ {
+ return -1;
+ }
+ NdbOperation *op= 0;
+ int r= 0;
+ r|= (op= trans->getNdbOperation(ndbtab)) == 0;
+ DBUG_ASSERT(r == 0);
+ if (do_update)
+ r|= op->updateTuple();
+ else
+ r|= op->writeTuple();
+ DBUG_ASSERT(r == 0);
+ // server_id
+ r|= op->equal(0u, (Uint32)thd->server_id);
+ DBUG_ASSERT(r == 0);
+ if (!do_update)
+ {
+ // epoch
+ r|= op->setValue(1u, (Uint64)0);
+ DBUG_ASSERT(r == 0);
+ }
+ // log_name
+ char tmp_buf[FN_REFLEN];
+ ndb_pack_varchar(ndbtab->getColumn(2u), tmp_buf,
+ active_mi->rli.group_master_log_name,
+ strlen(active_mi->rli.group_master_log_name));
+ r|= op->setValue(2u, tmp_buf);
+ DBUG_ASSERT(r == 0);
+ // start_pos
+ r|= op->setValue(3u, (Uint64)active_mi->rli.group_master_log_pos);
+ DBUG_ASSERT(r == 0);
+ // end_pos
+ r|= op->setValue(4u, (Uint64)active_mi->rli.group_master_log_pos +
+ ((Uint64)active_mi->rli.future_event_relay_log_pos -
+ (Uint64)active_mi->rli.group_relay_log_pos));
+ DBUG_ASSERT(r == 0);
+ return 0;
+}
+#endif /* HAVE_NDB_BINLOG */
+
int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
int error=0;
@@ -4142,8 +4345,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
m_transaction_on= FALSE;
/* Would be simpler if has_transactions() didn't always say "yes" */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
- thd->no_trans_update= TRUE;
+ thd->no_trans_update.all= thd->no_trans_update.stmt= TRUE;
}
else if (!thd->transaction.on)
m_transaction_on= FALSE;
@@ -4164,6 +4366,11 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
thd_ndb->init_open_tables();
thd_ndb->stmt= trans;
thd_ndb->query_state&= NDB_QUERY_NORMAL;
+ thd_ndb->trans_options= 0;
+ thd_ndb->m_slow_path= FALSE;
+ if (thd->slave_thread ||
+ !(thd->options & OPTION_BIN_LOG))
+ thd_ndb->m_slow_path= TRUE;
trans_register_ha(thd, FALSE, ndbcluster_hton);
}
else
@@ -4180,6 +4387,11 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
thd_ndb->init_open_tables();
thd_ndb->all= trans;
thd_ndb->query_state&= NDB_QUERY_NORMAL;
+ thd_ndb->trans_options= 0;
+ thd_ndb->m_slow_path= FALSE;
+ if (thd->slave_thread ||
+ !(thd->options & OPTION_BIN_LOG))
+ thd_ndb->m_slow_path= TRUE;
trans_register_ha(thd, TRUE, ndbcluster_hton);
/*
@@ -4220,7 +4432,14 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
// Start of transaction
m_rows_changed= 0;
m_ops_pending= 0;
-
+ m_slow_path= thd_ndb->m_slow_path;
+#ifdef HAVE_NDB_BINLOG
+ if (unlikely(m_slow_path))
+ {
+ if (m_share == ndb_apply_status_share && thd->slave_thread)
+ thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS;
+ }
+#endif
// TODO remove double pointers...
m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table);
m_table_info= &m_thd_ndb_share->stat;
@@ -4306,7 +4525,7 @@ void ha_ndbcluster::unlock_row()
DBUG_ENTER("unlock_row");
DBUG_PRINT("info", ("Unlocking row"));
- m_lock_tuple= false;
+ m_lock_tuple= FALSE;
DBUG_VOID_RETURN;
}
@@ -4334,11 +4553,10 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
ERR_RETURN(ndb->getNdbError());
no_uncommitted_rows_reset(thd);
thd_ndb->stmt= trans;
+ thd_ndb->query_state&= NDB_QUERY_NORMAL;
trans_register_ha(thd, FALSE, ndbcluster_hton);
}
- thd_ndb->query_state&= NDB_QUERY_NORMAL;
m_active_trans= trans;
-
// Start of statement
m_ops_pending= 0;
thd->set_current_stmt_binlog_row_based_if_mixed();
@@ -4362,7 +4580,18 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
DBUG_PRINT("transaction",("%s",
trans == thd_ndb->stmt ?
"stmt" : "all"));
- DBUG_ASSERT(ndb && trans);
+ DBUG_ASSERT(ndb);
+ if (trans == NULL)
+ DBUG_RETURN(0);
+
+#ifdef HAVE_NDB_BINLOG
+ if (unlikely(thd_ndb->m_slow_path))
+ {
+ if (thd->slave_thread)
+ ndbcluster_update_apply_status
+ (thd, thd_ndb->trans_options & TNTO_INJECTED_APPLY_STATUS);
+ }
+#endif /* HAVE_NDB_BINLOG */
if (execute_commit(thd,trans) != 0)
{
@@ -4452,7 +4681,10 @@ static int create_ndb_column(NDBCOL &col,
HA_CREATE_INFO *info)
{
// Set name
- col.setName(field->field_name);
+ if (col.setName(field->field_name))
+ {
+ return (my_errno= errno);
+ }
// Get char set
CHARSET_INFO *cs= field->charset();
// Set type and sizes
@@ -4636,19 +4868,29 @@ static int create_ndb_column(NDBCOL &col,
col.setType(NDBCOL::Text);
col.setCharset(cs);
}
- // Use "<=" even if "<" is the exact condition
- if (field->max_length() <= (1 << 8))
- goto mysql_type_tiny_blob;
- else if (field->max_length() <= (1 << 16))
{
- col.setInlineSize(256);
- col.setPartSize(2000);
- col.setStripeSize(16);
+ Field_blob *field_blob= (Field_blob *)field;
+ /*
+ * max_data_length is 2^8-1, 2^16-1, 2^24-1 for tiny, blob, medium.
+ * Tinyblob gets no blob parts. The other cases are just a crude
+ * way to control part size and striping.
+ *
+ * In mysql blob(256) is promoted to blob(65535) so it does not
+ * in fact fit "inline" in NDB.
+ */
+ if (field_blob->max_data_length() < (1 << 8))
+ goto mysql_type_tiny_blob;
+ else if (field_blob->max_data_length() < (1 << 16))
+ {
+ col.setInlineSize(256);
+ col.setPartSize(2000);
+ col.setStripeSize(16);
+ }
+ else if (field_blob->max_data_length() < (1 << 24))
+ goto mysql_type_medium_blob;
+ else
+ goto mysql_type_long_blob;
}
- else if (field->max_length() <= (1 << 24))
- goto mysql_type_medium_blob;
- else
- goto mysql_type_long_blob;
break;
mysql_type_medium_blob:
case MYSQL_TYPE_MEDIUM_BLOB:
@@ -4705,7 +4947,9 @@ static int create_ndb_column(NDBCOL &col,
// Set autoincrement
if (field->flags & AUTO_INCREMENT_FLAG)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
col.setAutoIncrement(TRUE);
ulonglong value= info->auto_increment_value ?
info->auto_increment_value : (ulonglong) 1;
@@ -4723,15 +4967,18 @@ static int create_ndb_column(NDBCOL &col,
int ha_ndbcluster::create(const char *name,
TABLE *form,
- HA_CREATE_INFO *info)
+ HA_CREATE_INFO *create_info)
{
THD *thd= current_thd;
NDBTAB tab;
NDBCOL col;
- uint pack_length, length, i, pk_length= 0;
- const void *data, *pack_data;
- bool create_from_engine= (info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
+ size_t pack_length, length;
+ uint i, pk_length= 0;
+ uchar *data= NULL, *pack_data= NULL;
+ bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE);
+ char tablespace[FN_LEN];
+ NdbDictionary::Table::SingleUserMode single_user_mode= NdbDictionary::Table::SingleUserModeLocked;
DBUG_ENTER("ha_ndbcluster::create");
DBUG_PRINT("enter", ("name: %s", name));
@@ -4740,8 +4987,22 @@ int ha_ndbcluster::create(const char *name,
set_dbname(name);
set_tabname(name);
+ if ((my_errno= check_ndb_connection()))
+ DBUG_RETURN(my_errno);
+
+ Ndb *ndb= get_ndb();
+ NDBDICT *dict= ndb->getDictionary();
+
if (is_truncate)
{
+ {
+ Ndb_table_guard ndbtab_g(dict, m_tabname);
+ if (!(m_table= ndbtab_g.get_table()))
+ ERR_RETURN(dict->getNdbError());
+ if ((get_tablespace_name(thd, tablespace, FN_LEN)))
+ create_info->tablespace= tablespace;
+ m_table= NULL;
+ }
DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE"));
if ((my_errno= delete_table(name)))
DBUG_RETURN(my_errno);
@@ -4769,19 +5030,26 @@ int ha_ndbcluster::create(const char *name,
schema distribution table is setup
( unless it is a creation of the schema dist table itself )
*/
- if (!ndb_schema_share &&
- !(strcmp(m_dbname, NDB_REP_DB) == 0 &&
- strcmp(m_tabname, NDB_SCHEMA_TABLE) == 0))
+ if (!ndb_schema_share)
{
- DBUG_PRINT("info", ("Schema distribution table not setup"));
- DBUG_RETURN(HA_ERR_NO_CONNECTION);
+ if (!(strcmp(m_dbname, NDB_REP_DB) == 0 &&
+ strcmp(m_tabname, NDB_SCHEMA_TABLE) == 0))
+ {
+ DBUG_PRINT("info", ("Schema distribution table not setup"));
+ DBUG_RETURN(HA_ERR_NO_CONNECTION);
+ }
+ single_user_mode = NdbDictionary::Table::SingleUserModeReadWrite;
}
#endif /* HAVE_NDB_BINLOG */
DBUG_PRINT("table", ("name: %s", m_tabname));
- tab.setName(m_tabname);
- tab.setLogging(!(info->options & HA_LEX_CREATE_TMP_TABLE));
-
+ if (tab.setName(m_tabname))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
+ tab.setLogging(!(create_info->options & HA_LEX_CREATE_TMP_TABLE));
+ tab.setSingleUserMode(single_user_mode);
+
// Save frm data for this table
if (readfrm(name, &data, &length))
DBUG_RETURN(1);
@@ -4790,26 +5058,103 @@ int ha_ndbcluster::create(const char *name,
my_free((char*)data, MYF(0));
DBUG_RETURN(2);
}
- DBUG_PRINT("info", ("setFrm data: 0x%lx len: %d", (long) pack_data, pack_length));
+ DBUG_PRINT("info",
+ ("setFrm data: 0x%lx len: %lu", (long) pack_data,
+ (ulong) pack_length));
tab.setFrm(pack_data, pack_length);
my_free((char*)data, MYF(0));
my_free((char*)pack_data, MYF(0));
+ /*
+ Check for disk options
+ */
+ if (create_info->storage_media == HA_SM_DISK)
+ {
+ if (create_info->tablespace)
+ tab.setTablespaceName(create_info->tablespace);
+ else
+ tab.setTablespaceName("DEFAULT-TS");
+ }
+ else if (create_info->tablespace)
+ {
+ if (create_info->storage_media == HA_SM_MEMORY)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ ER(ER_ILLEGAL_HA_CREATE_OPTION),
+ ndbcluster_hton_name,
+ "TABLESPACE currently only supported for "
+ "STORAGE DISK");
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ }
+ tab.setTablespaceName(create_info->tablespace);
+ create_info->storage_media = HA_SM_DISK; //if use tablespace, that also means store on disk
+ }
+
+ /*
+ Handle table row type
+
+ Default is to let table rows have var part reference so that online
+ add column can be performed in the future. Explicitly setting row
+ type to fixed will omit var part reference, which will save data
+ memory in ndb, but at the cost of not being able to online add
+ column to this table
+ */
+ switch (create_info->row_type) {
+ case ROW_TYPE_FIXED:
+ tab.setForceVarPart(FALSE);
+ break;
+ case ROW_TYPE_DYNAMIC:
+ /* fall through, treat as default */
+ default:
+ /* fall through, treat as default */
+ case ROW_TYPE_DEFAULT:
+ tab.setForceVarPart(TRUE);
+ break;
+ }
+
+ /*
+ Setup columns
+ */
for (i= 0; i < form->s->fields; i++)
{
Field *field= form->field[i];
- DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
+ DBUG_PRINT("info", ("name: %s type: %u pack_length: %d",
field->field_name, field->real_type(),
field->pack_length()));
- if ((my_errno= create_ndb_column(col, field, info)))
+ if ((my_errno= create_ndb_column(col, field, create_info)))
DBUG_RETURN(my_errno);
- if (info->store_on_disk || getenv("NDB_DEFAULT_DISK"))
+ if (create_info->storage_media == HA_SM_DISK)
col.setStorageType(NdbDictionary::Column::StorageTypeDisk);
else
col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
- tab.addColumn(col);
+ switch (create_info->row_type) {
+ case ROW_TYPE_FIXED:
+ if (field_type_forces_var_part(field->type()))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ ER(ER_ILLEGAL_HA_CREATE_OPTION),
+ ndbcluster_hton_name,
+ "Row format FIXED incompatible with "
+ "variable sized attribute");
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ }
+ break;
+ case ROW_TYPE_DYNAMIC:
+ /*
+ Future: make columns dynamic in this case
+ */
+ break;
+ default:
+ break;
+ }
+ if (tab.addColumn(col))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
if (col.getPrimaryKey())
pk_length += (field->pack_length() + 3) / 4;
}
@@ -4824,30 +5169,23 @@ int ha_ndbcluster::create(const char *name,
NdbDictionary::Column::StorageTypeMemory);
}
- if (info->store_on_disk)
- {
- if (info->tablespace)
- tab.setTablespace(info->tablespace);
- else
- tab.setTablespace("DEFAULT-TS");
- }
- else if (info->tablespace)
- {
- tab.setTablespace(info->tablespace);
- info->store_on_disk = true; //if use tablespace, that also means store on disk
- }
-
// No primary key, create shadow key as 64 bit, auto increment
if (form->s->primary_key == MAX_KEY)
{
DBUG_PRINT("info", ("Generating shadow key"));
- col.setName("$PK");
+ if (col.setName("$PK"))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
col.setType(NdbDictionary::Column::Bigunsigned);
col.setLength(1);
col.setNullable(FALSE);
col.setPrimaryKey(TRUE);
col.setAutoIncrement(TRUE);
- tab.addColumn(col);
+ if (tab.addColumn(col))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
pk_length += 2;
}
@@ -4865,13 +5203,13 @@ int ha_ndbcluster::create(const char *name,
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
{
- NdbDictionary::Column * col= tab.getColumn(i);
- int size= pk_length + (col->getPartSize()+3)/4 + 7;
+ NdbDictionary::Column * column= tab.getColumn(i);
+ int size= pk_length + (column->getPartSize()+3)/4 + 7;
if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
(pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS)
{
size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7;
- col->setPartSize(4*size);
+ column->setPartSize(4*size);
}
/**
* If size > NDB_MAX and pk_length+7 >= NDB_MAX
@@ -4891,12 +5229,7 @@ int ha_ndbcluster::create(const char *name,
DBUG_RETURN(my_errno);
}
- if ((my_errno= check_ndb_connection()))
- DBUG_RETURN(my_errno);
-
// Create the table in NDB
- Ndb *ndb= get_ndb();
- NDBDICT *dict= ndb->getDictionary();
if (dict->createTable(tab) != 0)
{
const NdbError err= dict->getNdbError();
@@ -4962,18 +5295,24 @@ int ha_ndbcluster::create(const char *name,
{
uint length= (uint) strlen(name);
if ((share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (byte*) name, length)))
+ (uchar*) name, length)))
handle_trailing_share(share);
}
/*
get a new share
*/
- if (!(share= get_share(name, form, true, true)))
+ /* ndb_share reference create */
+ if (!(share= get_share(name, form, TRUE, TRUE)))
{
sql_print_error("NDB: allocating table share for %s failed", name);
/* my_errno is set */
}
+ else
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u",
+ share->key, share->use_count));
+ }
pthread_mutex_unlock(&ndbcluster_mutex);
while (!IS_TMP_PREFIX(m_tabname))
@@ -4997,7 +5336,7 @@ int ha_ndbcluster::create(const char *name,
if (ndb_extra_logging)
sql_print_information("NDB Binlog: CREATE TABLE Event: %s",
event_name.c_ptr());
- if (share && do_event_op &&
+ if (share &&
ndbcluster_create_event_ops(share, m_table, event_name.c_ptr()))
{
sql_print_error("NDB Binlog: FAILED CREATE TABLE event operations."
@@ -5031,14 +5370,12 @@ int ha_ndbcluster::create(const char *name,
int ha_ndbcluster::create_handler_files(const char *file,
const char *old_name,
int action_flag,
- HA_CREATE_INFO *info)
+ HA_CREATE_INFO *create_info)
{
- char path[FN_REFLEN];
- const char *name;
Ndb* ndb;
const NDBTAB *tab;
- const void *data, *pack_data;
- uint length, pack_length;
+ uchar *data= NULL, *pack_data= NULL;
+ size_t length, pack_length;
int error= 0;
DBUG_ENTER("create_handler_files");
@@ -5052,7 +5389,7 @@ int ha_ndbcluster::create_handler_files(const char *file,
DBUG_RETURN(HA_ERR_NO_CONNECTION);
NDBDICT *dict= ndb->getDictionary();
- if (!info->frm_only)
+ if (!create_info->frm_only)
DBUG_RETURN(0); // Must be a create, ignore since frm is saved in create
// TODO handle this
@@ -5089,6 +5426,9 @@ int ha_ndbcluster::create_handler_files(const char *file,
}
set_ndb_share_state(m_share, NSS_INITIAL);
+ /* ndb_share reference schema(?) free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema(?) free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
DBUG_RETURN(error);
@@ -5131,6 +5471,17 @@ int ha_ndbcluster::create_index(const char *name, KEY *key_info,
error= create_unique_index(unique_name, key_info);
break;
case ORDERED_INDEX:
+ if (key_info->algorithm == HA_KEY_ALG_HASH)
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ ER(ER_ILLEGAL_HA_CREATE_OPTION),
+ ndbcluster_hton_name,
+ "Ndb does not support non-unique "
+ "hash based indexes");
+ error= HA_ERR_UNSUPPORTED;
+ break;
+ }
error= create_ordered_index(name, key_info);
break;
default:
@@ -5182,13 +5533,19 @@ int ha_ndbcluster::create_ndb_index(const char *name,
// TODO Only temporary ordered indexes supported
ndb_index.setLogging(FALSE);
}
- ndb_index.setTable(m_tabname);
+ if (ndb_index.setTable(m_tabname))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
for (; key_part != end; key_part++)
{
Field *field= key_part->field;
DBUG_PRINT("info", ("attr: %s", field->field_name));
- ndb_index.addColumnName(field->field_name);
+ if (ndb_index.addColumnName(field->field_name))
+ {
+ DBUG_RETURN(my_errno= errno);
+ }
}
if (dict->createIndex(ndb_index, *m_table))
@@ -5204,7 +5561,10 @@ int ha_ndbcluster::create_ndb_index(const char *name,
*/
void ha_ndbcluster::prepare_for_alter()
{
+ /* ndb_share reference schema */
ndbcluster_get_share(m_share); // Increase ref_count
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema use_count: %u",
+ m_share->key, m_share->use_count));
set_ndb_share_state(m_share, NSS_ALTERED);
}
@@ -5225,7 +5585,7 @@ int ha_ndbcluster::add_index(TABLE *table_arg,
KEY *key= key_info + idx;
KEY_PART_INFO *key_part= key->key_part;
KEY_PART_INFO *end= key_part + key->key_parts;
- NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key, false);
+ NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key_info, false);
DBUG_PRINT("info", ("Adding index: '%s'", key_info[idx].name));
// Add fields to key_part struct
for (; key_part != end; key_part++)
@@ -5238,6 +5598,9 @@ int ha_ndbcluster::add_index(TABLE *table_arg,
if (error)
{
set_ndb_share_state(m_share, NSS_INITIAL);
+ /* ndb_share reference schema free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
}
DBUG_RETURN(error);
@@ -5282,6 +5645,9 @@ int ha_ndbcluster::final_drop_index(TABLE *table_arg)
if((error= drop_indexes(ndb, table_arg)))
{
m_share->state= NSS_INITIAL;
+ /* ndb_share reference schema free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share); // Decrease ref_count
}
DBUG_RETURN(error);
@@ -5323,10 +5689,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
int ndb_table_id= orig_tab->getObjectId();
int ndb_table_version= orig_tab->getObjectVersion();
- NDB_SHARE *share= get_share(from, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(from, 0, FALSE);
if (share)
{
- int r= rename_share(share, to);
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ IF_DBUG(int r=) rename_share(share, to);
DBUG_ASSERT(r == 0);
}
#endif
@@ -5337,7 +5706,10 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
}
// Change current database to that of target table
set_dbname(to);
- ndb->setDatabaseName(m_dbname);
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ ERR_RETURN(ndb->getNdbError());
+ }
NdbDictionary::Table new_tab= *orig_tab;
new_tab.setName(new_tabname);
@@ -5347,8 +5719,11 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
#ifdef HAVE_NDB_BINLOG
if (share)
{
- int r= rename_share(share, from);
- DBUG_ASSERT(r == 0);
+ IF_DBUG(int ret=) rename_share(share, from);
+ DBUG_ASSERT(ret == 0);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
#endif
@@ -5361,7 +5736,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
// ToDo in 4.1 should rollback alter table...
#ifdef HAVE_NDB_BINLOG
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
#endif
DBUG_RETURN(result);
}
@@ -5395,7 +5775,7 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
if (ndb_extra_logging)
sql_print_information("NDB Binlog: RENAME Event: %s",
event_name.c_ptr());
- if (share && ndb_binlog_running &&
+ if (share &&
ndbcluster_create_event_ops(share, ndbtab, event_name.c_ptr()))
{
sql_print_error("NDB Binlog: FAILED create event operations "
@@ -5442,7 +5822,12 @@ int ha_ndbcluster::rename_table(const char *from, const char *to)
}
}
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
#endif
DBUG_RETURN(result);
@@ -5477,7 +5862,13 @@ ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
DBUG_PRINT("info", ("Schema distribution table not setup"));
DBUG_RETURN(HA_ERR_NO_CONNECTION);
}
- NDB_SHARE *share= get_share(path, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(path, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
#endif
/* Drop the table from NDB */
@@ -5490,6 +5881,7 @@ retry_temporary_error1:
{
ndb_table_id= h->m_table->getObjectId();
ndb_table_version= h->m_table->getObjectVersion();
+ DBUG_PRINT("info", ("success 1"));
}
else
{
@@ -5503,6 +5895,7 @@ retry_temporary_error1:
break;
}
res= ndb_to_mysql_error(&dict->getNdbError());
+ DBUG_PRINT("info", ("error(1) %u", res));
}
h->release_metadata(thd, ndb);
}
@@ -5519,6 +5912,8 @@ retry_temporary_error1:
{
ndb_table_id= ndbtab_g.get_table()->getObjectId();
ndb_table_version= ndbtab_g.get_table()->getObjectVersion();
+ DBUG_PRINT("info", ("success 2"));
+ break;
}
else
{
@@ -5538,8 +5933,8 @@ retry_temporary_error1:
}
}
}
- else
- res= ndb_to_mysql_error(&dict->getNdbError());
+ res= ndb_to_mysql_error(&dict->getNdbError());
+ DBUG_PRINT("info", ("error(2) %u", res));
break;
}
}
@@ -5557,9 +5952,14 @@ retry_temporary_error1:
The share kept by the server has not been freed, free it
*/
share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
}
- /* free the share taken above */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -5609,9 +6009,14 @@ retry_temporary_error1:
The share kept by the server has not been freed, free it
*/
share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
}
- /* free the share taken above */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -5669,24 +6074,28 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
m_rows_to_insert - m_rows_inserted :
((m_rows_to_insert > m_autoincrement_prefetch) ?
m_rows_to_insert : m_autoincrement_prefetch));
- int ret;
uint retries= NDB_AUTO_INCREMENT_RETRIES;
- do {
+ int retry_sleep= 30; /* 30 milliseconds, transaction */
+ for (;;)
+ {
Ndb_tuple_id_range_guard g(m_share);
- ret=
- m_skip_auto_increment ?
- ndb->readAutoIncrementValue(m_table, g.range, auto_value) :
- ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size);
- } while (ret == -1 &&
- --retries &&
- ndb->getNdbError().status == NdbError::TemporaryError);
- if (ret == -1)
- {
- const NdbError err= ndb->getNdbError();
- sql_print_error("Error %lu in ::get_auto_increment(): %s",
- (ulong) err.code, err.message);
- *first_value= ~(ulonglong) 0;
- DBUG_VOID_RETURN;
+ if (m_skip_auto_increment &&
+ ndb->readAutoIncrementValue(m_table, g.range, auto_value) ||
+ ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size))
+ {
+ if (--retries &&
+ ndb->getNdbError().status == NdbError::TemporaryError);
+ {
+ my_sleep(retry_sleep);
+ continue;
+ }
+ const NdbError err= ndb->getNdbError();
+ sql_print_error("Error %lu in ::get_auto_increment(): %s",
+ (ulong) err.code, err.message);
+ *first_value= ~(ulonglong) 0;
+ DBUG_VOID_RETURN;
+ }
+ break;
}
*first_value= (longlong)auto_value;
/* From the point of view of MySQL, NDB reserves one row at a time */
@@ -5734,6 +6143,8 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
m_bulk_insert_rows((ha_rows) 1024),
m_rows_changed((ha_rows) 0),
m_bulk_insert_not_flushed(FALSE),
+ m_delete_cannot_batch(FALSE),
+ m_update_cannot_batch(FALSE),
m_ops_pending(0),
m_skip_auto_increment(TRUE),
m_blobs_pending(0),
@@ -5745,7 +6156,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
m_force_send(TRUE),
m_autoincrement_prefetch((ha_rows) 32),
m_transaction_on(TRUE),
- m_cond_stack(NULL),
+ m_cond(NULL),
m_multi_cursor(NULL)
{
int i;
@@ -5787,6 +6198,9 @@ ha_ndbcluster::~ha_ndbcluster()
if (m_share)
{
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
}
release_metadata(thd, ndb);
@@ -5801,9 +6215,13 @@ ha_ndbcluster::~ha_ndbcluster()
}
DBUG_ASSERT(m_active_trans == NULL);
- // Discard the condition stack
- DBUG_PRINT("info", ("Clearing condition stack"));
- cond_clear();
+ // Discard any generated condition
+ DBUG_PRINT("info", ("Deleting generated condition"));
+ if (m_cond)
+ {
+ delete m_cond;
+ m_cond= NULL;
+ }
DBUG_VOID_RETURN;
}
@@ -5849,39 +6267,55 @@ int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
DBUG_PRINT("info", ("ref_length: %d", ref_length));
// Init table lock structure
+ /* ndb_share reference handler */
if (!(m_share=get_share(name, table)))
DBUG_RETURN(1);
+ DBUG_PRINT("NDB_SHARE", ("%s handler use_count: %u",
+ m_share->key, m_share->use_count));
thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0);
set_dbname(name);
set_tabname(name);
- if (check_ndb_connection()) {
+ if ((res= check_ndb_connection()) ||
+ (res= get_metadata(name)))
+ {
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
m_share= 0;
- DBUG_RETURN(HA_ERR_NO_CONNECTION);
+ DBUG_RETURN(res);
}
-
- res= get_metadata(name);
- if (!res)
+ while (1)
{
Ndb *ndb= get_ndb();
- ndb->setDatabaseName(m_dbname);
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ res= ndb_to_mysql_error(&ndb->getNdbError());
+ break;
+ }
struct Ndb_statistics stat;
- res= ndb_get_table_statistics(NULL, false, ndb, m_table, &stat);
+ res= ndb_get_table_statistics(NULL, FALSE, ndb, m_table, &stat);
stats.mean_rec_length= stat.row_size;
stats.data_file_length= stat.fragment_memory;
stats.records= stat.row_count;
if(!res)
res= info(HA_STATUS_CONST);
+ break;
+ }
+ if (res)
+ {
+ free_share(&m_share);
+ m_share= 0;
+ release_metadata(current_thd, get_ndb());
+ DBUG_RETURN(res);
}
-
#ifdef HAVE_NDB_BINLOG
if (!ndb_binlog_tables_inited && ndb_binlog_running)
table->db_stat|= HA_READ_ONLY;
#endif
-
- DBUG_RETURN(res);
+ DBUG_RETURN(0);
}
/*
@@ -5915,8 +6349,11 @@ void ha_ndbcluster::set_part_info(partition_info *part_info)
int ha_ndbcluster::close(void)
{
DBUG_ENTER("close");
- THD *thd= current_thd;
+ THD *thd= table->in_use;
Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
+ /* ndb_share reference handler free */
+ DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
+ m_share->key, m_share->use_count));
free_share(&m_share);
m_share= 0;
release_metadata(thd, ndb);
@@ -5930,6 +6367,11 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb()
DBUG_ENTER("seize_thd_ndb");
thd_ndb= new Thd_ndb();
+ if (thd_ndb == NULL)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ return NULL;
+ }
if (thd_ndb->ndb->init(max_transactions) != 0)
{
ERR_PRINT(thd_ndb->ndb->getNdbError());
@@ -5982,7 +6424,10 @@ int ha_ndbcluster::check_ndb_connection(THD* thd)
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
- ndb->setDatabaseName(m_dbname);
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ ERR_RETURN(ndb->getNdbError());
+ }
DBUG_RETURN(0);
}
@@ -6006,13 +6451,13 @@ static int ndbcluster_close_connection(handlerton *hton, THD *thd)
int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
const char *name,
- const void** frmblob,
- uint* frmlen)
+ uchar **frmblob,
+ size_t *frmlen)
{
int error= 0;
NdbError ndb_error;
- uint len;
- const void* data;
+ size_t len;
+ uchar* data= NULL;
Ndb* ndb;
char key[FN_REFLEN];
DBUG_ENTER("ndbcluster_discover");
@@ -6020,10 +6465,19 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
- ndb->setDatabaseName(db);
+ if (ndb->setDatabaseName(db))
+ {
+ ERR_RETURN(ndb->getNdbError());
+ }
NDBDICT* dict= ndb->getDictionary();
build_table_filename(key, sizeof(key), db, name, "", 0);
- NDB_SHARE *share= get_share(key, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(key, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
if (share && get_ndb_share_state(share) == NSS_ALTERED)
{
// Frm has been altered on disk, but not yet written to ndb
@@ -6042,9 +6496,16 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
{
const NdbError err= dict->getNdbError();
if (err.code == 709 || err.code == 723)
+ {
error= -1;
+ DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
+ }
else
+ {
+ error= -1;
ndb_error= err;
+ DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
+ }
goto err;
}
DBUG_PRINT("info", ("Found table %s", tab->getName()));
@@ -6057,7 +6518,7 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
goto err;
}
- if (unpackfrm(&data, &len, tab->getFrmData()))
+ if (unpackfrm(&data, &len, (uchar*) tab->getFrmData()))
{
DBUG_PRINT("error", ("Could not unpack table"));
error= 1;
@@ -6069,12 +6530,23 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
*frmblob= data;
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
DBUG_RETURN(0);
err:
+ my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
if (ndb_error.code)
{
ERR_RETURN(ndb_error);
@@ -6097,7 +6569,6 @@ int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd,
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
-
NDBDICT* dict= ndb->getDictionary();
NdbDictionary::Dictionary::List list;
if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
@@ -6110,18 +6581,18 @@ int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd,
if (my_strcasecmp(system_charset_info, elmt.name, name))
continue;
DBUG_PRINT("info", ("Found table"));
- DBUG_RETURN(1);
+ DBUG_RETURN(HA_ERR_TABLE_EXIST);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
-extern "C" byte* tables_get_key(const char *entry, uint *length,
+extern "C" uchar* tables_get_key(const char *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length= strlen(entry);
- return (byte*) entry;
+ return (uchar*) entry;
}
@@ -6167,8 +6638,10 @@ int ndbcluster_drop_database_impl(const char *path)
char full_path[FN_REFLEN];
char *tmp= full_path +
build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0);
-
- ndb->setDatabaseName(dbname);
+ if (ndb->setDatabaseName(dbname))
+ {
+ ERR_RETURN(ndb->getNdbError());
+ }
List_iterator_fast<char> it(drop_list);
while ((tabname=it++))
{
@@ -6190,7 +6663,6 @@ int ndbcluster_drop_database_impl(const char *path)
static void ndbcluster_drop_database(handlerton *hton, char *path)
{
- THD *thd= current_thd;
DBUG_ENTER("ndbcluster_drop_database");
#ifdef HAVE_NDB_BINLOG
/*
@@ -6207,6 +6679,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path)
ndbcluster_drop_database_impl(path);
#ifdef HAVE_NDB_BINLOG
char db[FN_REFLEN];
+ THD *thd= current_thd;
ha_ndbcluster::set_dbname(path, db);
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
@@ -6221,7 +6694,7 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
LEX *old_lex= thd->lex, newlex;
thd->lex= &newlex;
newlex.current_select= NULL;
- lex_start(thd, (const uchar*) "", 0);
+ lex_start(thd);
int res= ha_create_table_from_engine(thd, db, table_name);
thd->lex= old_lex;
return res;
@@ -6232,16 +6705,17 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
*/
int ndbcluster_find_all_files(THD *thd)
{
- DBUG_ENTER("ndbcluster_find_all_files");
Ndb* ndb;
char key[FN_REFLEN];
+ NDBDICT *dict;
+ int unhandled, retries= 5, skipped;
+ DBUG_ENTER("ndbcluster_find_all_files");
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(HA_ERR_NO_CONNECTION);
- NDBDICT *dict= ndb->getDictionary();
+ dict= ndb->getDictionary();
- int unhandled, retries= 5, skipped;
LINT_INIT(unhandled);
LINT_INIT(skipped);
do
@@ -6299,8 +6773,8 @@ int ndbcluster_find_all_files(THD *thd)
/* finalize construction of path */
end+= tablename_to_filename(elmt.name, end,
sizeof(key)-(end-key));
- const void *data= 0, *pack_data= 0;
- uint length, pack_length;
+ uchar *data= 0, *pack_data= 0;
+ size_t length, pack_length;
int discover= 0;
if (readfrm(key, &data, &length) ||
packfrm(data, length, &pack_data, &pack_length))
@@ -6311,7 +6785,13 @@ int ndbcluster_find_all_files(THD *thd)
}
else if (cmp_frm(ndbtab, pack_data, pack_length))
{
- NDB_SHARE *share= get_share(key, 0, false);
+ /* ndb_share reference temporary */
+ NDB_SHARE *share= get_share(key, 0, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
if (!share || get_ndb_share_state(share) != NSS_ALTERED)
{
discover= 1;
@@ -6319,7 +6799,12 @@ int ndbcluster_find_all_files(THD *thd)
elmt.database, elmt.name);
}
if (share)
+ {
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
}
my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR));
@@ -6417,7 +6902,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
continue;
}
DBUG_PRINT("info", ("Inserting %s into ndb_tables hash", elmt.name));
- my_hash_insert(&ndb_tables, (byte*)thd->strdup(elmt.name));
+ my_hash_insert(&ndb_tables, (uchar*)thd->strdup(elmt.name));
}
char *file_name;
@@ -6425,12 +6910,12 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
List<char> delete_list;
while ((file_name=it++))
{
- bool file_on_disk= false;
+ bool file_on_disk= FALSE;
DBUG_PRINT("info", ("%s", file_name));
- if (hash_search(&ndb_tables, file_name, strlen(file_name)))
+ if (hash_search(&ndb_tables, (uchar*) file_name, strlen(file_name)))
{
DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name));
- file_on_disk= true;
+ file_on_disk= TRUE;
}
// Check for .ndb file with this name
@@ -6443,7 +6928,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
if (file_on_disk)
{
// Ignore this ndb table
- gptr record= hash_search(&ndb_tables, file_name, strlen(file_name));
+ uchar *record= hash_search(&ndb_tables, (uchar*) file_name,
+ strlen(file_name));
DBUG_ASSERT(record);
hash_delete(&ndb_tables, record);
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -6456,13 +6942,13 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
if (file_on_disk)
{
// File existed in NDB and as frm file, put in ok_tables list
- my_hash_insert(&ok_tables, (byte*)file_name);
+ my_hash_insert(&ok_tables, (uchar*)file_name);
continue;
}
DBUG_PRINT("info", ("%s existed on disk", name));
// The .ndb file exists on disk, but it's not in list of tables in ndb
// Verify that handler agrees table is gone.
- if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name) == 0)
+ if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name) == HA_ERR_NO_SUCH_TABLE)
{
DBUG_PRINT("info", ("NDB says %s does not exists", file_name));
it.remove();
@@ -6494,8 +6980,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
List<char> create_list;
for (i= 0 ; i < ndb_tables.records ; i++)
{
- file_name= hash_element(&ndb_tables, i);
- if (!hash_search(&ok_tables, file_name, strlen(file_name)))
+ file_name= (char*) hash_element(&ndb_tables, i);
+ if (!hash_search(&ok_tables, (uchar*) file_name, strlen(file_name)))
{
build_table_filename(name, sizeof(name), db, file_name, reg_ext, 0);
if (my_access(name, F_OK))
@@ -6576,6 +7062,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
/* Call back after cluster connect */
static int connect_callback()
{
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
update_status_variables(g_ndb_cluster_connection);
uint node_id, i= 0;
@@ -6585,22 +7072,40 @@ static int connect_callback()
g_node_id_map[node_id]= i++;
pthread_cond_signal(&COND_ndb_util_thread);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
return 0;
}
extern int ndb_dictionary_is_mysqld;
+extern pthread_mutex_t LOCK_plugin;
static int ndbcluster_init(void *p)
{
int res;
DBUG_ENTER("ndbcluster_init");
+ if (ndbcluster_inited)
+ DBUG_RETURN(FALSE);
+
+ /*
+ Below we create new THD's. They'll need LOCK_plugin, but it's taken now by
+ plugin initialization code. Release it to avoid deadlocks. It's safe, as
+ there're no threads that may concurrently access plugin control structures.
+ */
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_ndb_util_thread, NULL);
+ pthread_cond_init(&COND_ndb_util_ready, NULL);
+ ndb_util_thread_running= -1;
+ ndbcluster_terminating= 0;
ndb_dictionary_is_mysqld= 1;
ndbcluster_hton= (handlerton *)p;
{
handlerton *h= ndbcluster_hton;
- h->state= have_ndbcluster;
+ h->state= SHOW_OPTION_YES;
h->db_type= DB_TYPE_NDBCLUSTER;
h->close_connection= ndbcluster_close_connection;
h->commit= ndbcluster_commit;
@@ -6622,9 +7127,6 @@ static int ndbcluster_init(void *p)
h->table_exists_in_engine= ndbcluster_table_exists_in_engine;
}
- if (have_ndbcluster != SHOW_OPTION_YES)
- DBUG_RETURN(0); // nothing else to do
-
// Initialize ndb interface
ndb_init_internal();
@@ -6636,6 +7138,7 @@ static int ndbcluster_init(void *p)
{
DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
opt_ndbcluster_connectstring));
+ my_errno= HA_ERR_OUT_OF_MEM;
goto ndbcluster_init_error;
}
{
@@ -6650,6 +7153,7 @@ static int ndbcluster_init(void *p)
if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
{
DBUG_PRINT("error", ("failed to create global ndb object"));
+ my_errno= HA_ERR_OUT_OF_MEM;
goto ndbcluster_init_error;
}
if (g_ndb->init() != 0)
@@ -6693,17 +7197,12 @@ static int ndbcluster_init(void *p)
(void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
(hash_get_key) ndbcluster_get_key,0,0);
- pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
#ifdef HAVE_NDB_BINLOG
/* start the ndb injector thread */
if (ndbcluster_binlog_start())
goto ndbcluster_init_error;
#endif /* HAVE_NDB_BINLOG */
- pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
- pthread_cond_init(&COND_ndb_util_thread, NULL);
-
-
ndb_cache_check_time = opt_ndb_cache_check_time;
// Create utility thread
pthread_t tmp;
@@ -6714,9 +7213,29 @@ static int ndbcluster_init(void *p)
pthread_mutex_destroy(&ndbcluster_mutex);
pthread_mutex_destroy(&LOCK_ndb_util_thread);
pthread_cond_destroy(&COND_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_ready);
+ goto ndbcluster_init_error;
+ }
+
+ /* Wait for the util thread to start */
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ while (ndb_util_thread_running < 0)
+ pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
+ if (!ndb_util_thread_running)
+ {
+ DBUG_PRINT("error", ("ndb utility thread exited prematurely"));
+ hash_free(&ndbcluster_open_tables);
+ pthread_mutex_destroy(&ndbcluster_mutex);
+ pthread_mutex_destroy(&LOCK_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_ready);
goto ndbcluster_init_error;
}
+ pthread_mutex_lock(&LOCK_plugin);
+
ndbcluster_inited= 1;
DBUG_RETURN(FALSE);
@@ -6727,9 +7246,10 @@ ndbcluster_init_error:
if (g_ndb_cluster_connection)
delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL;
- have_ndbcluster= SHOW_OPTION_DISABLED; // If we couldn't use handler
ndbcluster_hton->state= SHOW_OPTION_DISABLED; // If we couldn't use handler
+ pthread_mutex_lock(&LOCK_plugin);
+
DBUG_RETURN(TRUE);
}
@@ -6739,6 +7259,17 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
if (!ndbcluster_inited)
DBUG_RETURN(0);
+ ndbcluster_inited= 0;
+
+ /* wait for util thread to finish */
+ sql_print_information("Stopping Cluster Utility thread");
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ ndbcluster_terminating= 1;
+ pthread_cond_signal(&COND_ndb_util_thread);
+ while (ndb_util_thread_running > 0)
+ pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
#ifdef HAVE_NDB_BINLOG
{
@@ -6751,7 +7282,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
fprintf(stderr, "NDB: table share %s with use_count %d not freed\n",
share->key, share->use_count);
#endif
- real_free_share(&share);
+ ndbcluster_real_free_share(&share);
}
pthread_mutex_unlock(&ndbcluster_mutex);
}
@@ -6785,7 +7316,7 @@ static int ndbcluster_end(handlerton *hton, ha_panic_function type)
pthread_mutex_destroy(&ndbcluster_mutex);
pthread_mutex_destroy(&LOCK_ndb_util_thread);
pthread_cond_destroy(&COND_ndb_util_thread);
- ndbcluster_inited= 0;
+ pthread_cond_destroy(&COND_ndb_util_ready);
DBUG_RETURN(0);
}
@@ -6948,19 +7479,19 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
{
// We must provide approx table rows
Uint64 table_rows=0;
- Ndb_local_table_statistics *info= m_table_info;
- if (info->records != ~(ha_rows)0 && info->records != 0)
+ Ndb_local_table_statistics *ndb_info= m_table_info;
+ if (ndb_info->records != ~(ha_rows)0 && ndb_info->records != 0)
{
- table_rows = info->records;
- DBUG_PRINT("info", ("use info->records: %llu", table_rows));
+ table_rows = ndb_info->records;
+ DBUG_PRINT("info", ("use info->records: %lu", (ulong) table_rows));
}
else
{
Ndb_statistics stat;
- if ((res=ndb_get_table_statistics(this, true, ndb, m_table, &stat)) != 0)
+ if ((res=ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat)))
break;
table_rows=stat.row_count;
- DBUG_PRINT("info", ("use db row_count: %llu", table_rows));
+ DBUG_PRINT("info", ("use db row_count: %lu", (ulong) table_rows));
if (table_rows == 0) {
// Problem if autocommit=0
#ifdef ndb_get_table_statistics_uses_active_trans
@@ -6983,7 +7514,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
if ((op->readTuples(NdbOperation::LM_CommittedRead)) == -1)
ERR_BREAK(op->getNdbError(), res);
const key_range *keys[2]={ min_key, max_key };
- if ((res=set_bounds(op, inx, true, keys)) != 0)
+ if ((res=set_bounds(op, inx, TRUE, keys)) != 0)
break;
// Decide if db should be contacted
@@ -7082,14 +7613,17 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
DBUG_PRINT("enter", ("name: %s", name));
pthread_mutex_lock(&ndbcluster_mutex);
if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (byte*) name,
+ (uchar*) name,
strlen(name))))
{
pthread_mutex_unlock(&ndbcluster_mutex);
DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name));
DBUG_RETURN(1);
}
+ /* ndb_share reference temporary, free below */
share->use_count++;
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
pthread_mutex_unlock(&ndbcluster_mutex);
pthread_mutex_lock(&share->mutex);
@@ -7098,10 +7632,15 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
if (share->commit_count != 0)
{
*commit_count= share->commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Getting commit_count: %s from share",
llstr(share->commit_count, buff)));
pthread_mutex_unlock(&share->mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(0);
}
@@ -7110,7 +7649,10 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
Ndb *ndb;
if (!(ndb= check_ndb_in_thd(thd)))
DBUG_RETURN(1);
- ndb->setDatabaseName(dbname);
+ if (ndb->setDatabaseName(dbname))
+ {
+ ERR_RETURN(ndb->getNdbError());
+ }
uint lock= share->commit_count_lock;
pthread_mutex_unlock(&share->mutex);
@@ -7118,8 +7660,11 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
{
Ndb_table_guard ndbtab_g(ndb->getDictionary(), tabname);
if (ndbtab_g.get_table() == 0
- || ndb_get_table_statistics(NULL, false, ndb, ndbtab_g.get_table(), &stat))
+ || ndb_get_table_statistics(NULL, FALSE, ndb, ndbtab_g.get_table(), &stat))
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(1);
}
@@ -7128,7 +7673,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
pthread_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
{
+#ifndef DBUG_OFF
char buff[22];
+#endif
DBUG_PRINT("info", ("Setting commit_count to %s",
llstr(stat.commit_count, buff)));
share->commit_count= stat.commit_count;
@@ -7140,6 +7687,9 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
*commit_count= 0;
}
pthread_mutex_unlock(&share->mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
DBUG_RETURN(0);
}
@@ -7184,7 +7734,9 @@ ndbcluster_cache_retrieval_allowed(THD *thd,
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
char *dbname= full_name;
char *tabname= dbname+strlen(dbname)+1;
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
dbname, tabname, is_autocommit));
@@ -7251,7 +7803,9 @@ ha_ndbcluster::register_query_cache_table(THD *thd,
ulonglong *engine_data)
{
Uint64 commit_count;
+#ifndef DBUG_OFF
char buff[22];
+#endif
bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
@@ -7284,11 +7838,11 @@ ha_ndbcluster::register_query_cache_table(THD *thd,
data we want to or can share.
*/
-static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
+static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length= share->key_length;
- return (byte*) share->key;
+ return (uchar*) share->key;
}
@@ -7297,9 +7851,9 @@ static byte *ndbcluster_get_key(NDB_SHARE *share,uint *length,
static void print_share(const char* where, NDB_SHARE* share)
{
fprintf(DBUG_FILE,
- "%s %s.%s: use_count: %u, commit_count: %llu\n",
+ "%s %s.%s: use_count: %u, commit_count: %lu\n",
where, share->db, share->table_name, share->use_count,
- share->commit_count);
+ (ulong) share->commit_count);
fprintf(DBUG_FILE,
" - key: %s, key_length: %d\n",
share->key, share->key_length);
@@ -7356,21 +7910,34 @@ int handle_trailing_share(NDB_SHARE *share)
static ulong trailing_share_id= 0;
DBUG_ENTER("handle_trailing_share");
+ /* ndb_share reference temporary, free below */
++share->use_count;
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
pthread_mutex_unlock(&ndbcluster_mutex);
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
table_list.db= share->db;
table_list.alias= table_list.table_name= share->table_name;
+ safe_mutex_assert_owner(&LOCK_open);
close_cached_tables(thd, 0, &table_list, TRUE);
pthread_mutex_lock(&ndbcluster_mutex);
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
if (!--share->use_count)
{
- DBUG_PRINT("info", ("NDB_SHARE: close_cashed_tables %s freed share.",
- share->key));
- real_free_share(&share);
+ if (ndb_extra_logging)
+ sql_print_information("NDB_SHARE: trailing share "
+ "%s(connect_count: %u) "
+ "released by close_cached_tables at "
+ "connect_count: %u",
+ share->key,
+ share->connect_count,
+ g_ndb_cluster_connection->get_connect_count());
+ ndbcluster_real_free_share(&share);
DBUG_RETURN(0);
}
@@ -7378,16 +7945,28 @@ int handle_trailing_share(NDB_SHARE *share)
share still exists, if share has not been dropped by server
release that share
*/
- if (share->state != NSS_DROPPED && !--share->use_count)
+ if (share->state != NSS_DROPPED)
{
- DBUG_PRINT("info", ("NDB_SHARE: %s already exists, "
- "use_count=%d state != NSS_DROPPED.",
- share->key, share->use_count));
- real_free_share(&share);
- DBUG_RETURN(0);
+ share->state= NSS_DROPPED;
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
+ --share->use_count;
+
+ if (share->use_count == 0)
+ {
+ if (ndb_extra_logging)
+ sql_print_information("NDB_SHARE: trailing share "
+ "%s(connect_count: %u) "
+ "released after NSS_DROPPED check "
+ "at connect_count: %u",
+ share->key,
+ share->connect_count,
+ g_ndb_cluster_connection->get_connect_count());
+ ndbcluster_real_free_share(&share);
+ DBUG_RETURN(0);
+ }
}
- DBUG_PRINT("error", ("NDB_SHARE: %s already exists use_count=%d.",
- share->key, share->use_count));
sql_print_error("NDB_SHARE: %s already exists use_count=%d."
" Moving away for safety, but possible memleak.",
@@ -7397,14 +7976,16 @@ int handle_trailing_share(NDB_SHARE *share)
/*
Ndb share has not been released as it should
*/
+#ifdef NOT_YET
DBUG_ASSERT(FALSE);
+#endif
/*
This is probably an error. We can however save the situation
at the cost of a possible mem leak, by "renaming" the share
- First remove from hash
*/
- hash_delete(&ndbcluster_open_tables, (byte*) share);
+ hash_delete(&ndbcluster_open_tables, (uchar*) share);
/*
now give it a new name, just a running number
@@ -7414,7 +7995,7 @@ int handle_trailing_share(NDB_SHARE *share)
const uint min_key_length= 10;
if (share->key_length < min_key_length)
{
- share->key= alloc_root(&share->mem_root, min_key_length + 1);
+ share->key= (char*) alloc_root(&share->mem_root, min_key_length + 1);
share->key_length= min_key_length;
}
share->key_length=
@@ -7422,7 +8003,7 @@ int handle_trailing_share(NDB_SHARE *share)
trailing_share_id++);
}
/* Keep it for possible the future trailing free */
- my_hash_insert(&ndbcluster_open_tables, (byte*) share);
+ my_hash_insert(&ndbcluster_open_tables, (uchar*) share);
DBUG_RETURN(0);
}
@@ -7438,11 +8019,11 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
DBUG_PRINT("rename_share", ("old_key: %s old__length: %d",
share->key, share->key_length));
if ((tmp= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (byte*) new_key, new_length)))
+ (uchar*) new_key, new_length)))
handle_trailing_share(tmp);
/* remove the share from hash */
- hash_delete(&ndbcluster_open_tables, (byte*) share);
+ hash_delete(&ndbcluster_open_tables, (uchar*) share);
dbug_print_open_tables();
/* save old stuff if insert should fail */
@@ -7453,18 +8034,18 @@ static int rename_share(NDB_SHARE *share, const char *new_key)
now allocate and set the new key, db etc
enough space for key, db, and table_name
*/
- share->key= alloc_root(&share->mem_root, 2 * (new_length + 1));
+ share->key= (char*) alloc_root(&share->mem_root, 2 * (new_length + 1));
strmov(share->key, new_key);
share->key_length= new_length;
- if (my_hash_insert(&ndbcluster_open_tables, (byte*) share))
+ if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
{
// ToDo free the allocated stuff above?
DBUG_PRINT("error", ("rename_share: my_hash_insert %s failed",
share->key));
share->key= old_key;
share->key_length= old_length;
- if (my_hash_insert(&ndbcluster_open_tables, (byte*) share))
+ if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
{
sql_print_error("rename_share: failed to recover %s", share->key);
DBUG_PRINT("error", ("rename_share: my_hash_insert %s failed",
@@ -7536,7 +8117,6 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
bool create_if_not_exists,
bool have_lock)
{
- THD *thd= current_thd;
NDB_SHARE *share;
uint length= (uint) strlen(key);
DBUG_ENTER("ndbcluster_get_share");
@@ -7545,7 +8125,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
if (!have_lock)
pthread_mutex_lock(&ndbcluster_mutex);
if (!(share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (byte*) key,
+ (uchar*) key,
length)))
{
if (!create_if_not_exists)
@@ -7565,13 +8145,13 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
*root_ptr= &share->mem_root; // remember to reset before return
share->state= NSS_INITIAL;
/* enough space for key, db, and table_name */
- share->key= alloc_root(*root_ptr, 2 * (length + 1));
+ share->key= (char*) alloc_root(*root_ptr, 2 * (length + 1));
share->key_length= length;
strmov(share->key, key);
- if (my_hash_insert(&ndbcluster_open_tables, (byte*) share))
+ if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
{
free_root(&share->mem_root, MYF(0));
- my_free((gptr) share, 0);
+ my_free((uchar*) share, 0);
*root_ptr= old_root;
if (!have_lock)
pthread_mutex_unlock(&ndbcluster_mutex);
@@ -7614,7 +8194,7 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
DBUG_ENTER("ndbcluster_real_free_share");
dbug_print_share("ndbcluster_real_free_share:", *share);
- hash_delete(&ndbcluster_open_tables, (byte*) *share);
+ hash_delete(&ndbcluster_open_tables, (uchar*) *share);
thr_lock_delete(&(*share)->lock);
pthread_mutex_destroy(&(*share)->mutex);
@@ -7626,15 +8206,15 @@ void ndbcluster_real_free_share(NDB_SHARE **share)
// (*share)->table_share->mem_root is freed by free_table_share
free_table_share((*share)->table_share);
#ifndef DBUG_OFF
- bzero((gptr)(*share)->table_share, sizeof(*(*share)->table_share));
- bzero((gptr)(*share)->table, sizeof(*(*share)->table));
+ bzero((uchar*)(*share)->table_share, sizeof(*(*share)->table_share));
+ bzero((uchar*)(*share)->table, sizeof(*(*share)->table));
(*share)->table_share= 0;
(*share)->table= 0;
#endif
}
#endif
free_root(&(*share)->mem_root, MYF(0));
- my_free((gptr) *share, MYF(0));
+ my_free((uchar*) *share, MYF(0));
*share= 0;
dbug_print_open_tables();
@@ -7650,7 +8230,7 @@ void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
(*share)->util_lock= 0;
if (!--(*share)->use_count)
{
- real_free_share(share);
+ ndbcluster_real_free_share(share);
}
else
{
@@ -7671,8 +8251,10 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
NdbError error;
int retries= 10;
int reterr= 0;
- int retry_sleep= 30 * 1000; /* 30 milliseconds */
+ int retry_sleep= 30; /* 30 milliseconds, transaction */
+#ifndef DBUG_OFF
char buff[22], buff2[22], buff3[22], buff4[22];
+#endif
DBUG_ENTER("ndb_get_table_statistics");
DBUG_PRINT("enter", ("table: %s", ndbtab->getName()));
@@ -7688,7 +8270,6 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
Uint64 sum_row_size= 0;
Uint64 sum_mem= 0;
NdbScanOperation*pOp;
- NdbResultSet *rs;
int check;
if ((pTrans= ndb->startTransaction()) == NULL)
@@ -7724,7 +8305,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
(char*)&var_mem);
if (pTrans->execute(NdbTransaction::NoCommit,
- NdbTransaction::AbortOnError,
+ NdbOperation::AbortOnError,
TRUE) == -1)
{
error= pTrans->getNdbError();
@@ -7768,7 +8349,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const
retry:
if(report_error)
{
- if (file)
+ if (file && pTrans)
{
reterr= file->ndb_err(pTrans);
}
@@ -7858,19 +8439,19 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges,
KEY* key_info= table->key_info + active_index;
KEY_MULTI_RANGE *range= ranges;
ulong reclength= table->s->reclength;
- byte *curr= (byte*)buffer->buffer;
- byte *end_of_buffer= (byte*)buffer->buffer_end;
+ uchar *curr= (uchar*)buffer->buffer;
+ uchar *end_of_buffer= (uchar*)buffer->buffer_end;
for (; range<end_range && curr+reclength <= end_of_buffer;
range++)
{
- const byte *key= range->start_key.key;
+ const uchar *key= range->start_key.key;
uint key_len= range->start_key.length;
if (check_null_in_key(key_info, key, key_len))
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
curr += reclength;
}
- DBUG_RETURN(false);
+ DBUG_RETURN(FALSE);
}
int
@@ -7880,21 +8461,20 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
bool sorted,
HANDLER_BUFFER *buffer)
{
- DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
m_write_op= FALSE;
-
int res;
KEY* key_info= table->key_info + active_index;
- NDB_INDEX_TYPE index_type= get_index_type(active_index);
+ NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
ulong reclength= table_share->reclength;
NdbOperation* op;
Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
+ DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
/**
* blobs and unique hash index with NULL can't be batched currently
*/
if (uses_blob_value() ||
- (index_type == UNIQUE_INDEX &&
+ (cur_index_type == UNIQUE_INDEX &&
has_null_in_unique_index(active_index) &&
null_value_index_search(ranges, ranges+range_count, buffer)))
{
@@ -7933,8 +8513,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
/**
* Variables for loop
*/
- byte *curr= (byte*)buffer->buffer;
- byte *end_of_buffer= (byte*)buffer->buffer_end;
+ uchar *curr= (uchar*)buffer->buffer;
+ uchar *end_of_buffer= (uchar*)buffer->buffer_end;
NdbOperation::LockMode lm=
(NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
bool need_pk = (lm == NdbOperation::LM_Read);
@@ -7969,7 +8549,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
continue;
}
}
- switch(index_type){
+ switch (cur_index_type) {
case PRIMARY_KEY_ORDERED_INDEX:
if (!(multi_range_curr->start_key.length == key_info->key_length &&
multi_range_curr->start_key.flag == HA_READ_KEY_EXACT))
@@ -7982,9 +8562,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
!op->readTuple(lm) &&
!set_primary_key(op, multi_range_curr->start_key.key) &&
!define_read_attrs(curr, op) &&
- (op->setAbortOption(AO_IgnoreError), TRUE) &&
(!m_use_partition_function ||
- (op->setPartitionId(part_spec.start_part), true)))
+ (op->setPartitionId(part_spec.start_part), TRUE)))
curr += reclength;
else
ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
@@ -8004,8 +8583,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) &&
!op->readTuple(lm) &&
!set_index_key(op, key_info, multi_range_curr->start_key.key) &&
- !define_read_attrs(curr, op) &&
- (op->setAbortOption(AO_IgnoreError), TRUE))
+ !define_read_attrs(curr, op))
curr += reclength;
else
ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
@@ -8029,8 +8607,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
}
else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab))
&&!scanOp->readTuples(lm, 0, parallelism, sorted,
- FALSE, TRUE, need_pk)
- &&!generate_scan_filter(m_cond_stack, scanOp)
+ FALSE, TRUE, need_pk, TRUE)
+ &&!(m_cond && m_cond->generate_scan_filter(scanOp))
&&!define_read_attrs(end_of_buffer-reclength, scanOp))
{
m_multi_cursor= scanOp;
@@ -8045,7 +8623,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
const key_range *keys[2]= { &multi_range_curr->start_key,
&multi_range_curr->end_key };
- if ((res= set_bounds(scanOp, active_index, false, keys,
+ if ((res= set_bounds(scanOp, active_index, FALSE, keys,
multi_range_curr-ranges)))
DBUG_RETURN(res);
break;
@@ -8065,7 +8643,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
* This as we don't want mysqld to reuse the buffer when we read
* the remaining ranges
*/
- buffer->end_of_used_area= (byte*)buffer->buffer_end;
+ buffer->end_of_used_area= (uchar*)buffer->buffer_end;
}
else
{
@@ -8081,7 +8659,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
{
m_multi_range_defined= multi_range_curr;
multi_range_curr= ranges;
- m_multi_range_result_ptr= (byte*)buffer->buffer;
+ m_multi_range_result_ptr= (uchar*)buffer->buffer;
DBUG_RETURN(read_multi_range_next(found_range_p));
}
ERR_RETURN(m_active_trans->getNdbError());
@@ -8167,7 +8745,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
DBUG_MULTI_RANGE(6);
// First fetch from cursor
DBUG_ASSERT(range_no == -1);
- if ((res= m_multi_cursor->nextResult(true)))
+ if ((res= m_multi_cursor->nextResult(TRUE)))
{
DBUG_MULTI_RANGE(15);
goto close_scan;
@@ -8205,6 +8783,8 @@ close_scan:
if (multi_range_curr == multi_range_end)
{
DBUG_MULTI_RANGE(16);
+ Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
+ thd_ndb->query_state&= NDB_QUERY_NORMAL;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
@@ -8288,16 +8868,20 @@ ha_ndbcluster::update_table_comment(
return((char*)comment);
}
- ndb->setDatabaseName(m_dbname);
- NDBDICT* dict= ndb->getDictionary();
+ if (ndb->setDatabaseName(m_dbname))
+ {
+ return((char*)comment);
+ }
const NDBTAB* tab= m_table;
DBUG_ASSERT(tab != NULL);
char *str;
const char *fmt="%s%snumber_of_replicas: %d";
const unsigned fmt_len_plus_extra= length + strlen(fmt);
- if ((str= my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
+ if ((str= (char*) my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
{
+ sql_print_error("ha_ndbcluster::update_table_comment: "
+ "my_malloc(%u) failed", (unsigned int)fmt_len_plus_extra);
return (char*)comment;
}
@@ -8313,29 +8897,31 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
{
THD *thd; /* needs to be first for thread_stack */
struct timespec abstime;
- List<NDB_SHARE> util_open_tables;
Thd_ndb *thd_ndb;
+ uint share_list_size= 0;
+ NDB_SHARE **share_list= NULL;
my_thread_init();
DBUG_ENTER("ndb_util_thread");
DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time));
+
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
thd= new THD; /* note that contructor of THD uses DBUG_ */
+ if (thd == NULL)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(NULL);
+ }
THD_CHECK_SENTRY(thd);
-
pthread_detach_this_thread();
ndb_util_thread= pthread_self();
thd->thread_stack= (char*)&thd; /* remember where our stack is */
if (thd->store_globals())
- {
- thd->cleanup();
- delete thd;
- DBUG_RETURN(NULL);
- }
+ goto ndb_util_thread_fail;
thd->init_for_queries();
thd->version=refresh_version;
- thd->set_time();
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
@@ -8343,16 +8929,29 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
thd->main_security_ctx.priv_user = 0;
thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode
+ /* Signal successful initialization */
+ ndb_util_thread_running= 1;
+ pthread_cond_signal(&COND_ndb_util_ready);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
/*
wait for mysql server to start
*/
pthread_mutex_lock(&LOCK_server_started);
while (!mysqld_server_started)
- pthread_cond_wait(&COND_server_started, &LOCK_server_started);
+ {
+ set_timespec(abstime, 1);
+ pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
+ &abstime);
+ if (ndbcluster_terminating)
+ {
+ pthread_mutex_unlock(&LOCK_server_started);
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ goto ndb_util_thread_end;
+ }
+ }
pthread_mutex_unlock(&LOCK_server_started);
- ndbcluster_util_inited= 1;
-
/*
Wait for cluster to start
*/
@@ -8360,15 +8959,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
while (!ndb_cluster_node_id && (ndbcluster_hton->slot != ~(uint)0))
{
/* ndb not connected yet */
- set_timespec(abstime, 1);
- pthread_cond_timedwait(&COND_ndb_util_thread,
- &LOCK_ndb_util_thread,
- &abstime);
- if (abort_loop)
- {
- pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ pthread_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread);
+ if (ndbcluster_terminating)
goto ndb_util_thread_end;
- }
}
pthread_mutex_unlock(&LOCK_ndb_util_thread);
@@ -8376,6 +8969,7 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
{
sql_print_error("Could not allocate Thd_ndb object");
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
goto ndb_util_thread_end;
}
set_thd_ndb(thd, thd_ndb);
@@ -8394,19 +8988,20 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
#endif
set_timespec(abstime, 0);
- for (;!abort_loop;)
+ for (;;)
{
pthread_mutex_lock(&LOCK_ndb_util_thread);
- pthread_cond_timedwait(&COND_ndb_util_thread,
- &LOCK_ndb_util_thread,
- &abstime);
+ if (!ndbcluster_terminating)
+ pthread_cond_timedwait(&COND_ndb_util_thread,
+ &LOCK_ndb_util_thread,
+ &abstime);
+ if (ndbcluster_terminating) /* Shutting down server */
+ goto ndb_util_thread_end;
pthread_mutex_unlock(&LOCK_ndb_util_thread);
#ifdef NDB_EXTRA_DEBUG_UTIL_THREAD
DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %lu",
ndb_cache_check_time));
#endif
- if (abort_loop)
- break; /* Shutting down server */
#ifdef HAVE_NDB_BINLOG
/*
@@ -8428,7 +9023,22 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/* Lock mutex and fill list with pointers to all open tables */
NDB_SHARE *share;
pthread_mutex_lock(&ndbcluster_mutex);
- for (uint i= 0; i < ndbcluster_open_tables.records; i++)
+ uint i, open_count, record_count= ndbcluster_open_tables.records;
+ if (share_list_size < record_count)
+ {
+ NDB_SHARE ** new_share_list= new NDB_SHARE * [record_count];
+ if (!new_share_list)
+ {
+ sql_print_warning("ndb util thread: malloc failure, "
+ "query cache not maintained properly");
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ goto next; // At least do not crash
+ }
+ delete [] share_list;
+ share_list_size= record_count;
+ share_list= new_share_list;
+ }
+ for (i= 0, open_count= 0; i < record_count; i++)
{
share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i);
#ifdef HAVE_NDB_BINLOG
@@ -8437,20 +9047,23 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
continue; // injector thread is the only user, skip statistics
share->util_lock= current_thd; // Mark that util thread has lock
#endif /* HAVE_NDB_BINLOG */
+ /* ndb_share reference temporary, free below */
share->use_count++; /* Make sure the table can't be closed */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
DBUG_PRINT("ndb_util_thread",
("Found open table[%d]: %s, use_count: %d",
i, share->table_name, share->use_count));
/* Store pointer to table */
- util_open_tables.push_back(share);
+ share_list[open_count++]= share;
}
pthread_mutex_unlock(&ndbcluster_mutex);
- /* Iterate through the open files list */
- List_iterator_fast<NDB_SHARE> it(util_open_tables);
- while ((share= it++))
+ /* Iterate through the open files list */
+ for (i= 0; i < open_count; i++)
{
+ share= share_list[i];
#ifdef HAVE_NDB_BINLOG
if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
<= 1)
@@ -8458,6 +9071,9 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
/*
Util thread and injector thread is the only user, skip statistics
*/
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
continue;
}
@@ -8470,17 +9086,21 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
pthread_mutex_lock(&share->mutex);
lock= share->commit_count_lock;
pthread_mutex_unlock(&share->mutex);
-
{
/* Contact NDB to get commit count for table */
Ndb* ndb= thd_ndb->ndb;
- ndb->setDatabaseName(share->db);
+ if (ndb->setDatabaseName(share->db))
+ {
+ goto loop_next;
+ }
Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
if (ndbtab_g.get_table() &&
- ndb_get_table_statistics(NULL, false, ndb,
+ ndb_get_table_statistics(NULL, FALSE, ndb,
ndbtab_g.get_table(), &stat) == 0)
{
+#ifndef DBUG_OFF
char buff[22], buff2[22];
+#endif
DBUG_PRINT("info",
("Table: %s commit_count: %s rows: %s",
share->key,
@@ -8495,19 +9115,18 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
stat.commit_count= 0;
}
}
-
+ loop_next:
pthread_mutex_lock(&share->mutex);
if (share->commit_count_lock == lock)
share->commit_count= stat.commit_count;
pthread_mutex_unlock(&share->mutex);
- /* Decrease the use count and possibly free share */
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
-
- /* Clear the list of open tables */
- util_open_tables.empty();
-
+next:
/* Calculate new time to wake up */
int secs= 0;
int msecs= ndb_cache_check_time;
@@ -8529,11 +9148,21 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
abstime.tv_nsec-= 1000000000;
}
}
+
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+
ndb_util_thread_end:
- sql_print_information("Stopping Cluster Utility thread");
net_end(&thd->net);
+ndb_util_thread_fail:
+ if (share_list)
+ delete [] share_list;
thd->cleanup();
delete thd;
+
+ /* signal termination */
+ ndb_util_thread_running= 0;
+ pthread_cond_signal(&COND_ndb_util_ready);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
DBUG_PRINT("exit", ("ndb_util_thread"));
my_thread_end();
pthread_exit(0);
@@ -8565,23 +9194,15 @@ COND*
ha_ndbcluster::cond_push(const COND *cond)
{
DBUG_ENTER("cond_push");
- Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
- DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
- if (m_cond_stack)
- ndb_cond->next= m_cond_stack;
- else
- ndb_cond->next= NULL;
- m_cond_stack= ndb_cond;
-
- if (serialize_cond(cond, ndb_cond))
+ if (!m_cond)
+ m_cond= new ha_ndbcluster_cond;
+ if (!m_cond)
{
+ my_errno= HA_ERR_OUT_OF_MEM;
DBUG_RETURN(NULL);
}
- else
- {
- cond_pop();
- }
- DBUG_RETURN(cond);
+ DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
+ DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
}
/*
@@ -8590,1363 +9211,15 @@ ha_ndbcluster::cond_push(const COND *cond)
void
ha_ndbcluster::cond_pop()
{
- Ndb_cond_stack *ndb_cond_stack= m_cond_stack;
- if (ndb_cond_stack)
- {
- m_cond_stack= ndb_cond_stack->next;
- delete ndb_cond_stack;
- }
-}
-
-/*
- Clear the condition stack
-*/
-void
-ha_ndbcluster::cond_clear()
-{
- DBUG_ENTER("cond_clear");
- while (m_cond_stack)
- cond_pop();
-
- DBUG_VOID_RETURN;
-}
-
-/*
- Serialize the item tree into a linked list represented by Ndb_cond
- for fast generation of NbdScanFilter. Adds information such as
- position of fields that is not directly available in the Item tree.
- Also checks if condition is supported.
-*/
-void ndb_serialize_cond(const Item *item, void *arg)
-{
- Ndb_cond_traverse_context *context= (Ndb_cond_traverse_context *) arg;
- DBUG_ENTER("ndb_serialize_cond");
-
- // Check if we are skipping arguments to a function to be evaluated
- if (context->skip)
- {
- DBUG_PRINT("info", ("Skiping argument %d", context->skip));
- context->skip--;
- switch (item->type()) {
- case Item::FUNC_ITEM:
- {
- Item_func *func_item= (Item_func *) item;
- context->skip+= func_item->argument_count();
- break;
- }
- case Item::INT_ITEM:
- case Item::REAL_ITEM:
- case Item::STRING_ITEM:
- case Item::VARBIN_ITEM:
- case Item::DECIMAL_ITEM:
- break;
- default:
- context->supported= FALSE;
- break;
- }
-
- DBUG_VOID_RETURN;
- }
-
- if (context->supported)
- {
- Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
- const Item_func *func_item;
- // Check if we are rewriting some unsupported function call
- if (rewrite_context &&
- (func_item= rewrite_context->func_item) &&
- rewrite_context->count++ == 0)
- {
- switch (func_item->functype()) {
- case Item_func::BETWEEN:
- /*
- Rewrite
- <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
- to <field>|<const> > <const1>|<field1> AND
- <field>|<const> < <const2>|<field2>
- or actually in prefix format
- BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
- LT(<field>|<const>, <const2>|<field2>), END()
- */
- case Item_func::IN_FUNC:
- {
- /*
- Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
- to <field>|<const> = <const1>|<field1> OR
- <field> = <const2>|<field2> ...
- or actually in prefix format
- BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
- EQ(<field>|<const>, <const2>|<field2>), ... END()
- Each part of the disjunction is added for each call
- to ndb_serialize_cond and end of rewrite statement
- is wrapped in end of ndb_serialize_cond
- */
- if (context->expecting(item->type()))
- {
- // This is the <field>|<const> item, save it in the rewrite context
- rewrite_context->left_hand_item= item;
- if (item->type() == Item::FUNC_ITEM)
- {
- Item_func *func_item= (Item_func *) item;
- if (func_item->functype() == Item_func::UNKNOWN_FUNC &&
- func_item->const_item())
- {
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- }
- else
- {
- DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN"));
- context->supported= FALSE;
- DBUG_VOID_RETURN;
-
- }
- }
- }
- else
- {
- // Non-supported BETWEEN|IN expression
- DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN",
- item->type()));
- context->supported= FALSE;
- DBUG_VOID_RETURN;
- }
- break;
- }
- default:
- context->supported= FALSE;
- break;
- }
- DBUG_VOID_RETURN;
- }
- else
- {
- Ndb_cond_stack *ndb_stack= context->stack_ptr;
- Ndb_cond *prev_cond= context->cond_ptr;
- Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond();
- if (!ndb_stack->ndb_cond)
- ndb_stack->ndb_cond= curr_cond;
- curr_cond->prev= prev_cond;
- if (prev_cond) prev_cond->next= curr_cond;
- // Check if we are rewriting some unsupported function call
- if (context->rewrite_stack)
- {
- Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
- const Item_func *func_item= rewrite_context->func_item;
- switch (func_item->functype()) {
- case Item_func::BETWEEN:
- {
- /*
- Rewrite
- <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
- to <field>|<const> > <const1>|<field1> AND
- <field>|<const> < <const2>|<field2>
- or actually in prefix format
- BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
- LT(<field>|<const>, <const2>|<field2>), END()
- */
- if (rewrite_context->count == 2)
- {
- // Lower limit of BETWEEN
- DBUG_PRINT("info", ("GE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::GE_FUNC, 2);
- }
- else if (rewrite_context->count == 3)
- {
- // Upper limit of BETWEEN
- DBUG_PRINT("info", ("LE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::LE_FUNC, 2);
- }
- else
- {
- // Illegal BETWEEN expression
- DBUG_PRINT("info", ("Illegal BETWEEN expression"));
- context->supported= FALSE;
- DBUG_VOID_RETURN;
- }
- break;
- }
- case Item_func::IN_FUNC:
- {
- /*
- Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
- to <field>|<const> = <const1>|<field1> OR
- <field> = <const2>|<field2> ...
- or actually in prefix format
- BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
- EQ(<field>|<const>, <const2>|<field2>), ... END()
- Each part of the disjunction is added for each call
- to ndb_serialize_cond and end of rewrite statement
- is wrapped in end of ndb_serialize_cond
- */
- DBUG_PRINT("info", ("EQ_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::EQ_FUNC, 2);
- break;
- }
- default:
- context->supported= FALSE;
- }
- // Handle left hand <field>|<const>
- context->rewrite_stack= NULL; // Disable rewrite mode
- context->expect_only(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- context->expect(Item::INT_ITEM);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FUNC_ITEM);
- ndb_serialize_cond(rewrite_context->left_hand_item, arg);
- context->skip= 0; // Any FUNC_ITEM expression has already been parsed
- context->rewrite_stack= rewrite_context; // Enable rewrite mode
- if (!context->supported)
- DBUG_VOID_RETURN;
-
- prev_cond= context->cond_ptr;
- curr_cond= context->cond_ptr= new Ndb_cond();
- prev_cond->next= curr_cond;
- }
-
- // Check for end of AND/OR expression
- if (!item)
- {
- // End marker for condition group
- DBUG_PRINT("info", ("End of condition group"));
- curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
- }
- else
- {
- switch (item->type()) {
- case Item::FIELD_ITEM:
- {
- Item_field *field_item= (Item_field *) item;
- Field *field= field_item->field;
- enum_field_types type= field->type();
- /*
- Check that the field is part of the table of the handler
- instance and that we expect a field with of this result type.
- */
- if (context->table == field->table)
- {
- const NDBTAB *tab= (const NDBTAB *) context->ndb_table;
- DBUG_PRINT("info", ("FIELD_ITEM"));
- DBUG_PRINT("info", ("table %s", tab->getName()));
- DBUG_PRINT("info", ("column %s", field->field_name));
- DBUG_PRINT("info", ("type %d", field->type()));
- DBUG_PRINT("info", ("result type %d", field->result_type()));
-
- // Check that we are expecting a field and with the correct
- // result type
- if (context->expecting(Item::FIELD_ITEM) &&
- context->expecting_field_type(field->type()) &&
- (context->expecting_field_result(field->result_type()) ||
- // Date and year can be written as string or int
- ((type == MYSQL_TYPE_TIME ||
- type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_YEAR ||
- type == MYSQL_TYPE_DATETIME)
- ? (context->expecting_field_result(STRING_RESULT) ||
- context->expecting_field_result(INT_RESULT))
- : true)) &&
- // Bit fields no yet supported in scan filter
- type != MYSQL_TYPE_BIT &&
- // No BLOB support in scan filter
- type != MYSQL_TYPE_TINY_BLOB &&
- type != MYSQL_TYPE_MEDIUM_BLOB &&
- type != MYSQL_TYPE_LONG_BLOB &&
- type != MYSQL_TYPE_BLOB)
- {
- const NDBCOL *col= tab->getColumn(field->field_name);
- DBUG_ASSERT(col);
- curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo());
- context->dont_expect(Item::FIELD_ITEM);
- context->expect_no_field_result();
- if (! context->expecting_nothing())
- {
- // We have not seen second argument yet
- if (type == MYSQL_TYPE_TIME ||
- type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_YEAR ||
- type == MYSQL_TYPE_DATETIME)
- {
- context->expect_only(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- }
- else
- switch (field->result_type()) {
- case STRING_RESULT:
- // Expect char string or binary string
- context->expect_only(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect_collation(field_item->collation.collation);
- break;
- case REAL_RESULT:
- context->expect_only(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::INT_ITEM);
- break;
- case INT_RESULT:
- context->expect_only(Item::INT_ITEM);
- context->expect(Item::VARBIN_ITEM);
- break;
- case DECIMAL_RESULT:
- context->expect_only(Item::DECIMAL_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::INT_ITEM);
- break;
- default:
- break;
- }
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that field and string constant collations are the same
- if ((field->result_type() == STRING_RESULT) &&
- !context->expecting_collation(item->collation.collation)
- && type != MYSQL_TYPE_TIME
- && type != MYSQL_TYPE_DATE
- && type != MYSQL_TYPE_YEAR
- && type != MYSQL_TYPE_DATETIME)
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
- }
- break;
- }
- else
- {
- DBUG_PRINT("info", ("Was not expecting field of type %u(%u)",
- field->result_type(), type));
- context->supported= FALSE;
- }
- }
- else
- {
- DBUG_PRINT("info", ("Was not expecting field from table %s (%s)",
- context->table->s->table_name.str,
- field->table->s->table_name.str));
- context->supported= FALSE;
- }
- break;
- }
- case Item::FUNC_ITEM:
- {
- Item_func *func_item= (Item_func *) item;
- // Check that we expect a function or functional expression here
- if (context->expecting(Item::FUNC_ITEM) ||
- func_item->functype() == Item_func::UNKNOWN_FUNC)
- context->expect_nothing();
- else
- {
- // Did not expect function here
- context->supported= FALSE;
- break;
- }
-
- switch (func_item->functype()) {
- case Item_func::EQ_FUNC:
- {
- DBUG_PRINT("info", ("EQ_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::NE_FUNC:
- {
- DBUG_PRINT("info", ("NE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::LT_FUNC:
- {
- DBUG_PRINT("info", ("LT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::LE_FUNC:
- {
- DBUG_PRINT("info", ("LE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::GE_FUNC:
- {
- DBUG_PRINT("info", ("GE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::GT_FUNC:
- {
- DBUG_PRINT("info", ("GT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::LIKE_FUNC:
- {
- DBUG_PRINT("info", ("LIKE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_only_field_type(MYSQL_TYPE_STRING);
- context->expect_field_type(MYSQL_TYPE_VAR_STRING);
- context->expect_field_type(MYSQL_TYPE_VARCHAR);
- context->expect_field_result(STRING_RESULT);
- context->expect(Item::FUNC_ITEM);
- break;
- }
- case Item_func::ISNULL_FUNC:
- {
- DBUG_PRINT("info", ("ISNULL_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::ISNOTNULL_FUNC:
- {
- DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case Item_func::NOT_FUNC:
- {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- break;
- }
- case Item_func::BETWEEN:
- {
- DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
- Item_func_between *between_func= (Item_func_between *) func_item;
- Ndb_rewrite_context *rewrite_context=
- new Ndb_rewrite_context(func_item);
- rewrite_context->next= context->rewrite_stack;
- context->rewrite_stack= rewrite_context;
- if (between_func->negated)
- {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
- prev_cond= curr_cond;
- curr_cond= context->cond_ptr= new Ndb_cond();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- }
- DBUG_PRINT("info", ("COND_AND_FUNC"));
- curr_cond->ndb_item=
- new Ndb_item(Item_func::COND_AND_FUNC,
- func_item->argument_count() - 1);
- context->expect_only(Item::FIELD_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FUNC_ITEM);
- break;
- }
- case Item_func::IN_FUNC:
- {
- DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
- Item_func_in *in_func= (Item_func_in *) func_item;
- Ndb_rewrite_context *rewrite_context=
- new Ndb_rewrite_context(func_item);
- rewrite_context->next= context->rewrite_stack;
- context->rewrite_stack= rewrite_context;
- if (in_func->negated)
- {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
- prev_cond= curr_cond;
- curr_cond= context->cond_ptr= new Ndb_cond();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- }
- DBUG_PRINT("info", ("COND_OR_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::COND_OR_FUNC,
- func_item->argument_count() - 1);
- context->expect_only(Item::FIELD_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FUNC_ITEM);
- break;
- }
- case Item_func::UNKNOWN_FUNC:
- {
- DBUG_PRINT("info", ("UNKNOWN_FUNC %s",
- func_item->const_item()?"const":""));
- DBUG_PRINT("info", ("result type %d", func_item->result_type()));
- if (func_item->const_item())
- {
- switch (func_item->result_type()) {
- case STRING_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::STRING_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- context->expect_collation(func_item->collation.collation);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that string result have correct collation
- if (!context->expecting_collation(item->collation.collation))
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
- }
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case REAL_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::REAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case INT_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::INT_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case DECIMAL_RESULT:
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::DECIMAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(DECIMAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- default:
- break;
- }
- }
- else
- // Function does not return constant expression
- context->supported= FALSE;
- break;
- }
- default:
- {
- DBUG_PRINT("info", ("Found func_item of type %d",
- func_item->functype()));
- context->supported= FALSE;
- }
- }
- break;
- }
- case Item::STRING_ITEM:
- DBUG_PRINT("info", ("STRING_ITEM"));
- if (context->expecting(Item::STRING_ITEM))
- {
-#ifndef DBUG_OFF
- char buff[256];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- Item_string *string_item= (Item_string *) item;
- DBUG_PRINT("info", ("value \"%s\"",
- string_item->val_str(&str)->ptr()));
-#endif
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::STRING_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- context->expect_collation(item->collation.collation);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that we are comparing with a field with same collation
- if (!context->expecting_collation(item->collation.collation))
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
- }
- }
- else
- context->supported= FALSE;
- break;
- case Item::INT_ITEM:
- DBUG_PRINT("info", ("INT_ITEM"));
- if (context->expecting(Item::INT_ITEM))
- {
- Item_int *int_item= (Item_int *) item;
- DBUG_PRINT("info", ("value %ld", (long) int_item->value));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::INT_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- }
- else
- context->supported= FALSE;
- break;
- case Item::REAL_ITEM:
- DBUG_PRINT("info", ("REAL_ITEM"));
- if (context->expecting(Item::REAL_ITEM))
- {
- Item_float *float_item= (Item_float *) item;
- DBUG_PRINT("info", ("value %f", float_item->value));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::REAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- }
- else
- context->supported= FALSE;
- break;
- case Item::VARBIN_ITEM:
- DBUG_PRINT("info", ("VARBIN_ITEM"));
- if (context->expecting(Item::VARBIN_ITEM))
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::VARBIN_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- }
- else
- context->supported= FALSE;
- break;
- case Item::DECIMAL_ITEM:
- DBUG_PRINT("info", ("DECIMAL_ITEM"));
- if (context->expecting(Item::DECIMAL_ITEM))
- {
- Item_decimal *decimal_item= (Item_decimal *) item;
- DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::DECIMAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- }
- else
- context->supported= FALSE;
- break;
- case Item::COND_ITEM:
- {
- Item_cond *cond_item= (Item_cond *) item;
-
- if (context->expecting(Item::COND_ITEM))
- {
- switch (cond_item->functype()) {
- case Item_func::COND_AND_FUNC:
- DBUG_PRINT("info", ("COND_AND_FUNC"));
- curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
- cond_item);
- break;
- case Item_func::COND_OR_FUNC:
- DBUG_PRINT("info", ("COND_OR_FUNC"));
- curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
- cond_item);
- break;
- default:
- DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
- context->supported= FALSE;
- break;
- }
- }
- else
- {
- /* Did not expect condition */
- context->supported= FALSE;
- }
- break;
- }
- default:
- {
- DBUG_PRINT("info", ("Found item of type %d", item->type()));
- context->supported= FALSE;
- }
- }
- }
- if (context->supported && context->rewrite_stack)
- {
- Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
- if (rewrite_context->count ==
- rewrite_context->func_item->argument_count())
- {
- // Rewrite is done, wrap an END() at the en
- DBUG_PRINT("info", ("End of condition group"));
- prev_cond= curr_cond;
- curr_cond= context->cond_ptr= new Ndb_cond();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
- // Pop rewrite stack
- context->rewrite_stack= rewrite_context->next;
- rewrite_context->next= NULL;
- delete(rewrite_context);
- }
- }
- }
- }
-
- DBUG_VOID_RETURN;
-}
-
-bool
-ha_ndbcluster::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond)
-{
- DBUG_ENTER("serialize_cond");
- Item *item= (Item *) cond;
- Ndb_cond_traverse_context context(table, (void *)m_table, ndb_cond);
- // Expect a logical expression
- context.expect(Item::FUNC_ITEM);
- context.expect(Item::COND_ITEM);
- item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
- DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
-
- DBUG_RETURN(context.supported);
-}
-
-int
-ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
- NdbScanFilter *filter,
- bool negated)
-{
- DBUG_ENTER("build_scan_filter_predicate");
- switch (cond->ndb_item->type) {
- case NDB_FUNCTION:
- {
- if (!cond->next)
- break;
- Ndb_item *a= cond->next->ndb_item;
- Ndb_item *b, *field, *value= NULL;
- LINT_INIT(field);
-
- switch (cond->ndb_item->argument_count()) {
- case 1:
- field=
- (a->type == NDB_FIELD)? a : NULL;
- break;
- case 2:
- if (!cond->next->next)
- break;
- b= cond->next->next->ndb_item;
- value=
- (a->type == NDB_VALUE)? a
- : (b->type == NDB_VALUE)? b
- : NULL;
- field=
- (a->type == NDB_FIELD)? a
- : (b->type == NDB_FIELD)? b
- : NULL;
- break;
- default:
- field= NULL; //Keep compiler happy
- DBUG_ASSERT(0);
- break;
- }
- switch ((negated) ?
- Ndb_item::negate(cond->ndb_item->qualification.function_type)
- : cond->ndb_item->qualification.function_type) {
- case NDB_EQ_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating EQ filter"));
- if (filter->cmp(NdbScanFilter::COND_EQ,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_NE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating NE filter"));
- if (filter->cmp(NdbScanFilter::COND_NE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LT_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating LT filter"));
- if (filter->cmp(NdbScanFilter::COND_LT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating GT filter"));
- if (filter->cmp(NdbScanFilter::COND_GT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating LE filter"));
- if (filter->cmp(NdbScanFilter::COND_LE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating GE filter"));
- if (filter->cmp(NdbScanFilter::COND_GE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_GE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating GE filter"));
- if (filter->cmp(NdbScanFilter::COND_GE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating LE filter"));
- if (filter->cmp(NdbScanFilter::COND_LE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_GT_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating GT filter"));
- if (filter->cmp(NdbScanFilter::COND_GT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating LT filter"));
- if (filter->cmp(NdbScanFilter::COND_LT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LIKE_FUNC:
- {
- if (!value || !field) break;
- if ((value->qualification.value_type != Item::STRING_ITEM) &&
- (value->qualification.value_type != Item::VARBIN_ITEM))
- break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)",
- field->get_field_no(), value->get_val(),
- value->pack_length()));
- if (filter->cmp(NdbScanFilter::COND_LIKE,
- field->get_field_no(),
- value->get_val(),
- value->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_NOTLIKE_FUNC:
- {
- if (!value || !field) break;
- if ((value->qualification.value_type != Item::STRING_ITEM) &&
- (value->qualification.value_type != Item::VARBIN_ITEM))
- break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)",
- field->get_field_no(), value->get_val(),
- value->pack_length()));
- if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
- field->get_field_no(),
- value->get_val(),
- value->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_ISNULL_FUNC:
- if (!field)
- break;
- DBUG_PRINT("info", ("Generating ISNULL filter"));
- if (filter->isnull(field->get_field_no()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next;
- DBUG_RETURN(0);
- case NDB_ISNOTNULL_FUNC:
- {
- if (!field)
- break;
- DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
- if (filter->isnotnull(field->get_field_no()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next;
- DBUG_RETURN(0);
- }
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
- DBUG_PRINT("info", ("Found illegal condition"));
- DBUG_RETURN(1);
-}
-
-int
-ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
-{
- uint level=0;
- bool negated= FALSE;
- DBUG_ENTER("build_scan_filter_group");
-
- do
- {
- if (!cond)
- DBUG_RETURN(1);
- switch (cond->ndb_item->type) {
- case NDB_FUNCTION:
- {
- switch (cond->ndb_item->qualification.function_type) {
- case NDB_COND_AND_FUNC:
- {
- level++;
- DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
- level));
- if ((negated) ? filter->begin(NdbScanFilter::NAND)
- : filter->begin(NdbScanFilter::AND) == -1)
- DBUG_RETURN(1);
- negated= FALSE;
- cond= cond->next;
- break;
- }
- case NDB_COND_OR_FUNC:
- {
- level++;
- DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
- level));
- if ((negated) ? filter->begin(NdbScanFilter::NOR)
- : filter->begin(NdbScanFilter::OR) == -1)
- DBUG_RETURN(1);
- negated= FALSE;
- cond= cond->next;
- break;
- }
- case NDB_NOT_FUNC:
- {
- DBUG_PRINT("info", ("Generating negated query"));
- cond= cond->next;
- negated= TRUE;
- break;
- }
- default:
- if (build_scan_filter_predicate(cond, filter, negated))
- DBUG_RETURN(1);
- negated= FALSE;
- break;
- }
- break;
- }
- case NDB_END_COND:
- DBUG_PRINT("info", ("End of group %u", level));
- level--;
- if (cond) cond= cond->next;
- if (filter->end() == -1)
- DBUG_RETURN(1);
- if (!negated)
- break;
- // else fall through (NOT END is an illegal condition)
- default:
- {
- DBUG_PRINT("info", ("Illegal scan filter"));
- }
- }
- } while (level > 0 || negated);
-
- DBUG_RETURN(0);
-}
-
-int
-ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
-{
- bool simple_cond= TRUE;
- DBUG_ENTER("build_scan_filter");
-
- switch (cond->ndb_item->type) {
- case NDB_FUNCTION:
- switch (cond->ndb_item->qualification.function_type) {
- case NDB_COND_AND_FUNC:
- case NDB_COND_OR_FUNC:
- simple_cond= FALSE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- if (simple_cond && filter->begin() == -1)
- DBUG_RETURN(1);
- if (build_scan_filter_group(cond, filter))
- DBUG_RETURN(1);
- if (simple_cond && filter->end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
-}
-
-int
-ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
- NdbScanOperation *op)
-{
- DBUG_ENTER("generate_scan_filter");
-
- if (ndb_cond_stack)
- {
- NdbScanFilter filter(op);
-
- DBUG_RETURN(generate_scan_filter_from_cond(ndb_cond_stack, filter));
- }
- else
- {
- DBUG_PRINT("info", ("Empty stack"));
- }
-
- DBUG_RETURN(0);
-}
-
-int
-ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack,
- NdbScanFilter& filter)
-{
- DBUG_ENTER("generate_scan_filter_from_cond");
- bool multiple_cond= FALSE;
-
- DBUG_PRINT("info", ("Generating scan filter"));
- // Wrap an AND group around multiple conditions
- if (ndb_cond_stack->next)
- {
- multiple_cond= TRUE;
- if (filter.begin() == -1)
- DBUG_RETURN(1);
- }
- for (Ndb_cond_stack *stack= ndb_cond_stack;
- (stack);
- stack= stack->next)
- {
- Ndb_cond *cond= stack->ndb_cond;
-
- if (build_scan_filter(cond, &filter))
- {
- DBUG_PRINT("info", ("build_scan_filter failed"));
- DBUG_RETURN(1);
- }
- }
- if (multiple_cond && filter.end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
-}
-
-int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op,
- const KEY* key_info,
- const byte *key,
- uint key_len,
- byte *buf)
-{
- KEY_PART_INFO* key_part= key_info->key_part;
- KEY_PART_INFO* end= key_part+key_info->key_parts;
- NdbScanFilter filter(op);
- int res;
-
- DBUG_ENTER("generate_scan_filter_from_key");
- filter.begin(NdbScanFilter::AND);
- for (; key_part != end; key_part++)
- {
- Field* field= key_part->field;
- uint32 pack_len= field->pack_length();
- const byte* ptr= key;
- char buf[256];
- DBUG_PRINT("info", ("Filtering value for %s", field->field_name));
- DBUG_DUMP("key", (char*)ptr, pack_len);
- if (key_part->null_bit)
- {
- DBUG_PRINT("info", ("Generating ISNULL filter"));
- if (filter.isnull(key_part->fieldnr-1) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating EQ filter"));
- if (filter.cmp(NdbScanFilter::COND_EQ,
- key_part->fieldnr-1,
- ptr,
- pack_len) == -1)
- DBUG_RETURN(1);
- }
- key += key_part->store_length;
- }
- // Add any pushed condition
- if (m_cond_stack &&
- (res= generate_scan_filter_from_cond(m_cond_stack, filter)))
- DBUG_RETURN(res);
-
- if (filter.end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
+ if (m_cond)
+ m_cond->cond_pop();
}
/*
get table space info for SHOW CREATE TABLE
*/
-char* ha_ndbcluster::get_tablespace_name(THD *thd)
+char* ha_ndbcluster::get_tablespace_name(THD *thd, char* name, uint name_len)
{
Ndb *ndb= check_ndb_in_thd(thd);
NDBDICT *ndbdict= ndb->getDictionary();
@@ -9964,7 +9237,14 @@ char* ha_ndbcluster::get_tablespace_name(THD *thd)
ndberr= ndbdict->getNdbError();
if(ndberr.classification != NdbError::NoError)
goto err;
- return (my_strdup(ts.getName(), MYF(0)));
+ DBUG_PRINT("info", ("Found tablespace '%s'", ts.getName()));
+ if (name)
+ {
+ strxnmov(name, name_len, ts.getName(), NullS);
+ return name;
+ }
+ else
+ return (my_strdup(ts.getName(), MYF(0)));
}
err:
if (ndberr.status == NdbError::TemporaryError)
@@ -9989,10 +9269,6 @@ ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print,
uint buflen;
DBUG_ENTER("ndbcluster_show_status");
- if (have_ndbcluster != SHOW_OPTION_YES)
- {
- DBUG_RETURN(FALSE);
- }
if (stat_type != HA_ENGINE_STATUS)
{
DBUG_RETURN(FALSE);
@@ -10082,13 +9358,13 @@ static bool adjusted_frag_count(uint no_fragments, uint no_nodes,
return (reported_frags < no_fragments);
}
-int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *info)
+int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info)
{
ha_rows max_rows, min_rows;
- if (info)
+ if (create_info)
{
- max_rows= info->max_rows;
- min_rows= info->min_rows;
+ max_rows= create_info->max_rows;
+ min_rows= create_info->min_rows;
}
else
{
@@ -10239,15 +9515,14 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
{
uint16 frag_data[MAX_PARTITIONS];
char *ts_names[MAX_PARTITIONS];
- ulong ts_index= 0, fd_index= 0, i, j;
+ ulong fd_index= 0, i, j;
NDBTAB *tab= (NDBTAB*)tab_par;
NDBTAB::FragmentType ftype= NDBTAB::UserDefined;
partition_element *part_elem;
bool first= TRUE;
- uint ts_id, ts_version, part_count= 0, tot_ts_name_len;
+ uint tot_ts_name_len;
List_iterator<partition_element> part_it(part_info->partitions);
int error;
- char *name_ptr;
DBUG_ENTER("ha_ndbcluster::set_up_partition_info");
if (part_info->part_type == HASH_PARTITION &&
@@ -10361,7 +9636,7 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
}
-bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
+bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
uint table_changes)
{
DBUG_ENTER("ha_ndbcluster::check_if_incompatible_data");
@@ -10376,10 +9651,23 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
int pk= 0;
int ai= 0;
+
+ if (create_info->tablespace)
+ create_info->storage_media = HA_SM_DISK;
+ else
+ create_info->storage_media = HA_SM_MEMORY;
+
for (i= 0; i < table->s->fields; i++)
{
Field *field= table->field[i];
const NDBCOL *col= tab->getColumn(i);
+ if (col->getStorageType() == NDB_STORAGETYPE_MEMORY && create_info->storage_media != HA_SM_MEMORY ||
+ col->getStorageType() == NDB_STORAGETYPE_DISK && create_info->storage_media != HA_SM_DISK)
+ {
+ DBUG_PRINT("info", ("Column storage media is changed"));
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+
if (field->flags & FIELD_IS_RENAMED)
{
DBUG_PRINT("info", ("Field has been renamed, copy table"));
@@ -10397,6 +9685,36 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
if (field->flags & FIELD_IN_ADD_INDEX)
ai=1;
}
+
+ char tablespace_name[FN_LEN];
+ if (get_tablespace_name(current_thd, tablespace_name, FN_LEN))
+ {
+ if (create_info->tablespace)
+ {
+ if (strcmp(create_info->tablespace, tablespace_name))
+ {
+ DBUG_PRINT("info", ("storage media is changed, old tablespace=%s, new tablespace=%s",
+ tablespace_name, create_info->tablespace));
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("storage media is changed, old is DISK and tablespace=%s, new is MEM",
+ tablespace_name));
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+ }
+ else
+ {
+ if (create_info->storage_media != HA_SM_MEMORY)
+ {
+ DBUG_PRINT("info", ("storage media is changed, old is MEM, new is DISK and tablespace=%s",
+ create_info->tablespace));
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+ }
+
if (table_changes != IS_EQUAL_YES)
DBUG_RETURN(COMPATIBLE_DATA_NO);
@@ -10419,76 +9737,78 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info,
}
/* Check that auto_increment value was not changed */
- if ((info->used_fields & HA_CREATE_USED_AUTO) &&
- info->auto_increment_value != 0)
+ if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
+ create_info->auto_increment_value != 0)
DBUG_RETURN(COMPATIBLE_DATA_NO);
/* Check that row format didn't change */
- if ((info->used_fields & HA_CREATE_USED_AUTO) &&
- get_row_type() != info->row_type)
+ if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
+ get_row_type() != create_info->row_type)
DBUG_RETURN(COMPATIBLE_DATA_NO);
DBUG_RETURN(COMPATIBLE_DATA_YES);
}
-bool set_up_tablespace(st_alter_tablespace *info,
+bool set_up_tablespace(st_alter_tablespace *alter_info,
NdbDictionary::Tablespace *ndb_ts)
{
- ndb_ts->setName(info->tablespace_name);
- ndb_ts->setExtentSize(info->extent_size);
- ndb_ts->setDefaultLogfileGroup(info->logfile_group_name);
- return false;
+ ndb_ts->setName(alter_info->tablespace_name);
+ ndb_ts->setExtentSize(alter_info->extent_size);
+ ndb_ts->setDefaultLogfileGroup(alter_info->logfile_group_name);
+ return FALSE;
}
-bool set_up_datafile(st_alter_tablespace *info,
+bool set_up_datafile(st_alter_tablespace *alter_info,
NdbDictionary::Datafile *ndb_df)
{
- if (info->max_size > 0)
+ if (alter_info->max_size > 0)
{
my_error(ER_TABLESPACE_AUTO_EXTEND_ERROR, MYF(0));
- return true;
+ return TRUE;
}
- ndb_df->setPath(info->data_file_name);
- ndb_df->setSize(info->initial_size);
- ndb_df->setTablespace(info->tablespace_name);
- return false;
+ ndb_df->setPath(alter_info->data_file_name);
+ ndb_df->setSize(alter_info->initial_size);
+ ndb_df->setTablespace(alter_info->tablespace_name);
+ return FALSE;
}
-bool set_up_logfile_group(st_alter_tablespace *info,
+bool set_up_logfile_group(st_alter_tablespace *alter_info,
NdbDictionary::LogfileGroup *ndb_lg)
{
- ndb_lg->setName(info->logfile_group_name);
- ndb_lg->setUndoBufferSize(info->undo_buffer_size);
- return false;
+ ndb_lg->setName(alter_info->logfile_group_name);
+ ndb_lg->setUndoBufferSize(alter_info->undo_buffer_size);
+ return FALSE;
}
-bool set_up_undofile(st_alter_tablespace *info,
+bool set_up_undofile(st_alter_tablespace *alter_info,
NdbDictionary::Undofile *ndb_uf)
{
- ndb_uf->setPath(info->undo_file_name);
- ndb_uf->setSize(info->initial_size);
- ndb_uf->setLogfileGroup(info->logfile_group_name);
- return false;
+ ndb_uf->setPath(alter_info->undo_file_name);
+ ndb_uf->setSize(alter_info->initial_size);
+ ndb_uf->setLogfileGroup(alter_info->logfile_group_name);
+ return FALSE;
}
-int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace *info)
+int ndbcluster_alter_tablespace(handlerton *hton,
+ THD* thd, st_alter_tablespace *alter_info)
{
+ int is_tablespace= 0;
+ NdbError err;
+ NDBDICT *dict;
+ int error;
+ const char *errmsg;
+ Ndb *ndb;
DBUG_ENTER("ha_ndbcluster::alter_tablespace");
+ LINT_INIT(errmsg);
- int is_tablespace= 0;
- Ndb *ndb= check_ndb_in_thd(thd);
+ ndb= check_ndb_in_thd(thd);
if (ndb == NULL)
{
DBUG_RETURN(HA_ERR_NO_CONNECTION);
}
+ dict= ndb->getDictionary();
- NdbError err;
- NDBDICT *dict= ndb->getDictionary();
- int error;
- const char * errmsg;
- LINT_INIT(errmsg);
-
- switch (info->ts_cmd_type){
+ switch (alter_info->ts_cmd_type){
case (CREATE_TABLESPACE):
{
error= ER_CREATE_FILEGROUP_FAILED;
@@ -10496,11 +9816,11 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
NdbDictionary::Tablespace ndb_ts;
NdbDictionary::Datafile ndb_df;
NdbDictionary::ObjectId objid;
- if (set_up_tablespace(info, &ndb_ts))
+ if (set_up_tablespace(alter_info, &ndb_ts))
{
DBUG_RETURN(1);
}
- if (set_up_datafile(info, &ndb_df))
+ if (set_up_datafile(alter_info, &ndb_df))
{
DBUG_RETURN(1);
}
@@ -10510,7 +9830,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
DBUG_PRINT("error", ("createTablespace returned %d", error));
goto ndberror;
}
- DBUG_PRINT("info", ("Successfully created Tablespace"));
+ DBUG_PRINT("alter_info", ("Successfully created Tablespace"));
errmsg= "DATAFILE";
if (dict->createDatafile(ndb_df))
{
@@ -10532,10 +9852,10 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
case (ALTER_TABLESPACE):
{
error= ER_ALTER_FILEGROUP_FAILED;
- if (info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
+ if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
{
NdbDictionary::Datafile ndb_df;
- if (set_up_datafile(info, &ndb_df))
+ if (set_up_datafile(alter_info, &ndb_df))
{
DBUG_RETURN(1);
}
@@ -10545,14 +9865,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
goto ndberror;
}
}
- else if(info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
+ else if(alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
{
- NdbDictionary::Tablespace ts= dict->getTablespace(info->tablespace_name);
- NdbDictionary::Datafile df= dict->getDatafile(0, info->data_file_name);
+ NdbDictionary::Tablespace ts= dict->getTablespace(alter_info->tablespace_name);
+ NdbDictionary::Datafile df= dict->getDatafile(0, alter_info->data_file_name);
NdbDictionary::ObjectId objid;
df.getTablespaceId(&objid);
if (ts.getObjectId() == objid.getObjectId() &&
- strcmp(df.getPath(), info->data_file_name) == 0)
+ strcmp(df.getPath(), alter_info->data_file_name) == 0)
{
errmsg= " DROP DATAFILE";
if (dict->dropDatafile(df))
@@ -10570,7 +9890,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
else
{
DBUG_PRINT("error", ("Unsupported alter tablespace: %d",
- info->ts_alter_tablespace_type));
+ alter_info->ts_alter_tablespace_type));
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
is_tablespace= 1;
@@ -10582,14 +9902,14 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
NdbDictionary::LogfileGroup ndb_lg;
NdbDictionary::Undofile ndb_uf;
NdbDictionary::ObjectId objid;
- if (info->undo_file_name == NULL)
+ if (alter_info->undo_file_name == NULL)
{
/*
REDO files in LOGFILE GROUP not supported yet
*/
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
- if (set_up_logfile_group(info, &ndb_lg))
+ if (set_up_logfile_group(alter_info, &ndb_lg))
{
DBUG_RETURN(1);
}
@@ -10598,8 +9918,8 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
goto ndberror;
}
- DBUG_PRINT("info", ("Successfully created Logfile Group"));
- if (set_up_undofile(info, &ndb_uf))
+ DBUG_PRINT("alter_info", ("Successfully created Logfile Group"));
+ if (set_up_undofile(alter_info, &ndb_uf))
{
DBUG_RETURN(1);
}
@@ -10621,7 +9941,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
case (ALTER_LOGFILE_GROUP):
{
error= ER_ALTER_FILEGROUP_FAILED;
- if (info->undo_file_name == NULL)
+ if (alter_info->undo_file_name == NULL)
{
/*
REDO files in LOGFILE GROUP not supported yet
@@ -10629,7 +9949,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
}
NdbDictionary::Undofile ndb_uf;
- if (set_up_undofile(info, &ndb_uf))
+ if (set_up_undofile(alter_info, &ndb_uf))
{
DBUG_RETURN(1);
}
@@ -10644,7 +9964,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
error= ER_DROP_FILEGROUP_FAILED;
errmsg= "TABLESPACE";
- if (dict->dropTablespace(dict->getTablespace(info->tablespace_name)))
+ if (dict->dropTablespace(dict->getTablespace(alter_info->tablespace_name)))
{
goto ndberror;
}
@@ -10655,7 +9975,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
{
error= ER_DROP_FILEGROUP_FAILED;
errmsg= "LOGFILE GROUP";
- if (dict->dropLogfileGroup(dict->getLogfileGroup(info->logfile_group_name)))
+ if (dict->dropLogfileGroup(dict->getLogfileGroup(alter_info->logfile_group_name)))
{
goto ndberror;
}
@@ -10678,13 +9998,13 @@ int ndbcluster_alter_tablespace(handlerton *hton, THD* thd, st_alter_tablespace
if (is_tablespace)
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
- "", info->tablespace_name,
+ "", alter_info->tablespace_name,
0, 0,
SOT_TABLESPACE, 0, 0, 0);
else
ndbcluster_log_schema_op(thd, 0,
thd->query, thd->query_length,
- "", info->logfile_group_name,
+ "", alter_info->logfile_group_name,
0, 0,
SOT_LOGFILE_GROUP, 0, 0, 0);
#endif
@@ -10705,7 +10025,6 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
{
Ndb *ndb;
NDBDICT *dict;
- const NDBTAB *tab;
int err;
DBUG_ENTER("ha_ndbcluster::get_no_parts");
LINT_INIT(err);
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index ed9e5ea41cc..a84ec66f399 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -38,11 +37,11 @@ class NdbOperation; // Forward declaration
class NdbTransaction; // Forward declaration
class NdbRecAttr; // Forward declaration
class NdbScanOperation;
-class NdbScanFilter;
class NdbIndexScanOperation;
class NdbBlob;
class NdbIndexStat;
class NdbEventOperation;
+class ha_ndbcluster_cond;
// connectstring to cluster if given by mysqld
extern const char *ndbcluster_connectstring;
@@ -85,7 +84,7 @@ typedef struct ndb_index_data {
typedef union { const NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue;
int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
- byte*& buffer, uint& buffer_size,
+ uchar*& buffer, uint& buffer_size,
my_ptrdiff_t ptrdiff);
typedef enum {
@@ -109,13 +108,14 @@ typedef struct st_ndbcluster_share {
char *table_name;
Ndb::TupleIdRange tuple_id_range;
#ifdef HAVE_NDB_BINLOG
+ uint32 connect_count;
uint32 flags;
NdbEventOperation *op;
NdbEventOperation *op_old; // for rename table
char *old_names; // for rename table
TABLE_SHARE *table_share;
TABLE *table;
- byte *record[2]; // pointer to allocated records for receiving data
+ uchar *record[2]; // pointer to allocated records for receiving data
NdbValue *ndb_value[2];
MY_BITMAP *subscriber_bitmap;
#endif
@@ -161,424 +161,6 @@ struct Ndb_tuple_id_range_guard {
#define NSF_NO_BINLOG 4 /* table should not be binlogged */
#endif
-typedef enum ndb_item_type {
- NDB_VALUE = 0, // Qualified more with Item::Type
- NDB_FIELD = 1, // Qualified from table definition
- NDB_FUNCTION = 2,// Qualified from Item_func::Functype
- NDB_END_COND = 3 // End marker for condition group
-} NDB_ITEM_TYPE;
-
-typedef enum ndb_func_type {
- NDB_EQ_FUNC = 0,
- NDB_NE_FUNC = 1,
- NDB_LT_FUNC = 2,
- NDB_LE_FUNC = 3,
- NDB_GT_FUNC = 4,
- NDB_GE_FUNC = 5,
- NDB_ISNULL_FUNC = 6,
- NDB_ISNOTNULL_FUNC = 7,
- NDB_LIKE_FUNC = 8,
- NDB_NOTLIKE_FUNC = 9,
- NDB_NOT_FUNC = 10,
- NDB_UNKNOWN_FUNC = 11,
- NDB_COND_AND_FUNC = 12,
- NDB_COND_OR_FUNC = 13,
- NDB_UNSUPPORTED_FUNC = 14
-} NDB_FUNC_TYPE;
-
-typedef union ndb_item_qualification {
- Item::Type value_type;
- enum_field_types field_type; // Instead of Item::FIELD_ITEM
- NDB_FUNC_TYPE function_type; // Instead of Item::FUNC_ITEM
-} NDB_ITEM_QUALIFICATION;
-
-typedef struct ndb_item_field_value {
- Field* field;
- int column_no;
-} NDB_ITEM_FIELD_VALUE;
-
-typedef union ndb_item_value {
- const Item *item;
- NDB_ITEM_FIELD_VALUE *field_value;
- uint arg_count;
-} NDB_ITEM_VALUE;
-
-struct negated_function_mapping
-{
- NDB_FUNC_TYPE pos_fun;
- NDB_FUNC_TYPE neg_fun;
-};
-
-
-/*
- Define what functions can be negated in condition pushdown.
- Note, these HAVE to be in the same order as in definition enum
-*/
-static const negated_function_mapping neg_map[]=
-{
- {NDB_EQ_FUNC, NDB_NE_FUNC},
- {NDB_NE_FUNC, NDB_EQ_FUNC},
- {NDB_LT_FUNC, NDB_GE_FUNC},
- {NDB_LE_FUNC, NDB_GT_FUNC},
- {NDB_GT_FUNC, NDB_LE_FUNC},
- {NDB_GE_FUNC, NDB_LT_FUNC},
- {NDB_ISNULL_FUNC, NDB_ISNOTNULL_FUNC},
- {NDB_ISNOTNULL_FUNC, NDB_ISNULL_FUNC},
- {NDB_LIKE_FUNC, NDB_NOTLIKE_FUNC},
- {NDB_NOTLIKE_FUNC, NDB_LIKE_FUNC},
- {NDB_NOT_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_UNKNOWN_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_COND_AND_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_COND_OR_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_UNSUPPORTED_FUNC, NDB_UNSUPPORTED_FUNC}
-};
-
-/*
- This class is the construction element for serialization of Item tree
- in condition pushdown.
- An instance of Ndb_Item represents a constant, table field reference,
- unary or binary comparison predicate, and start/end of AND/OR.
- Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
- class.
- The order of elements produced by Ndb_cond::next corresponds to
- breadth-first traversal of the Item (i.e. expression) tree in prefix order.
- AND and OR have arbitrary arity, so the end of AND/OR group is marked with
- Ndb_item with type == NDB_END_COND.
- NOT items represent negated conditions and generate NAND/NOR groups.
-*/
-class Ndb_item {
- public:
- Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
- Ndb_item(NDB_ITEM_TYPE item_type,
- NDB_ITEM_QUALIFICATION item_qualification,
- const Item *item_value)
- : type(item_type), qualification(item_qualification)
- {
- switch(item_type) {
- case(NDB_VALUE):
- value.item= item_value;
- break;
- case(NDB_FIELD): {
- NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
- Item_field *field_item= (Item_field *) item_value;
- field_value->field= field_item->field;
- field_value->column_no= -1; // Will be fetched at scan filter generation
- value.field_value= field_value;
- break;
- }
- case(NDB_FUNCTION):
- value.item= item_value;
- value.arg_count= ((Item_func *) item_value)->argument_count();
- break;
- case(NDB_END_COND):
- break;
- }
- };
- Ndb_item(Field *field, int column_no) : type(NDB_FIELD)
- {
- NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
- qualification.field_type= field->type();
- field_value->field= field;
- field_value->column_no= column_no;
- value.field_value= field_value;
- };
- Ndb_item(Item_func::Functype func_type, const Item *item_value)
- : type(NDB_FUNCTION)
- {
- qualification.function_type= item_func_to_ndb_func(func_type);
- value.item= item_value;
- value.arg_count= ((Item_func *) item_value)->argument_count();
- };
- Ndb_item(Item_func::Functype func_type, uint no_args)
- : type(NDB_FUNCTION)
- {
- qualification.function_type= item_func_to_ndb_func(func_type);
- value.arg_count= no_args;
- };
- ~Ndb_item()
- {
- if (type == NDB_FIELD)
- {
- delete value.field_value;
- value.field_value= NULL;
- }
- };
-
- uint32 pack_length()
- {
- switch(type) {
- case(NDB_VALUE):
- if(qualification.value_type == Item::STRING_ITEM)
- return value.item->str_value.length();
- break;
- case(NDB_FIELD):
- return value.field_value->field->pack_length();
- default:
- break;
- }
-
- return 0;
- };
-
- Field * get_field() { return value.field_value->field; };
-
- int get_field_no() { return value.field_value->column_no; };
-
- int argument_count()
- {
- return value.arg_count;
- };
-
- const char* get_val()
- {
- switch(type) {
- case(NDB_VALUE):
- if(qualification.value_type == Item::STRING_ITEM)
- return value.item->str_value.ptr();
- break;
- case(NDB_FIELD):
- return value.field_value->field->ptr;
- default:
- break;
- }
-
- return NULL;
- };
-
- void save_in_field(Ndb_item *field_item)
- {
- Field *field = field_item->value.field_value->field;
- const Item *item= value.item;
-
- if (item && field)
- {
- my_bitmap_map *old_map=
- dbug_tmp_use_all_columns(field->table, field->table->write_set);
- ((Item *)item)->save_in_field(field, FALSE);
- dbug_tmp_restore_column_map(field->table->write_set, old_map);
- }
- };
-
- static NDB_FUNC_TYPE item_func_to_ndb_func(Item_func::Functype fun)
- {
- switch (fun) {
- case (Item_func::EQ_FUNC): { return NDB_EQ_FUNC; }
- case (Item_func::NE_FUNC): { return NDB_NE_FUNC; }
- case (Item_func::LT_FUNC): { return NDB_LT_FUNC; }
- case (Item_func::LE_FUNC): { return NDB_LE_FUNC; }
- case (Item_func::GT_FUNC): { return NDB_GT_FUNC; }
- case (Item_func::GE_FUNC): { return NDB_GE_FUNC; }
- case (Item_func::ISNULL_FUNC): { return NDB_ISNULL_FUNC; }
- case (Item_func::ISNOTNULL_FUNC): { return NDB_ISNOTNULL_FUNC; }
- case (Item_func::LIKE_FUNC): { return NDB_LIKE_FUNC; }
- case (Item_func::NOT_FUNC): { return NDB_NOT_FUNC; }
- case (Item_func::UNKNOWN_FUNC): { return NDB_UNKNOWN_FUNC; }
- case (Item_func::COND_AND_FUNC): { return NDB_COND_AND_FUNC; }
- case (Item_func::COND_OR_FUNC): { return NDB_COND_OR_FUNC; }
- default: { return NDB_UNSUPPORTED_FUNC; }
- }
- };
-
- static NDB_FUNC_TYPE negate(NDB_FUNC_TYPE fun)
- {
- uint i= (uint) fun;
- DBUG_ASSERT(fun == neg_map[i].pos_fun);
- return neg_map[i].neg_fun;
- };
-
- NDB_ITEM_TYPE type;
- NDB_ITEM_QUALIFICATION qualification;
- private:
- NDB_ITEM_VALUE value;
-};
-
-/*
- This class implements a linked list used for storing a
- serialization of the Item tree for condition pushdown.
- */
-class Ndb_cond
-{
- public:
- Ndb_cond() : ndb_item(NULL), next(NULL), prev(NULL) {};
- ~Ndb_cond()
- {
- if (ndb_item) delete ndb_item;
- ndb_item= NULL;
- if (next) delete next;
- next= prev= NULL;
- };
- Ndb_item *ndb_item;
- Ndb_cond *next;
- Ndb_cond *prev;
-};
-
-/*
- This class implements a stack for storing several conditions
- for pushdown (represented as serialized Item trees using Ndb_cond).
- The current implementation only pushes one condition, but is
- prepared for handling several (C1 AND C2 ...) if the logic for
- pushing conditions is extended in sql_select.
-*/
-class Ndb_cond_stack
-{
- public:
- Ndb_cond_stack() : ndb_cond(NULL), next(NULL) {};
- ~Ndb_cond_stack()
- {
- if (ndb_cond) delete ndb_cond;
- ndb_cond= NULL;
- if (next) delete next;
- next= NULL;
- };
- Ndb_cond *ndb_cond;
- Ndb_cond_stack *next;
-};
-
-class Ndb_rewrite_context
-{
-public:
- Ndb_rewrite_context(Item_func *func)
- : func_item(func), left_hand_item(NULL), count(0) {};
- ~Ndb_rewrite_context()
- {
- if (next) delete next;
- }
- const Item_func *func_item;
- const Item *left_hand_item;
- uint count;
- Ndb_rewrite_context *next;
-};
-
-/*
- This class is used for storing the context when traversing
- the Item tree. It stores a reference to the table the condition
- is defined on, the serialized representation being generated,
- if the condition found is supported, and information what is
- expected next in the tree inorder for the condition to be supported.
-*/
-class Ndb_cond_traverse_context
-{
- public:
- Ndb_cond_traverse_context(TABLE *tab, void* ndb_tab, Ndb_cond_stack* stack)
- : table(tab), ndb_table(ndb_tab),
- supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
- skip(0), collation(NULL), rewrite_stack(NULL)
- {
- // Allocate type checking bitmaps
- bitmap_init(&expect_mask, 0, 512, FALSE);
- bitmap_init(&expect_field_type_mask, 0, 512, FALSE);
- bitmap_init(&expect_field_result_mask, 0, 512, FALSE);
-
- if (stack)
- cond_ptr= stack->ndb_cond;
- };
- ~Ndb_cond_traverse_context()
- {
- bitmap_free(&expect_mask);
- bitmap_free(&expect_field_type_mask);
- bitmap_free(&expect_field_result_mask);
- if (rewrite_stack) delete rewrite_stack;
- }
- void expect(Item::Type type)
- {
- bitmap_set_bit(&expect_mask, (uint) type);
- if (type == Item::FIELD_ITEM) expect_all_field_types();
- };
- void dont_expect(Item::Type type)
- {
- bitmap_clear_bit(&expect_mask, (uint) type);
- };
- bool expecting(Item::Type type)
- {
- return bitmap_is_set(&expect_mask, (uint) type);
- };
- void expect_nothing()
- {
- bitmap_clear_all(&expect_mask);
- };
- bool expecting_nothing()
- {
- return bitmap_is_clear_all(&expect_mask);
- }
- void expect_only(Item::Type type)
- {
- expect_nothing();
- expect(type);
- };
-
- void expect_field_type(enum_field_types type)
- {
- bitmap_set_bit(&expect_field_type_mask, (uint) type);
- };
- void expect_all_field_types()
- {
- bitmap_set_all(&expect_field_type_mask);
- };
- bool expecting_field_type(enum_field_types type)
- {
- return bitmap_is_set(&expect_field_type_mask, (uint) type);
- };
- void expect_no_field_type()
- {
- bitmap_clear_all(&expect_field_type_mask);
- };
- bool expecting_no_field_type()
- {
- return bitmap_is_clear_all(&expect_field_type_mask);
- }
- void expect_only_field_type(enum_field_types result)
- {
- expect_no_field_type();
- expect_field_type(result);
- };
-
- void expect_field_result(Item_result result)
- {
- bitmap_set_bit(&expect_field_result_mask, (uint) result);
- };
- bool expecting_field_result(Item_result result)
- {
- return bitmap_is_set(&expect_field_result_mask, (uint) result);
- };
- void expect_no_field_result()
- {
- bitmap_clear_all(&expect_field_result_mask);
- };
- bool expecting_no_field_result()
- {
- return bitmap_is_clear_all(&expect_field_result_mask);
- }
- void expect_only_field_result(Item_result result)
- {
- expect_no_field_result();
- expect_field_result(result);
- };
- void expect_collation(CHARSET_INFO* col)
- {
- collation= col;
- };
- bool expecting_collation(CHARSET_INFO* col)
- {
- bool matching= (!collation) ? true : (collation == col);
- collation= NULL;
-
- return matching;
- };
-
- TABLE* table;
- void* ndb_table;
- bool supported;
- Ndb_cond_stack* stack_ptr;
- Ndb_cond* cond_ptr;
- MY_BITMAP expect_mask;
- MY_BITMAP expect_field_type_mask;
- MY_BITMAP expect_field_result_mask;
- uint skip;
- CHARSET_INFO* collation;
- Ndb_rewrite_context *rewrite_stack;
-};
-
-
typedef enum ndb_query_state_bits {
NDB_QUERY_NORMAL = 0,
NDB_QUERY_MULTI_READ_RANGE = 1
@@ -593,6 +175,11 @@ enum THD_NDB_OPTIONS
TNO_NO_LOG_SCHEMA_OP= 1 << 0
};
+enum THD_NDB_TRANS_OPTIONS
+{
+ TNTO_INJECTED_APPLY_STATUS= 1 << 0
+};
+
struct Ndb_local_table_statistics {
int no_uncommitted_rows_count;
ulong last_count;
@@ -618,8 +205,10 @@ class Thd_ndb
uint lock_count;
NdbTransaction *all;
NdbTransaction *stmt;
- int error;
+ bool m_error;
+ bool m_slow_path;
uint32 options;
+ uint32 trans_options;
List<NDB_SHARE> changed_tables;
uint query_state;
HASH open_tables;
@@ -635,32 +224,30 @@ class ha_ndbcluster: public handler
int open(const char *name, int mode, uint test_if_locked);
int close(void);
- int write_row(byte *buf);
- int update_row(const byte *old_data, byte *new_data);
- int delete_row(const byte *buf);
+ int write_row(uchar *buf);
+ int update_row(const uchar *old_data, uchar *new_data);
+ int delete_row(const uchar *buf);
int index_init(uint index, bool sorted);
int index_end();
- int index_read(byte *buf, const byte *key, uint key_len,
+ int index_read(uchar *buf, const uchar *key, uint key_len,
enum ha_rkey_function find_flag);
- int index_read_idx(byte *buf, uint index, const byte *key, uint key_len,
- enum ha_rkey_function find_flag);
- int index_next(byte *buf);
- int index_prev(byte *buf);
- int index_first(byte *buf);
- int index_last(byte *buf);
- int index_read_last(byte * buf, const byte * key, uint key_len);
+ int index_next(uchar *buf);
+ int index_prev(uchar *buf);
+ int index_first(uchar *buf);
+ int index_last(uchar *buf);
+ int index_read_last(uchar * buf, const uchar * key, uint key_len);
int rnd_init(bool scan);
int rnd_end();
- int rnd_next(byte *buf);
- int rnd_pos(byte *buf, byte *pos);
- void position(const byte *record);
+ int rnd_next(uchar *buf);
+ int rnd_pos(uchar *buf, uchar *pos);
+ void position(const uchar *record);
int read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted);
int read_range_first_to_buf(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted,
- byte* buf);
+ uchar* buf);
int read_range_next();
int alter_tablespace(st_alter_tablespace *info);
@@ -677,6 +264,8 @@ class ha_ndbcluster: public handler
bool get_error_message(int error, String *buf);
ha_rows records();
+ ha_rows estimate_rows_upper_bound()
+ { return HA_POS_ERROR; }
int info(uint);
void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id);
int extra(enum ha_extra_function operation);
@@ -824,59 +413,59 @@ private:
uint set_up_partition_info(partition_info *part_info,
TABLE *table,
void *tab);
- char* get_tablespace_name(THD *thd);
+ char* get_tablespace_name(THD *thd, char *name, uint name_len);
int set_range_data(void *tab, partition_info* part_info);
int set_list_data(void *tab, partition_info* part_info);
- int complemented_read(const byte *old_data, byte *new_data,
+ int complemented_read(const uchar *old_data, uchar *new_data,
uint32 old_part_id);
- int pk_read(const byte *key, uint key_len, byte *buf, uint32 part_id);
+ int pk_read(const uchar *key, uint key_len, uchar *buf, uint32 part_id);
int ordered_index_scan(const key_range *start_key,
const key_range *end_key,
- bool sorted, bool descending, byte* buf,
+ bool sorted, bool descending, uchar* buf,
part_id_range *part_spec);
- int unique_index_read(const byte *key, uint key_len,
- byte *buf);
+ int unique_index_read(const uchar *key, uint key_len,
+ uchar *buf);
int unique_index_scan(const KEY* key_info,
- const byte *key,
+ const uchar *key,
uint key_len,
- byte *buf);
- int full_table_scan(byte * buf);
+ uchar *buf);
+ int full_table_scan(uchar * buf);
bool check_all_operations_for_error(NdbTransaction *trans,
const NdbOperation *first,
const NdbOperation *last,
uint errcode);
- int peek_indexed_rows(const byte *record, bool check_pk);
+ int peek_indexed_rows(const uchar *record, bool check_pk);
int fetch_next(NdbScanOperation* op);
- int next_result(byte *buf);
- int define_read_attrs(byte* buf, NdbOperation* op);
- int filtered_scan(const byte *key, uint key_len,
- byte *buf,
+ int next_result(uchar *buf);
+ int define_read_attrs(uchar* buf, NdbOperation* op);
+ int filtered_scan(const uchar *key, uint key_len,
+ uchar *buf,
enum ha_rkey_function find_flag);
int close_scan();
- void unpack_record(byte *buf);
+ void unpack_record(uchar *buf);
int get_ndb_lock_type(enum thr_lock_type type);
void set_dbname(const char *pathname);
void set_tabname(const char *pathname);
bool set_hidden_key(NdbOperation*,
- uint fieldnr, const byte* field_ptr);
+ uint fieldnr, const uchar* field_ptr);
int set_ndb_key(NdbOperation*, Field *field,
- uint fieldnr, const byte* field_ptr);
+ uint fieldnr, const uchar* field_ptr);
int set_ndb_value(NdbOperation*, Field *field, uint fieldnr,
int row_offset= 0, bool *set_blob_value= 0);
- int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, byte*);
+ int get_ndb_value(NdbOperation*, Field *field, uint fieldnr, uchar*);
int get_ndb_partition_id(NdbOperation *);
friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
- int set_primary_key(NdbOperation *op, const byte *key);
- int set_primary_key_from_record(NdbOperation *op, const byte *record);
- int set_index_key_from_record(NdbOperation *op, const byte *record,
+ int set_primary_key(NdbOperation *op, const uchar *key);
+ int set_primary_key_from_record(NdbOperation *op, const uchar *record);
+ int set_index_key_from_record(NdbOperation *op, const uchar *record,
uint keyno);
int set_bounds(NdbIndexScanOperation*, uint inx, bool rir,
const key_range *keys[2], uint= 0);
- int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
- int set_index_key(NdbOperation *, const KEY *key_info, const byte *key_ptr);
+ int key_cmp(uint keynr, const uchar * old_row, const uchar * new_row);
+ int set_index_key(NdbOperation *, const KEY *key_info, const uchar *key_ptr);
void print_results();
virtual void get_auto_increment(ulonglong offset, ulonglong increment,
@@ -899,27 +488,6 @@ private:
void release_completed_operations(NdbTransaction*, bool);
- /*
- Condition pushdown
- */
- void cond_clear();
- bool serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond);
- int build_scan_filter_predicate(Ndb_cond* &cond,
- NdbScanFilter* filter,
- bool negated= false);
- int build_scan_filter_group(Ndb_cond* &cond,
- NdbScanFilter* filter);
- int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
- int generate_scan_filter(Ndb_cond_stack* cond_stack,
- NdbScanOperation* op);
- int generate_scan_filter_from_cond(Ndb_cond_stack* cond_stack,
- NdbScanFilter& filter);
- int generate_scan_filter_from_key(NdbScanOperation* op,
- const KEY* key_info,
- const byte *key,
- uint key_len,
- byte *buf);
-
friend int execute_commit(ha_ndbcluster*, NdbTransaction*);
friend int execute_no_commit_ignore_no_key(ha_ndbcluster*, NdbTransaction*);
friend int execute_no_commit(ha_ndbcluster*, NdbTransaction*, bool);
@@ -940,10 +508,10 @@ private:
THD_NDB_SHARE *m_thd_ndb_share;
// NdbRecAttr has no reference to blob
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
- byte m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH];
+ uchar m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH];
partition_info *m_part_info;
uint32 m_part_id;
- byte *m_rec0;
+ uchar *m_rec0;
Field **m_part_field_array;
bool m_use_partition_function;
bool m_sorted;
@@ -958,12 +526,15 @@ private:
ha_rows m_bulk_insert_rows;
ha_rows m_rows_changed;
bool m_bulk_insert_not_flushed;
+ bool m_delete_cannot_batch;
+ bool m_update_cannot_batch;
ha_rows m_ops_pending;
bool m_skip_auto_increment;
bool m_blobs_pending;
+ bool m_slow_path;
my_ptrdiff_t m_blobs_offset;
// memory for blobs in one tuple
- char *m_blobs_buffer;
+ uchar *m_blobs_buffer;
uint32 m_blobs_buffer_size;
uint m_dupkey;
// set from thread variables at external lock
@@ -972,14 +543,14 @@ private:
ha_rows m_autoincrement_prefetch;
bool m_transaction_on;
- Ndb_cond_stack *m_cond_stack;
+ ha_ndbcluster_cond *m_cond;
bool m_disable_multi_read;
- byte *m_multi_range_result_ptr;
+ uchar *m_multi_range_result_ptr;
KEY_MULTI_RANGE *m_multi_ranges;
KEY_MULTI_RANGE *m_multi_range_defined;
const NdbOperation *m_current_multi_operation;
NdbIndexScanOperation *m_multi_cursor;
- byte *m_multi_range_cursor_result_ptr;
+ uchar *m_multi_range_cursor_result_ptr;
int setup_recattr(const NdbRecAttr*);
Ndb *get_ndb();
};
@@ -996,4 +567,6 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op);
static const char ndbcluster_hton_name[]= "ndbcluster";
static const int ndbcluster_hton_name_length=sizeof(ndbcluster_hton_name)-1;
-
+extern int ndbcluster_terminating;
+extern int ndb_util_thread_running;
+extern pthread_cond_t COND_ndb_util_ready;
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 490114bf4a9..391051d8775 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -81,6 +80,9 @@ THD *injector_thd= 0;
static Ndb *injector_ndb= 0;
static Ndb *schema_ndb= 0;
+static int ndbcluster_binlog_inited= 0;
+static int ndbcluster_binlog_terminating= 0;
+
/*
Mutex and condition used for interacting between client sql thread
and injector thread
@@ -96,6 +98,7 @@ static ulonglong ndb_latest_received_binlog_epoch= 0;
NDB_SHARE *ndb_apply_status_share= 0;
NDB_SHARE *ndb_schema_share= 0;
+pthread_mutex_t ndb_schema_share_mutex;
/* Schema object distribution handling */
HASH ndb_schema_objects;
@@ -127,14 +130,14 @@ static TABLE_LIST binlog_tables;
#ifndef DBUG_OFF
/* purecov: begin deadcode */
-static void print_records(TABLE *table, const char *record)
+static void print_records(TABLE *table, const uchar *record)
{
for (uint j= 0; j < table->s->fields; j++)
{
char buf[40];
int pos= 0;
Field *field= table->field[j];
- const byte* field_ptr= field->ptr - table->record[0] + record;
+ const uchar* field_ptr= field->ptr - table->record[0] + record;
int pack_len= field->pack_length();
int n= pack_len < 10 ? pack_len : 10;
@@ -193,14 +196,14 @@ static void dbug_print_table(const char *info, TABLE *table)
(long) f->ptr, (int) (f->ptr - table->record[0]),
f->null_bit,
(long) f->null_ptr,
- (int) ((byte*) f->null_ptr - table->record[0])));
+ (int) ((uchar*) f->null_ptr - table->record[0])));
if (f->type() == MYSQL_TYPE_BIT)
{
Field_bit *g= (Field_bit*) f;
DBUG_PRINT("MYSQL_TYPE_BIT",("field_length: %d bit_ptr: 0x%lx[+%d] "
"bit_ofs: %d bit_len: %u",
g->field_length, (long) g->bit_ptr,
- (int) ((byte*) g->bit_ptr -
+ (int) ((uchar*) g->bit_ptr -
table->record[0]),
g->bit_ofs, g->bit_len));
}
@@ -227,6 +230,7 @@ static void run_query(THD *thd, char *buf, char *end,
ulonglong save_thd_options= thd->options;
DBUG_ASSERT(sizeof(save_thd_options) == sizeof(thd->options));
NET save_net= thd->net;
+ const char* found_semicolon= NULL;
bzero((char*) &thd->net, sizeof(NET));
thd->query_length= end - buf;
@@ -236,7 +240,7 @@ static void run_query(THD *thd, char *buf, char *end,
thd->options&= ~OPTION_BIN_LOG;
DBUG_PRINT("query", ("%s", thd->query));
- mysql_parse(thd, thd->query, thd->query_length);
+ mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
if (print_error && thd->query_error)
{
@@ -360,6 +364,8 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
int do_event_op= ndb_binlog_running;
DBUG_ENTER("ndbcluster_binlog_init_share");
+ share->connect_count= g_ndb_cluster_connection->get_connect_count();
+
share->op= 0;
share->table= 0;
@@ -367,6 +373,10 @@ void ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table)
strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
do_event_op= 1;
+ else if (!ndb_apply_status_share &&
+ strcmp(share->db, NDB_REP_DB) == 0 &&
+ strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
+ do_event_op= 1;
{
int i, no_nodes= g_ndb_cluster_connection->no_db_nodes();
@@ -491,7 +501,7 @@ static int ndbcluster_reset_logs(THD *thd)
static int
ndbcluster_binlog_index_purge_file(THD *thd, const char *file)
{
- if (!ndb_binlog_running)
+ if (!ndb_binlog_running || thd->slave_thread)
return 0;
DBUG_ENTER("ndbcluster_binlog_index_purge_file");
@@ -558,67 +568,54 @@ ndbcluster_binlog_log_query(handlerton *hton, THD *thd, enum_binlog_command binl
DBUG_VOID_RETURN;
}
+
/*
- End use of the NDB Cluster table handler
- - free all global variables allocated by
- ndbcluster_init()
+ End use of the NDB Cluster binlog
+ - wait for binlog thread to shutdown
*/
static int ndbcluster_binlog_end(THD *thd)
{
- DBUG_ENTER("ndb_binlog_end");
+ DBUG_ENTER("ndbcluster_binlog_end");
- if (!ndbcluster_util_inited)
+ if (!ndbcluster_binlog_inited)
DBUG_RETURN(0);
-
- // Kill ndb utility thread
- (void) pthread_mutex_lock(&LOCK_ndb_util_thread);
- DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread));
- (void) pthread_cond_signal(&COND_ndb_util_thread);
- (void) pthread_mutex_unlock(&LOCK_ndb_util_thread);
+ ndbcluster_binlog_inited= 0;
#ifdef HAVE_NDB_BINLOG
- /* wait for injector thread to finish */
- if (ndb_binlog_thread_running > 0)
+ if (ndb_util_thread_running > 0)
{
- pthread_mutex_lock(&injector_mutex);
- while (ndb_binlog_thread_running > 0)
- {
- struct timespec abstime;
- set_timespec(abstime, 1);
- pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
- }
- pthread_mutex_unlock(&injector_mutex);
+ /*
+ Wait for util thread to die (as this uses the injector mutex)
+ There is a very small change that ndb_util_thread dies and the
+ following mutex is freed before it's accessed. This shouldn't
+ however be a likely case as the ndbcluster_binlog_end is supposed to
+ be called before ndb_cluster_end().
+ */
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ /* Ensure mutex are not freed if ndb_cluster_end is running at same time */
+ ndb_util_thread_running++;
+ ndbcluster_terminating= 1;
+ pthread_cond_signal(&COND_ndb_util_thread);
+ while (ndb_util_thread_running > 1)
+ pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
+ ndb_util_thread_running--;
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
}
- /* remove all shares */
- {
- pthread_mutex_lock(&ndbcluster_mutex);
- for (uint i= 0; i < ndbcluster_open_tables.records; i++)
- {
- NDB_SHARE *share=
- (NDB_SHARE*) hash_element(&ndbcluster_open_tables, i);
- if (share->table)
- DBUG_PRINT("share",
- ("table->s->db.table_name: %s.%s",
- share->table->s->db.str, share->table->s->table_name.str));
- if (share->state != NSS_DROPPED && !--share->use_count)
- real_free_share(&share);
- else
- {
- DBUG_PRINT("share",
- ("[%d] 0x%lx key: %s key_length: %d",
- i, (long) share, share->key, share->key_length));
- DBUG_PRINT("share",
- ("db.tablename: %s.%s use_count: %d commit_count: %lu",
- share->db, share->table_name,
- share->use_count, (long) share->commit_count));
- }
- }
- pthread_mutex_unlock(&ndbcluster_mutex);
- }
+ /* wait for injector thread to finish */
+ ndbcluster_binlog_terminating= 1;
+ pthread_mutex_lock(&injector_mutex);
+ pthread_cond_signal(&injector_cond);
+ while (ndb_binlog_thread_running > 0)
+ pthread_cond_wait(&injector_cond, &injector_mutex);
+ pthread_mutex_unlock(&injector_mutex);
+
+ pthread_mutex_destroy(&injector_mutex);
+ pthread_cond_destroy(&injector_cond);
+ pthread_mutex_destroy(&ndb_schema_share_mutex);
#endif
- ndbcluster_util_inited= 0;
+
DBUG_RETURN(0);
}
@@ -686,7 +683,7 @@ static NDB_SHARE *ndbcluster_check_ndb_apply_status_share()
pthread_mutex_lock(&ndbcluster_mutex);
void *share= hash_search(&ndbcluster_open_tables,
- NDB_APPLY_TABLE_FILE,
+ (uchar*) NDB_APPLY_TABLE_FILE,
sizeof(NDB_APPLY_TABLE_FILE) - 1);
DBUG_PRINT("info",("ndbcluster_check_ndb_apply_status_share %s 0x%lx",
NDB_APPLY_TABLE_FILE, (long) share));
@@ -704,7 +701,7 @@ static NDB_SHARE *ndbcluster_check_ndb_schema_share()
pthread_mutex_lock(&ndbcluster_mutex);
void *share= hash_search(&ndbcluster_open_tables,
- NDB_SCHEMA_TABLE_FILE,
+ (uchar*) NDB_SCHEMA_TABLE_FILE,
sizeof(NDB_SCHEMA_TABLE_FILE) - 1);
DBUG_PRINT("info",("ndbcluster_check_ndb_schema_share %s 0x%lx",
NDB_SCHEMA_TABLE_FILE, (long) share));
@@ -753,6 +750,9 @@ static int ndbcluster_create_ndb_apply_status_table(THD *thd)
NDB_REP_DB "." NDB_APPLY_TABLE
" ( server_id INT UNSIGNED NOT NULL,"
" epoch BIGINT UNSIGNED NOT NULL, "
+ " log_name VARCHAR(255) BINARY NOT NULL, "
+ " start_pos BIGINT UNSIGNED NOT NULL, "
+ " end_pos BIGINT UNSIGNED NOT NULL, "
" PRIMARY KEY USING HASH (server_id) ) ENGINE=NDB");
run_query(thd, buf, end, TRUE, TRUE);
@@ -893,6 +893,7 @@ struct Cluster_schema
uint32 id;
uint32 version;
uint32 type;
+ uint32 any_value;
};
/*
@@ -904,7 +905,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
TABLE *table= share->table;
Field **field;
/* unpack blob values */
- byte* blobs_buffer= 0;
+ uchar* blobs_buffer= 0;
uint blobs_buffer_size= 0;
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
{
@@ -919,14 +920,14 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
DBUG_ASSERT(FALSE);
}
}
- /* db varchar 1 length byte */
+ /* db varchar 1 length uchar */
field= table->field;
s->db_length= *(uint8*)(*field)->ptr;
DBUG_ASSERT(s->db_length <= (*field)->field_length);
DBUG_ASSERT((*field)->field_length + 1 == sizeof(s->db));
memcpy(s->db, (*field)->ptr + 1, s->db_length);
s->db[s->db_length]= 0;
- /* name varchar 1 length byte */
+ /* name varchar 1 length uchar */
field++;
s->name_length= *(uint8*)(*field)->ptr;
DBUG_ASSERT(s->name_length <= (*field)->field_length);
@@ -943,13 +944,11 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
{
Field_blob *field_blob= (Field_blob*)(*field);
uint blob_len= field_blob->get_length((*field)->ptr);
- char *blob_ptr= 0;
+ uchar *blob_ptr= 0;
field_blob->get_ptr(&blob_ptr);
assert(blob_len == 0 || blob_ptr != 0);
s->query_length= blob_len;
- s->query= sql_alloc(blob_len+1);
- memcpy(s->query, blob_ptr, blob_len);
- s->query[blob_len]= 0;
+ s->query= sql_strmake((char*) blob_ptr, blob_len);
}
/* node_id */
field++;
@@ -974,8 +973,8 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
/*
helper function to pack a ndb varchar
*/
-static char *ndb_pack_varchar(const NDBCOL *col, char *buf,
- const char *str, int sz)
+char *ndb_pack_varchar(const NDBCOL *col, char *buf,
+ const char *str, int sz)
{
switch (col->getArrayType())
{
@@ -1021,6 +1020,7 @@ ndbcluster_update_slock(THD *thd,
const NDBTAB *ndbtab= ndbtab_g.get_table();
NdbTransaction *trans= 0;
int retries= 100;
+ int retry_sleep= 10; /* 10 milliseconds, transaction */
const NDBCOL *col[SCHEMA_SIZE];
unsigned sz[SCHEMA_SIZE];
@@ -1122,13 +1122,14 @@ ndbcluster_update_slock(THD *thd,
{
if (trans)
ndb->closeTransaction(trans);
+ my_sleep(retry_sleep);
continue; // retry
}
}
ndb_error= this_error;
break;
}
-end:
+
if (ndb_error)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
@@ -1268,6 +1269,16 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes();
bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE);
bitmap_set_all(&schema_subscribers);
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ if (ndb_schema_share == 0)
+ {
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ if (ndb_schema_object)
+ ndb_free_schema_object(&ndb_schema_object, FALSE);
+ DBUG_RETURN(0);
+ }
(void) pthread_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
@@ -1280,6 +1291,9 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
}
}
(void) pthread_mutex_unlock(&ndb_schema_share->mutex);
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
+
if (updated)
{
bitmap_clear_bit(&schema_subscribers, node_id);
@@ -1303,7 +1317,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
(void) pthread_mutex_unlock(&ndb_schema_object->mutex);
}
- DBUG_DUMP("schema_subscribers", (char*)schema_subscribers.bitmap,
+ DBUG_DUMP("schema_subscribers", (uchar*)schema_subscribers.bitmap,
no_bytes_in_map(&schema_subscribers));
DBUG_PRINT("info", ("bitmap_is_clear_all(&schema_subscribers): %d",
bitmap_is_clear_all(&schema_subscribers)));
@@ -1320,6 +1334,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
const NDBTAB *ndbtab= ndbtab_g.get_table();
NdbTransaction *trans= 0;
int retries= 100;
+ int retry_sleep= 10; /* 10 milliseconds, transaction */
const NDBCOL *col[SCHEMA_SIZE];
unsigned sz[SCHEMA_SIZE];
@@ -1400,6 +1415,12 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
/* type */
r|= op->setValue(SCHEMA_TYPE_I, log_type);
DBUG_ASSERT(r == 0);
+ /* any value */
+ if (!(thd->options & OPTION_BIN_LOG))
+ r|= op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
+ else
+ r|= op->setAnyValue(thd->server_id);
+ DBUG_ASSERT(r == 0);
if (log_db != new_db && new_db && new_table_name)
{
log_db= new_db;
@@ -1424,6 +1445,7 @@ err:
{
if (trans)
ndb->closeTransaction(trans);
+ my_sleep(retry_sleep);
continue; // retry
}
}
@@ -1475,6 +1497,14 @@ end:
&abstime);
if (thd->killed)
break;
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ if (ndb_schema_share == 0)
+ {
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ break;
+ }
(void) pthread_mutex_lock(&ndb_schema_share->mutex);
for (i= 0; i < no_storage_nodes; i++)
{
@@ -1484,12 +1514,14 @@ end:
bitmap_intersect(&schema_subscribers, tmp);
}
(void) pthread_mutex_unlock(&ndb_schema_share->mutex);
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
/* remove any unsubscribed from ndb_schema_object->slock */
bitmap_intersect(&ndb_schema_object->slock_bitmap, &schema_subscribers);
DBUG_DUMP("ndb_schema_object->slock_bitmap.bitmap",
- (char*)ndb_schema_object->slock_bitmap.bitmap,
+ (uchar*)ndb_schema_object->slock_bitmap.bitmap,
no_bytes_in_map(&ndb_schema_object->slock_bitmap));
if (bitmap_is_clear_all(&ndb_schema_object->slock_bitmap))
@@ -1574,8 +1606,8 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
{
const char *tabname= table_share->table_name.str;
char key[FN_REFLEN];
- const void *data= 0, *pack_data= 0;
- uint length, pack_length;
+ uchar *data= 0, *pack_data= 0;
+ size_t length, pack_length;
int error;
NDBDICT *dict= ndb->getDictionary();
const NDBTAB *altered_table= pOp->getTable();
@@ -1593,7 +1625,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
packfrm(data, length, &pack_data, &pack_length) == 0 &&
cmp_frm(altered_table, pack_data, pack_length))
{
- DBUG_DUMP("frm", (char*)altered_table->getFrmData(),
+ DBUG_DUMP("frm", (uchar*) altered_table->getFrmData(),
altered_table->getFrmLength());
pthread_mutex_lock(&LOCK_open);
Ndb_table_guard ndbtab_g(dict, tabname);
@@ -1604,7 +1636,8 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
data= NULL;
- if ((error= unpackfrm(&data, &length, altered_table->getFrmData())) ||
+ if ((error= unpackfrm(&data, &length,
+ (const uchar*) altered_table->getFrmData())) ||
(error= writefrm(key, data, length)))
{
sql_print_information("NDB: Failed write frm for %s.%s, error %d",
@@ -1686,15 +1719,25 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
(void) pthread_cond_signal(&injector_cond);
pthread_mutex_lock(&ndbcluster_mutex);
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
if (is_remote_change && share && share->state != NSS_DROPPED)
{
DBUG_PRINT("info", ("remote change"));
share->state= NSS_DROPPED;
if (share->use_count != 1)
+ {
+ /* open handler holding reference */
+ /* wait with freeing create ndb_share to below */
do_close_cached_tables= TRUE;
+ }
else
{
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share, TRUE);
share= 0;
}
@@ -1717,11 +1760,39 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
table_list.db= (char *)dbname;
table_list.alias= table_list.table_name= (char *)tabname;
close_cached_tables(thd, 0, &table_list);
+ /* ndb_share reference create free */
+ DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
}
DBUG_RETURN(0);
}
+static void ndb_binlog_query(THD *thd, Cluster_schema *schema)
+{
+ if (schema->any_value & NDB_ANYVALUE_RESERVED)
+ {
+ if (schema->any_value != NDB_ANYVALUE_FOR_NOLOGGING)
+ sql_print_warning("NDB: unknown value for binlog signalling 0x%X, "
+ "query not logged",
+ schema->any_value);
+ return;
+ }
+ uint32 thd_server_id_save= thd->server_id;
+ DBUG_ASSERT(sizeof(thd_server_id_save) == sizeof(thd->server_id));
+ char *thd_db_save= thd->db;
+ if (schema->any_value == 0)
+ thd->server_id= ::server_id;
+ else
+ thd->server_id= schema->any_value;
+ thd->db= schema->db;
+ thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
+ schema->query_length, FALSE,
+ schema->name[0] == 0 || thd->db[0] == 0);
+ thd->server_id= thd_server_id_save;
+ thd->db= thd_db_save;
+}
+
static int
ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
NdbEventOperation *pOp,
@@ -1746,7 +1817,10 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
MY_BITMAP slock;
bitmap_init(&slock, schema->slock, 8*SCHEMA_SLOCK_SIZE, FALSE);
uint node_id= g_ndb_cluster_connection->node_id();
- ndbcluster_get_schema(tmp_share, schema);
+ {
+ ndbcluster_get_schema(tmp_share, schema);
+ schema->any_value= pOp->getAnyValue();
+ }
enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
DBUG_PRINT("info",
("%s.%s: log query_length: %d query: '%s' type: %d",
@@ -1784,7 +1858,13 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
char key[FN_REFLEN];
build_table_filename(key, sizeof(key),
schema->db, schema->name, "", 0);
+ /* ndb_share reference temporary, free below */
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
// invalidation already handled by binlog thread
if (!share || !share->op)
{
@@ -1800,24 +1880,29 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
table_list.alias= table_list.table_name= schema->name;
close_cached_tables(thd, 0, &table_list, FALSE);
}
+ /* ndb_share reference temporary free */
if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
+ }
}
// fall through
case SOT_CREATE_TABLE:
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
- sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
+ sql_print_error("NDB Binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
{
- sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
+ sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
"binlog schema event '%s' from node %d. "
"my_errno: %d",
schema->db, schema->name, schema->query,
@@ -1825,33 +1910,33 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
MYSQL_ERROR *err;
while ((err= it++))
- sql_print_warning("NDB binlog: (%d)%s", err->code, err->msg);
+ sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
}
pthread_mutex_unlock(&LOCK_open);
log_query= 1;
break;
case SOT_DROP_DB:
- /* Drop the database locally if it only contains ndb tables */
- if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
- {
- run_query(thd, schema->query,
- schema->query + schema->query_length,
- TRUE, /* print error */
- TRUE); /* don't binlog the query */
- /* binlog dropping database after any table operations */
- post_epoch_log_list->push_back(schema, mem_root);
- /* acknowledge this query _after_ epoch completion */
- post_epoch_unlock= 1;
- }
- else
- {
- /* Database contained local tables, leave it */
- sql_print_error("NDB binlog: Skipping drop database '%s' since it contained local tables "
+ /* Drop the database locally if it only contains ndb tables */
+ if (! ndbcluster_check_if_local_tables_in_db(thd, schema->db))
+ {
+ run_query(thd, schema->query,
+ schema->query + schema->query_length,
+ TRUE, /* print error */
+ TRUE); /* don't binlog the query */
+ /* binlog dropping database after any table operations */
+ post_epoch_log_list->push_back(schema, mem_root);
+ /* acknowledge this query _after_ epoch completion */
+ post_epoch_unlock= 1;
+ }
+ else
+ {
+ /* Database contained local tables, leave it */
+ sql_print_error("NDB Binlog: Skipping drop database '%s' since it contained local tables "
"binlog schema event '%s' from node %d. ",
schema->db, schema->query,
schema->node_id);
- log_query= 1;
- }
+ log_query= 1;
+ }
break;
case SOT_CREATE_DB:
/* fall through */
@@ -1859,7 +1944,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
run_query(thd, schema->query,
schema->query + schema->query_length,
TRUE, /* print error */
- FALSE); /* binlog the query */
+ TRUE); /* don't binlog the query */
+ log_query= 1;
break;
case SOT_TABLESPACE:
case SOT_LOGFILE_GROUP:
@@ -1869,16 +1955,9 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
abort();
}
if (log_query && ndb_binlog_running)
- {
- char *thd_db_save= thd->db;
- thd->db= schema->db;
- thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
- schema->query_length, FALSE,
- schema->name[0] == 0 || thd->db[0] == 0);
- thd->db= thd_db_save;
- }
+ ndb_binlog_query(thd, schema);
/* signal that schema operation has been handled */
- DBUG_DUMP("slock", (char*)schema->slock, schema->slock_length);
+ DBUG_DUMP("slock", (uchar*) schema->slock, schema->slock_length);
if (bitmap_is_set(&slock, node_id))
{
if (post_epoch_unlock)
@@ -1907,8 +1986,18 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_schema_share->key,
+ ndb_schema_share->use_count));
free_share(&ndb_schema_share);
ndb_schema_share= 0;
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
+
close_cached_tables((THD*) 0, 0, (TABLE_LIST*) 0, FALSE);
// fall through
case NDBEVENT::TE_ALTER:
@@ -2015,14 +2104,14 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
pthread_mutex_lock(&ndbcluster_mutex);
NDB_SCHEMA_OBJECT *ndb_schema_object=
(NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
- (byte*) key, strlen(key));
+ (uchar*) key, strlen(key));
if (ndb_schema_object)
{
pthread_mutex_lock(&ndb_schema_object->mutex);
memcpy(ndb_schema_object->slock, schema->slock,
sizeof(ndb_schema_object->slock));
DBUG_DUMP("ndb_schema_object->slock_bitmap.bitmap",
- (char*)ndb_schema_object->slock_bitmap.bitmap,
+ (uchar*)ndb_schema_object->slock_bitmap.bitmap,
no_bytes_in_map(&ndb_schema_object->slock_bitmap));
pthread_mutex_unlock(&ndb_schema_object->mutex);
pthread_cond_signal(&injector_cond);
@@ -2030,17 +2119,23 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
pthread_mutex_unlock(&ndbcluster_mutex);
continue;
}
+ /* ndb_share reference temporary, free below */
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
+ if (share)
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
+ share->key, share->use_count));
+ }
switch (schema_type)
{
case SOT_DROP_DB:
log_query= 1;
break;
case SOT_DROP_TABLE:
+ log_query= 1;
// invalidation already handled by binlog thread
if (share && share->op)
{
- log_query= 1;
break;
}
// fall through
@@ -2075,29 +2170,32 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
*/
if (share)
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
share= 0;
}
pthread_mutex_lock(&LOCK_open);
- if (ndbcluster_check_if_local_table(schema->db, schema->name))
- {
- DBUG_PRINT("info", ("NDB binlog: Skipping locally defined table '%s.%s'",
- schema->db, schema->name));
- sql_print_error("NDB binlog: Skipping locally defined table '%s.%s' from "
+ if (ndbcluster_check_if_local_table(schema->db, schema->name))
+ {
+ DBUG_PRINT("info", ("NDB Binlog: Skipping locally defined table '%s.%s'",
+ schema->db, schema->name));
+ sql_print_error("NDB Binlog: Skipping locally defined table '%s.%s' from "
"binlog schema event '%s' from node %d. ",
schema->db, schema->name, schema->query,
schema->node_id);
- }
+ }
else if (ndb_create_table_from_engine(thd, schema->db, schema->name))
- {
- sql_print_error("NDB binlog: Could not discover table '%s.%s' from "
+ {
+ sql_print_error("NDB Binlog: Could not discover table '%s.%s' from "
"binlog schema event '%s' from node %d. my_errno: %d",
schema->db, schema->name, schema->query,
schema->node_id, my_errno);
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
MYSQL_ERROR *err;
while ((err= it++))
- sql_print_warning("NDB binlog: (%d)%s", err->code, err->msg);
+ sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
}
pthread_mutex_unlock(&LOCK_open);
}
@@ -2107,19 +2205,15 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
}
if (share)
{
+ /* ndb_share reference temporary free */
+ DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
share= 0;
}
}
if (ndb_binlog_running && log_query)
- {
- char *thd_db_save= thd->db;
- thd->db= schema->db;
- thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
- schema->query_length, FALSE,
- schema->name[0] == 0);
- thd->db= thd_db_save;
- }
+ ndb_binlog_query(thd, schema);
}
while ((schema= post_epoch_unlock_list->pop()))
{
@@ -2215,7 +2309,7 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
{
TABLE_LIST *p_binlog_tables= &binlog_tables;
close_tables_for_reopen(thd, &p_binlog_tables);
- ndb_binlog_index= 0;
+ ndb_binlog_index= 0;
continue;
}
sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
@@ -2225,9 +2319,11 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row)
break;
}
- // Set all fields non-null.
- if(ndb_binlog_index->s->null_bytes > 0)
- bzero(ndb_binlog_index->record[0], ndb_binlog_index->s->null_bytes);
+ /*
+ Intialize ndb_binlog_index->record[0]
+ */
+ empty_record(ndb_binlog_index);
+
ndb_binlog_index->field[0]->store(row.master_log_pos);
ndb_binlog_index->field[1]->store(row.master_log_file,
strlen(row.master_log_file),
@@ -2273,8 +2369,21 @@ int ndbcluster_binlog_start()
{
DBUG_ENTER("ndbcluster_binlog_start");
+ if (::server_id == 0)
+ {
+ sql_print_warning("NDB: server id set to zero will cause any other mysqld "
+ "with bin log to log with wrong server id");
+ }
+ else if (::server_id & 0x1 << 31)
+ {
+ sql_print_error("NDB: server id's with high bit set is reserved for internal "
+ "purposes");
+ DBUG_RETURN(-1);
+ }
+
pthread_mutex_init(&injector_mutex, MY_MUTEX_INIT_FAST);
pthread_cond_init(&injector_cond, NULL);
+ pthread_mutex_init(&ndb_schema_share_mutex, MY_MUTEX_INIT_FAST);
/* Create injector thread */
if (pthread_create(&ndb_binlog_thread, &connection_attrib,
@@ -2286,31 +2395,20 @@ int ndbcluster_binlog_start()
DBUG_RETURN(-1);
}
- /*
- Wait for the ndb injector thread to finish starting up.
- */
+ ndbcluster_binlog_inited= 1;
+
+ /* Wait for the injector thread to start */
pthread_mutex_lock(&injector_mutex);
while (!ndb_binlog_thread_running)
pthread_cond_wait(&injector_cond, &injector_mutex);
pthread_mutex_unlock(&injector_mutex);
-
+
if (ndb_binlog_thread_running < 0)
DBUG_RETURN(-1);
DBUG_RETURN(0);
}
-static void ndbcluster_binlog_close_connection(THD *thd)
-{
- DBUG_ENTER("ndbcluster_binlog_close_connection");
- const char *save_info= thd->proc_info;
- thd->proc_info= "ndbcluster_binlog_close_connection";
- do_ndbcluster_binlog_close_connection= BCCC_exit;
- while (ndb_binlog_thread_running > 0)
- sleep(1);
- thd->proc_info= save_info;
- DBUG_VOID_RETURN;
-}
/**************************************************************
Internal helper functions for creating/dropping ndb events
@@ -2397,7 +2495,7 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
/* Handle any trailing share */
NDB_SHARE *share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
- (byte*) key, key_len);
+ (uchar*) key, key_len);
if (share && share_may_exist)
{
@@ -2418,20 +2516,42 @@ int ndbcluster_create_binlog_setup(Ndb *ndb, const char *key,
pthread_mutex_unlock(&ndbcluster_mutex);
DBUG_RETURN(1);
}
- handle_trailing_share(share);
+ if (!share_may_exist || share->connect_count !=
+ g_ndb_cluster_connection->get_connect_count())
+ {
+ handle_trailing_share(share);
+ share= NULL;
+ }
}
/* Create share which is needed to hold replication information */
- if (!(share= get_share(key, 0, TRUE, TRUE)))
+ if (share)
+ {
+ /* ndb_share reference create */
+ ++share->use_count;
+ DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u",
+ share->key, share->use_count));
+ }
+ /* ndb_share reference create */
+ else if (!(share= get_share(key, 0, TRUE, TRUE)))
{
sql_print_error("NDB Binlog: "
"allocating table share for %s failed", key);
}
+ else
+ {
+ DBUG_PRINT("NDB_SHARE", ("%s create use_count: %u",
+ share->key, share->use_count));
+ }
if (!ndb_schema_share &&
strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
do_event_op= 1;
+ else if (!ndb_apply_status_share &&
+ strcmp(share->db, NDB_REP_DB) == 0 &&
+ strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
+ do_event_op= 1;
if (!do_event_op)
{
@@ -2703,7 +2823,7 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
else if (!ndb_apply_status_share && strcmp(share->db, NDB_REP_DB) == 0 &&
strcmp(share->table_name, NDB_APPLY_TABLE) == 0)
do_ndb_apply_status_share= 1;
- else if (!binlog_filter->db_ok(share->db))
+ else if (!binlog_filter->db_ok(share->db) || !ndb_binlog_running)
{
share->flags|= NSF_NO_BINLOG;
DBUG_RETURN(0);
@@ -2715,6 +2835,9 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
DBUG_ASSERT(share->use_count > 1);
sql_print_error("NDB Binlog: discover reusing old ev op");
+ /* ndb_share reference ToDo free */
+ DBUG_PRINT("NDB_SHARE", ("%s ToDo free use_count: %u",
+ share->key, share->use_count));
free_share(&share); // old event op already has reference
DBUG_RETURN(0);
}
@@ -2722,6 +2845,11 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
TABLE *table= share->table;
int retries= 100;
+ /*
+ 100 milliseconds, temporary error on schema operation can
+ take some time to be resolved
+ */
+ int retry_sleep= 100;
while (1)
{
pthread_mutex_lock(&injector_mutex);
@@ -2778,10 +2906,10 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
if (is_ndb_compatible_type(f))
{
DBUG_PRINT("info", ("%s compatible", col_name));
- attr0.rec= op->getValue(col_name, f->ptr);
+ attr0.rec= op->getValue(col_name, (char*) f->ptr);
attr1.rec= op->getPreValue(col_name,
- (f->ptr - share->table->record[0]) +
- share->table->record[1]);
+ (f->ptr - share->table->record[0]) +
+ (char*) share->table->record[1]);
}
else if (! (f->flags & BLOB_FLAG))
{
@@ -2850,22 +2978,34 @@ ndbcluster_create_event_ops(NDB_SHARE *share, const NDBTAB *ndbtab,
ndb->dropEventOperation(op);
pthread_mutex_unlock(&injector_mutex);
if (retries)
+ {
+ my_sleep(retry_sleep);
continue;
+ }
DBUG_RETURN(-1);
}
pthread_mutex_unlock(&injector_mutex);
break;
}
+ /* ndb_share reference binlog */
get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog use_count: %u",
+ share->key, share->use_count));
if (do_ndb_apply_status_share)
{
+ /* ndb_share reference binlog extra */
ndb_apply_status_share= get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
+ share->key, share->use_count));
(void) pthread_cond_signal(&injector_cond);
}
else if (do_ndb_schema_share)
{
+ /* ndb_share reference binlog extra */
ndb_schema_share= get_share(share);
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra use_count: %u",
+ share->key, share->use_count));
(void) pthread_cond_signal(&injector_cond);
}
@@ -3052,6 +3192,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ share->key, share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
@@ -3068,6 +3211,9 @@ ndb_binlog_thread_handle_non_data_event(THD *thd, Ndb *ndb,
ndb_binlog_tables_inited && ndb_binlog_running)
sql_print_information("NDB Binlog: ndb tables initially "
"read only on reconnect.");
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ share->key, share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
@@ -3111,8 +3257,20 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
NDB_SHARE *share= (NDB_SHARE*) pOp->getCustomData();
if (share == ndb_apply_status_share)
return 0;
- TABLE *table= share->table;
+ uint32 originating_server_id= pOp->getAnyValue();
+ if (originating_server_id == 0)
+ originating_server_id= ::server_id;
+ else if (originating_server_id & NDB_ANYVALUE_RESERVED)
+ {
+ if (originating_server_id != NDB_ANYVALUE_FOR_NOLOGGING)
+ sql_print_warning("NDB: unknown value for binlog signalling 0x%X, "
+ "event not logged",
+ originating_server_id);
+ return 0;
+ }
+
+ TABLE *table= share->table;
DBUG_ASSERT(trans.good());
DBUG_ASSERT(table != 0);
@@ -3137,7 +3295,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
for now malloc/free blobs buffer each time
TODO if possible share single permanent buffer with handlers
*/
- byte* blobs_buffer[2] = { 0, 0 };
+ uchar* blobs_buffer[2] = { 0, 0 };
uint blobs_buffer_size[2] = { 0, 0 };
switch(pOp->getEventType())
@@ -3150,15 +3308,17 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0], &b, table->record[0]);
- int ret= trans.write_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[0]);
+ IF_DBUG(int ret=) trans.write_row(originating_server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[0]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3176,27 +3336,29 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
n= 0; /*
use the primary key only as it save time and space and
it is the only thing needed to log the delete
- */
+ */
else
n= 1; /*
we use the before values since we don't have a primary key
since the mysql server does not handle the hidden primary
key
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[n] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[n],
- blobs_buffer[n], blobs_buffer_size[n],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[n],
+ blobs_buffer[n],
+ blobs_buffer_size[n],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[n], &b, table->record[n]);
DBUG_EXECUTE("info", print_records(table, table->record[n]););
- int ret= trans.delete_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields, table->record[n]);
+ IF_DBUG(int ret =) trans.delete_row(originating_server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields, table->record[n]);
DBUG_ASSERT(ret == 0);
}
break;
@@ -3208,9 +3370,10 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= 0;
- int ret= get_ndb_blobs_value(table, share->ndb_value[0],
- blobs_buffer[0], blobs_buffer_size[0],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[0],
+ blobs_buffer[0],
+ blobs_buffer_size[0],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[0],
@@ -3221,8 +3384,9 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
since table has a primary key, we can do a write
using only after values
- */
- trans.write_row(::server_id, injector::transaction::table(table, TRUE),
+ */
+ trans.write_row(originating_server_id,
+ injector::transaction::table(table, TRUE),
&b, n_fields, table->record[0]);// after values
}
else
@@ -3230,22 +3394,24 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp,
/*
mysql server cannot handle the ndb hidden key and
therefore needs the before image as well
- */
+ */
if (share->flags & NSF_BLOB_FLAG)
{
my_ptrdiff_t ptrdiff= table->record[1] - table->record[0];
- int ret= get_ndb_blobs_value(table, share->ndb_value[1],
- blobs_buffer[1], blobs_buffer_size[1],
- ptrdiff);
+ IF_DBUG(int ret =) get_ndb_blobs_value(table, share->ndb_value[1],
+ blobs_buffer[1],
+ blobs_buffer_size[1],
+ ptrdiff);
DBUG_ASSERT(ret == 0);
}
ndb_unpack_record(table, share->ndb_value[1], &b, table->record[1]);
DBUG_EXECUTE("info", print_records(table, table->record[1]););
- int ret= trans.update_row(::server_id,
- injector::transaction::table(table, TRUE),
- &b, n_fields,
- table->record[1], // before values
- table->record[0]);// after values
+ IF_DBUG(int ret =) trans.update_row(originating_server_id,
+ injector::transaction::table(table,
+ TRUE),
+ &b, n_fields,
+ table->record[1], // before values
+ table->record[0]);// after values
DBUG_ASSERT(ret == 0);
}
}
@@ -3289,11 +3455,13 @@ private:
Injector thread main loop
****************************************************************/
-static byte *ndb_schema_objects_get_key(NDB_SCHEMA_OBJECT *schema_object, uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar *
+ndb_schema_objects_get_key(NDB_SCHEMA_OBJECT *schema_object,
+ size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= schema_object->key_length;
- return (byte*) schema_object->key;
+ return (uchar*) schema_object->key;
}
static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
@@ -3309,7 +3477,7 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
pthread_mutex_lock(&ndbcluster_mutex);
while (!(ndb_schema_object=
(NDB_SCHEMA_OBJECT*) hash_search(&ndb_schema_objects,
- (byte*) key,
+ (uchar*) key,
length)))
{
if (!create_if_not_exists)
@@ -3327,9 +3495,9 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key,
ndb_schema_object->key= (char *)(ndb_schema_object+1);
memcpy(ndb_schema_object->key, key, length + 1);
ndb_schema_object->key_length= length;
- if (my_hash_insert(&ndb_schema_objects, (byte*) ndb_schema_object))
+ if (my_hash_insert(&ndb_schema_objects, (uchar*) ndb_schema_object))
{
- my_free((gptr) ndb_schema_object, 0);
+ my_free((uchar*) ndb_schema_object, 0);
break;
}
pthread_mutex_init(&ndb_schema_object->mutex, MY_MUTEX_INIT_FAST);
@@ -3359,9 +3527,9 @@ static void ndb_free_schema_object(NDB_SCHEMA_OBJECT **ndb_schema_object,
if (!--(*ndb_schema_object)->use_count)
{
DBUG_PRINT("info", ("use_count: %d", (*ndb_schema_object)->use_count));
- hash_delete(&ndb_schema_objects, (byte*) *ndb_schema_object);
+ hash_delete(&ndb_schema_objects, (uchar*) *ndb_schema_object);
pthread_mutex_destroy(&(*ndb_schema_object)->mutex);
- my_free((gptr) *ndb_schema_object, MYF(0));
+ my_free((uchar*) *ndb_schema_object, MYF(0));
*ndb_schema_object= 0;
}
else
@@ -3421,7 +3589,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
thd->command= COM_DAEMON;
thd->system_thread= SYSTEM_THREAD_NDBCLUSTER_BINLOG;
thd->version= refresh_version;
- thd->set_time();
thd->main_security_ctx.host_or_ip= "";
thd->client_capabilities= 0;
my_net_init(&thd->net, 0);
@@ -3444,6 +3611,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
s_ndb->init())
{
sql_print_error("NDB Binlog: Getting Schema Ndb object failed");
+ ndb_binlog_thread_running= -1;
+ pthread_mutex_unlock(&injector_mutex);
+ pthread_cond_signal(&injector_cond);
goto err;
}
@@ -3474,7 +3644,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
p_latest_trans_gci=
injector_ndb->get_ndb_cluster_connection().get_latest_trans_gci();
schema_ndb= s_ndb;
- ndb_binlog_thread_running= 1;
+
if (opt_bin_log)
{
if (global_system_variables.binlog_format == BINLOG_FORMAT_ROW ||
@@ -3487,10 +3657,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
sql_print_error("NDB: only row based binary logging is supported");
}
}
- /*
- We signal the thread that started us that we've finished
- starting up.
- */
+
+ /* Thread start up completed */
+ ndb_binlog_thread_running= 1;
pthread_mutex_unlock(&injector_mutex);
pthread_cond_signal(&injector_cond);
@@ -3499,6 +3668,14 @@ restart:
Main NDB Injector loop
*/
{
+ /*
+ Always insert a GAP event as we cannot know what has happened in the cluster
+ while not being connected.
+ */
+ LEX_STRING const msg= { C_STRING_WITH_LEN("Cluster connect") };
+ inj->record_incident(thd, INCIDENT_LOST_EVENTS, msg);
+ }
+ {
thd->proc_info= "Waiting for ndbcluster to start";
pthread_mutex_lock(&injector_mutex);
@@ -3509,7 +3686,7 @@ restart:
struct timespec abstime;
set_timespec(abstime, 1);
pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
- if (abort_loop)
+ if (ndbcluster_binlog_terminating)
{
pthread_mutex_unlock(&injector_mutex);
goto err;
@@ -3534,21 +3711,23 @@ restart:
{
// wait for the first event
thd->proc_info= "Waiting for first event from ndbcluster";
- DBUG_PRINT("info", ("Waiting for the first event"));
int schema_res, res;
Uint64 schema_gci;
do
{
- if (abort_loop)
+ DBUG_PRINT("info", ("Waiting for the first event"));
+
+ if (ndbcluster_binlog_terminating)
goto err;
+
schema_res= s_ndb->pollEvents(100, &schema_gci);
- } while (ndb_latest_received_binlog_epoch == schema_gci);
+ } while (schema_gci == 0 || ndb_latest_received_binlog_epoch == schema_gci);
if (ndb_binlog_running)
{
Uint64 gci= i_ndb->getLatestGCI();
while (gci < schema_gci || gci == ndb_latest_received_binlog_epoch)
{
- if (abort_loop)
+ if (ndbcluster_binlog_terminating)
goto err;
res= i_ndb->pollEvents(10, &gci);
}
@@ -3595,7 +3774,8 @@ restart:
thd->db= db;
}
do_ndbcluster_binlog_close_connection= BCCC_running;
- for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) &&
+ for ( ; !((ndbcluster_binlog_terminating ||
+ do_ndbcluster_binlog_close_connection) &&
ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci) &&
do_ndbcluster_binlog_close_connection != BCCC_restart; )
{
@@ -3630,6 +3810,17 @@ restart:
res= i_ndb->pollEvents(tot_poll_wait, &gci);
tot_poll_wait= 0;
}
+ else
+ {
+ /*
+ Just consume any events, not used if no binlogging
+ e.g. node failure events
+ */
+ Uint64 tmp_gci;
+ if (i_ndb->pollEvents(0, &tmp_gci))
+ while (i_ndb->nextEvent())
+ ;
+ }
int schema_res= s_ndb->pollEvents(tot_poll_wait, &schema_gci);
ndb_latest_received_binlog_epoch= gci;
@@ -3642,7 +3833,8 @@ restart:
schema_res= s_ndb->pollEvents(10, &schema_gci);
}
- if ((abort_loop || do_ndbcluster_binlog_close_connection) &&
+ if ((ndbcluster_binlog_terminating ||
+ do_ndbcluster_binlog_close_connection) &&
(ndb_latest_handled_binlog_epoch >= *p_latest_trans_gci ||
!ndb_binlog_running))
break; /* Shutting down server */
@@ -3769,13 +3961,15 @@ restart:
continue;
}
TABLE *table= share->table;
+#ifndef DBUG_OFF
const LEX_STRING &name= table->s->table_name;
+#endif
if ((event_types & (NdbDictionary::Event::TE_INSERT |
NdbDictionary::Event::TE_UPDATE |
NdbDictionary::Event::TE_DELETE)) == 0)
{
DBUG_PRINT("info", ("skipping non data event table: %.*s",
- name.length, name.str));
+ (int) name.length, name.str));
continue;
}
if (!trans.good())
@@ -3784,9 +3978,10 @@ restart:
("Found new data event, initializing transaction"));
inj->new_trans(thd, &trans);
}
- DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
+ DBUG_PRINT("info", ("use_table: %.*s",
+ (int) name.length, name.str));
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
}
}
@@ -3796,17 +3991,25 @@ restart:
{
TABLE *table= ndb_apply_status_share->table;
- const LEX_STRING& name=table->s->table_name;
- DBUG_PRINT("info", ("use_table: %.*s", name.length, name.str));
+#ifndef DBUG_OFF
+ const LEX_STRING& name= table->s->table_name;
+ DBUG_PRINT("info", ("use_table: %.*s",
+ (int) name.length, name.str));
+#endif
injector::transaction::table tbl(table, TRUE);
- int ret= trans.use_table(::server_id, tbl);
+ IF_DBUG(int ret=) trans.use_table(::server_id, tbl);
DBUG_ASSERT(ret == 0);
- // Set all fields non-null.
- if(table->s->null_bytes > 0)
- bzero(table->record[0], table->s->null_bytes);
+ /*
+ Intialize table->record[0]
+ */
+ empty_record(table);
+
table->field[0]->store((longlong)::server_id);
table->field[1]->store((longlong)gci);
+ table->field[2]->store("", 0, &my_charset_bin);
+ table->field[3]->store((longlong)0);
+ table->field[4]->store((longlong)0);
trans.write_row(::server_id,
injector::transaction::table(table, TRUE),
&table->s->all_set, table->s->fields,
@@ -3864,7 +4067,7 @@ restart:
else
{
// set injector_ndb database/schema from table internal name
- int ret=
+ IF_DBUG(int ret=)
i_ndb->setDatabaseAndSchemaName(pOp->getEvent()->getTable());
DBUG_ASSERT(ret == 0);
ndb_binlog_thread_handle_non_data_event(thd, i_ndb, pOp, row);
@@ -3898,7 +4101,7 @@ restart:
/*
note! pOp is not referring to an event in the next epoch
or is == 0
- */
+ */
#ifdef RUN_NDB_BINLOG_TIMER
write_timer.stop();
#endif
@@ -3910,7 +4113,7 @@ restart:
injector::transaction::binlog_pos start= trans.start_pos();
if (int r= trans.commit())
{
- sql_print_error("NDB binlog: "
+ sql_print_error("NDB Binlog: "
"Error during COMMIT of GCI. Error: %d",
r);
/* TODO: Further handling? */
@@ -3931,9 +4134,9 @@ restart:
"%ld(%d e/s), total time %ld(%d e/s)",
(ulong)gci, event_count,
write_timer.elapsed_ms(),
- event_count / write_timer.elapsed_ms(),
+ (1000*event_count) / write_timer.elapsed_ms(),
gci_timer.elapsed_ms(),
- event_count / gci_timer.elapsed_ms());
+ (1000*event_count) / gci_timer.elapsed_ms());
#endif
}
}
@@ -3953,15 +4156,12 @@ restart:
goto restart;
}
err:
+ sql_print_information("Stopping Cluster Binlog");
DBUG_PRINT("info",("Shutting down cluster binlog thread"));
thd->proc_info= "Shutting down";
close_thread_tables(thd);
pthread_mutex_lock(&injector_mutex);
/* don't mess with the injector_ndb anymore from other threads */
- uint ndb_obj_cnt= 1; // g_ndb
- ndb_obj_cnt+= injector_ndb == 0 ? 0 : 1;
- ndb_obj_cnt+= schema_ndb == 0 ? 0 : 1;
- ndb_obj_cnt+= ndbcluster_util_inited ? 1 : 0;
injector_thd= 0;
injector_ndb= 0;
p_latest_trans_gci= 0;
@@ -3969,38 +4169,27 @@ err:
pthread_mutex_unlock(&injector_mutex);
thd->db= 0; // as not to try to free memory
- if (!ndb_extra_logging)
- sql_print_information("Stopping Cluster Binlog");
- else
- sql_print_information("Stopping Cluster Binlog: %u(%u)",
- g_ndb_cluster_connection->get_active_ndb_objects(),
- ndb_obj_cnt);
-
- /**
- * Add extra wait loop to make user "user" ndb-object go away...
- * otherwise user thread can have ongoing SUB_DATA
- */
- int sleep_cnt= 0;
- while (sleep_cnt < 300 &&
- g_ndb_cluster_connection->get_active_ndb_objects() > ndb_obj_cnt)
- {
- my_sleep(10000); // 10ms
- sleep_cnt++;
- }
- if (ndb_extra_logging)
- sql_print_information("Stopping Cluster Binlog: waited %ums %u(%u)",
- 10*sleep_cnt, g_ndb_cluster_connection->get_active_ndb_objects(),
- ndb_obj_cnt);
-
if (ndb_apply_status_share)
{
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_apply_status_share->key,
+ ndb_apply_status_share->use_count));
free_share(&ndb_apply_status_share);
ndb_apply_status_share= 0;
}
if (ndb_schema_share)
{
+ /* begin protect ndb_schema_share */
+ pthread_mutex_lock(&ndb_schema_share_mutex);
+ /* ndb_share reference binlog extra free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog extra free use_count: %u",
+ ndb_schema_share->key,
+ ndb_schema_share->use_count));
free_share(&ndb_schema_share);
ndb_schema_share= 0;
+ pthread_mutex_unlock(&ndb_schema_share_mutex);
+ /* end protect ndb_schema_share */
}
/* remove all event operations */
@@ -4018,6 +4207,9 @@ err:
DBUG_ASSERT(share->op == op ||
share->op_old == op);
share->op= share->op_old= 0;
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
s_ndb->dropEventOperation(op);
}
@@ -4038,6 +4230,9 @@ err:
DBUG_ASSERT(share->op == op ||
share->op_old == op);
share->op= share->op_old= 0;
+ /* ndb_share reference binlog free */
+ DBUG_PRINT("NDB_SHARE", ("%s binlog free use_count: %u",
+ share->key, share->use_count));
free_share(&share);
i_ndb->dropEventOperation(op);
}
@@ -4047,8 +4242,8 @@ err:
hash_free(&ndb_schema_objects);
- // Placed here to avoid a memory leak; TODO: check if needed
net_end(&thd->net);
+ thd->cleanup();
delete thd;
ndb_binlog_thread_running= -1;
diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h
index 18b94bb8f2a..b5b8d0d9745 100644
--- a/sql/ha_ndbcluster_binlog.h
+++ b/sql/ha_ndbcluster_binlog.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -31,6 +30,10 @@ extern ulong ndb_extra_logging;
#define NDB_INVALID_SCHEMA_OBJECT 241
+/* server id's with high bit set is reservered */
+#define NDB_ANYVALUE_FOR_NOLOGGING 0xFFFFFFFF
+#define NDB_ANYVALUE_RESERVED 0x80000000
+
extern handlerton *ndbcluster_hton;
/*
@@ -181,7 +184,9 @@ int ndbcluster_find_all_files(THD *thd);
#endif /* HAVE_NDB_BINLOG */
void ndb_unpack_record(TABLE *table, NdbValue *value,
- MY_BITMAP *defined, byte *buf);
+ MY_BITMAP *defined, uchar *buf);
+char *ndb_pack_varchar(const NDBCOL *col, char *buf,
+ const char *str, int sz);
NDB_SHARE *ndbcluster_get_share(const char *key,
TABLE *table,
@@ -209,11 +214,6 @@ inline void free_share(NDB_SHARE **share, bool have_lock= FALSE)
ndbcluster_free_share(share, have_lock);
}
-inline void real_free_share(NDB_SHARE **share)
-{
- ndbcluster_real_free_share(share);
-}
-
inline
Thd_ndb *
get_thd_ndb(THD *thd) { return (Thd_ndb *) thd->ha_data[ndbcluster_hton->slot]; }
diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc
new file mode 100644
index 00000000000..c686e83504c
--- /dev/null
+++ b/sql/ha_ndbcluster_cond.cc
@@ -0,0 +1,1426 @@
+/* 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; version 2 of the License.
+
+ 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 the NDB Cluster handler engine_condition_pushdown
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
+#include <ndbapi/NdbApi.hpp>
+#include "ha_ndbcluster_cond.h"
+
+// Typedefs for long names
+typedef NdbDictionary::Column NDBCOL;
+typedef NdbDictionary::Table NDBTAB;
+
+/*
+ Serialize the item tree into a linked list represented by Ndb_cond
+ for fast generation of NbdScanFilter. Adds information such as
+ position of fields that is not directly available in the Item tree.
+ Also checks if condition is supported.
+*/
+void ndb_serialize_cond(const Item *item, void *arg)
+{
+ Ndb_cond_traverse_context *context= (Ndb_cond_traverse_context *) arg;
+ DBUG_ENTER("ndb_serialize_cond");
+
+ // Check if we are skipping arguments to a function to be evaluated
+ if (context->skip)
+ {
+ DBUG_PRINT("info", ("Skiping argument %d", context->skip));
+ context->skip--;
+ switch (item->type()) {
+ case Item::FUNC_ITEM:
+ {
+ Item_func *func_item= (Item_func *) item;
+ context->skip+= func_item->argument_count();
+ break;
+ }
+ case Item::INT_ITEM:
+ case Item::REAL_ITEM:
+ case Item::STRING_ITEM:
+ case Item::VARBIN_ITEM:
+ case Item::DECIMAL_ITEM:
+ break;
+ default:
+ context->supported= FALSE;
+ break;
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ if (context->supported)
+ {
+ Ndb_rewrite_context *rewrite_context2= context->rewrite_stack;
+ const Item_func *rewrite_func_item;
+ // Check if we are rewriting some unsupported function call
+ if (rewrite_context2 &&
+ (rewrite_func_item= rewrite_context2->func_item) &&
+ rewrite_context2->count++ == 0)
+ {
+ switch (rewrite_func_item->functype()) {
+ case Item_func::BETWEEN:
+ /*
+ Rewrite
+ <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
+ to <field>|<const> > <const1>|<field1> AND
+ <field>|<const> < <const2>|<field2>
+ or actually in prefix format
+ BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
+ LT(<field>|<const>, <const2>|<field2>), END()
+ */
+ case Item_func::IN_FUNC:
+ {
+ /*
+ Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
+ to <field>|<const> = <const1>|<field1> OR
+ <field> = <const2>|<field2> ...
+ or actually in prefix format
+ BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
+ EQ(<field>|<const>, <const2>|<field2>), ... END()
+ Each part of the disjunction is added for each call
+ to ndb_serialize_cond and end of rewrite statement
+ is wrapped in end of ndb_serialize_cond
+ */
+ if (context->expecting(item->type()))
+ {
+ // This is the <field>|<const> item, save it in the rewrite context
+ rewrite_context2->left_hand_item= item;
+ if (item->type() == Item::FUNC_ITEM)
+ {
+ Item_func *func_item= (Item_func *) item;
+ if (func_item->functype() == Item_func::UNKNOWN_FUNC &&
+ func_item->const_item())
+ {
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN"));
+ context->supported= FALSE;
+ DBUG_VOID_RETURN;
+
+ }
+ }
+ }
+ else
+ {
+ // Non-supported BETWEEN|IN expression
+ DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN",
+ item->type()));
+ context->supported= FALSE;
+ DBUG_VOID_RETURN;
+ }
+ break;
+ }
+ default:
+ context->supported= FALSE;
+ break;
+ }
+ DBUG_VOID_RETURN;
+ }
+ else
+ {
+ Ndb_cond_stack *ndb_stack= context->stack_ptr;
+ Ndb_cond *prev_cond= context->cond_ptr;
+ Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond();
+ if (!ndb_stack->ndb_cond)
+ ndb_stack->ndb_cond= curr_cond;
+ curr_cond->prev= prev_cond;
+ if (prev_cond) prev_cond->next= curr_cond;
+ // Check if we are rewriting some unsupported function call
+ if (context->rewrite_stack)
+ {
+ Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
+ const Item_func *func_item= rewrite_context->func_item;
+ switch (func_item->functype()) {
+ case Item_func::BETWEEN:
+ {
+ /*
+ Rewrite
+ <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
+ to <field>|<const> > <const1>|<field1> AND
+ <field>|<const> < <const2>|<field2>
+ or actually in prefix format
+ BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
+ LT(<field>|<const>, <const2>|<field2>), END()
+ */
+ if (rewrite_context->count == 2)
+ {
+ // Lower limit of BETWEEN
+ DBUG_PRINT("info", ("GE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::GE_FUNC, 2);
+ }
+ else if (rewrite_context->count == 3)
+ {
+ // Upper limit of BETWEEN
+ DBUG_PRINT("info", ("LE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::LE_FUNC, 2);
+ }
+ else
+ {
+ // Illegal BETWEEN expression
+ DBUG_PRINT("info", ("Illegal BETWEEN expression"));
+ context->supported= FALSE;
+ DBUG_VOID_RETURN;
+ }
+ break;
+ }
+ case Item_func::IN_FUNC:
+ {
+ /*
+ Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
+ to <field>|<const> = <const1>|<field1> OR
+ <field> = <const2>|<field2> ...
+ or actually in prefix format
+ BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
+ EQ(<field>|<const>, <const2>|<field2>), ... END()
+ Each part of the disjunction is added for each call
+ to ndb_serialize_cond and end of rewrite statement
+ is wrapped in end of ndb_serialize_cond
+ */
+ DBUG_PRINT("info", ("EQ_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::EQ_FUNC, 2);
+ break;
+ }
+ default:
+ context->supported= FALSE;
+ }
+ // Handle left hand <field>|<const>
+ context->rewrite_stack= NULL; // Disable rewrite mode
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ ndb_serialize_cond(rewrite_context->left_hand_item, arg);
+ context->skip= 0; // Any FUNC_ITEM expression has already been parsed
+ context->rewrite_stack= rewrite_context; // Enable rewrite mode
+ if (!context->supported)
+ DBUG_VOID_RETURN;
+
+ prev_cond= context->cond_ptr;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ prev_cond->next= curr_cond;
+ }
+
+ // Check for end of AND/OR expression
+ if (!item)
+ {
+ // End marker for condition group
+ DBUG_PRINT("info", ("End of condition group"));
+ curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
+ }
+ else
+ {
+ switch (item->type()) {
+ case Item::FIELD_ITEM:
+ {
+ Item_field *field_item= (Item_field *) item;
+ Field *field= field_item->field;
+ enum_field_types type= field->type();
+ /*
+ Check that the field is part of the table of the handler
+ instance and that we expect a field with of this result type.
+ */
+ if (context->table->s == field->table->s)
+ {
+ const NDBTAB *tab= context->ndb_table;
+ DBUG_PRINT("info", ("FIELD_ITEM"));
+ DBUG_PRINT("info", ("table %s", tab->getName()));
+ DBUG_PRINT("info", ("column %s", field->field_name));
+ DBUG_PRINT("info", ("type %d", field->type()));
+ DBUG_PRINT("info", ("result type %d", field->result_type()));
+
+ // Check that we are expecting a field and with the correct
+ // result type
+ if (context->expecting(Item::FIELD_ITEM) &&
+ context->expecting_field_type(field->type()) &&
+ (context->expecting_field_result(field->result_type()) ||
+ // Date and year can be written as string or int
+ ((type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ ? (context->expecting_field_result(STRING_RESULT) ||
+ context->expecting_field_result(INT_RESULT))
+ : TRUE)) &&
+ // Bit fields no yet supported in scan filter
+ type != MYSQL_TYPE_BIT &&
+ // No BLOB support in scan filter
+ type != MYSQL_TYPE_TINY_BLOB &&
+ type != MYSQL_TYPE_MEDIUM_BLOB &&
+ type != MYSQL_TYPE_LONG_BLOB &&
+ type != MYSQL_TYPE_BLOB)
+ {
+ const NDBCOL *col= tab->getColumn(field->field_name);
+ DBUG_ASSERT(col);
+ curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo());
+ context->dont_expect(Item::FIELD_ITEM);
+ context->expect_no_field_result();
+ if (! context->expecting_nothing())
+ {
+ // We have not seen second argument yet
+ if (type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ {
+ context->expect_only(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ }
+ else
+ switch (field->result_type()) {
+ case STRING_RESULT:
+ // Expect char string or binary string
+ context->expect_only(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect_collation(field_item->collation.collation);
+ break;
+ case REAL_RESULT:
+ context->expect_only(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::INT_ITEM);
+ break;
+ case INT_RESULT:
+ context->expect_only(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ break;
+ case DECIMAL_RESULT:
+ context->expect_only(Item::DECIMAL_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::INT_ITEM);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that field and string constant collations are the same
+ if ((field->result_type() == STRING_RESULT) &&
+ !context->expecting_collation(item->collation.collation)
+ && type != MYSQL_TYPE_TIME
+ && type != MYSQL_TYPE_DATE
+ && type != MYSQL_TYPE_YEAR
+ && type != MYSQL_TYPE_DATETIME)
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ break;
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Was not expecting field of type %u(%u)",
+ field->result_type(), type));
+ context->supported= FALSE;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Was not expecting field from table %s (%s)",
+ context->table->s->table_name.str,
+ field->table->s->table_name.str));
+ context->supported= FALSE;
+ }
+ break;
+ }
+ case Item::FUNC_ITEM:
+ {
+ Item_func *func_item= (Item_func *) item;
+ // Check that we expect a function or functional expression here
+ if (context->expecting(Item::FUNC_ITEM) ||
+ func_item->functype() == Item_func::UNKNOWN_FUNC)
+ context->expect_nothing();
+ else
+ {
+ // Did not expect function here
+ context->supported= FALSE;
+ break;
+ }
+
+ switch (func_item->functype()) {
+ case Item_func::EQ_FUNC:
+ {
+ DBUG_PRINT("info", ("EQ_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::NE_FUNC:
+ {
+ DBUG_PRINT("info", ("NE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::LT_FUNC:
+ {
+ DBUG_PRINT("info", ("LT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::LE_FUNC:
+ {
+ DBUG_PRINT("info", ("LE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::GE_FUNC:
+ {
+ DBUG_PRINT("info", ("GE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::GT_FUNC:
+ {
+ DBUG_PRINT("info", ("GT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::LIKE_FUNC:
+ {
+ DBUG_PRINT("info", ("LIKE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_only_field_type(MYSQL_TYPE_STRING);
+ context->expect_field_type(MYSQL_TYPE_VAR_STRING);
+ context->expect_field_type(MYSQL_TYPE_VARCHAR);
+ context->expect_field_result(STRING_RESULT);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case Item_func::ISNULL_FUNC:
+ {
+ DBUG_PRINT("info", ("ISNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::ISNOTNULL_FUNC:
+ {
+ DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case Item_func::NOT_FUNC:
+ {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ break;
+ }
+ case Item_func::BETWEEN:
+ {
+ DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
+ Item_func_between *between_func= (Item_func_between *) func_item;
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ if (between_func->negated)
+ {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ }
+ DBUG_PRINT("info", ("COND_AND_FUNC"));
+ curr_cond->ndb_item=
+ new Ndb_item(Item_func::COND_AND_FUNC,
+ func_item->argument_count() - 1);
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case Item_func::IN_FUNC:
+ {
+ DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
+ Item_func_in *in_func= (Item_func_in *) func_item;
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ if (in_func->negated)
+ {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ }
+ DBUG_PRINT("info", ("COND_OR_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::COND_OR_FUNC,
+ func_item->argument_count() - 1);
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case Item_func::UNKNOWN_FUNC:
+ {
+ DBUG_PRINT("info", ("UNKNOWN_FUNC %s",
+ func_item->const_item()?"const":""));
+ DBUG_PRINT("info", ("result type %d", func_item->result_type()));
+ if (func_item->const_item())
+ {
+ switch (func_item->result_type()) {
+ case STRING_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(func_item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that string result have correct collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case REAL_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case INT_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else
+ // Function does not return constant expression
+ context->supported= FALSE;
+ break;
+ }
+ default:
+ {
+ DBUG_PRINT("info", ("Found func_item of type %d",
+ func_item->functype()));
+ context->supported= FALSE;
+ }
+ }
+ break;
+ }
+ case Item::STRING_ITEM:
+ DBUG_PRINT("info", ("STRING_ITEM"));
+ if (context->expecting(Item::STRING_ITEM))
+ {
+#ifndef DBUG_OFF
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ Item_string *string_item= (Item_string *) item;
+ DBUG_PRINT("info", ("value \"%s\"",
+ string_item->val_str(&str)->ptr()));
+#endif
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that we are comparing with a field with same collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case Item::INT_ITEM:
+ DBUG_PRINT("info", ("INT_ITEM"));
+ if (context->expecting(Item::INT_ITEM))
+ {
+ DBUG_PRINT("info", ("value %ld",
+ (long) ((Item_int*) item)->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case Item::REAL_ITEM:
+ DBUG_PRINT("info", ("REAL_ITEM"));
+ if (context->expecting(Item::REAL_ITEM))
+ {
+ DBUG_PRINT("info", ("value %f", ((Item_float*) item)->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case Item::VARBIN_ITEM:
+ DBUG_PRINT("info", ("VARBIN_ITEM"));
+ if (context->expecting(Item::VARBIN_ITEM))
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::VARBIN_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case Item::DECIMAL_ITEM:
+ DBUG_PRINT("info", ("DECIMAL_ITEM"));
+ if (context->expecting(Item::DECIMAL_ITEM))
+ {
+ DBUG_PRINT("info", ("value %f",
+ ((Item_decimal*) item)->val_real()));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case Item::COND_ITEM:
+ {
+ Item_cond *cond_item= (Item_cond *) item;
+
+ if (context->expecting(Item::COND_ITEM))
+ {
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC:
+ DBUG_PRINT("info", ("COND_AND_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
+ cond_item);
+ break;
+ case Item_func::COND_OR_FUNC:
+ DBUG_PRINT("info", ("COND_OR_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
+ cond_item);
+ break;
+ default:
+ DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
+ context->supported= FALSE;
+ break;
+ }
+ }
+ else
+ {
+ /* Did not expect condition */
+ context->supported= FALSE;
+ }
+ break;
+ }
+ default:
+ {
+ DBUG_PRINT("info", ("Found item of type %d", item->type()));
+ context->supported= FALSE;
+ }
+ }
+ }
+ if (context->supported && context->rewrite_stack)
+ {
+ Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
+ if (rewrite_context->count ==
+ rewrite_context->func_item->argument_count())
+ {
+ // Rewrite is done, wrap an END() at the en
+ DBUG_PRINT("info", ("End of condition group"));
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
+ // Pop rewrite stack
+ context->rewrite_stack= rewrite_context->next;
+ rewrite_context->next= NULL;
+ delete(rewrite_context);
+ }
+ }
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Push a condition
+ */
+const
+COND*
+ha_ndbcluster_cond::cond_push(const COND *cond,
+ TABLE *table, const NDBTAB *ndb_table)
+{
+ DBUG_ENTER("cond_push");
+ Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
+ if (ndb_cond == NULL)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(NULL);
+ }
+ if (m_cond_stack)
+ ndb_cond->next= m_cond_stack;
+ else
+ ndb_cond->next= NULL;
+ m_cond_stack= ndb_cond;
+
+ if (serialize_cond(cond, ndb_cond, table, ndb_table))
+ {
+ DBUG_RETURN(NULL);
+ }
+ else
+ {
+ cond_pop();
+ }
+ DBUG_RETURN(cond);
+}
+
+/*
+ Pop the top condition from the condition stack
+*/
+void
+ha_ndbcluster_cond::cond_pop()
+{
+ Ndb_cond_stack *ndb_cond_stack= m_cond_stack;
+ if (ndb_cond_stack)
+ {
+ m_cond_stack= ndb_cond_stack->next;
+ ndb_cond_stack->next= NULL;
+ delete ndb_cond_stack;
+ }
+}
+
+/*
+ Clear the condition stack
+*/
+void
+ha_ndbcluster_cond::cond_clear()
+{
+ DBUG_ENTER("cond_clear");
+ while (m_cond_stack)
+ cond_pop();
+
+ DBUG_VOID_RETURN;
+}
+
+bool
+ha_ndbcluster_cond::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond,
+ TABLE *table, const NDBTAB *ndb_table)
+{
+ DBUG_ENTER("serialize_cond");
+ Item *item= (Item *) cond;
+ Ndb_cond_traverse_context context(table, ndb_table, ndb_cond);
+ // Expect a logical expression
+ context.expect(Item::FUNC_ITEM);
+ context.expect(Item::COND_ITEM);
+ item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
+ DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
+
+ DBUG_RETURN(context.supported);
+}
+
+int
+ha_ndbcluster_cond::build_scan_filter_predicate(Ndb_cond * &cond,
+ NdbScanFilter *filter,
+ bool negated)
+{
+ DBUG_ENTER("build_scan_filter_predicate");
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
+ if (!cond->next)
+ break;
+ Ndb_item *a= cond->next->ndb_item;
+ Ndb_item *b, *field, *value= NULL;
+
+ switch (cond->ndb_item->argument_count()) {
+ case 1:
+ field= (a->type == NDB_FIELD)? a : NULL;
+ break;
+ case 2:
+ if (!cond->next->next)
+ {
+ field= NULL;
+ break;
+ }
+ b= cond->next->next->ndb_item;
+ value= ((a->type == NDB_VALUE) ? a :
+ (b->type == NDB_VALUE) ? b :
+ NULL);
+ field= ((a->type == NDB_FIELD) ? a :
+ (b->type == NDB_FIELD) ? b :
+ NULL);
+ break;
+ default:
+ field= NULL; //Keep compiler happy
+ DBUG_ASSERT(0);
+ break;
+ }
+ switch ((negated) ?
+ Ndb_item::negate(cond->ndb_item->qualification.function_type)
+ : cond->ndb_item->qualification.function_type) {
+ case NDB_EQ_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating EQ filter"));
+ if (filter->cmp(NdbScanFilter::COND_EQ,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_NE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NE filter"));
+ if (filter->cmp(NdbScanFilter::COND_NE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LT_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_GE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_GT_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LIKE_FUNC:
+ {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_NOTLIKE_FUNC:
+ {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_ISNULL_FUNC:
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNULL filter"));
+ if (filter->isnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ case NDB_ISNOTNULL_FUNC:
+ {
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
+ if (filter->isnotnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ DBUG_PRINT("info", ("Found illegal condition"));
+ DBUG_RETURN(1);
+}
+
+
+int
+ha_ndbcluster_cond::build_scan_filter_group(Ndb_cond* &cond,
+ NdbScanFilter *filter)
+{
+ uint level=0;
+ bool negated= FALSE;
+ DBUG_ENTER("build_scan_filter_group");
+
+ do
+ {
+ if (!cond)
+ DBUG_RETURN(1);
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
+ switch (cond->ndb_item->qualification.function_type) {
+ case NDB_COND_AND_FUNC:
+ {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NAND)
+ : filter->begin(NdbScanFilter::AND) == -1)
+ DBUG_RETURN(1);
+ negated= FALSE;
+ cond= cond->next;
+ break;
+ }
+ case NDB_COND_OR_FUNC:
+ {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NOR)
+ : filter->begin(NdbScanFilter::OR) == -1)
+ DBUG_RETURN(1);
+ negated= FALSE;
+ cond= cond->next;
+ break;
+ }
+ case NDB_NOT_FUNC:
+ {
+ DBUG_PRINT("info", ("Generating negated query"));
+ cond= cond->next;
+ negated= TRUE;
+ break;
+ }
+ default:
+ if (build_scan_filter_predicate(cond, filter, negated))
+ DBUG_RETURN(1);
+ negated= FALSE;
+ break;
+ }
+ break;
+ }
+ case NDB_END_COND:
+ DBUG_PRINT("info", ("End of group %u", level));
+ level--;
+ if (cond) cond= cond->next;
+ if (filter->end() == -1)
+ DBUG_RETURN(1);
+ if (!negated)
+ break;
+ // else fall through (NOT END is an illegal condition)
+ default:
+ {
+ DBUG_PRINT("info", ("Illegal scan filter"));
+ }
+ }
+ } while (level > 0 || negated);
+
+ DBUG_RETURN(0);
+}
+
+
+int
+ha_ndbcluster_cond::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
+{
+ bool simple_cond= TRUE;
+ DBUG_ENTER("build_scan_filter");
+
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ switch (cond->ndb_item->qualification.function_type) {
+ case NDB_COND_AND_FUNC:
+ case NDB_COND_OR_FUNC:
+ simple_cond= FALSE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (simple_cond && filter->begin() == -1)
+ DBUG_RETURN(1);
+ if (build_scan_filter_group(cond, filter))
+ DBUG_RETURN(1);
+ if (simple_cond && filter->end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+int
+ha_ndbcluster_cond::generate_scan_filter(NdbScanOperation *op)
+{
+ DBUG_ENTER("generate_scan_filter");
+
+ if (m_cond_stack)
+ {
+ NdbScanFilter filter(op);
+
+ DBUG_RETURN(generate_scan_filter_from_cond(filter));
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Empty stack"));
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+int
+ha_ndbcluster_cond::generate_scan_filter_from_cond(NdbScanFilter& filter)
+{
+ bool multiple_cond= FALSE;
+ DBUG_ENTER("generate_scan_filter_from_cond");
+
+ // Wrap an AND group around multiple conditions
+ if (m_cond_stack->next)
+ {
+ multiple_cond= TRUE;
+ if (filter.begin() == -1)
+ DBUG_RETURN(1);
+ }
+ for (Ndb_cond_stack *stack= m_cond_stack;
+ (stack);
+ stack= stack->next)
+ {
+ Ndb_cond *cond= stack->ndb_cond;
+
+ if (build_scan_filter(cond, &filter))
+ {
+ DBUG_PRINT("info", ("build_scan_filter failed"));
+ DBUG_RETURN(1);
+ }
+ }
+ if (multiple_cond && filter.end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+
+int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op,
+ const KEY* key_info,
+ const uchar *key,
+ uint key_len,
+ uchar *buf)
+{
+ KEY_PART_INFO* key_part= key_info->key_part;
+ KEY_PART_INFO* end= key_part+key_info->key_parts;
+ NdbScanFilter filter(op);
+ int res;
+ DBUG_ENTER("generate_scan_filter_from_key");
+
+ filter.begin(NdbScanFilter::AND);
+ for (; key_part != end; key_part++)
+ {
+ Field* field= key_part->field;
+ uint32 pack_len= field->pack_length();
+ const uchar* ptr= key;
+ DBUG_PRINT("info", ("Filtering value for %s", field->field_name));
+ DBUG_DUMP("key", ptr, pack_len);
+ if (key_part->null_bit)
+ {
+ DBUG_PRINT("info", ("Generating ISNULL filter"));
+ if (filter.isnull(key_part->fieldnr-1) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating EQ filter"));
+ if (filter.cmp(NdbScanFilter::COND_EQ,
+ key_part->fieldnr-1,
+ ptr,
+ pack_len) == -1)
+ DBUG_RETURN(1);
+ }
+ key += key_part->store_length;
+ }
+ // Add any pushed condition
+ if (m_cond_stack &&
+ (res= generate_scan_filter_from_cond(filter)))
+ DBUG_RETURN(res);
+
+ if (filter.end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+#endif /* HAVE_NDBCLUSTER_DB */
diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h
new file mode 100644
index 00000000000..d5b3b913f22
--- /dev/null
+++ b/sql/ha_ndbcluster_cond.h
@@ -0,0 +1,475 @@
+/* Copyright (C) 2000-2007 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; version 2 of the License.
+
+ 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 the data structures used by engine condition pushdown in
+ the NDB Cluster handler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+typedef enum ndb_item_type {
+ NDB_VALUE = 0, // Qualified more with Item::Type
+ NDB_FIELD = 1, // Qualified from table definition
+ NDB_FUNCTION = 2,// Qualified from Item_func::Functype
+ NDB_END_COND = 3 // End marker for condition group
+} NDB_ITEM_TYPE;
+
+typedef enum ndb_func_type {
+ NDB_EQ_FUNC = 0,
+ NDB_NE_FUNC = 1,
+ NDB_LT_FUNC = 2,
+ NDB_LE_FUNC = 3,
+ NDB_GT_FUNC = 4,
+ NDB_GE_FUNC = 5,
+ NDB_ISNULL_FUNC = 6,
+ NDB_ISNOTNULL_FUNC = 7,
+ NDB_LIKE_FUNC = 8,
+ NDB_NOTLIKE_FUNC = 9,
+ NDB_NOT_FUNC = 10,
+ NDB_UNKNOWN_FUNC = 11,
+ NDB_COND_AND_FUNC = 12,
+ NDB_COND_OR_FUNC = 13,
+ NDB_UNSUPPORTED_FUNC = 14
+} NDB_FUNC_TYPE;
+
+typedef union ndb_item_qualification {
+ Item::Type value_type;
+ enum_field_types field_type; // Instead of Item::FIELD_ITEM
+ NDB_FUNC_TYPE function_type; // Instead of Item::FUNC_ITEM
+} NDB_ITEM_QUALIFICATION;
+
+typedef struct ndb_item_field_value {
+ Field* field;
+ int column_no;
+} NDB_ITEM_FIELD_VALUE;
+
+typedef union ndb_item_value {
+ const Item *item;
+ NDB_ITEM_FIELD_VALUE *field_value;
+ uint arg_count;
+} NDB_ITEM_VALUE;
+
+struct negated_function_mapping
+{
+ NDB_FUNC_TYPE pos_fun;
+ NDB_FUNC_TYPE neg_fun;
+};
+
+/*
+ Define what functions can be negated in condition pushdown.
+ Note, these HAVE to be in the same order as in definition enum
+*/
+static const negated_function_mapping neg_map[]=
+{
+ {NDB_EQ_FUNC, NDB_NE_FUNC},
+ {NDB_NE_FUNC, NDB_EQ_FUNC},
+ {NDB_LT_FUNC, NDB_GE_FUNC},
+ {NDB_LE_FUNC, NDB_GT_FUNC},
+ {NDB_GT_FUNC, NDB_LE_FUNC},
+ {NDB_GE_FUNC, NDB_LT_FUNC},
+ {NDB_ISNULL_FUNC, NDB_ISNOTNULL_FUNC},
+ {NDB_ISNOTNULL_FUNC, NDB_ISNULL_FUNC},
+ {NDB_LIKE_FUNC, NDB_NOTLIKE_FUNC},
+ {NDB_NOTLIKE_FUNC, NDB_LIKE_FUNC},
+ {NDB_NOT_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_UNKNOWN_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_COND_AND_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_COND_OR_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_UNSUPPORTED_FUNC, NDB_UNSUPPORTED_FUNC}
+};
+
+/*
+ This class is the construction element for serialization of Item tree
+ in condition pushdown.
+ An instance of Ndb_Item represents a constant, table field reference,
+ unary or binary comparison predicate, and start/end of AND/OR.
+ Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
+ class.
+ The order of elements produced by Ndb_cond::next corresponds to
+ breadth-first traversal of the Item (i.e. expression) tree in prefix order.
+ AND and OR have arbitrary arity, so the end of AND/OR group is marked with
+ Ndb_item with type == NDB_END_COND.
+ NOT items represent negated conditions and generate NAND/NOR groups.
+*/
+class Ndb_item : public Sql_alloc
+{
+public:
+ Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
+ Ndb_item(NDB_ITEM_TYPE item_type,
+ NDB_ITEM_QUALIFICATION item_qualification,
+ const Item *item_value)
+ : type(item_type), qualification(item_qualification)
+ {
+ switch(item_type) {
+ case(NDB_VALUE):
+ value.item= item_value;
+ break;
+ case(NDB_FIELD): {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ Item_field *field_item= (Item_field *) item_value;
+ field_value->field= field_item->field;
+ field_value->column_no= -1; // Will be fetched at scan filter generation
+ value.field_value= field_value;
+ break;
+ }
+ case(NDB_FUNCTION):
+ value.item= item_value;
+ value.arg_count= ((Item_func *) item_value)->argument_count();
+ break;
+ case(NDB_END_COND):
+ break;
+ }
+ };
+ Ndb_item(Field *field, int column_no) : type(NDB_FIELD)
+ {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ qualification.field_type= field->type();
+ field_value->field= field;
+ field_value->column_no= column_no;
+ value.field_value= field_value;
+ };
+ Ndb_item(Item_func::Functype func_type, const Item *item_value)
+ : type(NDB_FUNCTION)
+ {
+ qualification.function_type= item_func_to_ndb_func(func_type);
+ value.item= item_value;
+ value.arg_count= ((Item_func *) item_value)->argument_count();
+ };
+ Ndb_item(Item_func::Functype func_type, uint no_args)
+ : type(NDB_FUNCTION)
+ {
+ qualification.function_type= item_func_to_ndb_func(func_type);
+ value.arg_count= no_args;
+ };
+ ~Ndb_item()
+ {
+ if (type == NDB_FIELD)
+ {
+ delete value.field_value;
+ value.field_value= NULL;
+ }
+ };
+
+ uint32 pack_length()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.length();
+ break;
+ case(NDB_FIELD):
+ return value.field_value->field->pack_length();
+ default:
+ break;
+ }
+
+ return 0;
+ };
+
+ Field * get_field() { return value.field_value->field; };
+
+ int get_field_no() { return value.field_value->column_no; };
+
+ int argument_count()
+ {
+ return value.arg_count;
+ };
+
+ const char* get_val()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.ptr();
+ break;
+ case(NDB_FIELD):
+ return (char*) value.field_value->field->ptr;
+ default:
+ break;
+ }
+
+ return NULL;
+ };
+
+ void save_in_field(Ndb_item *field_item)
+ {
+ Field *field = field_item->value.field_value->field;
+ const Item *item= value.item;
+
+ if (item && field)
+ {
+ my_bitmap_map *old_map=
+ dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ ((Item *)item)->save_in_field(field, FALSE);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
+ }
+ };
+
+ static NDB_FUNC_TYPE item_func_to_ndb_func(Item_func::Functype fun)
+ {
+ switch (fun) {
+ case (Item_func::EQ_FUNC): { return NDB_EQ_FUNC; }
+ case (Item_func::NE_FUNC): { return NDB_NE_FUNC; }
+ case (Item_func::LT_FUNC): { return NDB_LT_FUNC; }
+ case (Item_func::LE_FUNC): { return NDB_LE_FUNC; }
+ case (Item_func::GT_FUNC): { return NDB_GT_FUNC; }
+ case (Item_func::GE_FUNC): { return NDB_GE_FUNC; }
+ case (Item_func::ISNULL_FUNC): { return NDB_ISNULL_FUNC; }
+ case (Item_func::ISNOTNULL_FUNC): { return NDB_ISNOTNULL_FUNC; }
+ case (Item_func::LIKE_FUNC): { return NDB_LIKE_FUNC; }
+ case (Item_func::NOT_FUNC): { return NDB_NOT_FUNC; }
+ case (Item_func::UNKNOWN_FUNC): { return NDB_UNKNOWN_FUNC; }
+ case (Item_func::COND_AND_FUNC): { return NDB_COND_AND_FUNC; }
+ case (Item_func::COND_OR_FUNC): { return NDB_COND_OR_FUNC; }
+ default: { return NDB_UNSUPPORTED_FUNC; }
+ }
+ };
+
+ static NDB_FUNC_TYPE negate(NDB_FUNC_TYPE fun)
+ {
+ uint i= (uint) fun;
+ DBUG_ASSERT(fun == neg_map[i].pos_fun);
+ return neg_map[i].neg_fun;
+ };
+
+ NDB_ITEM_TYPE type;
+ NDB_ITEM_QUALIFICATION qualification;
+ private:
+ NDB_ITEM_VALUE value;
+};
+
+/*
+ This class implements a linked list used for storing a
+ serialization of the Item tree for condition pushdown.
+ */
+class Ndb_cond : public Sql_alloc
+{
+ public:
+ Ndb_cond() : ndb_item(NULL), next(NULL), prev(NULL) {};
+ ~Ndb_cond()
+ {
+ if (ndb_item) delete ndb_item;
+ ndb_item= NULL;
+ if (next) delete next;
+ next= prev= NULL;
+ };
+ Ndb_item *ndb_item;
+ Ndb_cond *next;
+ Ndb_cond *prev;
+};
+
+/*
+ This class implements a stack for storing several conditions
+ for pushdown (represented as serialized Item trees using Ndb_cond).
+ The current implementation only pushes one condition, but is
+ prepared for handling several (C1 AND C2 ...) if the logic for
+ pushing conditions is extended in sql_select.
+*/
+class Ndb_cond_stack : public Sql_alloc
+{
+ public:
+ Ndb_cond_stack() : ndb_cond(NULL), next(NULL) {};
+ ~Ndb_cond_stack()
+ {
+ if (ndb_cond) delete ndb_cond;
+ ndb_cond= NULL;
+ if (next) delete next;
+ next= NULL;
+ };
+ Ndb_cond *ndb_cond;
+ Ndb_cond_stack *next;
+};
+
+class Ndb_rewrite_context : public Sql_alloc
+{
+public:
+ Ndb_rewrite_context(Item_func *func)
+ : func_item(func), left_hand_item(NULL), count(0) {};
+ ~Ndb_rewrite_context()
+ {
+ if (next) delete next;
+ }
+ const Item_func *func_item;
+ const Item *left_hand_item;
+ uint count;
+ Ndb_rewrite_context *next;
+};
+
+/*
+ This class is used for storing the context when traversing
+ the Item tree. It stores a reference to the table the condition
+ is defined on, the serialized representation being generated,
+ if the condition found is supported, and information what is
+ expected next in the tree inorder for the condition to be supported.
+*/
+class Ndb_cond_traverse_context : public Sql_alloc
+{
+ public:
+ Ndb_cond_traverse_context(TABLE *tab, const NdbDictionary::Table *ndb_tab,
+ Ndb_cond_stack* stack)
+ : table(tab), ndb_table(ndb_tab),
+ supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
+ skip(0), collation(NULL), rewrite_stack(NULL)
+ {
+ // Allocate type checking bitmaps
+ bitmap_init(&expect_mask, 0, 512, FALSE);
+ bitmap_init(&expect_field_type_mask, 0, 512, FALSE);
+ bitmap_init(&expect_field_result_mask, 0, 512, FALSE);
+
+ if (stack)
+ cond_ptr= stack->ndb_cond;
+ };
+ ~Ndb_cond_traverse_context()
+ {
+ bitmap_free(&expect_mask);
+ bitmap_free(&expect_field_type_mask);
+ bitmap_free(&expect_field_result_mask);
+ if (rewrite_stack) delete rewrite_stack;
+ }
+ void expect(Item::Type type)
+ {
+ bitmap_set_bit(&expect_mask, (uint) type);
+ if (type == Item::FIELD_ITEM) expect_all_field_types();
+ };
+ void dont_expect(Item::Type type)
+ {
+ bitmap_clear_bit(&expect_mask, (uint) type);
+ };
+ bool expecting(Item::Type type)
+ {
+ return bitmap_is_set(&expect_mask, (uint) type);
+ };
+ void expect_nothing()
+ {
+ bitmap_clear_all(&expect_mask);
+ };
+ bool expecting_nothing()
+ {
+ return bitmap_is_clear_all(&expect_mask);
+ }
+ void expect_only(Item::Type type)
+ {
+ expect_nothing();
+ expect(type);
+ };
+
+ void expect_field_type(enum_field_types type)
+ {
+ bitmap_set_bit(&expect_field_type_mask, (uint) type);
+ };
+ void expect_all_field_types()
+ {
+ bitmap_set_all(&expect_field_type_mask);
+ };
+ bool expecting_field_type(enum_field_types type)
+ {
+ return bitmap_is_set(&expect_field_type_mask, (uint) type);
+ };
+ void expect_no_field_type()
+ {
+ bitmap_clear_all(&expect_field_type_mask);
+ };
+ bool expecting_no_field_type()
+ {
+ return bitmap_is_clear_all(&expect_field_type_mask);
+ }
+ void expect_only_field_type(enum_field_types result)
+ {
+ expect_no_field_type();
+ expect_field_type(result);
+ };
+
+ void expect_field_result(Item_result result)
+ {
+ bitmap_set_bit(&expect_field_result_mask, (uint) result);
+ };
+ bool expecting_field_result(Item_result result)
+ {
+ return bitmap_is_set(&expect_field_result_mask, (uint) result);
+ };
+ void expect_no_field_result()
+ {
+ bitmap_clear_all(&expect_field_result_mask);
+ };
+ bool expecting_no_field_result()
+ {
+ return bitmap_is_clear_all(&expect_field_result_mask);
+ }
+ void expect_only_field_result(Item_result result)
+ {
+ expect_no_field_result();
+ expect_field_result(result);
+ };
+ void expect_collation(CHARSET_INFO* col)
+ {
+ collation= col;
+ };
+ bool expecting_collation(CHARSET_INFO* col)
+ {
+ bool matching= (!collation) ? true : (collation == col);
+ collation= NULL;
+
+ return matching;
+ };
+
+ TABLE* table;
+ const NdbDictionary::Table *ndb_table;
+ bool supported;
+ Ndb_cond_stack* stack_ptr;
+ Ndb_cond* cond_ptr;
+ MY_BITMAP expect_mask;
+ MY_BITMAP expect_field_type_mask;
+ MY_BITMAP expect_field_result_mask;
+ uint skip;
+ CHARSET_INFO* collation;
+ Ndb_rewrite_context *rewrite_stack;
+};
+
+class ha_ndbcluster;
+
+class ha_ndbcluster_cond
+{
+public:
+ ha_ndbcluster_cond()
+ : m_cond_stack(NULL)
+ {}
+ ~ha_ndbcluster_cond()
+ { if (m_cond_stack) delete m_cond_stack; }
+ const COND *cond_push(const COND *cond,
+ TABLE *table, const NdbDictionary::Table *ndb_table);
+ void cond_pop();
+ void cond_clear();
+ int generate_scan_filter(NdbScanOperation* op);
+ int generate_scan_filter_from_cond(NdbScanFilter& filter);
+ int generate_scan_filter_from_key(NdbScanOperation* op,
+ const KEY* key_info,
+ const uchar *key,
+ uint key_len,
+ uchar *buf);
+private:
+ bool serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond,
+ TABLE *table, const NdbDictionary::Table *ndb_table);
+ int build_scan_filter_predicate(Ndb_cond* &cond,
+ NdbScanFilter* filter,
+ bool negated= false);
+ int build_scan_filter_group(Ndb_cond* &cond,
+ NdbScanFilter* filter);
+ int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
+
+ Ndb_cond_stack *m_cond_stack;
+};
diff --git a/sql/ha_ndbcluster_tables.h b/sql/ha_ndbcluster_tables.h
index 2b1bdbc2b89..c6bc8f577f8 100644
--- a/sql/ha_ndbcluster_tables.h
+++ b/sql/ha_ndbcluster_tables.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,7 +15,9 @@
*/
#define NDB_REP_DB "mysql"
+#define OLD_NDB_REP_DB "cluster"
#define NDB_REP_TABLE "ndb_binlog_index"
#define NDB_APPLY_TABLE "ndb_apply_status"
#define OLD_NDB_APPLY_TABLE "apply_status"
#define NDB_SCHEMA_TABLE "ndb_schema"
+#define OLD_NDB_SCHEMA_TABLE "schema"
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7cd33dd5726..e9f4bc4c745 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -159,7 +158,7 @@ static uint alter_table_flags(uint flags __attribute__((unused)))
ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
:handler(hton, share), m_part_info(NULL), m_create_handler(FALSE),
- m_is_sub_partitioned(0)
+ m_is_sub_partitioned(0), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(table)");
init_handler_variables();
@@ -181,8 +180,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
ha_partition::ha_partition(handlerton *hton, partition_info *part_info)
:handler(hton, NULL), m_part_info(part_info),
m_create_handler(TRUE),
- m_is_sub_partitioned(m_part_info->is_sub_partitioned())
-
+ m_is_sub_partitioned(m_part_info->is_sub_partitioned()), is_clone(FALSE)
{
DBUG_ENTER("ha_partition::ha_partition(part_info)");
init_handler_variables();
@@ -585,7 +583,6 @@ int ha_partition::drop_partitions(const char *path)
List_iterator<partition_element> part_it(m_part_info->partitions);
char part_name_buff[FN_REFLEN];
uint no_parts= m_part_info->partitions.elements;
- uint part_count= 0;
uint no_subparts= m_part_info->no_subparts;
uint i= 0;
uint name_variant;
@@ -1076,7 +1073,6 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
uint no_parts= m_part_info->no_parts;
uint no_subparts= m_part_info->no_subparts;
uint i= 0;
- LEX *lex= thd->lex;
int error;
DBUG_ENTER("ha_partition::handle_opt_partitions");
DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag));
@@ -1088,11 +1084,9 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
{
if (m_is_sub_partitioned)
{
- List_iterator<partition_element> sub_it(part_elem->subpartitions);
uint j= 0, part;
do
{
- partition_element *sub_elem= sub_it++;
part= i * no_subparts + j;
DBUG_PRINT("info", ("Optimize subpartition %u",
part));
@@ -1137,7 +1131,6 @@ int ha_partition::prepare_new_partition(TABLE *table,
{
int error;
bool create_flag= FALSE;
- bool open_flag= FALSE;
DBUG_ENTER("prepare_new_partition");
if ((error= set_up_table_before_create(table, part_name, create_info,
@@ -1231,9 +1224,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
const char *path,
ulonglong *copied,
ulonglong *deleted,
- const void *pack_frm_data
+ const uchar *pack_frm_data
__attribute__((unused)),
- uint pack_frm_len
+ size_t pack_frm_len
__attribute__((unused)))
{
List_iterator<partition_element> part_it(m_part_info->partitions);
@@ -1246,7 +1239,6 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
handler **new_file_array;
int error= 1;
bool first;
- bool copy_parts= FALSE;
uint temp_partitions= m_part_info->temp_partitions.elements;
THD *thd= current_thd;
DBUG_ENTER("ha_partition::change_partitions");
@@ -1972,8 +1964,8 @@ bool ha_partition::create_handler_file(const char *name)
if ((file= my_create(file_name, CREATE_MODE, O_RDWR | O_TRUNC,
MYF(MY_WME))) >= 0)
{
- result= my_write(file, (byte *) file_buffer, tot_len_byte,
- MYF(MY_WME | MY_NABP));
+ result= my_write(file, (uchar *) file_buffer, tot_len_byte,
+ MYF(MY_WME | MY_NABP)) != 0;
VOID(my_close(file, MYF(0)));
}
else
@@ -1994,6 +1986,8 @@ bool ha_partition::create_handler_file(const char *name)
void ha_partition::clear_handler_file()
{
+ if (m_engine_array)
+ plugin_unlock_list(NULL, m_engine_array, m_tot_parts);
my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR));
m_file_buffer= NULL;
@@ -2016,6 +2010,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
{
uint i;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
+ handlerton *hton0;
DBUG_ENTER("create_handlers");
if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
@@ -2024,19 +2019,21 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
bzero((char*) m_file, alloc_len);
for (i= 0; i < m_tot_parts; i++)
{
+ handlerton *hton= plugin_data(m_engine_array[i], handlerton*);
if (!(m_file[i]= get_new_handler(table_share, mem_root,
- m_engine_array[i])))
+ hton)))
DBUG_RETURN(TRUE);
- DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i]->db_type));
+ DBUG_PRINT("info", ("engine_type: %u", hton->db_type));
}
/* For the moment we only support partition over the same table engine */
- if (m_engine_array[0] == myisam_hton)
+ hton0= plugin_data(m_engine_array[0], handlerton*);
+ if (hton0 == myisam_hton)
{
DBUG_PRINT("info", ("MyISAM"));
m_myisam= TRUE;
}
/* INNODB may not be compiled in... */
- else if (ha_legacy_type(m_engine_array[0]) == DB_TYPE_INNODB)
+ else if (ha_legacy_type(hton0) == DB_TYPE_INNODB)
{
DBUG_PRINT("info", ("InnoDB"));
m_innodb= TRUE;
@@ -2062,7 +2059,6 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root)
partition_element *part_elem;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
List_iterator_fast <partition_element> part_it(m_part_info->partitions);
- THD *thd= current_thd;
DBUG_ENTER("ha_partition::new_handlers_from_part_info");
if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
@@ -2150,14 +2146,14 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
/* Following could be done with my_stat to read in whole file */
if ((file= my_open(buff, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(TRUE);
- if (my_read(file, (byte *) & buff[0], 8, MYF(MY_NABP)))
+ if (my_read(file, (uchar *) & buff[0], 8, MYF(MY_NABP)))
goto err1;
len_words= uint4korr(buff);
len_bytes= 4 * len_words;
- if (!(file_buffer= my_malloc(len_bytes, MYF(0))))
+ if (!(file_buffer= (char*) my_malloc(len_bytes, MYF(0))))
goto err1;
VOID(my_seek(file, 0, MY_SEEK_SET, MYF(0)));
- if (my_read(file, (byte *) file_buffer, len_bytes, MYF(MY_NABP)))
+ if (my_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP)))
goto err2;
chksum= 0;
@@ -2168,8 +2164,7 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
m_tot_parts= uint4korr((file_buffer) + 8);
DBUG_PRINT("info", ("No of parts = %u", m_tot_parts));
tot_partition_words= (m_tot_parts + 3) / 4;
- if (!(engine_array= (handlerton **) my_malloc(m_tot_parts * sizeof(handlerton*),MYF(0))))
- goto err2;
+ engine_array= (handlerton **) my_alloca(m_tot_parts * sizeof(handlerton*));
for (i= 0; i < m_tot_parts; i++)
engine_array[i]= ha_resolve_by_legacy_type(current_thd,
(enum legacy_db_type)
@@ -2177,12 +2172,21 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
address_tot_name_len= file_buffer + 12 + 4 * tot_partition_words;
tot_name_words= (uint4korr(address_tot_name_len) + 3) / 4;
if (len_words != (tot_partition_words + tot_name_words + 4))
- goto err2;
+ goto err3;
name_buffer_ptr= file_buffer + 16 + 4 * tot_partition_words;
VOID(my_close(file, MYF(0)));
m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
m_name_buffer_ptr= name_buffer_ptr;
- m_engine_array= engine_array;
+
+ if (!(m_engine_array= (plugin_ref*)
+ my_malloc(m_tot_parts * sizeof(plugin_ref), MYF(MY_WME))))
+ goto err3;
+
+ for (i= 0; i < m_tot_parts; i++)
+ m_engine_array[i]= ha_lock_engine(NULL, engine_array[i]);
+
+ my_afree((gptr) engine_array);
+
if (!m_file && create_handlers(mem_root))
{
clear_handler_file();
@@ -2190,6 +2194,8 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
}
DBUG_RETURN(FALSE);
+err3:
+ my_afree((gptr) engine_array);
err2:
my_free(file_buffer, MYF(0));
err1:
@@ -2246,7 +2252,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
alloc_len+= table->s->max_key_length;
if (!m_ordered_rec_buffer)
{
- if (!(m_ordered_rec_buffer= (byte*)my_malloc(alloc_len, MYF(MY_WME))))
+ if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME))))
{
DBUG_RETURN(1);
}
@@ -2265,14 +2271,17 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
int2store(ptr, i);
ptr+= m_rec_length + PARTITION_BYTES_IN_POS;
} while (++i < m_tot_parts);
- m_start_key.key= (const byte*)ptr;
+ m_start_key.key= (const uchar*)ptr;
}
}
/* Initialise the bitmap we use to determine what partitions are used */
- if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
- DBUG_RETURN(1);
- bitmap_set_all(&(m_part_info->used_partitions));
+ if (!is_clone)
+ {
+ if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
+ DBUG_RETURN(1);
+ bitmap_set_all(&(m_part_info->used_partitions));
+ }
/* Recalculate table flags as they may change after open */
m_table_flags= m_file[0]->table_flags();
@@ -2328,6 +2337,20 @@ err_handler:
DBUG_RETURN(error);
}
+handler *ha_partition::clone(MEM_ROOT *mem_root)
+{
+ handler *new_handler= get_new_handler(table->s, mem_root,
+ table->s->db_type());
+ ((ha_partition*)new_handler)->m_part_info= m_part_info;
+ ((ha_partition*)new_handler)->is_clone= TRUE;
+ if (new_handler && !new_handler->ha_open(table,
+ table->s->normalized_path.str,
+ table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ return new_handler;
+ return NULL;
+}
+
/*
Close handler object
@@ -2354,7 +2377,8 @@ int ha_partition::close(void)
DBUG_ENTER("ha_partition::close");
delete_queue(&m_queue);
- bitmap_free(&(m_part_info->used_partitions));
+ if (!is_clone)
+ bitmap_free(&(m_part_info->used_partitions));
file= m_file;
repeat:
@@ -2633,13 +2657,13 @@ void ha_partition::unlock_row()
may be used in determining which partition the row should be written to.
*/
-int ha_partition::write_row(byte * buf)
+int ha_partition::write_row(uchar * buf)
{
uint32 part_id;
int error;
longlong func_value;
#ifdef NOT_NEEDED
- byte *rec0= m_rec0;
+ uchar *rec0= m_rec0;
#endif
DBUG_ENTER("ha_partition::write_row");
DBUG_ASSERT(buf == m_rec0);
@@ -2713,7 +2737,7 @@ int ha_partition::write_row(byte * buf)
old_data is normally record[1] but may be anything
*/
-int ha_partition::update_row(const byte *old_data, byte *new_data)
+int ha_partition::update_row(const uchar *old_data, uchar *new_data)
{
uint32 new_part_id, old_part_id;
int error;
@@ -2785,7 +2809,7 @@ int ha_partition::update_row(const byte *old_data, byte *new_data)
buf is either record[0] or record[1]
*/
-int ha_partition::delete_row(const byte *buf)
+int ha_partition::delete_row(const uchar *buf)
{
uint32 part_id;
int error;
@@ -3056,7 +3080,7 @@ int ha_partition::rnd_end()
sql_table.cc, and sql_update.cc.
*/
-int ha_partition::rnd_next(byte *buf)
+int ha_partition::rnd_next(uchar *buf)
{
handler *file;
int result= HA_ERR_END_OF_FILE;
@@ -3149,7 +3173,7 @@ end:
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
*/
-void ha_partition::position(const byte *record)
+void ha_partition::position(const uchar *record)
{
handler *file= m_file[m_last_part];
DBUG_ENTER("ha_partition::position");
@@ -3189,13 +3213,13 @@ void ha_partition::position(const byte *record)
sql_update.cc.
*/
-int ha_partition::rnd_pos(byte * buf, byte *pos)
+int ha_partition::rnd_pos(uchar * buf, uchar *pos)
{
uint part_id;
handler *file;
DBUG_ENTER("ha_partition::rnd_pos");
- part_id= uint2korr((const byte *) pos);
+ part_id= uint2korr((const uchar *) pos);
DBUG_ASSERT(part_id < m_tot_parts);
file= m_file[part_id];
m_last_part= part_id;
@@ -3327,14 +3351,15 @@ int ha_partition::index_end()
used in conjuntion with multi read ranges.
*/
-int ha_partition::index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
+int ha_partition::index_read(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_partition::index_read");
end_range= 0;
m_index_scan_type= partition_index_read;
- DBUG_RETURN(common_index_read(buf, key, key_len, find_flag));
+ DBUG_RETURN(common_index_read(buf, key, keypart_map, find_flag));
}
@@ -3347,14 +3372,17 @@ int ha_partition::index_read(byte * buf, const byte * key,
see index_read for rest
*/
-int ha_partition::common_index_read(byte *buf, const byte *key, uint key_len,
+int ha_partition::common_index_read(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
enum ha_rkey_function find_flag)
{
int error;
bool reverse_order= FALSE;
+ uint key_len= calculate_key_len(table, active_index, key, keypart_map);
DBUG_ENTER("ha_partition::common_index_read");
memcpy((void*)m_start_key.key, key, key_len);
+ m_start_key.keypart_map= keypart_map;
m_start_key.length= key_len;
m_start_key.flag= find_flag;
@@ -3421,7 +3449,7 @@ int ha_partition::common_index_read(byte *buf, const byte *key, uint key_len,
and sql_select.cc.
*/
-int ha_partition::index_first(byte * buf)
+int ha_partition::index_first(uchar * buf)
{
DBUG_ENTER("ha_partition::index_first");
@@ -3452,7 +3480,7 @@ int ha_partition::index_first(byte * buf)
and sql_select.cc.
*/
-int ha_partition::index_last(byte * buf)
+int ha_partition::index_last(uchar * buf)
{
DBUG_ENTER("ha_partition::index_last");
@@ -3469,7 +3497,7 @@ int ha_partition::index_last(byte * buf)
see index_first for rest
*/
-int ha_partition::common_first_last(byte *buf)
+int ha_partition::common_first_last(uchar *buf)
{
int error;
@@ -3483,33 +3511,6 @@ int ha_partition::common_first_last(byte *buf)
/*
- Perform index read using index where always only one row is returned
-
- SYNOPSIS
- index_read_idx()
- see index_read for rest of parameters and return values
-
- DESCRIPTION
- Positions an index cursor to the index specified in key. Fetches the
- row if any. This is only used to read whole keys.
- TODO: Optimise this code to avoid index_init and index_end
-*/
-
-int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len,
- enum ha_rkey_function find_flag)
-{
- int res;
- DBUG_ENTER("ha_partition::index_read_idx");
-
- index_init(index, 0);
- res= index_read(buf, key, key_len, find_flag);
- index_end();
- DBUG_RETURN(res);
-}
-
-
-/*
Read last using key
SYNOPSIS
@@ -3527,14 +3528,15 @@ int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
Can only be used on indexes supporting HA_READ_ORDER
*/
-int ha_partition::index_read_last(byte *buf, const byte *key, uint keylen)
+int ha_partition::index_read_last(uchar *buf, const uchar *key,
+ key_part_map keypart_map)
{
DBUG_ENTER("ha_partition::index_read_last");
m_ordered= TRUE; // Safety measure
end_range= 0;
m_index_scan_type= partition_index_read_last;
- DBUG_RETURN(common_index_read(buf, key, keylen, HA_READ_PREFIX_LAST));
+ DBUG_RETURN(common_index_read(buf, key, keypart_map, HA_READ_PREFIX_LAST));
}
@@ -3553,7 +3555,7 @@ int ha_partition::index_read_last(byte *buf, const byte *key, uint keylen)
Used to read forward through the index.
*/
-int ha_partition::index_next(byte * buf)
+int ha_partition::index_next(uchar * buf)
{
DBUG_ENTER("ha_partition::index_next");
@@ -3589,7 +3591,7 @@ int ha_partition::index_next(byte * buf)
as supplied in the call.
*/
-int ha_partition::index_next_same(byte *buf, const byte *key, uint keylen)
+int ha_partition::index_next_same(uchar *buf, const uchar *key, uint keylen)
{
DBUG_ENTER("ha_partition::index_next_same");
@@ -3616,7 +3618,7 @@ int ha_partition::index_next_same(byte *buf, const byte *key, uint keylen)
Used to read backwards through the index.
*/
-int ha_partition::index_prev(byte * buf)
+int ha_partition::index_prev(uchar * buf)
{
DBUG_ENTER("ha_partition::index_prev");
@@ -3680,7 +3682,7 @@ int ha_partition::read_range_first(const key_range *start_key,
m_index_scan_type= partition_index_read;
error= common_index_read(m_rec0,
start_key->key,
- start_key->length, start_key->flag);
+ start_key->keypart_map, start_key->flag);
}
DBUG_RETURN(error);
}
@@ -3725,7 +3727,7 @@ int ha_partition::read_range_next()
of them
*/
-int ha_partition::partition_scan_set_up(byte * buf, bool idx_read_flag)
+int ha_partition::partition_scan_set_up(uchar * buf, bool idx_read_flag)
{
DBUG_ENTER("ha_partition::partition_scan_set_up");
@@ -3806,7 +3808,7 @@ int ha_partition::partition_scan_set_up(byte * buf, bool idx_read_flag)
perform any sort.
*/
-int ha_partition::handle_unordered_next(byte *buf, bool is_next_same)
+int ha_partition::handle_unordered_next(uchar *buf, bool is_next_same)
{
handler *file= file= m_file[m_part_spec.start_part];
int error;
@@ -3861,7 +3863,7 @@ int ha_partition::handle_unordered_next(byte *buf, bool is_next_same)
Both initial start and after completing scan on one partition.
*/
-int ha_partition::handle_unordered_scan_next_partition(byte * buf)
+int ha_partition::handle_unordered_scan_next_partition(uchar * buf)
{
uint i;
DBUG_ENTER("ha_partition::handle_unordered_scan_next_partition");
@@ -3879,7 +3881,7 @@ int ha_partition::handle_unordered_scan_next_partition(byte * buf)
case partition_index_read:
DBUG_PRINT("info", ("index_read on partition %d", i));
error= file->index_read(buf, m_start_key.key,
- m_start_key.length,
+ m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@@ -3948,7 +3950,7 @@ int ha_partition::handle_unordered_scan_next_partition(byte * buf)
entries.
*/
-int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
+int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order)
{
uint i;
uint j= 0;
@@ -3963,7 +3965,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
{
if (!(bitmap_is_set(&(m_part_info->used_partitions), i)))
continue;
- byte *rec_buf_ptr= rec_buf(i);
+ uchar *rec_buf_ptr= rec_buf(i);
int error;
handler *file= m_file[i];
@@ -3971,7 +3973,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read:
error= file->index_read(rec_buf_ptr,
m_start_key.key,
- m_start_key.length,
+ m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@@ -3985,7 +3987,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read_last:
error= file->index_read_last(rec_buf_ptr,
m_start_key.key,
- m_start_key.length);
+ m_start_key.keypart_map);
reverse_order= TRUE;
break;
default:
@@ -3998,7 +4000,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
/*
Initialise queue without order first, simply insert
*/
- queue_element(&m_queue, j++)= (byte*)queue_buf(i);
+ queue_element(&m_queue, j++)= (uchar*)queue_buf(i);
}
else if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
@@ -4016,6 +4018,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
m_queue.elements= j;
queue_fix(&m_queue);
return_top_record(buf);
+ table->status= 0;
DBUG_PRINT("info", ("Record returned from partition %d", m_top_entry));
DBUG_RETURN(0);
}
@@ -4034,11 +4037,11 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
NONE
*/
-void ha_partition::return_top_record(byte *buf)
+void ha_partition::return_top_record(uchar *buf)
{
uint part_id;
- byte *key_buffer= queue_top(&m_queue);
- byte *rec_buffer= key_buffer + PARTITION_BYTES_IN_POS;
+ uchar *key_buffer= queue_top(&m_queue);
+ uchar *rec_buffer= key_buffer + PARTITION_BYTES_IN_POS;
part_id= uint2korr(key_buffer);
memcpy(buf, rec_buffer, m_rec_length);
@@ -4061,7 +4064,7 @@ void ha_partition::return_top_record(byte *buf)
other Error code
*/
-int ha_partition::handle_ordered_next(byte *buf, bool is_next_same)
+int ha_partition::handle_ordered_next(uchar *buf, bool is_next_same)
{
int error;
uint part_id= m_top_entry;
@@ -4084,6 +4087,7 @@ int ha_partition::handle_ordered_next(byte *buf, bool is_next_same)
DBUG_PRINT("info", ("Record returned from partition %u (2)",
m_top_entry));
return_top_record(buf);
+ table->status= 0;
error= 0;
}
}
@@ -4109,7 +4113,7 @@ int ha_partition::handle_ordered_next(byte *buf, bool is_next_same)
other Error code
*/
-int ha_partition::handle_ordered_prev(byte *buf)
+int ha_partition::handle_ordered_prev(uchar *buf)
{
int error;
uint part_id= m_top_entry;
@@ -4127,6 +4131,7 @@ int ha_partition::handle_ordered_prev(byte *buf)
DBUG_PRINT("info", ("Record returned from partition %d (2)",
m_top_entry));
error= 0;
+ table->status= 0;
}
}
DBUG_RETURN(error);
@@ -4471,7 +4476,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
2) It is called from close_thread_table which in turn is called from
close_thread_tables except in the case where the tables are locked
in which case ha_commit_stmt is called instead.
- It is only called from here if flush_version hasn't changed and the
+ It is only called from here if refresh_version hasn't changed and the
table is not an old table when calling close_thread_table.
close_thread_tables is called from many places as a general clean up
function after completing a query.
@@ -4492,8 +4497,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
The handler will set HA_KEYREAD_ONLY in its table flags to indicate this
feature is supported.
HA_EXTRA_FLUSH:
- Indication to flush tables to disk, called at close_thread_table to
+ Indication to flush tables to disk, is supposed to be used to
ensure disk based tables are flushed at end of query execution.
+ Currently is never used.
2) Parameters used by some non-MyISAM handlers
----------------------------------------------
@@ -5352,7 +5358,7 @@ uint ha_partition::min_record_length(uint options) const
they are the same. Sort in partition id order if not equal.
*/
-int ha_partition::cmp_ref(const byte *ref1, const byte *ref2)
+int ha_partition::cmp_ref(const uchar *ref1, const uchar *ref2)
{
uint part_id;
my_ptrdiff_t diff1, diff2;
@@ -5561,11 +5567,11 @@ static int partition_init= 0;
Function we use in the creation of our hash to get key.
*/
-static byte *partition_get_key(PARTITION_SHARE *share, uint *length,
+static uchar *partition_get_key(PARTITION_SHARE *share, size_t *length,
my_bool not_used __attribute__ ((unused)))
{
*length= share->table_name_length;
- return (byte *) share->table_name;
+ return (uchar *) share->table_name;
}
/*
@@ -5605,12 +5611,12 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE *table)
length= (uint) strlen(table_name);
if (!(share= (PARTITION_SHARE *) hash_search(&partition_open_tables,
- (byte *) table_name, length)))
+ (uchar *) table_name, length)))
{
if (!(share= (PARTITION_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, sizeof(*share),
- &tmp_name, length + 1, NullS)))
+ &share, (uint) sizeof(*share),
+ &tmp_name, (uint) length + 1, NullS)))
{
pthread_mutex_unlock(&partition_mutex);
return NULL;
@@ -5620,7 +5626,7 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE *table)
share->table_name_length= length;
share->table_name= tmp_name;
strmov(share->table_name, table_name);
- if (my_hash_insert(&partition_open_tables, (byte *) share))
+ if (my_hash_insert(&partition_open_tables, (uchar *) share))
goto error;
thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
@@ -5632,7 +5638,7 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE *table)
error:
pthread_mutex_unlock(&partition_mutex);
- my_free((gptr) share, MYF(0));
+ my_free((uchar*) share, MYF(0));
return NULL;
}
@@ -5649,10 +5655,10 @@ static int free_share(PARTITION_SHARE *share)
pthread_mutex_lock(&partition_mutex);
if (!--share->use_count)
{
- hash_delete(&partition_open_tables, (byte *) share);
+ hash_delete(&partition_open_tables, (uchar *) share);
thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex);
- my_free((gptr) share, MYF(0));
+ my_free((uchar*) share, MYF(0));
}
pthread_mutex_unlock(&partition_mutex);
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 40af30bf08c..a168007ea04 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,6 +27,7 @@ enum partition_keywords
The partition implements the minimum of what you will probably need.
*/
+#ifdef NOT_USED
typedef struct st_partition_share
{
char *table_name;
@@ -35,6 +35,7 @@ typedef struct st_partition_share
pthread_mutex_t mutex;
THR_LOCK lock;
} PARTITION_SHARE;
+#endif
#define PARTITION_BYTES_IN_POS 2
@@ -55,19 +56,19 @@ private:
uint m_open_test_lock; // Open test_if_locked
char *m_file_buffer; // Buffer with names
char *m_name_buffer_ptr; // Pointer to first partition name
- handlerton **m_engine_array; // Array of types of the handlers
+ plugin_ref *m_engine_array; // Array of types of the handlers
handler **m_file; // Array of references to handler inst.
uint m_file_tot_parts; // Debug
handler **m_new_file; // Array of references to new handlers
handler **m_reorged_file; // Reorganised partitions
handler **m_added_file; // Added parts kept for errors
partition_info *m_part_info; // local reference to partition
- byte *m_start_key_ref; // Reference of start key in current
+ uchar *m_start_key_ref; // Reference of start key in current
// index scan info
Field **m_part_field_array; // Part field array locally to save acc
- byte *m_ordered_rec_buffer; // Row and key buffer for ord. idx scan
+ uchar *m_ordered_rec_buffer; // Row and key buffer for ord. idx scan
KEY *m_curr_key_info; // Current index
- byte *m_rec0; // table->record[0]
+ uchar *m_rec0; // table->record[0]
QUEUE m_queue; // Prio queue used by sorted read
/*
Since the partition handler is a handler on top of other handlers, it
@@ -131,9 +132,17 @@ private:
Variables for lock structures.
*/
THR_LOCK_DATA lock; /* MySQL lock */
+#ifdef NOT_USED
PARTITION_SHARE *share; /* Shared lock info */
+#endif
+ /*
+ TRUE <=> this object was created with ha_partition::clone and doesn't
+ "own" the m_part_info structure.
+ */
+ bool is_clone;
public:
+ handler *clone(MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info)
{
m_part_info= part_info;
@@ -190,8 +199,8 @@ public:
const char *path,
ulonglong *copied,
ulonglong *deleted,
- const void *pack_frm_data,
- uint pack_frm_len);
+ const uchar *pack_frm_data,
+ size_t pack_frm_len);
virtual int drop_partitions(const char *path);
virtual int rename_partitions(const char *path);
bool get_no_parts(const char *name, uint *no_parts)
@@ -301,9 +310,9 @@ public:
number of calls to write_row.
Not yet though.
*/
- virtual int write_row(byte * buf);
- virtual int update_row(const byte * old_data, byte * new_data);
- virtual int delete_row(const byte * buf);
+ virtual int write_row(uchar * buf);
+ virtual int update_row(const uchar * old_data, uchar * new_data);
+ virtual int delete_row(const uchar * buf);
virtual int delete_all_rows(void);
virtual void start_bulk_insert(ha_rows rows);
virtual int end_bulk_insert();
@@ -342,9 +351,9 @@ public:
*/
virtual int rnd_init(bool scan);
virtual int rnd_end();
- virtual int rnd_next(byte * buf);
- virtual int rnd_pos(byte * buf, byte * pos);
- virtual void position(const byte * record);
+ virtual int rnd_next(uchar * buf);
+ virtual int rnd_pos(uchar * buf, uchar * pos);
+ virtual void position(const uchar * record);
/*
-------------------------------------------------------------------------
@@ -378,10 +387,9 @@ public:
index_init initializes an index before using it and index_end does
any end processing needed.
*/
- virtual int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- virtual int index_read_idx(byte * buf, uint idx, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
+ virtual int index_read(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
virtual int index_init(uint idx, bool sorted);
virtual int index_end();
@@ -389,19 +397,20 @@ public:
These methods are used to jump to next or previous entry in the index
scan. There are also methods to jump to first and last entry.
*/
- virtual int index_next(byte * buf);
- virtual int index_prev(byte * buf);
- virtual int index_first(byte * buf);
- virtual int index_last(byte * buf);
- virtual int index_next_same(byte * buf, const byte * key, uint keylen);
- virtual int index_read_last(byte * buf, const byte * key, uint keylen);
+ virtual int index_next(uchar * buf);
+ virtual int index_prev(uchar * buf);
+ virtual int index_first(uchar * buf);
+ virtual int index_last(uchar * buf);
+ virtual int index_next_same(uchar * buf, const uchar * key, uint keylen);
+ virtual int index_read_last(uchar * buf, const uchar * key,
+ key_part_map keypart_map);
/*
read_first_row is virtual method but is only implemented by
handler.cc, no storage engine has implemented it so neither
will the partition handler.
- virtual int read_first_row(byte *buf, uint primary_key);
+ virtual int read_first_row(uchar *buf, uint primary_key);
*/
/*
@@ -419,26 +428,27 @@ public:
virtual int read_range_next();
private:
- int common_index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- int common_first_last(byte * buf);
- int partition_scan_set_up(byte * buf, bool idx_read_flag);
- int handle_unordered_next(byte * buf, bool next_same);
- int handle_unordered_scan_next_partition(byte * buf);
- byte *queue_buf(uint part_id)
+ int common_index_read(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int common_first_last(uchar * buf);
+ int partition_scan_set_up(uchar * buf, bool idx_read_flag);
+ int handle_unordered_next(uchar * buf, bool next_same);
+ int handle_unordered_scan_next_partition(uchar * buf);
+ uchar *queue_buf(uint part_id)
{
return (m_ordered_rec_buffer +
(part_id * (m_rec_length + PARTITION_BYTES_IN_POS)));
}
- byte *rec_buf(uint part_id)
+ uchar *rec_buf(uint part_id)
{
return (queue_buf(part_id) +
PARTITION_BYTES_IN_POS);
}
- int handle_ordered_index_scan(byte * buf, bool reverse_order);
- int handle_ordered_next(byte * buf, bool next_same);
- int handle_ordered_prev(byte * buf);
- void return_top_record(byte * buf);
+ int handle_ordered_index_scan(uchar * buf, bool reverse_order);
+ int handle_ordered_next(uchar * buf, bool next_same);
+ int handle_ordered_prev(uchar * buf);
+ void return_top_record(uchar * buf);
void include_partition_fields_in_used_fields();
public:
/*
@@ -803,7 +813,7 @@ public:
to check whether the rest of the reference part is also the same.
-------------------------------------------------------------------------
*/
- virtual int cmp_ref(const byte * ref1, const byte * ref2);
+ virtual int cmp_ref(const uchar * ref1, const uchar * ref2);
/*
-------------------------------------------------------------------------
MODULE auto increment
@@ -867,10 +877,10 @@ public:
Fulltext stuff not yet.
-------------------------------------------------------------------------
virtual int ft_init() { return HA_ERR_WRONG_COMMAND; }
- virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key,
+ virtual FT_INFO *ft_init_ext(uint flags,uint inx,const uchar *key,
uint keylen)
{ return NULL; }
- virtual int ft_read(byte *buf) { return HA_ERR_WRONG_COMMAND; }
+ virtual int ft_read(uchar *buf) { return HA_ERR_WRONG_COMMAND; }
*/
/*
@@ -879,7 +889,7 @@ public:
-------------------------------------------------------------------------
The following method is only used by MyISAM when used as
temporary tables in a join.
- virtual int restart_rnd_next(byte *buf, byte *pos);
+ virtual int restart_rnd_next(uchar *buf, uchar *pos);
*/
/*
diff --git a/sql/handler.cc b/sql/handler.cc
index 9c4221dc43c..afb88dc962d 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,8 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/** @file handler.cc
-/* Handler-calling-functions */
+ @brief
+ Handler-calling-functions
+*/
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
@@ -45,12 +47,6 @@ static handlerton *installed_htons[128];
KEY_CREATE_INFO default_key_create_info= { HA_KEY_ALG_UNDEF, 0, {NullS,0} };
-/* static functions defined in this file */
-
-static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root);
-
-static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
-
/* number of entries in handlertons[] */
ulong total_ha= 0;
/* number of storage engines (from handlertons[]) that support 2pc */
@@ -81,27 +77,36 @@ static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
uint known_extensions_id= 0;
-/*
+
+static plugin_ref ha_default_plugin(THD *thd)
+{
+ if (thd->variables.table_plugin)
+ return thd->variables.table_plugin;
+ return my_plugin_lock(thd, &global_system_variables.table_plugin);
+}
+
+
+/** @brief
Return the default storage engine handlerton for thread
-
+
SYNOPSIS
ha_default_handlerton(thd)
thd current thread
-
+
RETURN
pointer to handlerton
*/
-
handlerton *ha_default_handlerton(THD *thd)
{
- return (thd->variables.table_type != NULL) ?
- thd->variables.table_type :
- (global_system_variables.table_type != NULL ?
- global_system_variables.table_type : myisam_hton);
+ plugin_ref plugin= ha_default_plugin(thd);
+ DBUG_ASSERT(plugin);
+ handlerton *hton= plugin_data(plugin, handlerton*);
+ DBUG_ASSERT(hton);
+ return hton;
}
-/*
+/** @brief
Return the storage engine handlerton for the supplied name
SYNOPSIS
@@ -110,27 +115,30 @@ handlerton *ha_default_handlerton(THD *thd)
name name of storage engine
RETURN
- pointer to handlerton
+ pointer to storage engine plugin handle
*/
-
-handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name)
+plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name)
{
const LEX_STRING *table_alias;
- st_plugin_int *plugin;
+ plugin_ref plugin;
redo:
/* my_strnncoll is a macro and gcc doesn't do early expansion of macro */
if (thd && !my_charset_latin1.coll->strnncoll(&my_charset_latin1,
(const uchar *)name->str, name->length,
(const uchar *)STRING_WITH_LEN("DEFAULT"), 0))
- return ha_default_handlerton(thd);
+ return ha_default_plugin(thd);
- if ((plugin= plugin_lock(name, MYSQL_STORAGE_ENGINE_PLUGIN)))
+ if ((plugin= my_plugin_lock_by_name(thd, name, MYSQL_STORAGE_ENGINE_PLUGIN)))
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (!(hton->flags & HTON_NOT_USER_SELECTABLE))
- return hton;
- plugin_unlock(plugin);
+ return plugin;
+
+ /*
+ unlocking plugin immediately after locking is relatively low cost.
+ */
+ plugin_unlock(thd, plugin);
}
/*
@@ -151,46 +159,51 @@ redo:
}
-const char *ha_get_storage_engine(enum legacy_db_type db_type)
+plugin_ref ha_lock_engine(THD *thd, handlerton *hton)
{
- switch (db_type) {
- case DB_TYPE_DEFAULT:
- return "DEFAULT";
- default:
- if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
- installed_htons[db_type])
- return hton2plugin[installed_htons[db_type]->slot]->name.str;
- /* fall through */
- case DB_TYPE_UNKNOWN:
- return "UNKNOWN";
+ if (hton)
+ {
+ st_plugin_int **plugin= hton2plugin + hton->slot;
+
+#ifdef DBUG_OFF
+ return my_plugin_lock(thd, plugin);
+#else
+ return my_plugin_lock(thd, &plugin);
+#endif
}
+ return NULL;
}
+#ifdef NOT_USED
static handler *create_default(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
handlerton *hton= ha_default_handlerton(current_thd);
return (hton && hton->create) ? hton->create(hton, table, mem_root) : NULL;
}
+#endif
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type)
{
+ plugin_ref plugin;
switch (db_type) {
case DB_TYPE_DEFAULT:
return ha_default_handlerton(thd);
- case DB_TYPE_UNKNOWN:
- return NULL;
default:
- if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT)
- return installed_htons[db_type];
+ if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
+ (plugin= ha_lock_engine(thd, installed_htons[db_type])))
+ return plugin_data(plugin, handlerton*);
+ /* fall through */
+ case DB_TYPE_UNKNOWN:
return NULL;
}
}
-/* Use other database handler if databasehandler is not compiled in */
-
+/** @brief
+ Use other database handler if databasehandler is not compiled in
+*/
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
bool no_substitute, bool report_error)
{
@@ -202,7 +215,7 @@ handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
{
if (report_error)
{
- const char *engine_name= ha_get_storage_engine(database_type);
+ const char *engine_name= ha_resolve_storage_engine_name(hton);
my_error(ER_FEATURE_DISABLED,MYF(0),engine_name,engine_name);
}
return NULL;
@@ -241,8 +254,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
Here the call to current_thd() is ok as we call this function a lot of
times but we enter this branch very seldom.
*/
- DBUG_RETURN(get_new_handler(share, alloc,
- current_thd->variables.table_type));
+ DBUG_RETURN(get_new_handler(share, alloc, ha_default_handlerton(current_thd)));
}
@@ -270,7 +282,7 @@ handler *get_ha_partition(partition_info *part_info)
#endif
-/*
+/** @brief
Register handler error messages for use with my_error().
SYNOPSIS
@@ -280,7 +292,6 @@ handler *get_ha_partition(partition_info *part_info)
0 OK
!= 0 Error
*/
-
static int ha_init_errors(void)
{
#define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg)
@@ -340,7 +351,7 @@ static int ha_init_errors(void)
}
-/*
+/** @brief
Unregister handler error messages.
SYNOPSIS
@@ -350,7 +361,6 @@ static int ha_init_errors(void)
0 OK
!= 0 Error
*/
-
static int ha_finish_errors(void)
{
const char **errmsgs;
@@ -358,7 +368,7 @@ static int ha_finish_errors(void)
/* Allocate a pointer array for the error message strings. */
if (! (errmsgs= my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST)))
return 1;
- my_free((gptr) errmsgs, MYF(0));
+ my_free((uchar*) errmsgs, MYF(0));
return 0;
}
@@ -396,7 +406,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
}
}
- my_free((gptr)hton, MYF(0));
+ my_free((uchar*)hton, MYF(0));
DBUG_RETURN(0);
}
@@ -406,6 +416,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
{
handlerton *hton;
DBUG_ENTER("ha_initialize_handlerton");
+ DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str));
hton= (handlerton *)my_malloc(sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
@@ -527,10 +538,10 @@ int ha_end()
DBUG_RETURN(error);
}
-static my_bool dropdb_handlerton(THD *unused1, st_plugin_int *plugin,
+static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin,
void *path)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->drop_database)
hton->drop_database(hton, (char *)path);
return FALSE;
@@ -543,10 +554,10 @@ void ha_drop_database(char* path)
}
-static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
void *unused)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
/*
there's no need to rollback here as all transactions must
be rolled back already
@@ -558,7 +569,9 @@ static my_bool closecon_handlerton(THD *thd, st_plugin_int *plugin,
}
-/* don't bother to rollback here, it's done already */
+/** @brief
+ don't bother to rollback here, it's done already
+*/
void ha_close_connection(THD* thd)
{
plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0);
@@ -567,7 +580,7 @@ void ha_close_connection(THD* thd)
/* ========================================================================
======================= TRANSACTIONS ===================================*/
-/*
+/** @brief
Register a storage engine for a transaction
DESCRIPTION
@@ -609,7 +622,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
DBUG_VOID_RETURN;
}
-/*
+/** @brief
RETURN
0 - ok
1 - error, transaction was rolled back
@@ -626,7 +639,7 @@ int ha_prepare(THD *thd)
for (; *ht; ht++)
{
int err;
- statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_prepare_count);
if ((*ht)->prepare)
{
if ((err= (*(*ht)->prepare)(*ht, thd, all)))
@@ -641,7 +654,7 @@ int ha_prepare(THD *thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
- hton2plugin[(*ht)->slot]->name.str);
+ ha_resolve_storage_engine_name(*ht));
}
}
}
@@ -649,7 +662,7 @@ int ha_prepare(THD *thd)
DBUG_RETURN(error);
}
-/*
+/** @brief
RETURN
0 - ok
1 - transaction was rolled back
@@ -692,6 +705,19 @@ int ha_commit_trans(THD *thd, bool all)
ha_rollback_trans(thd, all);
DBUG_RETURN(1);
}
+
+ if ( is_real_trans
+ && opt_readonly
+ && ! (thd->security_ctx->master_access & SUPER_ACL)
+ && ! thd->slave_thread
+ )
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ ha_rollback_trans(thd, all);
+ error= 1;
+ goto end;
+ }
+
DBUG_EXECUTE_IF("crash_commit_before", abort(););
/* Close all cursors that can not survive COMMIT */
@@ -708,11 +734,11 @@ int ha_commit_trans(THD *thd, bool all)
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error= 1;
}
- statistic_increment(thd->status_var.ha_prepare_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_prepare_count);
}
DBUG_EXECUTE_IF("crash_commit_after_prepare", abort(););
if (error || (is_real_trans && xid &&
- (error= !(cookie= tc_log->log(thd, xid)))))
+ (error= !(cookie= tc_log->log_xid(thd, xid)))))
{
ha_rollback_trans(thd, all);
error= 1;
@@ -720,7 +746,7 @@ int ha_commit_trans(THD *thd, bool all)
}
DBUG_EXECUTE_IF("crash_commit_after_log", abort(););
}
- error=ha_commit_one_phase(thd, all) ? cookie ? 2 : 1 : 0;
+ error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
DBUG_EXECUTE_IF("crash_commit_before_unlog", abort(););
if (cookie)
tc_log->unlog(cookie, xid);
@@ -733,7 +759,7 @@ end:
DBUG_RETURN(error);
}
-/*
+/** @brief
NOTE - this function does not care about global read lock.
A caller should.
*/
@@ -755,7 +781,7 @@ int ha_commit_one_phase(THD *thd, bool all)
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error=1;
}
- statistic_increment(thd->status_var.ha_commit_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_commit_count);
*ht= 0;
}
trans->nht=0;
@@ -811,7 +837,7 @@ int ha_rollback_trans(THD *thd, bool all)
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
- statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_rollback_count);
*ht= 0;
}
trans->nht=0;
@@ -834,15 +860,15 @@ int ha_rollback_trans(THD *thd, bool all)
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
*/
- if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
- !thd->slave_thread)
+ if (is_real_trans && thd->no_trans_update.all &&
+ !thd->slave_thread && thd->killed != THD::KILL_CONNECTION)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
DBUG_RETURN(error);
}
-/*
+/** @brief
This is used to commit or rollback a single statement depending on the value
of error. Note that if the autocommit is on, then the following call inside
InnoDB will commit or rollback the whole transaction (= the statement). The
@@ -850,7 +876,6 @@ int ha_rollback_trans(THD *thd, bool all)
the user has used LOCK TABLES then that mechanism does not know to do the
commit.
*/
-
int ha_autocommit_or_rollback(THD *thd, int error)
{
DBUG_ENTER("ha_autocommit_or_rollback");
@@ -877,10 +902,10 @@ struct xahton_st {
int result;
};
-static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin,
+static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
@@ -889,10 +914,10 @@ static my_bool xacommit_handlerton(THD *unused1, st_plugin_int *plugin,
return FALSE;
}
-static my_bool xarollback_handlerton(THD *unused1, st_plugin_int *plugin,
+static my_bool xarollback_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->recover)
{
hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
@@ -968,7 +993,7 @@ static char* xid_to_str(char *buf, XID *xid)
}
#endif
-/*
+/** @brief
recover() step of xa
NOTE
@@ -987,7 +1012,6 @@ static char* xid_to_str(char *buf, XID *xid)
in this case commit_list==0, tc_heuristic_recover == 0
there should be no prepared transactions in this case.
*/
-
struct xarecover_st
{
int len, found_foreign_xids, found_my_xids;
@@ -996,10 +1020,10 @@ struct xarecover_st
bool dry_run;
};
-static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
+static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
void *arg)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
struct xarecover_st *info= (struct xarecover_st *) arg;
int got;
@@ -1008,7 +1032,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
{
sql_print_information("Found %d prepared transaction(s) in %s",
- got, hton2plugin[hton->slot]->name.str);
+ got, ha_resolve_storage_engine_name(hton));
for (int i=0; i < got; i ++)
{
my_xid x=info->list[i].get_my_xid();
@@ -1029,7 +1053,7 @@ static my_bool xarecover_handlerton(THD *unused, st_plugin_int *plugin,
}
// recovery mode
if (info->commit_list ?
- hash_search(info->commit_list, (byte *)&x, sizeof(x)) != 0 :
+ hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
{
#ifndef DBUG_OFF
@@ -1099,7 +1123,7 @@ int ha_recover(HASH *commit_list)
plugin_foreach(NULL, xarecover_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &info);
- my_free((gptr)info.list, MYF(0));
+ my_free((uchar*)info.list, MYF(0));
if (info.found_foreign_xids)
sql_print_warning("Found %d prepared XA transactions",
info.found_foreign_xids);
@@ -1119,7 +1143,7 @@ int ha_recover(HASH *commit_list)
DBUG_RETURN(0);
}
-/*
+/** @brief
return the list of XID's to a client, the same way SHOW commands do
NOTE
@@ -1135,9 +1159,9 @@ bool mysql_xa_recover(THD *thd)
XID_STATE *xs;
DBUG_ENTER("mysql_xa_recover");
- field_list.push_back(new Item_int("formatID",0,11));
- field_list.push_back(new Item_int("gtrid_length",0,11));
- field_list.push_back(new Item_int("bqual_length",0,11));
+ field_list.push_back(new Item_int("formatID", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_int("gtrid_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
if (protocol->send_fields(&field_list,
@@ -1168,7 +1192,7 @@ bool mysql_xa_recover(THD *thd)
DBUG_RETURN(0);
}
-/*
+/** @brief
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
@@ -1184,11 +1208,10 @@ bool mysql_xa_recover(THD *thd)
thd: the thread handle of the current connection
return value: always 0
*/
-
-static my_bool release_temporary_latches(THD *thd, st_plugin_int *plugin,
+static my_bool release_temporary_latches(THD *thd, plugin_ref plugin,
void *unused)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->release_temporary_latches)
hton->release_temporary_latches(hton, thd);
@@ -1224,13 +1247,12 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
{
int err;
DBUG_ASSERT((*ht)->savepoint_set != 0);
- if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
+ if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
- statistic_increment(thd->status_var.ha_savepoint_rollback_count,
- &LOCK_status);
+ status_var_increment(thd->status_var.ha_savepoint_rollback_count);
trans->no_2pc|=(*ht)->prepare == 0;
}
/*
@@ -1245,18 +1267,17 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
- statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_rollback_count);
*ht=0; // keep it conveniently zero-filled
}
DBUG_RETURN(error);
}
-/*
+/** @brief
note, that according to the sql standard (ISO/IEC 9075-2:2003)
section "4.33.4 SQL-statements and transaction states",
SAVEPOINT is *not* transaction-initiating SQL-statement
*/
-
int ha_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
@@ -1274,12 +1295,12 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
error=1;
break;
}
- if ((err= (*(*ht)->savepoint_set)(*ht, thd, (byte *)(sv+1)+(*ht)->savepoint_offset)))
+ if ((err= (*(*ht)->savepoint_set)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
error=1;
}
- statistic_increment(thd->status_var.ha_savepoint_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_savepoint_count);
}
sv->nht=trans->nht;
#endif /* USING_TRANSACTIONS */
@@ -1301,7 +1322,7 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
if (!(*ht)->savepoint_release)
continue;
if ((err= (*(*ht)->savepoint_release)(*ht, thd,
- (byte *)(sv+1)+
+ (uchar *)(sv+1)+
(*ht)->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
@@ -1312,10 +1333,10 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
}
-static my_bool snapshot_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES &&
hton->start_consistent_snapshot)
{
@@ -1343,10 +1364,10 @@ int ha_start_consistent_snapshot(THD *thd)
}
-static my_bool flush_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool flush_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
hton->flush_logs(hton))
return TRUE;
@@ -1371,11 +1392,10 @@ bool ha_flush_logs(handlerton *db_type)
return FALSE;
}
-/*
+/** @brief
This should return ENOENT if the file doesn't exists.
The .frm file will be deleted only if we return 0 or ENOENT
*/
-
int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
const char *db, const char *alias, bool generate_warning)
{
@@ -1392,7 +1412,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
if (table_type == NULL ||
- ! (file=get_new_handler(&dummy_share, thd->mem_root, table_type)))
+ ! (file=get_new_handler((TABLE_SHARE*)0, thd->mem_root, table_type)))
DBUG_RETURN(ENOENT);
if (lower_case_table_names == 2 && !(file->ha_table_flags() & HA_FILE_BASED))
@@ -1433,6 +1453,8 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
dummy_share.table_name.length= strlen(alias);
dummy_table.alias= alias;
+ file->table_share= &dummy_share;
+ file->table= &dummy_table;
file->print_error(error, 0);
strmake(new_error, thd->net.last_error, sizeof(buff)-1);
@@ -1453,7 +1475,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
****************************************************************************/
handler *handler::clone(MEM_ROOT *mem_root)
{
- handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type);
+ handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
if (new_handler && !new_handler->ha_open(table,
table->s->normalized_path.str,
table->db_stat,
@@ -1466,7 +1488,18 @@ handler *handler::clone(MEM_ROOT *mem_root)
void handler::ha_statistic_increment(ulong SSV::*offset) const
{
- statistic_increment(table->in_use->status_var.*offset, &LOCK_status);
+ status_var_increment(table->in_use->status_var.*offset);
+}
+
+void **handler::ha_data(THD *thd) const
+{
+ return (void **) thd->ha_data + ht->slot;
+}
+
+THD *handler::ha_thd(void) const
+{
+ DBUG_ASSERT(!table || !table->in_use || table->in_use == current_thd);
+ return (table && table->in_use) ? table->in_use : current_thd;
}
@@ -1498,14 +1531,13 @@ bool handler::check_if_log_table_locking_is_allowed(uint sql_command,
return TRUE;
}
-/*
+/** @brief
Open database-handler.
IMPLEMENTATION
Try O_RDONLY if cannot open as O_RDWR
Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set
*/
-
int handler::ha_open(TABLE *table_arg, const char *name, int mode,
int test_if_locked)
{
@@ -1540,7 +1572,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
- if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
+ if (!(ref= (uchar*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2)))
{
close();
error=HA_ERR_OUT_OF_MEM;
@@ -1553,19 +1585,17 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
}
-/*
+/** @brief
Read first row (only) from a table
This is never called for InnoDB tables, as these table types
has the HA_STATS_RECORDS_IS_EXACT set.
*/
-
-int handler::read_first_row(byte * buf, uint primary_key)
+int handler::read_first_row(uchar * buf, uint primary_key)
{
register int error;
DBUG_ENTER("handler::read_first_row");
- statistic_increment(table->in_use->status_var.ha_read_first_count,
- &LOCK_status);
+ ha_statistic_increment(&SSV::ha_read_first_count);
/*
If there is very few deleted rows in the table, find the first row by
@@ -1589,7 +1619,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
DBUG_RETURN(error);
}
-/*
+/** @brief
Generate the next auto-increment number based on increment and offset:
computes the lowest number
- strictly greater than "nr"
@@ -1600,7 +1630,6 @@ int handler::read_first_row(byte * buf, uint primary_key)
If increment=10 and offset=5 and previous number is 1, we get:
1,5,15,25,35,...
*/
-
inline ulonglong
compute_next_insert_id(ulonglong nr,struct system_variables *variables)
{
@@ -1626,7 +1655,7 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
}
-/*
+/** @brief
Computes the largest number X:
- smaller than or equal to "nr"
- of the form: auto_increment_offset + N * auto_increment_increment
@@ -1641,7 +1670,6 @@ void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr)
RETURN
The number X if it exists, "nr" otherwise.
*/
-
inline ulonglong
prev_insert_id(ulonglong nr, struct system_variables *variables)
{
@@ -1752,7 +1780,6 @@ int handler::update_auto_increment()
bool append= FALSE;
THD *thd= table->in_use;
struct system_variables *variables= &thd->variables;
- bool auto_increment_field_not_null;
DBUG_ENTER("handler::update_auto_increment");
/*
@@ -1760,11 +1787,9 @@ int handler::update_auto_increment()
than the interval, but not smaller.
*/
DBUG_ASSERT(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
- auto_increment_field_not_null= table->auto_increment_field_not_null;
- table->auto_increment_field_not_null= FALSE; // to reset for next row
if ((nr= table->next_number_field->val_int()) != 0 ||
- auto_increment_field_not_null &&
+ table->auto_increment_field_not_null &&
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
{
/*
@@ -1842,7 +1867,7 @@ int handler::update_auto_increment()
nr= compute_next_insert_id(nr-1, variables);
}
- if (table->s->next_number_key_offset == 0)
+ if (table->s->next_number_keypart == 0)
{
/* We must defer the appending until "nr" has been possibly truncated */
append= TRUE;
@@ -1910,7 +1935,7 @@ int handler::update_auto_increment()
}
-/*
+/** @brief
MySQL signal that it changed the column bitmap
USAGE
@@ -1923,7 +1948,6 @@ int handler::update_auto_increment()
rnd_init() call is made as after this, MySQL will not use the bitmap
for any program logic checking.
*/
-
void handler::column_bitmaps_signal()
{
DBUG_ENTER("column_bitmaps_signal");
@@ -1933,7 +1957,7 @@ void handler::column_bitmaps_signal()
}
-/*
+/** @brief
Reserves an interval of auto_increment values from the handler.
SYNOPSIS
@@ -1950,7 +1974,6 @@ void handler::column_bitmaps_signal()
If the function sets *nb_reserved_values to ULONGLONG_MAX it means it has
reserved to "positive infinite".
*/
-
void handler::get_auto_increment(ulonglong offset, ulonglong increment,
ulonglong nb_desired_values,
ulonglong *first_value,
@@ -1964,7 +1987,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
table->read_set);
column_bitmaps_signal();
index_init(table->s->next_number_index, 1);
- if (!table->s->next_number_key_offset)
+ if (table->s->next_number_keypart == 0)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
/*
@@ -1976,11 +1999,12 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
}
else
{
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
key_copy(key, table->record[0],
table->key_info + table->s->next_number_index,
table->s->next_number_key_offset);
- error= index_read(table->record[1], key, table->s->next_number_key_offset,
+ error= index_read(table->record[1], key,
+ make_prev_keypart_map(table->s->next_number_keypart),
HA_READ_PREFIX_LAST);
/*
MySQL needs to call us for next row: assume we are inserting ("a",null)
@@ -2029,7 +2053,7 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
{
/* Key is unknown */
str.copy("", 0, system_charset_info);
- my_printf_error(ER_DUP_ENTRY, msg,
+ my_printf_error(ER_DUP_ENTRY_WITH_KEY_NAME, msg,
MYF(0), str.c_ptr(), "*UNKNOWN*");
}
else
@@ -2042,13 +2066,13 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
str.length(max_length-4);
str.append(STRING_WITH_LEN("..."));
}
- my_printf_error(ER_DUP_ENTRY, msg,
+ my_printf_error(ER_DUP_ENTRY_WITH_KEY_NAME, msg,
MYF(0), str.c_ptr(), table->key_info[key_nr].name);
}
}
-/*
+/** @brief
Print error that we got from handler function
NOTE
@@ -2057,7 +2081,6 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
table->s->path
table->alias
*/
-
void handler::print_error(int error, myf errflag)
{
DBUG_ENTER("handler::print_error");
@@ -2087,7 +2110,7 @@ void handler::print_error(int error, myf errflag)
uint key_nr=get_dup_key(error);
if ((int) key_nr >= 0)
{
- print_keydup_error(key_nr, ER(ER_DUP_ENTRY));
+ print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
DBUG_VOID_RETURN;
}
textno=ER_DUP_KEY;
@@ -2243,7 +2266,7 @@ void handler::print_error(int error, myf errflag)
}
-/*
+/** @brief
Return an error message specific to this handler
SYNOPSIS
@@ -2251,8 +2274,7 @@ void handler::print_error(int error, myf errflag)
buf Pointer to String where to add error message
Returns true if this is a temporary error
- */
-
+*/
bool handler::get_error_message(int error, String* buf)
{
return FALSE;
@@ -2278,7 +2300,7 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt)
if (!keypart->fieldnr)
continue;
Field *field= table->field[keypart->fieldnr-1];
- if (field->type() == FIELD_TYPE_BLOB)
+ if (field->type() == MYSQL_TYPE_BLOB)
{
if (check_opt->sql_flags & TT_FOR_UPGRADE)
check_opt->flags= T_MEDIUM;
@@ -2300,7 +2322,7 @@ int handler::check_old_types()
/* check for bad DECIMAL field */
for (field= table->field; (*field); field++)
{
- if ((*field)->type() == FIELD_TYPE_NEWDECIMAL)
+ if ((*field)->type() == MYSQL_TYPE_NEWDECIMAL)
{
return HA_ADMIN_NEEDS_ALTER;
}
@@ -2314,7 +2336,7 @@ int handler::check_old_types()
}
-static bool update_frm_version(TABLE *table, bool needs_lock)
+static bool update_frm_version(TABLE *table)
{
char path[FN_REFLEN];
File file;
@@ -2326,9 +2348,6 @@ static bool update_frm_version(TABLE *table, bool needs_lock)
strxmov(path, table->s->normalized_path.str, reg_ext, NullS);
- if (needs_lock)
- pthread_mutex_lock(&LOCK_open);
-
if ((file= my_open(path, O_RDWR|O_BINARY, MYF(MY_WME))) >= 0)
{
uchar version[4];
@@ -2339,26 +2358,24 @@ static bool update_frm_version(TABLE *table, bool needs_lock)
int4store(version, MYSQL_VERSION_ID);
- if ((result= my_pwrite(file,(byte*) version,4,51L,MYF_RW)))
+ if ((result= my_pwrite(file,(uchar*) version,4,51L,MYF_RW)))
goto err;
- for (entry=(TABLE*) hash_first(&open_cache,(byte*) key,key_length, &state);
+ for (entry=(TABLE*) hash_first(&open_cache,(uchar*) key,key_length, &state);
entry;
- entry= (TABLE*) hash_next(&open_cache,(byte*) key,key_length, &state))
+ entry= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length, &state))
entry->s->mysql_version= MYSQL_VERSION_ID;
}
err:
if (file >= 0)
VOID(my_close(file,MYF(MY_WME)));
- if (needs_lock)
- pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(result);
}
-/* Return key if error because of duplicated keys */
-
+/** @brief
+ Return key if error because of duplicated keys */
uint handler::get_dup_key(int error)
{
DBUG_ENTER("handler::get_dup_key");
@@ -2371,7 +2388,7 @@ uint handler::get_dup_key(int error)
}
-/*
+/** @brief
Delete all files with extension from bas_ext()
SYNOPSIS
@@ -2387,7 +2404,6 @@ uint handler::get_dup_key(int error)
didn't get any other errors than ENOENT
# Error
*/
-
int handler::delete_table(const char *name)
{
int error= 0;
@@ -2433,7 +2449,7 @@ void handler::drop_table(const char *name)
}
-/*
+/** @brief
Performs checks upon the table.
SYNOPSIS
@@ -2449,7 +2465,6 @@ void handler::drop_table(const char *name)
HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE
HA_ADMIN_NOT_IMPLEMENTED
*/
-
int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
{
int error;
@@ -2470,7 +2485,7 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
}
if ((error= check(thd, check_opt)))
return error;
- return update_frm_version(table, 0);
+ return update_frm_version(table);
}
@@ -2479,11 +2494,11 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
int result;
if ((result= repair(thd, check_opt)))
return result;
- return update_frm_version(table, 0);
+ return update_frm_version(table);
}
-/*
+/** @brief
Tell the storage engine that it is allowed to "disable transaction" in the
handler. It is a hint that ACID is not required - it is used in NDB for
ALTER TABLE, for example, when data are copied to temporary table.
@@ -2491,7 +2506,6 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
starts to commit every now and then automatically.
This hint can be safely ignored.
*/
-
int ha_enable_transaction(THD *thd, bool on)
{
int error=0;
@@ -2512,7 +2526,7 @@ int ha_enable_transaction(THD *thd, bool on)
DBUG_RETURN(error);
}
-int handler::index_next_same(byte *buf, const byte *key, uint keylen)
+int handler::index_next_same(uchar *buf, const uchar *key, uint keylen)
{
int error;
if (!(error=index_next(buf)))
@@ -2552,7 +2566,7 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
** Some general functions that isn't in the handler class
****************************************************************************/
-/*
+/** @brief
Initiates table-file and calls appropriate database-creator
NOTES
@@ -2563,7 +2577,6 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
0 ok
1 error
*/
-
int ha_create_table(THD *thd, const char *path,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
@@ -2607,7 +2620,7 @@ err:
DBUG_RETURN(error != 0);
}
-/*
+/** @brief
Try to discover table from engine
NOTES
@@ -2619,12 +2632,11 @@ err:
> 0 Error, table existed but could not be created
*/
-
int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
{
int error;
- const void *frmblob;
- uint frmlen;
+ uchar *frmblob;
+ size_t frmlen;
char path[FN_REFLEN];
HA_CREATE_INFO create_info;
TABLE table;
@@ -2632,7 +2644,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
DBUG_ENTER("ha_create_table_from_engine");
DBUG_PRINT("enter", ("name '%s'.'%s'", db, name));
- bzero((char*) &create_info,sizeof(create_info));
+ bzero((uchar*) &create_info,sizeof(create_info));
if ((error= ha_discover(thd, db, name, &frmblob, &frmlen)))
{
/* Table could not be discovered and thus not created */
@@ -2647,7 +2659,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
(void)strxnmov(path,FN_REFLEN-1,mysql_data_home,"/",db,"/",name,NullS);
// Save the frm file
error= writefrm(path, frmblob, frmlen);
- my_free((char*) frmblob, MYF(0));
+ my_free(frmblob, MYF(0));
if (error)
DBUG_RETURN(2);
@@ -2694,9 +2706,9 @@ void st_ha_check_opt::init()
call to ha_init_key_cache() (probably out of memory)
*****************************************************************************/
-/* Init a key cache if it has not been initied before */
-
-
+/** @brief
+ Init a key cache if it has not been initied before
+*/
int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
{
DBUG_ENTER("ha_init_key_cache");
@@ -2704,8 +2716,8 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
if (!key_cache->key_cache_inited)
{
pthread_mutex_lock(&LOCK_global_system_variables);
- long tmp_buff_size= (long) key_cache->param_buff_size;
- long tmp_block_size= (long) key_cache->param_block_size;
+ ulong tmp_buff_size= (ulong) key_cache->param_buff_size;
+ uint tmp_block_size= (uint) key_cache->param_block_size;
uint division_limit= key_cache->param_division_limit;
uint age_threshold= key_cache->param_age_threshold;
pthread_mutex_unlock(&LOCK_global_system_variables);
@@ -2718,8 +2730,9 @@ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache)
}
-/* Resize key cache */
-
+/** @brief
+ Resize key cache
+*/
int ha_resize_key_cache(KEY_CACHE *key_cache)
{
DBUG_ENTER("ha_resize_key_cache");
@@ -2740,8 +2753,9 @@ int ha_resize_key_cache(KEY_CACHE *key_cache)
}
-/* Change parameters for key cache (like size) */
-
+/** @brief
+ Change parameters for key cache (like size)
+*/
int ha_change_key_cache_param(KEY_CACHE *key_cache)
{
if (key_cache->key_cache_inited)
@@ -2755,16 +2769,18 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache)
return 0;
}
-/* Free memory allocated by a key cache */
-
+/** @brief
+ Free memory allocated by a key cache
+*/
int ha_end_key_cache(KEY_CACHE *key_cache)
{
end_key_cache(key_cache, 1); // Can never fail
return 0;
}
-/* Move all tables from one key cache to another one */
-
+/** @brief
+ Move all tables from one key cache to another one
+*/
int ha_change_key_cache(KEY_CACHE *old_key_cache,
KEY_CACHE *new_key_cache)
{
@@ -2773,7 +2789,7 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
}
-/*
+/** @brief
Try to discover one table from handler(s)
RETURN
@@ -2781,20 +2797,19 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache,
0 : OK. In this case *frmblob and *frmlen are set
>0 : error. frmblob and frmlen may not be set
*/
-
struct st_discover_args
{
const char *db;
const char *name;
- const void** frmblob;
- uint* frmlen;
+ uchar **frmblob;
+ size_t *frmlen;
};
-static my_bool discover_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
st_discover_args *vargs= (st_discover_args *)arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->discover &&
(!(hton->discover(hton, thd, vargs->db, vargs->name,
vargs->frmblob,
@@ -2805,7 +2820,7 @@ static my_bool discover_handlerton(THD *thd, st_plugin_int *plugin,
}
int ha_discover(THD *thd, const char *db, const char *name,
- const void **frmblob, uint *frmlen)
+ uchar **frmblob, size_t *frmlen)
{
int error= -1; // Table does not exist in any handler
DBUG_ENTER("ha_discover");
@@ -2820,12 +2835,12 @@ int ha_discover(THD *thd, const char *db, const char *name,
error= 0;
if (!error)
- statistic_increment(thd->status_var.ha_discover_count,&LOCK_status);
+ status_var_increment(thd->status_var.ha_discover_count);
DBUG_RETURN(error);
}
-/*
+/** @brief
Call this function in order to give the handler the possibility
to ask engine if there are any new tables that should be written to disk
or any dropped tables that need to be removed from disk
@@ -2839,11 +2854,11 @@ struct st_find_files_args
List<char> *files;
};
-static my_bool find_files_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool find_files_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
st_find_files_args *vargs= (st_find_files_args *)arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->find_files)
@@ -2860,8 +2875,8 @@ ha_find_files(THD *thd,const char *db,const char *path,
{
int error= 0;
DBUG_ENTER("ha_find_files");
- DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d",
- db, path, wild, dir));
+ DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d",
+ db, path, wild ? wild : "NULL", dir));
st_find_files_args args= {db, path, wild, dir, files};
plugin_foreach(thd, find_files_handlerton,
@@ -2870,14 +2885,13 @@ ha_find_files(THD *thd,const char *db,const char *path,
DBUG_RETURN(error);
}
-
/*
Ask handler if the table exists in engine
RETURN
- 0 Table does not exist
- 1 Table exists
- # Error code
+ HA_ERR_NO_SUCH_TABLE Table does not exist
+ HA_ERR_TABLE_EXIST Table exists
+ # Error code
*/
@@ -2885,31 +2899,36 @@ struct st_table_exists_in_engine_args
{
const char *db;
const char *name;
+ int err;
};
-static my_bool table_exists_in_engine_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
st_table_exists_in_engine_args *vargs= (st_table_exists_in_engine_args *)arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
+
+ int err= HA_ERR_NO_SUCH_TABLE;
if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
- if ((hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name)) == 1)
- return TRUE;
+ err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name);
+
+ vargs->err = err;
+ if (vargs->err == HA_ERR_TABLE_EXIST)
+ return TRUE;
return FALSE;
}
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name)
{
- int error= 0;
DBUG_ENTER("ha_table_exists_in_engine");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
- st_table_exists_in_engine_args args= {db, name};
- error= plugin_foreach(thd, table_exists_in_engine_handlerton,
+ st_table_exists_in_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE};
+ plugin_foreach(thd, table_exists_in_engine_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
- DBUG_PRINT("exit", ("error: %d", error));
- DBUG_RETURN(error);
+ DBUG_PRINT("exit", ("error: %d", args.err));
+ DBUG_RETURN(args.err);
}
#ifdef HAVE_NDB_BINLOG
@@ -2932,13 +2951,13 @@ struct binlog_func_st
void *arg;
};
-/*
+/** @brief
Listing handlertons first to avoid recursive calls and deadlock
*/
-static my_bool binlog_func_list(THD *thd, st_plugin_int *plugin, void *arg)
+static my_bool binlog_func_list(THD *thd, plugin_ref plugin, void *arg)
{
hton_list_st *hton_list= (hton_list_st *)arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->binlog_func)
{
uint sz= hton_list->sz;
@@ -3025,10 +3044,10 @@ static my_bool binlog_log_query_handlerton2(THD *thd,
}
static my_bool binlog_log_query_handlerton(THD *thd,
- st_plugin_int *plugin,
+ plugin_ref plugin,
void *args)
{
- return binlog_log_query_handlerton2(thd, (handlerton *)plugin->data, args);
+ return binlog_log_query_handlerton2(thd, plugin_data(plugin, handlerton *), args);
}
void ha_binlog_log_query(THD *thd, handlerton *hton,
@@ -3050,7 +3069,7 @@ void ha_binlog_log_query(THD *thd, handlerton *hton,
}
#endif
-/*
+/** @brief
Read the first row of a multi-range set.
SYNOPSIS
@@ -3074,7 +3093,6 @@ void ha_binlog_log_query(THD *thd, handlerton *hton,
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer)
@@ -3091,9 +3109,9 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
multi_range_curr < multi_range_end;
multi_range_curr++)
{
- result= read_range_first(multi_range_curr->start_key.length ?
+ result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
- multi_range_curr->end_key.length ?
+ multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@@ -3107,7 +3125,7 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
}
-/*
+/** @brief
Read the next row of a multi-range set.
SYNOPSIS
@@ -3125,7 +3143,6 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
HA_ERR_END_OF_FILE No (more) rows in range
# Error code
*/
-
int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
{
int result;
@@ -3159,9 +3176,9 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
multi_range_curr < multi_range_end;
multi_range_curr++)
{
- result= read_range_first(multi_range_curr->start_key.length ?
+ result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
- multi_range_curr->end_key.length ?
+ multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@@ -3178,7 +3195,7 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
}
-/*
+/** @brief
Read first row between two ranges.
Store ranges for future calls to read_range_next
@@ -3197,7 +3214,6 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range_arg, bool sorted)
@@ -3221,7 +3237,7 @@ int handler::read_range_first(const key_range *start_key,
else
result= index_read(table->record[0],
start_key->key,
- start_key->length,
+ start_key->keypart_map,
start_key->flag);
if (result)
DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND)
@@ -3232,7 +3248,7 @@ int handler::read_range_first(const key_range *start_key,
}
-/*
+/** @brief
Read next row between two ranges.
SYNOPSIS
@@ -3246,7 +3262,6 @@ int handler::read_range_first(const key_range *start_key,
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
-
int handler::read_range_next()
{
int result;
@@ -3266,7 +3281,7 @@ int handler::read_range_next()
}
-/*
+/** @brief
Compare if found key (in row) is over max-value
SYNOPSIS
@@ -3283,7 +3298,6 @@ int handler::read_range_next()
-1 Key is less than range
1 Key is larger than range
*/
-
int handler::compare_key(key_range *range)
{
int cmp;
@@ -3295,19 +3309,23 @@ int handler::compare_key(key_range *range)
return cmp;
}
-int handler::index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
+
+int handler::index_read_idx(uchar * buf, uint index, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
{
- int error= ha_index_init(index, 0);
- if (!error)
- error= index_read(buf, key, key_len, find_flag);
+ int error, error1;
+ error= index_init(index, 0);
if (!error)
- error= ha_index_end();
- return error;
+ {
+ error= index_read(buf, key, keypart_map, find_flag);
+ error1= index_end();
+ }
+ return error ? error : error1;
}
-/*
+/** @brief
Returns a list of all known extensions.
SYNOPSIS
@@ -3321,12 +3339,11 @@ int handler::index_read_idx(byte * buf, uint index, const byte * key,
RETURN VALUE
pointer pointer to TYPELIB structure
*/
-
-static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
+static my_bool exts_handlerton(THD *unused, plugin_ref plugin,
void *arg)
{
List<char> *found_exts= (List<char> *) arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
handler *file;
if (hton->state == SHOW_OPTION_YES && hton->create &&
(file= hton->create(hton, (TABLE_SHARE*) 0, current_thd->mem_root)))
@@ -3353,7 +3370,6 @@ static my_bool exts_handlerton(THD *unused, st_plugin_int *plugin,
TYPELIB *ha_known_exts(void)
{
- MEM_ROOT *mem_root= current_thd->mem_root;
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
{
List<char> found_exts;
@@ -3398,11 +3414,11 @@ static bool stat_print(THD *thd, const char *type, uint type_len,
}
-static my_bool showstat_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool showstat_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
enum ha_stat_type stat= *(enum ha_stat_type *) arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->show_status &&
hton->show_status(hton, thd, stat_print, stat))
return TRUE;
@@ -3469,7 +3485,7 @@ namespace {
{
int const check(table->s->tmp_table == NO_TMP_TABLE &&
binlog_filter->db_ok(table->s->db.str) &&
- strcmp("mysql", table->s->db.str) != 0);
+ !table->no_replicate);
table->s->cached_row_logging_check= check;
}
@@ -3483,7 +3499,7 @@ namespace {
}
}
-/*
+/** @brief
Write table maps for all (manually or automatically) locked tables
to the binary log.
@@ -3504,7 +3520,7 @@ namespace {
SEE ALSO
THD::lock
THD::locked_tables
- */
+*/
namespace
{
int write_locked_table_maps(THD *thd)
@@ -3554,8 +3570,8 @@ namespace
template<class RowsEventT> int
binlog_log_row(TABLE* table,
- const byte *before_record,
- const byte *after_record)
+ const uchar *before_record,
+ const uchar *after_record)
{
if (table->file->ha_table_flags() & HA_HAS_OWN_BINLOGGING)
return 0;
@@ -3604,13 +3620,13 @@ namespace
*/
template int
- binlog_log_row<Write_rows_log_event>(TABLE *, const byte *, const byte *);
+ binlog_log_row<Write_rows_log_event>(TABLE *, const uchar *, const uchar *);
template int
- binlog_log_row<Delete_rows_log_event>(TABLE *, const byte *, const byte *);
+ binlog_log_row<Delete_rows_log_event>(TABLE *, const uchar *, const uchar *);
template int
- binlog_log_row<Update_rows_log_event>(TABLE *, const byte *, const byte *);
+ binlog_log_row<Update_rows_log_event>(TABLE *, const uchar *, const uchar *);
}
@@ -3627,17 +3643,16 @@ int handler::ha_external_lock(THD *thd, int lock_type)
}
-/*
+/** @brief
Check handler usage and reset state of file to after 'open'
*/
-
int handler::ha_reset()
{
DBUG_ENTER("ha_reset");
/* Check that we have called all proper deallocation functions */
- DBUG_ASSERT((byte*) table->def_read_set.bitmap +
+ DBUG_ASSERT((uchar*) table->def_read_set.bitmap +
table->s->column_bitmap_size ==
- (byte*) table->def_write_set.bitmap);
+ (uchar*) table->def_write_set.bitmap);
DBUG_ASSERT(bitmap_is_set_all(&table->s->all_set));
DBUG_ASSERT(table->key_read == 0);
/* ensure that ha_index_end / ha_rnd_end has been called */
@@ -3648,7 +3663,7 @@ int handler::ha_reset()
}
-int handler::ha_write_row(byte *buf)
+int handler::ha_write_row(uchar *buf)
{
int error;
if (unlikely(error= write_row(buf)))
@@ -3658,7 +3673,7 @@ int handler::ha_write_row(byte *buf)
return 0;
}
-int handler::ha_update_row(const byte *old_data, byte *new_data)
+int handler::ha_update_row(const uchar *old_data, uchar *new_data)
{
int error;
@@ -3675,7 +3690,7 @@ int handler::ha_update_row(const byte *old_data, byte *new_data)
return 0;
}
-int handler::ha_delete_row(const byte *buf)
+int handler::ha_delete_row(const uchar *buf)
{
int error;
if (unlikely(error= delete_row(buf)))
@@ -3687,12 +3702,11 @@ int handler::ha_delete_row(const byte *buf)
-/*
+/** @brief
use_hidden_primary_key() is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key
*/
-
void handler::use_hidden_primary_key()
{
/* fallback to use all columns in the table to identify row */
@@ -3700,11 +3714,10 @@ void handler::use_hidden_primary_key()
}
-/*
+/** @brief
Dummy function which accept information about log files which is not need
by handlers
*/
-
void signal_log_not_needed(struct handlerton, char *log_file)
{
DBUG_ENTER("signal_log_not_needed");
@@ -3760,12 +3773,11 @@ err:
#define fl_dir FN_ROOTDIR
-/*
+/** @brief
Dummy function to return log status should be replaced by function which
really detect the log status and check that the file is a log of this
handler.
*/
-
enum log_status fl_get_log_status(char *log)
{
MY_STAT stat_buff;
@@ -3801,11 +3813,11 @@ int fl_log_iterator_next(struct handler_iterator *iterator,
void fl_log_iterator_destroy(struct handler_iterator *iterator)
{
- my_free((gptr)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*)iterator->buffer, MYF(MY_ALLOW_ZERO_PTR));
}
-/*
+/** @brief
returns buffer, to be assigned in handler_iterator struct
*/
enum handler_create_iterator_result
@@ -3814,7 +3826,7 @@ fl_log_iterator_buffer_init(struct handler_iterator *iterator)
MY_DIR *dirp;
struct fl_buff *buff;
char *name_ptr;
- byte *ptr;
+ uchar *ptr;
FILEINFO *file;
uint32 i;
@@ -3825,7 +3837,7 @@ fl_log_iterator_buffer_init(struct handler_iterator *iterator)
{
return HA_ITERATOR_ERROR;
}
- if ((ptr= (byte*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) +
+ if ((ptr= (uchar*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) +
((ALIGN_SIZE(sizeof(LEX_STRING)) +
sizeof(enum log_status) +
+ FN_REFLEN) *
diff --git a/sql/handler.h b/sql/handler.h
index f27912f4d1e..6a16dd96f49 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -224,6 +223,7 @@
#define HA_LEX_CREATE_TMP_TABLE 1
#define HA_LEX_CREATE_IF_NOT_EXISTS 2
+#define HA_LEX_CREATE_TABLE_LIKE 4
#define HA_OPTION_NO_CHECKSUM (1L << 17)
#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
#define HA_MAX_REC_LENGTH 65535
@@ -379,9 +379,9 @@ struct xid_t {
return sizeof(formatID)+sizeof(gtrid_length)+sizeof(bqual_length)+
gtrid_length+bqual_length;
}
- byte *key()
+ uchar *key()
{
- return (byte *)&gtrid_length;
+ return (uchar *)&gtrid_length;
}
uint key_length()
{
@@ -675,8 +675,8 @@ struct handlerton
struct handler_iterator *fill_this_in);
int (*discover)(handlerton *hton, THD* thd, const char *db,
const char *name,
- const void** frmblob,
- uint* frmlen);
+ uchar **frmblob,
+ size_t *frmlen);
int (*find_files)(handlerton *hton, THD *thd,
const char *db,
const char *path,
@@ -764,7 +764,7 @@ typedef struct st_ha_create_information
bool table_existed; /* 1 in create if table existed */
bool frm_only; /* 1 if no ha_create_table() */
bool varchar; /* 1 if table has a VARCHAR */
- bool store_on_disk; /* 1 if table stored on disk */
+ enum ha_storage_media storage_media; /* DEFAULT, DISK or MEMORY */
} HA_CREATE_INFO;
@@ -836,9 +836,9 @@ typedef struct st_ha_check_opt
typedef struct st_handler_buffer
{
- const byte *buffer; /* Buffer one can start using */
- const byte *buffer_end; /* End of buffer */
- byte *end_of_used_area; /* End of area that was used by handler */
+ const uchar *buffer; /* Buffer one can start using */
+ const uchar *buffer_end; /* End of buffer */
+ uchar *end_of_used_area; /* End of area that was used by handler */
} HANDLER_BUFFER;
typedef struct system_status_var SSV;
@@ -852,7 +852,15 @@ public:
ulonglong max_index_file_length;
ulonglong delete_length; /* Free bytes */
ulonglong auto_increment_value;
- ha_rows records; /* Estimated records in table */
+ /*
+ The number of records in the table.
+ 0 - means the table has exactly 0 rows
+ other - if (table_flags() & HA_STATS_RECORDS_IS_EXACT)
+ the value is the exact number of records in the table
+ else
+ it is an estimate
+ */
+ ha_rows records;
ha_rows deleted; /* Deleted records */
ulong mean_rec_length; /* physical reclength */
time_t create_time; /* When table was created */
@@ -868,6 +876,18 @@ public:
{}
};
+uint calculate_key_len(TABLE *, uint, const uchar *, key_part_map);
+/*
+ bitmap with first N+1 bits set
+ (keypart_map for a key prefix of [0..N] keyparts)
+*/
+#define make_keypart_map(N) (((key_part_map)2 << (N)) - 1)
+/*
+ bitmap with first N bits set
+ (keypart_map for a key prefix of [0..N-1] keyparts)
+*/
+#define make_prev_keypart_map(N) (((key_part_map)1 << (N)) - 1)
+
/*
The handler class is the interface for dynamically loadable
storage engines. Do not add ifdefs and take care when adding or
@@ -877,6 +897,8 @@ public:
class handler :public Sql_alloc
{
friend class ha_partition;
+ friend int ha_delete_table(THD*,handlerton*,const char*,const char*,
+ const char*,bool);
protected:
struct st_table_share *table_share; /* The table definition */
@@ -895,15 +917,18 @@ class handler :public Sql_alloc
virtual int rnd_init(bool scan) =0;
virtual int rnd_end() { return 0; }
virtual ulonglong table_flags(void) const =0;
+
void ha_statistic_increment(ulong SSV::*offset) const;
+ void **ha_data(THD *) const;
+ THD *ha_thd(void) const;
ha_rows estimation_rows_to_insert;
virtual void start_bulk_insert(ha_rows rows) {}
virtual int end_bulk_insert() {return 0; }
public:
handlerton *ht; /* storage engine of this handler */
- byte *ref; /* Pointer to current row */
- byte *dup_ref; /* Pointer to duplicate row */
+ uchar *ref; /* Pointer to current row */
+ uchar *dup_ref; /* Pointer to duplicate row */
ha_statistics stats;
@@ -952,11 +977,12 @@ public:
Discrete_interval auto_inc_interval_for_cur_row;
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
- :table_share(share_arg), estimation_rows_to_insert(0), ht(ht_arg),
+ :table_share(share_arg), table(0),
+ estimation_rows_to_insert(0), ht(ht_arg),
ref(0), key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)),
ft_handler(0), inited(NONE), implicit_emptied(0),
- pushed_cond(NULL), next_insert_id(0), insert_id_for_cur_row(0)
+ pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0)
{}
virtual ~handler(void)
{
@@ -975,7 +1001,11 @@ public:
check_if_locking_is_allowed()
thd Handler of the thread, trying to lock the table
table Table handler to check
- count Number of locks already granted to the table
+ count Total number of tables to be locked
+ current Index of the current table in the list of the tables
+ to be locked.
+ system_count Pointer to the counter of system tables seen thus
+ far.
called_by_privileged_thread TRUE if called from a logger THD
(general_log_thd or slow_log_thd)
or by a privileged thread, which
@@ -994,7 +1024,8 @@ public:
*/
virtual bool check_if_locking_is_allowed(uint sql_command,
ulong type, TABLE *table,
- uint count,
+ uint count, uint current,
+ uint *system_count,
bool called_by_privileged_thread)
{
return TRUE;
@@ -1120,9 +1151,9 @@ public:
and delete_row() below.
*/
int ha_external_lock(THD *thd, int lock_type);
- int ha_write_row(byte * buf);
- int ha_update_row(const byte * old_data, byte * new_data);
- int ha_delete_row(const byte * buf);
+ int ha_write_row(uchar * buf);
+ int ha_update_row(const uchar * old_data, uchar * new_data);
+ int ha_delete_row(const uchar * buf);
/*
SYNOPSIS
@@ -1155,7 +1186,7 @@ public:
0 Bulk delete used by handler
1 Bulk delete not used, normal operation used
*/
- virtual int bulk_update_row(const byte *old_data, byte *new_data,
+ virtual int bulk_update_row(const uchar *old_data, uchar *new_data,
uint *dup_key_found)
{
DBUG_ASSERT(FALSE);
@@ -1203,22 +1234,56 @@ public:
DBUG_ASSERT(FALSE);
return HA_ERR_WRONG_COMMAND;
}
- virtual int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
+ private:
+ virtual int index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
- virtual int index_next(byte * buf)
+ public:
+/**
+ @brief
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index.
+*/
+ virtual int index_read(uchar * buf, const uchar * key, key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+ {
+ uint key_len= calculate_key_len(table, active_index, key, keypart_map);
+ return index_read(buf, key, key_len, find_flag);
+ }
+/**
+ @brief
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index.
+*/
+ virtual int index_read_idx(uchar * buf, uint index, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ virtual int index_next(uchar * buf)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int index_prev(byte * buf)
+ virtual int index_prev(uchar * buf)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int index_first(byte * buf)
+ virtual int index_first(uchar * buf)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int index_last(byte * buf)
+ virtual int index_last(uchar * buf)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int index_next_same(byte *buf, const byte *key, uint keylen);
- virtual int index_read_last(byte * buf, const byte * key, uint key_len)
+ virtual int index_next_same(uchar *buf, const uchar *key, uint keylen);
+ private:
+ virtual int index_read_last(uchar * buf, const uchar * key, uint key_len)
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
+ public:
+/**
+ @brief
+ The following functions works like index_read, but it find the last
+ row with the current key value or prefix.
+*/
+ virtual int index_read_last(uchar * buf, const uchar * key,
+ key_part_map keypart_map)
+ {
+ uint key_len= calculate_key_len(table, active_index, key, keypart_map);
+ return index_read_last(buf, key, key_len);
+ }
virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer);
@@ -1232,22 +1297,21 @@ public:
void ft_end() { ft_handler=NULL; }
virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key)
{ return NULL; }
- virtual int ft_read(byte *buf) { return HA_ERR_WRONG_COMMAND; }
- virtual int rnd_next(byte *buf)=0;
- virtual int rnd_pos(byte * buf, byte *pos)=0;
- virtual int read_first_row(byte *buf, uint primary_key);
+ virtual int ft_read(uchar *buf) { return HA_ERR_WRONG_COMMAND; }
+ virtual int rnd_next(uchar *buf)=0;
+ virtual int rnd_pos(uchar * buf, uchar *pos)=0;
+ virtual int read_first_row(uchar *buf, uint primary_key);
/*
The following function is only needed for tables that may be temporary
tables during joins
*/
- virtual int restart_rnd_next(byte *buf, byte *pos)
+ virtual int restart_rnd_next(uchar *buf, uchar *pos)
{ return HA_ERR_WRONG_COMMAND; }
- virtual int rnd_same(byte *buf, uint inx)
+ virtual int rnd_same(uchar *buf, uint inx)
{ return HA_ERR_WRONG_COMMAND; }
- virtual ha_rows records_in_range(uint inx, key_range *min_key,
- key_range *max_key)
+ virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key)
{ return (ha_rows) 10; }
- virtual void position(const byte *record)=0;
+ virtual void position(const uchar *record)=0;
virtual int info(uint)=0; // see my_base.h for full description
virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info,
uint part_id);
@@ -1410,7 +1474,7 @@ public:
{ return FALSE; }
virtual char* get_foreign_key_create_info()
{ return(NULL);} /* gets foreign key create string from InnoDB */
- virtual char* get_tablespace_name(THD *thd)
+ virtual char* get_tablespace_name(THD *thd, char *name, uint name_len)
{ return(NULL);} /* gets tablespace name from handler */
/* used in ALTER TABLE; 1 if changing storage engine is allowed */
virtual bool can_switch_engines() { return 1; }
@@ -1423,6 +1487,17 @@ public:
virtual void free_foreign_key_create_info(char* str) {}
/* The following can be called without an open handler */
virtual const char *table_type() const =0;
+ /*
+ If frm_error() is called then we will use this to find out what file
+ extentions exist for the storage engine. This is also used by the default
+ rename_table and delete_table method in handler.cc.
+
+ For engines that have two file name extentions (separate meta/index file
+ and data file), the order of elements is relevant. First element of engine
+ file name extentions array should be meta/index file extention. Second
+ element - data file extention. This order is assumed by
+ prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
+ */
virtual const char **bas_ext() const =0;
virtual int get_default_no_partitions(HA_CREATE_INFO *info) { return 1;}
@@ -1492,8 +1567,8 @@ public:
const char *path,
ulonglong *copied,
ulonglong *deleted,
- const void *pack_frm_data,
- uint pack_frm_len)
+ const uchar *pack_frm_data,
+ size_t pack_frm_len)
{ return HA_ERR_WRONG_COMMAND; }
virtual int drop_partitions(const char *path)
{ return HA_ERR_WRONG_COMMAND; }
@@ -1510,6 +1585,10 @@ public:
/* lock_count() can be more than one if the table is a MERGE */
virtual uint lock_count(void) const { return 1; }
+ /*
+ NOTE that one can NOT rely on table->in_use in store_lock(). It may
+ refer to a different thread if called from mysql_lock_abort_for_thread().
+ */
virtual THR_LOCK_DATA **store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)=0;
@@ -1532,7 +1611,7 @@ public:
false otherwise
*/
virtual bool primary_key_is_clustered() { return FALSE; }
- virtual int cmp_ref(const byte *ref1, const byte *ref2)
+ virtual int cmp_ref(const uchar *ref1, const uchar *ref2)
{
return memcmp(ref1, ref2, ref_length);
}
@@ -1577,18 +1656,18 @@ public:
{ return COMPATIBLE_DATA_NO; }
/* These are only called from sql_select for internal temporary tables */
- virtual int write_row(byte *buf __attribute__((unused)))
+ virtual int write_row(uchar *buf __attribute__((unused)))
{
return HA_ERR_WRONG_COMMAND;
}
- virtual int update_row(const byte *old_data __attribute__((unused)),
- byte *new_data __attribute__((unused)))
+ virtual int update_row(const uchar *old_data __attribute__((unused)),
+ uchar *new_data __attribute__((unused)))
{
return HA_ERR_WRONG_COMMAND;
}
- virtual int delete_row(const byte *buf __attribute__((unused)))
+ virtual int delete_row(const uchar *buf __attribute__((unused)))
{
return HA_ERR_WRONG_COMMAND;
}
@@ -1627,9 +1706,9 @@ extern ulong total_ha, total_ha_2pc;
/* lookups */
handlerton *ha_default_handlerton(THD *thd);
-handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name);
+plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
+plugin_ref ha_lock_engine(THD *thd, handlerton *hton);
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type);
-const char *ha_get_storage_engine(enum legacy_db_type db_type);
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
handlerton *db_type);
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
@@ -1681,7 +1760,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat);
/* discovery */
int ha_create_table_from_engine(THD* thd, const char *db, const char *name);
int ha_discover(THD* thd, const char* dbname, const char* name,
- const void** frmblob, uint* frmlen);
+ uchar** frmblob, size_t* frmlen);
int ha_find_files(THD *thd,const char *db,const char *path,
const char *wild, bool dir,List<char>* files);
int ha_table_exists_in_engine(THD* thd, const char* db, const char* name);
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
index ec200768222..9303120e18a 100644
--- a/sql/hash_filo.cc
+++ b/sql/hash_filo.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index fc48c3b1540..ab13d338695 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -85,10 +84,10 @@ public:
first_link=last_link=0;
}
- hash_filo_element *search(gptr key,uint length)
+ hash_filo_element *search(uchar* key, size_t length)
{
hash_filo_element *entry=(hash_filo_element*)
- hash_search(&cache,(byte*) key,length);
+ hash_search(&cache,(uchar*) key,length);
if (entry)
{ // Found; link it first
if (entry != first_link)
@@ -114,9 +113,9 @@ public:
{
hash_filo_element *tmp=last_link;
last_link=last_link->prev_used;
- hash_delete(&cache,(byte*) tmp);
+ hash_delete(&cache,(uchar*) tmp);
}
- if (my_hash_insert(&cache,(byte*) entry))
+ if (my_hash_insert(&cache,(uchar*) entry))
{
if (free_element)
(*free_element)(entry); // This should never happen
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 52c4107372f..34384a9c8c0 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -85,7 +84,7 @@ static void add_hostname(struct in_addr *in,const char *name)
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
host_entry *entry;
- if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ if (!(entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
{
uint length=name ? (uint) strlen(name) : 0;
@@ -116,7 +115,7 @@ void inc_host_errors(struct in_addr *in)
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
host_entry *entry;
- if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
entry->errors++;
VOID(pthread_mutex_unlock(&hostname_cache->lock));
}
@@ -125,7 +124,7 @@ void reset_host_errors(struct in_addr *in)
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
host_entry *entry;
- if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
entry->errors=0;
VOID(pthread_mutex_unlock(&hostname_cache->lock));
}
@@ -135,7 +134,7 @@ void reset_host_errors(struct in_addr *in)
#define INADDR_LOOPBACK 0x7f000001UL
#endif
-my_string ip_to_hostname(struct in_addr *in, uint *errors)
+char * ip_to_hostname(struct in_addr *in, uint *errors)
{
uint i;
host_entry *entry;
@@ -150,7 +149,7 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors)
if (!(specialflag & SPECIAL_NO_HOST_CACHE))
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
- if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
+ if ((entry=(host_entry*) hostname_cache->search((uchar*) &in->s_addr,0)))
{
char *name;
if (!entry->hostname)
diff --git a/sql/init.cc b/sql/init.cc
index 9f975296cb6..ff236c03204 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -46,5 +45,11 @@ void unireg_init(ulong options)
{ /* It's used by filesort... */
log_10[i]= nr ; nr*= 10.0;
}
+ /* Make a tab of powers of 0.1 */
+ for (i= 0, nr= 0.1; i < array_elements(log_01); i++)
+ {
+ log_01[i]= nr;
+ nr*= 0.1;
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/item.cc b/sql/item.cc
index e2ab28dd452..6f68ba37603 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,10 +25,6 @@
#include "sql_trigger.h"
#include "sql_select.h"
-static void mark_as_dependent(THD *thd,
- SELECT_LEX *last, SELECT_LEX *current,
- Item_ident *item);
-
const String my_null_string("NULL", 4, default_charset_info);
/****************************************************************************/
@@ -153,7 +148,7 @@ void
Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
{
item->decimals= 0;
- item->max_length= 21;
+ item->max_length= MY_INT64_NUM_DECIMAL_DIGITS;
item->unsigned_flag= 0;
}
@@ -166,6 +161,7 @@ Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
void item_init(void)
{
item_user_lock_init();
+ uuid_short_init();
}
@@ -272,7 +268,7 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
{
my_decimal_set_zero(decimal_value);
@@ -285,7 +281,7 @@ my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_time(&ltime))
{
my_decimal_set_zero(decimal_value);
@@ -320,7 +316,7 @@ longlong Item::val_int_from_decimal()
int Item::save_time_in_field(Field *field)
{
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_time(&ltime))
return set_field_to_null(field);
field->set_notnull();
@@ -330,7 +326,7 @@ int Item::save_time_in_field(Field *field)
int Item::save_date_in_field(Field *field)
{
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return set_field_to_null(field);
field->set_notnull();
@@ -436,7 +432,7 @@ void Item::cleanup()
arg - a dummy parameter, is not used here
*/
-bool Item::cleanup_processor(byte *arg)
+bool Item::cleanup_processor(uchar *arg)
{
if (fixed)
cleanup();
@@ -499,7 +495,7 @@ void Item::rename(char *new_name)
pointer to newly allocated item is returned.
*/
-Item* Item::transform(Item_transformer transformer, byte *arg)
+Item* Item::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -557,7 +553,7 @@ void Item_ident::cleanup()
DBUG_VOID_RETURN;
}
-bool Item_ident::remove_dependence_processor(byte * arg)
+bool Item_ident::remove_dependence_processor(uchar * arg)
{
DBUG_ENTER("Item_ident::remove_dependence_processor");
if (depended_from == (st_select_lex *) arg)
@@ -588,7 +584,7 @@ bool Item_ident::remove_dependence_processor(byte * arg)
for the subsequent items.
*/
-bool Item_field::collect_item_field_processor(byte *arg)
+bool Item_field::collect_item_field_processor(uchar *arg)
{
DBUG_ENTER("Item_field::collect_item_field_processor");
DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
@@ -623,7 +619,7 @@ bool Item_field::collect_item_field_processor(byte *arg)
FALSE otherwise
*/
-bool Item_field::find_item_in_field_list_processor(byte *arg)
+bool Item_field::find_item_in_field_list_processor(uchar *arg)
{
KEY_PART_INFO *first_non_group_part= *((KEY_PART_INFO **) arg);
KEY_PART_INFO *last_part= *(((KEY_PART_INFO **) arg) + 1);
@@ -646,7 +642,7 @@ bool Item_field::find_item_in_field_list_processor(byte *arg)
column read set or to register used fields in a view
*/
-bool Item_field::register_field_in_read_map(byte *arg)
+bool Item_field::register_field_in_read_map(uchar *arg)
{
TABLE *table= (TABLE *) arg;
if (field->table == table || !table)
@@ -695,7 +691,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
}
if (!my_charset_same(cs, system_charset_info))
{
- uint32 res_length;
+ size_t res_length;
name= sql_strmake_with_convert(str, name_length= length, cs,
MAX_ALIAS_NAME, system_charset_info,
&res_length);
@@ -790,7 +786,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
*/
return NULL;
}
- if (!(ptr= current_thd->memdup(cstr.ptr(), cstr.length() + 1 )))
+ if (!(ptr= current_thd->strmake(cstr.ptr(), cstr.length())))
return NULL;
conv->str_value.set(ptr, cstr.length(), cstr.charset());
/* Ensure that no one is going to change the result string */
@@ -858,22 +854,40 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
/*
- Get the value of the function as a TIME structure.
+ Get the value of the function as a MYSQL_TIME structure.
As a extra convenience the time structure is reset on error!
*/
-bool Item::get_date(TIME *ltime,uint fuzzydate)
+bool Item::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
- char buff[40];
- String tmp(buff,sizeof(buff), &my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->ptr(), res->length(),
- ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+ if (result_type() == STRING_RESULT)
{
- bzero((char*) ltime,sizeof(*ltime));
- return 1;
+ char buff[40];
+ String tmp(buff,sizeof(buff), &my_charset_bin),*res;
+ if (!(res=val_str(&tmp)) ||
+ str_to_datetime_with_warn(res->ptr(), res->length(),
+ ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
+ goto err;
+ }
+ else
+ {
+ longlong value= val_int();
+ int was_cut;
+ if (number_to_datetime(value, ltime, fuzzydate, &was_cut) == LL(-1))
+ {
+ char buff[22], *end;
+ end= longlong10_to_str(value, buff, -10);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ buff, (int) (end-buff), MYSQL_TIMESTAMP_NONE,
+ NullS);
+ goto err;
+ }
}
return 0;
+
+err:
+ bzero((char*) ltime,sizeof(*ltime));
+ return 1;
}
/*
@@ -881,7 +895,7 @@ bool Item::get_date(TIME *ltime,uint fuzzydate)
As a extra convenience the time structure is reset on error!
*/
-bool Item::get_time(TIME *ltime)
+bool Item::get_time(MYSQL_TIME *ltime)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
@@ -1044,6 +1058,7 @@ Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
maybe_null= TRUE;
m_type= sp_map_item_type(sp_var_type);
+ m_field_type= sp_var_type;
m_result_type= sp_map_result_type(sp_var_type);
}
@@ -1093,7 +1108,7 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
Item_case_expr methods
*****************************************************************************/
-Item_case_expr::Item_case_expr(int case_expr_id)
+Item_case_expr::Item_case_expr(uint case_expr_id)
:Item_sp_variable( C_STRING_WITH_LEN("case_expr")),
m_case_expr_id(case_expr_id)
{
@@ -1130,6 +1145,8 @@ Item_case_expr::this_item_addr(THD *thd, Item **)
void Item_case_expr::print(String *str)
{
+ if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@")))
+ return; /* purecov: inspected */
VOID(str->append(STRING_WITH_LEN("case_expr@")));
str->qs_append(m_case_expr_id);
}
@@ -1271,7 +1288,10 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
if (type() == SUM_FUNC_ITEM && skip_registered &&
((Item_sum *) this)->ref_by)
return;
- if (type() != SUM_FUNC_ITEM && with_sum_func)
+ if ((type() != SUM_FUNC_ITEM && with_sum_func) ||
+ (type() == FUNC_ITEM &&
+ (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
+ ((Item_func *) this)->functype() == Item_func::TRIG_COND_FUNC)))
{
/* Will split complicated items and ignore simple ones */
split_sum_func(thd, ref_pointer_array, fields);
@@ -1291,15 +1311,18 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
Exception is Item_direct_view_ref which we need to convert to
Item_ref to allow fields from view being stored in tmp table.
*/
+ Item_aggregate_ref *item_ref;
uint el= fields.elements;
- Item *new_item, *real_itm= real_item();
+ Item *real_itm= real_item();
ref_pointer_array[el]= real_itm;
- if (!(new_item= new Item_aggregate_ref(&thd->lex->current_select->context,
+ if (!(item_ref= new Item_aggregate_ref(&thd->lex->current_select->context,
ref_pointer_array + el, 0, name)))
return; // fatal_error is set
+ if (type() == SUM_FUNC_ITEM)
+ item_ref->depended_from= ((Item_sum *) this)->depended_from();
fields.push_front(real_itm);
- thd->change_item_tree(ref, new_item);
+ thd->change_item_tree(ref, item_ref);
}
}
@@ -1555,6 +1578,8 @@ bool agg_item_charsets(DTCollation &coll, const char *fname,
doesn't display each argument's characteristics.
- if nargs is 1, then this error cannot happen.
*/
+ LINT_INIT(safe_args[0]);
+ LINT_INIT(safe_args[1]);
if (nargs >=2 && nargs <= 3)
{
safe_args[0]= args[0];
@@ -1695,7 +1720,10 @@ Item_field::Item_field(Name_resolution_context *context_arg,
field(0), result_field(0), item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{
+ SELECT_LEX *select= current_thd->lex->current_select;
collation.set(DERIVATION_IMPLICIT);
+ if (select && select->parsing_place != IN_HAVING)
+ select->select_n_where_fields++;
}
// Constructor need to process subselect with temporary tables (see Item)
@@ -1716,7 +1744,7 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
decimals= field->decimals();
- max_length= field_par->max_length();
+ max_length= field_par->max_display_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db.str;
@@ -1787,9 +1815,10 @@ void Item_ident::print(String *str)
}
}
- if (!table_name || !field_name)
+ if (!table_name || !field_name || !field_name[0])
{
- const char *nm= field_name ? field_name : name ? name : "tmp_field";
+ const char *nm= (field_name && field_name[0]) ?
+ field_name : name ? name : "tmp_field";
append_identifier(thd, str, nm, (uint) strlen(nm));
return;
}
@@ -1863,7 +1892,7 @@ String *Item_field::str_result(String *str)
return result_field->val_str(str,&str_value);
}
-bool Item_field::get_date(TIME *ltime,uint fuzzydate)
+bool Item_field::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate))
{
@@ -1873,7 +1902,7 @@ bool Item_field::get_date(TIME *ltime,uint fuzzydate)
return 0;
}
-bool Item_field::get_date_result(TIME *ltime,uint fuzzydate)
+bool Item_field::get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{
if ((null_value=result_field->is_null()) ||
result_field->get_date(ltime,fuzzydate))
@@ -1884,7 +1913,7 @@ bool Item_field::get_date_result(TIME *ltime,uint fuzzydate)
return 0;
}
-bool Item_field::get_time(TIME *ltime)
+bool Item_field::get_time(MYSQL_TIME *ltime)
{
if ((null_value=field->is_null()) || field->get_time(ltime))
{
@@ -2111,7 +2140,7 @@ Item_decimal::Item_decimal(my_decimal *value_par)
}
-Item_decimal::Item_decimal(const char *bin, int precision, int scale)
+Item_decimal::Item_decimal(const uchar *bin, int precision, int scale)
{
binary2my_decimal(E_DEC_FATAL_ERROR, bin,
&decimal_value, precision, scale);
@@ -2411,7 +2440,7 @@ void Item_param::set_decimal(const char *str, ulong length)
/*
- Set parameter value from TIME value.
+ Set parameter value from MYSQL_TIME value.
SYNOPSIS
set_time()
@@ -2425,21 +2454,23 @@ void Item_param::set_decimal(const char *str, ulong length)
the fact that even wrong value sent over binary protocol fits into
MAX_DATE_STRING_REP_LENGTH buffer.
*/
-void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
+void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
+ uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
value.time= *tm;
- value.time.time_type= type;
+ value.time.time_type= time_type;
if (value.time.year > 9999 || value.time.month > 12 ||
value.time.day > 31 ||
- type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
+ time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
value.time.minute > 59 || value.time.second > 59)
{
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= my_TIME_to_str(&value.time, buff);
- make_truncated_value_warning(current_thd, buff, length, type, 0);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ buff, length, time_type, 0);
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
}
@@ -2519,7 +2550,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
item_result_type= REAL_RESULT;
break;
case INT_RESULT:
- set_int(*(longlong*)entry->value, 21);
+ set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
item_type= Item::INT_ITEM;
item_result_type= INT_RESULT;
break;
@@ -2641,7 +2672,7 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
}
-bool Item_param::get_time(TIME *res)
+bool Item_param::get_time(MYSQL_TIME *res)
{
if (state == TIME_VALUE)
{
@@ -2656,7 +2687,7 @@ bool Item_param::get_time(TIME *res)
}
-bool Item_param::get_date(TIME *res, uint fuzzydate)
+bool Item_param::get_date(MYSQL_TIME *res, uint fuzzydate)
{
if (state == TIME_VALUE)
{
@@ -2905,7 +2936,7 @@ bool Item_param::basic_const_item() const
Item *
-Item_param::new_item()
+Item_param::clone_item()
{
/* see comments in the header file */
switch (state) {
@@ -3082,7 +3113,7 @@ String* Item_ref_null_helper::val_str(String* s)
}
-bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate)
+bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, uint fuzzydate)
{
return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate));
}
@@ -3349,7 +3380,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
ORDER *group_list= (ORDER*) select->group_list.first;
bool ambiguous_fields= FALSE;
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
/*
Search for a column or derived column named as 'ref' in the SELECT
@@ -3357,8 +3388,10 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
*/
if (!(select_ref= find_item_in_list(ref, *(select->get_item_list()),
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used)))
+ &resolution)))
return NULL; /* Some error occurred. */
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ ref->alias_name_used= TRUE;
/* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
if (select->having_fix_field && !ref->with_sum_func && group_list)
@@ -3468,12 +3501,18 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*/
Name_resolution_context *last_checked_context= context;
Item **ref= (Item **) not_found_item;
- Name_resolution_context *outer_context= context->outer_context;
+ SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
+ Name_resolution_context *outer_context= 0;
+ SELECT_LEX *select= 0;
+ /* Currently derived tables cannot be correlated */
+ if (current_sel->master_unit()->first_select()->linkage !=
+ DERIVED_TABLE_TYPE)
+ outer_context= context->outer_context;
for (;
outer_context;
outer_context= outer_context->outer_context)
{
- SELECT_LEX *select= outer_context->select_lex;
+ select= outer_context->select_lex;
Item_subselect *prev_subselect_item=
last_checked_context->select_lex->master_unit()->item;
last_checked_context= outer_context;
@@ -3504,36 +3543,73 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
if (*from_field)
{
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ /*
+ As this is an outer field it should be added to the list of
+ non aggregated fields of the outer select.
+ */
+ marker= select->cur_pos_in_select_list;
+ select->non_agg_fields.push_back(this);
+ }
if (*from_field != view_ref_found)
{
prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
prev_subselect_item->const_item_cache= 0;
+ set_field(*from_field);
+ if (!last_checked_context->select_lex->having_fix_field &&
+ select->group_list.elements &&
+ (place == SELECT_LIST || place == IN_HAVING))
+ {
+ Item_outer_ref *rf;
+ /*
+ If an outer field is resolved in a grouping select then it
+ is replaced for an Item_outer_ref object. Otherwise an
+ Item_field object is used.
+ The new Item_outer_ref object is saved in the inner_refs_list of
+ the outer select. Here it is only created. It can be fixed only
+ after the original field has been fixed and this is done in the
+ fix_inner_refs() function.
+ */
+ ;
+ if (!(rf= new Item_outer_ref(context, this)))
+ return -1;
+ thd->change_item_tree(reference, rf);
+ select->inner_refs_list.push_back(rf);
+ rf->in_sum_func= thd->lex->in_sum_func;
+ }
+ /*
+ A reference is resolved to a nest level that's outer or the same as
+ the nest level of the enclosing set function : adjust the value of
+ max_arg_level for the function if it's needed.
+ */
if (thd->lex->in_sum_func &&
- thd->lex->in_sum_func->nest_level ==
- thd->lex->current_select->nest_level)
+ thd->lex->in_sum_func->nest_level >= select->nest_level)
{
- Item::Type type= (*reference)->type();
+ Item::Type ref_type= (*reference)->type();
set_if_bigger(thd->lex->in_sum_func->max_arg_level,
select->nest_level);
set_field(*from_field);
fixed= 1;
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((ref_type == REF_ITEM ||
+ ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) : 0));
return 0;
}
}
else
{
- Item::Type type= (*reference)->type();
+ Item::Type ref_type= (*reference)->type();
prev_subselect_item->used_tables_cache|=
(*reference)->used_tables();
prev_subselect_item->const_item_cache&=
(*reference)->const_item();
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
/*
@@ -3610,12 +3686,21 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
new Item_ref(context, ref, (char*) table_name,
- (char*) field_name) :
+ (char*) field_name, alias_name_used) :
+ (!select->group_list.elements ?
new Item_direct_ref(context, ref, (char*) table_name,
- (char*) field_name));
+ (char*) field_name, alias_name_used) :
+ new Item_outer_ref(context, ref, (char*) table_name,
+ (char*) field_name, alias_name_used)));
*ref= save;
if (!rf)
return -1;
+
+ if (place != IN_HAVING && select->group_list.elements)
+ {
+ outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf);
+ ((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func;
+ }
thd->change_item_tree(reference, rf);
/*
rf is Item_ref => never substitute other items (in this case)
@@ -3634,7 +3719,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
- this, this);
+ this, (Item_ident*)*reference);
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
@@ -3706,10 +3791,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
bool Item_field::fix_fields(THD *thd, Item **reference)
{
DBUG_ASSERT(fixed == 0);
+ Field *from_field= (Field *)not_found_field;
+ bool outer_fixed= false;
+
if (!field) // If field is not checked
{
- Field *from_field= (Field *)not_found_field;
- bool outer_fixed= false;
/*
In case of view, find_field_in_tables() write pointer to view field
expression to 'reference', i.e. it substitute that expression instead
@@ -3729,10 +3815,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (thd->lex->current_select->is_item_list_lookup)
{
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used);
+ &resolution);
+ if (!res)
+ return 1;
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ alias_name_used= TRUE;
if (res != (Item **)not_found_item)
{
if ((*res)->type() == Item::FIELD_ITEM)
@@ -3743,7 +3833,18 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
use the field from the Item_field in the select list and leave
the Item_field instance in place.
*/
- set_field((*((Item_field**)res))->field);
+
+ Field *field= (*((Item_field**)res))->field;
+
+ if (field == NULL)
+ {
+ /* The column to which we link isn't valid. */
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name,
+ current_thd->where);
+ return(1);
+ }
+
+ set_field(field);
return 0;
}
else
@@ -3799,6 +3900,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
goto error;
if (!ret)
return FALSE;
+ outer_fixed= 1;
}
set_field(from_field);
@@ -3828,7 +3930,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
/* First usage of column */
table->used_fields++; // Used to optimize loops
- table->used_keys.intersect(field->part_of_key);
+ /* purecov: begin inspected */
+ table->covering_keys.intersect(field->part_of_key);
+ /* purecov: end */
}
}
}
@@ -3858,6 +3962,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
}
#endif
fixed= 1;
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ !outer_fixed && !thd->lex->in_sum_func &&
+ thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ thd->lex->current_select->non_agg_fields.push_back(this);
+ marker= thd->lex->current_select->cur_pos_in_select_list;
+ }
return FALSE;
error:
@@ -3957,7 +4068,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
FALSE otherwise
*/
-bool Item_field::subst_argument_checker(byte **arg)
+bool Item_field::subst_argument_checker(uchar **arg)
{
return (result_type() != STRING_RESULT) || (*arg);
}
@@ -3989,7 +4100,7 @@ bool Item_field::subst_argument_checker(byte **arg)
pointer to the field item, otherwise.
*/
-Item *Item_field::equal_fields_propagator(byte *arg)
+Item *Item_field::equal_fields_propagator(uchar *arg)
{
if (no_const_subst)
return this;
@@ -4020,7 +4131,7 @@ Item *Item_field::equal_fields_propagator(byte *arg)
See comments in Arg_comparator::set_compare_func() for details
*/
-bool Item_field::set_no_const_sub(byte *arg)
+bool Item_field::set_no_const_sub(uchar *arg)
{
if (field->charset() != &my_charset_bin)
no_const_subst=1;
@@ -4039,7 +4150,9 @@ bool Item_field::set_no_const_sub(byte *arg)
DESCRIPTION
The function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field
- object refers to (belongs to).
+ object refers to (belongs to) unless item_equal contains a constant
+ item. In this case the function returns this constant item,
+ (if the substitution does not require conversion).
If the Item_field object does not refer any Item_equal object
'this' is returned
@@ -4048,14 +4161,23 @@ bool Item_field::set_no_const_sub(byte *arg)
of the thransformer method.
RETURN VALUES
- pointer to a replacement Item_field if there is a better equal item;
+ pointer to a replacement Item_field if there is a better equal item or
+ a pointer to a constant equal item;
this - otherwise.
*/
-Item *Item_field::replace_equal_field(byte *arg)
+Item *Item_field::replace_equal_field(uchar *arg)
{
if (item_equal)
{
+ Item *const_item= item_equal->get_const();
+ if (const_item)
+ {
+ if (cmp_context != (Item_result)-1 &&
+ const_item->cmp_context != cmp_context)
+ return this;
+ return const_item;
+ }
Item_field *subst= item_equal->get_first();
if (subst && !field->eq(subst->field))
return subst;
@@ -4065,7 +4187,7 @@ Item *Item_field::replace_equal_field(byte *arg)
void Item::init_make_field(Send_field *tmp_field,
- enum enum_field_types field_type)
+ enum enum_field_types field_type_arg)
{
char *empty_name= (char*) "";
tmp_field->db_name= empty_name;
@@ -4077,7 +4199,7 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
(my_binary_compare(collation.collation) ?
BINARY_FLAG : 0);
- tmp_field->type=field_type;
+ tmp_field->type= field_type_arg;
tmp_field->length=max_length;
tmp_field->decimals=decimals;
if (unsigned_flag)
@@ -4092,12 +4214,12 @@ void Item::make_field(Send_field *tmp_field)
enum_field_types Item::string_field_type() const
{
- enum_field_types type= FIELD_TYPE_VAR_STRING;
+ enum_field_types f_type= MYSQL_TYPE_VAR_STRING;
if (max_length >= 16777216)
- type= FIELD_TYPE_LONG_BLOB;
+ f_type= MYSQL_TYPE_LONG_BLOB;
else if (max_length >= 65536)
- type= FIELD_TYPE_MEDIUM_BLOB;
- return type;
+ f_type= MYSQL_TYPE_MEDIUM_BLOB;
+ return f_type;
}
@@ -4111,9 +4233,9 @@ enum_field_types Item::field_type() const
{
switch (result_type()) {
case STRING_RESULT: return string_field_type();
- case INT_RESULT: return FIELD_TYPE_LONGLONG;
- case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL;
- case REAL_RESULT: return FIELD_TYPE_DOUBLE;
+ case INT_RESULT: return MYSQL_TYPE_LONGLONG;
+ case DECIMAL_RESULT: return MYSQL_TYPE_NEWDECIMAL;
+ case REAL_RESULT: return MYSQL_TYPE_DOUBLE;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@@ -4122,6 +4244,21 @@ enum_field_types Item::field_type() const
}
+bool Item::is_datetime()
+{
+ switch (field_type())
+ {
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
/*
Create a field to hold a string value from an item
@@ -4179,42 +4316,42 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
switch (field_type()) {
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
- field= new Field_new_decimal((char*) 0, max_length, null_ptr, 0,
+ field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0,
Field::NONE, name, decimals, 0,
unsigned_flag);
break;
case MYSQL_TYPE_TINY:
- field= new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, 0, unsigned_flag);
break;
case MYSQL_TYPE_SHORT:
- field= new Field_short((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, 0, unsigned_flag);
break;
case MYSQL_TYPE_LONG:
- field= new Field_long((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, 0, unsigned_flag);
break;
#ifdef HAVE_LONG_LONG
case MYSQL_TYPE_LONGLONG:
- field= new Field_longlong((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, 0, unsigned_flag);
break;
#endif
case MYSQL_TYPE_FLOAT:
- field= new Field_float((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, decimals, 0, unsigned_flag);
break;
case MYSQL_TYPE_DOUBLE:
- field= new Field_double((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, decimals, 0, unsigned_flag);
break;
case MYSQL_TYPE_NULL:
- field= new Field_null((char*) 0, max_length, Field::NONE,
+ field= new Field_null((uchar*) 0, max_length, Field::NONE,
name, &my_charset_bin);
break;
case MYSQL_TYPE_INT24:
- field= new Field_medium((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name, 0, unsigned_flag);
break;
case MYSQL_TYPE_NEWDATE:
@@ -4231,7 +4368,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
field= new Field_datetime(maybe_null, name, &my_charset_bin);
break;
case MYSQL_TYPE_YEAR:
- field= new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE,
+ field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
name);
break;
case MYSQL_TYPE_BIT:
@@ -4259,13 +4396,16 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_GEOMETRY:
if (this->type() == Item::TYPE_HOLDER)
field= new Field_blob(max_length, maybe_null, name, collation.collation,
1);
else
field= new Field_blob(max_length, maybe_null, name, collation.collation);
break; // Blob handled outside of case
+ case MYSQL_TYPE_GEOMETRY:
+ return new Field_geom(max_length, maybe_null, name, table->s,
+ (Field::geometry_type)
+ ((Item_geometry_func *)this)->get_geometry_type());
}
if (field)
field->init(table);
@@ -4308,18 +4448,19 @@ void Item_field::save_org_in_field(Field *to)
int Item_field::save_in_field(Field *to, bool no_conversions)
{
+ int res;
if (result_field->is_null())
{
null_value=1;
- return set_field_to_null_with_conversions(to, no_conversions);
+ res= set_field_to_null_with_conversions(to, no_conversions);
}
else
{
to->set_notnull();
- field_conv(to,result_field);
+ res= field_conv(to,result_field);
null_value=0;
}
- return 0;
+ return res;
}
@@ -4467,7 +4608,7 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const
}
-Item *Item_int_with_ref::new_item()
+Item *Item_int_with_ref::clone_item()
{
DBUG_ASSERT(ref->const_item());
/*
@@ -4592,7 +4733,6 @@ inline uint char_val(char X)
Item_hex_string::Item_hex_string(const char *str, uint str_length)
{
- name=(char*) str-2; // Lex makes this start with 0x
max_length=(str_length+1)/2;
char *ptr=(char*) sql_alloc(max_length+1);
if (!ptr)
@@ -4638,18 +4778,31 @@ my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value)
int Item_hex_string::save_in_field(Field *field, bool no_conversions)
{
- int error;
field->set_notnull();
if (field->result_type() == STRING_RESULT)
+ return field->store(str_value.ptr(), str_value.length(),
+ collation.collation);
+
+ ulonglong nr;
+ uint32 length= str_value.length();
+ if (length > 8)
{
- error=field->store(str_value.ptr(),str_value.length(),collation.collation);
+ nr= field->flags & UNSIGNED_FLAG ? ULONGLONG_MAX : LONGLONG_MAX;
+ goto warn;
}
- else
+ nr= (ulonglong) val_int();
+ if ((length == 8) && !(field->flags & UNSIGNED_FLAG) && (nr > LONGLONG_MAX))
{
- longlong nr=val_int();
- error=field->store(nr, TRUE); // Assume hex numbers are unsigned
+ nr= LONGLONG_MAX;
+ goto warn;
}
- return error;
+ return field->store((longlong) nr, TRUE); // Assume hex numbers are unsigned
+
+warn:
+ if (!field->store((longlong) nr, TRUE))
+ field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE,
+ 1);
+ return 1;
}
@@ -4690,7 +4843,6 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length)
uchar bits= 0;
uint power= 1;
- name= (char*) str - 2;
max_length= (str_length + 7) >> 3;
char *ptr= (char*) sql_alloc(max_length + 1);
if (!ptr)
@@ -4732,10 +4884,10 @@ bool Item_null::send(Protocol *protocol, String *packet)
bool Item::send(Protocol *protocol, String *buffer)
{
bool result;
- enum_field_types type;
+ enum_field_types f_type;
LINT_INIT(result); // Will be set if null_value == 0
- switch ((type=field_type())) {
+ switch ((f_type=field_type())) {
default:
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_DECIMAL:
@@ -4810,11 +4962,11 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIMESTAMP:
{
- TIME tm;
+ MYSQL_TIME tm;
get_date(&tm, TIME_FUZZY_DATE);
if (!null_value)
{
- if (type == MYSQL_TYPE_DATE)
+ if (f_type == MYSQL_TYPE_DATE)
return protocol->store_date(&tm);
else
result= protocol->store(&tm);
@@ -4823,7 +4975,7 @@ bool Item::send(Protocol *protocol, String *buffer)
}
case MYSQL_TYPE_TIME:
{
- TIME tm;
+ MYSQL_TIME tm;
get_time(&tm);
if (!null_value)
result= protocol->store_time(&tm);
@@ -4858,17 +5010,79 @@ void Item_field::update_null_value()
}
+/*
+ Add the field to the select list and substitute it for the reference to
+ the field.
+
+ SYNOPSIS
+ Item_field::update_value_transformer()
+ select_arg current select
+
+ DESCRIPTION
+ If the field doesn't belong to the table being inserted into then it is
+ added to the select list, pointer to it is stored in the ref_pointer_array
+ of the select and the field itself is substituted for the Item_ref object.
+ This is done in order to get correct values from update fields that
+ belongs to the SELECT part in the INSERT .. SELECT .. ON DUPLICATE KEY
+ UPDATE statement.
+
+ RETURN
+ 0 if error occured
+ ref if all conditions are met
+ this field otherwise
+*/
+
+Item *Item_field::update_value_transformer(uchar *select_arg)
+{
+ SELECT_LEX *select= (SELECT_LEX*)select_arg;
+ DBUG_ASSERT(fixed);
+
+ if (field->table != select->context.table_list->table &&
+ type() != Item::TRIGGER_FIELD_ITEM)
+ {
+ List<Item> *all_fields= &select->join->all_fields;
+ Item **ref_pointer_array= select->ref_pointer_array;
+ int el= all_fields->elements;
+ Item_ref *ref;
+
+ ref_pointer_array[el]= (Item*)this;
+ all_fields->push_front((Item*)this);
+ ref= new Item_ref(&select->context, ref_pointer_array + el,
+ table_name, field_name);
+ return ref;
+ }
+ return this;
+}
+
+
+void Item_field::print(String *str)
+{
+ if (field && field->table->const_table)
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff),str->charset());
+ field->val_str(&tmp);
+ str->append('\'');
+ str->append(tmp);
+ str->append('\'');
+ return;
+ }
+ Item_ident::print(str);
+}
+
+
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
- const char *field_name_arg)
+ const char *field_name_arg,
+ bool alias_name_used_arg)
:Item_ident(context_arg, NullS, table_name_arg, field_name_arg),
result_field(0), ref(item)
{
+ alias_name_used= alias_name_used_arg;
/*
This constructor used to create some internals references over fixed items
*/
- DBUG_ASSERT(ref != 0);
- if (*ref && (*ref)->fixed)
+ if (ref && *ref && (*ref)->fixed)
set_properties();
}
@@ -5027,7 +5241,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error;
if (from_field == view_ref_found)
{
- Item::Type type= (*reference)->type();
+ Item::Type refer_type= (*reference)->type();
prev_subselect_item->used_tables_cache|=
(*reference)->used_tables();
prev_subselect_item->const_item_cache&=
@@ -5035,7 +5249,8 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT((*reference)->type() == REF_ITEM);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
- ((type == REF_ITEM || type == FIELD_ITEM) ?
+ ((refer_type == REF_ITEM ||
+ refer_type == FIELD_ITEM) ?
(Item_ident*) (*reference) :
0));
/*
@@ -5088,6 +5303,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
thd->lex->current_select, this, fld);
+ /*
+ A reference is resolved to a nest level that's outer or the same as
+ the nest level of the enclosing set function : adjust the value of
+ max_arg_level for the function if it's needed.
+ */
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level >=
+ last_checked_context->select_lex->nest_level)
+ set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+ last_checked_context->select_lex->nest_level);
return FALSE;
}
if (ref == 0)
@@ -5101,6 +5326,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
DBUG_ASSERT(*ref && (*ref)->fixed);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this, this);
+ /*
+ A reference is resolved to a nest level that's outer or the same as
+ the nest level of the enclosing set function : adjust the value of
+ max_arg_level for the function if it's needed.
+ */
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level >=
+ last_checked_context->select_lex->nest_level)
+ set_if_bigger(thd->lex->in_sum_func->max_arg_level,
+ last_checked_context->select_lex->nest_level);
}
}
@@ -5146,11 +5381,13 @@ void Item_ref::set_properties()
*/
with_sum_func= (*ref)->with_sum_func;
unsigned_flag= (*ref)->unsigned_flag;
+ fixed= 1;
+ if (alias_name_used)
+ return;
if ((*ref)->type() == FIELD_ITEM)
alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
else
alias_name_used= TRUE; // it is not field, so it is was resolved by alias
- fixed= 1;
}
@@ -5168,7 +5405,7 @@ void Item_ref::print(String *str)
if (ref)
{
if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
- name && alias_name_used)
+ !table_name && name && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, name, (uint) strlen(name));
@@ -5310,7 +5547,7 @@ bool Item_ref::is_null()
}
-bool Item_ref::get_date(TIME *ltime,uint fuzzydate)
+bool Item_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
}
@@ -5326,18 +5563,7 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
int Item_ref::save_in_field(Field *to, bool no_conversions)
{
int res;
- if (result_field)
- {
- if (result_field->is_null())
- {
- null_value= 1;
- return set_field_to_null_with_conversions(to, no_conversions);
- }
- to->set_notnull();
- field_conv(to, result_field);
- null_value= 0;
- return 0;
- }
+ DBUG_ASSERT(!result_field);
res= (*ref)->save_in_field(to, no_conversions);
null_value= (*ref)->null_value;
return res;
@@ -5420,14 +5646,14 @@ bool Item_direct_ref::is_null()
}
-bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
+bool Item_direct_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate)
{
return (null_value=(*ref)->get_date(ltime,fuzzydate));
}
/*
- Prepare referenced view viewld then call usual Item_direct_ref::fix_fields
+ Prepare referenced field then call usual Item_direct_ref::fix_fields
SYNOPSIS
Item_direct_view_ref::fix_fields()
@@ -5451,6 +5677,34 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
}
/*
+ Prepare referenced outer field then call usual Item_direct_ref::fix_fields
+
+ SYNOPSIS
+ Item_outer_ref::fix_fields()
+ thd thread handler
+ reference reference on reference where this item stored
+
+ RETURN
+ FALSE OK
+ TRUE Error
+*/
+
+bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
+{
+ bool err;
+ /* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */
+ if ((*ref) && !(*ref)->fixed && ((*ref)->fix_fields(thd, reference)))
+ return TRUE;
+ err= Item_direct_ref::fix_fields(thd, reference);
+ if (!outer_ref)
+ outer_ref= *ref;
+ if ((*ref)->type() == Item::FIELD_ITEM)
+ table_name= ((Item_field*)outer_ref)->table_name;
+ return err;
+}
+
+
+/*
Compare two view column references for equality.
SYNOPSIS
@@ -5556,6 +5810,13 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
if (field_arg->flags & NO_DEFAULT_VALUE_FLAG)
{
+ if (field_arg->reset())
+ {
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+ }
+
if (context->error_processor == &view_error_processor)
{
TABLE_LIST *view= cached_table->top_table();
@@ -5574,7 +5835,6 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
ER(ER_NO_DEFAULT_FOR_FIELD),
field_arg->field_name);
}
- field_arg->set_default();
return 1;
}
field_arg->set_default();
@@ -5589,7 +5849,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
same time it can replace some nodes in the tree
*/
-Item *Item_default_value::transform(Item_transformer transformer, byte *args)
+Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -5781,8 +6041,8 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
{
table_grants->want_privilege= want_privilege;
- if (check_grant_column(thd, table_grants, triggers->table->s->db.str,
- triggers->table->s->table_name.str, field_name,
+ if (check_grant_column(thd, table_grants, triggers->trigger_table->s->db.str,
+ triggers->trigger_table->s->table_name.str, field_name,
strlen(field_name), thd->security_ctx))
return TRUE;
}
@@ -5895,7 +6155,8 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
col= item_row->cols();
while (col-- > 0)
- resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col));
+ resolve_const_item(thd, item_row->addr(col),
+ comp_item_row->element_index(col));
break;
}
/* Fallthrough */
@@ -6007,6 +6268,14 @@ void Item_cache_int::store(Item *item)
}
+void Item_cache_int::store(Item *item, longlong val_arg)
+{
+ value= val_arg;
+ null_value= item->null_value;
+ unsigned_flag= item->unsigned_flag;
+}
+
+
String *Item_cache_int::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -6163,7 +6432,7 @@ bool Item_cache_row::setup(Item * item)
return 1;
for (uint i= 0; i < item_count; i++)
{
- Item *el= item->el(i);
+ Item *el= item->element_index(i);
Item_cache *tmp;
if (!(tmp= values[i]= Item_cache::get_cache(el->result_type())))
return 1;
@@ -6179,7 +6448,7 @@ void Item_cache_row::store(Item * item)
item->bring_value();
for (uint i= 0; i < item_count; i++)
{
- values[i]->store(item->el(i));
+ values[i]->store(item->element_index(i));
null_value|= values[i]->null_value;
}
}
@@ -6238,8 +6507,6 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
:Item(thd, item), enum_set_typelib(0), fld_type(get_real_type(item))
{
DBUG_ASSERT(item->fixed);
-
- max_length= display_length(item);
maybe_null= item->maybe_null;
collation.set(item->collation);
get_full_info(item);
@@ -6411,11 +6678,17 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
{
int delta1= max_length_orig - decimals_orig;
int delta2= item->max_length - item->decimals;
- if (fld_type == MYSQL_TYPE_DECIMAL)
- max_length= max(delta1, delta2) + decimals;
- else
- max_length= min(max(delta1, delta2) + decimals,
- (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7);
+ max_length= max(delta1, delta2) + decimals;
+ if (fld_type == MYSQL_TYPE_FLOAT && max_length > FLT_DIG + 2)
+ {
+ max_length= FLT_DIG + 6;
+ decimals= NOT_FIXED_DEC;
+ }
+ if (fld_type == MYSQL_TYPE_DOUBLE && max_length > DBL_DIG + 2)
+ {
+ max_length= DBL_DIG + 7;
+ decimals= NOT_FIXED_DEC;
+ }
}
else
max_length= (fld_type == MYSQL_TYPE_FLOAT) ? FLT_DIG+6 : DBL_DIG+7;
@@ -6477,7 +6750,7 @@ uint32 Item_type_holder::display_length(Item *item)
case MYSQL_TYPE_SHORT:
return 6;
case MYSQL_TYPE_LONG:
- return 11;
+ return MY_INT32_NUM_DECIMAL_DIGITS;
case MYSQL_TYPE_FLOAT:
return 25;
case MYSQL_TYPE_DOUBLE:
@@ -6518,7 +6791,7 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
switch (fld_type) {
case MYSQL_TYPE_ENUM:
DBUG_ASSERT(enum_set_typelib);
- field= new Field_enum((char *) 0, max_length, null_ptr, 0,
+ field= new Field_enum((uchar *) 0, max_length, null_ptr, 0,
Field::NONE, name,
get_enum_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
@@ -6527,7 +6800,7 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
return field;
case MYSQL_TYPE_SET:
DBUG_ASSERT(enum_set_typelib);
- field= new Field_set((char *) 0, max_length, null_ptr, 0,
+ field= new Field_set((uchar *) 0, max_length, null_ptr, 0,
Field::NONE, name,
get_set_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
diff --git a/sql/item.h b/sql/item.h
index bda57020cf2..1c8b46fe0c7 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -326,10 +325,10 @@ private:
TABLE_LIST *save_first_name_resolution_table;
TABLE_LIST *save_next_name_resolution_table;
bool save_resolve_in_select_list;
+ TABLE_LIST *save_next_local;
public:
Name_resolution_context_state() {} /* Remove gcc warning */
- TABLE_LIST *save_next_local;
public:
/* Save the state of a name resolution context. */
@@ -337,25 +336,25 @@ public:
{
save_table_list= context->table_list;
save_first_name_resolution_table= context->first_name_resolution_table;
- save_next_name_resolution_table= (context->first_name_resolution_table) ?
- context->first_name_resolution_table->
- next_name_resolution_table :
- NULL;
save_resolve_in_select_list= context->resolve_in_select_list;
save_next_local= table_list->next_local;
+ save_next_name_resolution_table= table_list->next_name_resolution_table;
}
/* Restore a name resolution context from saved state. */
void restore_state(Name_resolution_context *context, TABLE_LIST *table_list)
{
table_list->next_local= save_next_local;
+ table_list->next_name_resolution_table= save_next_name_resolution_table;
context->table_list= save_table_list;
context->first_name_resolution_table= save_first_name_resolution_table;
- if (context->first_name_resolution_table)
- context->first_name_resolution_table->
- next_name_resolution_table= save_next_name_resolution_table;
context->resolve_in_select_list= save_resolve_in_select_list;
}
+
+ TABLE_LIST *get_first_name_resolution_table()
+ {
+ return save_first_name_resolution_table;
+ }
};
@@ -427,7 +426,7 @@ public:
};
-typedef bool (Item::*Item_processor) (byte *arg);
+typedef bool (Item::*Item_processor) (uchar *arg);
/*
Analyzer function
SYNOPSIS
@@ -439,8 +438,8 @@ typedef bool (Item::*Item_processor) (byte *arg);
FALSE Don't do it
*/
-typedef bool (Item::*Item_analyzer) (byte **argp);
-typedef Item* (Item::*Item_transformer) (byte *arg);
+typedef bool (Item::*Item_analyzer) (uchar **argp);
+typedef Item* (Item::*Item_transformer) (uchar *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
@@ -449,9 +448,9 @@ class Item {
void operator=(Item &);
public:
static void *operator new(size_t size)
- { return (void*) sql_alloc((uint) size); }
+ { return sql_alloc(size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, (uint) size); }
+ { return alloc_root(mem_root, size); }
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
@@ -477,13 +476,14 @@ public:
save_in_field
*/
String str_value;
- my_string name; /* Name from select */
+ char * name; /* Name from select */
/* Original item name (if it was renamed)*/
- my_string orig_name;
+ char * orig_name;
Item *next;
uint32 max_length;
uint name_length; /* Length of name */
- uint8 marker, decimals;
+ int8 marker;
+ uint8 decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
@@ -692,7 +692,7 @@ public:
*/
virtual bool basic_const_item() const { return 0; }
/* cloning of constant items (0 if it is not const) */
- virtual Item *new_item() { return 0; }
+ virtual Item *clone_item() { return 0; }
virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
@@ -730,17 +730,16 @@ public:
/* Called for items that really have to be split */
void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
Item **ref, bool skip_registered);
- virtual bool get_date(TIME *ltime,uint fuzzydate);
- virtual bool get_time(TIME *ltime);
- virtual bool get_date_result(TIME *ltime,uint fuzzydate)
+ virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ virtual bool get_time(MYSQL_TIME *ltime);
+ virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
- This function is used only in Item_func_isnull/Item_func_isnotnull
- (implementations of IS NULL/IS NOT NULL clauses). Item_func_is{not}null
- calls this method instead of one of val/result*() methods, which
- normally will set null_value. This allows to determine nullness of
- a complex expression without fully evaluating it.
- Any new item which can be NULL must implement this call.
+ The method allows to determine nullness of a complex expression
+ without fully evaluating it, instead of calling val/result*() then
+ checking null_value. Used in Item_func_isnull/Item_func_isnotnull
+ and Item_sum_count/Item_sum_count_distinct.
+ Any new item which can be NULL must implement this method.
*/
virtual bool is_null() { return 0; }
@@ -780,12 +779,12 @@ public:
static CHARSET_INFO *default_charset();
virtual CHARSET_INFO *compare_collation() { return NULL; }
- virtual bool walk(Item_processor processor, bool walk_subquery, byte *arg)
+ virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
return (this->*processor)(arg);
}
- virtual Item* transform(Item_transformer transformer, byte *arg);
+ virtual Item* transform(Item_transformer transformer, uchar *arg);
/*
This function performs a generic "compilation" of the Item tree.
@@ -803,8 +802,8 @@ public:
i.e. analysis is performed top-down while transformation is done
bottom-up.
*/
- virtual Item* compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t)
+ virtual Item* compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t)
{
if ((this->*analyzer) (arg_p))
return ((this->*transformer) (arg_t));
@@ -817,14 +816,15 @@ public:
(*traverser)(this, arg);
}
- virtual bool remove_dependence_processor(byte * arg) { return 0; }
- virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
- virtual bool cleanup_processor(byte *arg);
- virtual bool collect_item_field_processor(byte * arg) { return 0; }
- virtual bool find_item_in_field_list_processor(byte *arg) { return 0; }
- virtual bool change_context_processor(byte *context) { return 0; }
- virtual bool is_expensive_processor(byte *arg) { return 0; }
- virtual bool register_field_in_read_map(byte *arg) { return 0; }
+ virtual bool remove_dependence_processor(uchar * arg) { return 0; }
+ virtual bool remove_fixed(uchar * arg) { fixed= 0; return 0; }
+ virtual bool cleanup_processor(uchar *arg);
+ virtual bool collect_item_field_processor(uchar * arg) { return 0; }
+ virtual bool find_item_in_field_list_processor(uchar *arg) { return 0; }
+ virtual bool change_context_processor(uchar *context) { return 0; }
+ virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
+ virtual bool is_expensive_processor(uchar *arg) { return 0; }
+ virtual bool register_field_in_read_map(uchar *arg) { return 0; }
/*
Check if a partition function is allowed
SYNOPSIS
@@ -877,17 +877,17 @@ public:
assumes that there are no multi-byte collations amongst the partition
fields.
*/
- virtual bool check_partition_func_processor(byte *bool_arg) { return TRUE;}
- virtual bool subst_argument_checker(byte **arg)
+ virtual bool check_partition_func_processor(uchar *bool_arg) { return TRUE;}
+ virtual bool subst_argument_checker(uchar **arg)
{
if (*arg)
*arg= NULL;
return TRUE;
}
- virtual Item *equal_fields_propagator(byte * arg) { return this; }
- virtual bool set_no_const_sub(byte *arg) { return FALSE; }
- virtual Item *replace_equal_field(byte * arg) { return this; }
+ virtual Item *equal_fields_propagator(uchar * arg) { return this; }
+ virtual bool set_no_const_sub(uchar *arg) { return FALSE; }
+ virtual Item *replace_equal_field(uchar * arg) { return this; }
/*
For SP local variable returns pointer to Item representing its
@@ -900,11 +900,11 @@ public:
For SP local variable returns address of pointer to Item representing its
current value and pointer passed via parameter otherwise.
*/
- virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
+ virtual Item **this_item_addr(THD *thd, Item **addr_arg) { return addr_arg; }
// Row emulation
virtual uint cols() { return 1; }
- virtual Item* el(uint i) { return this; }
+ virtual Item* element_index(uint i) { return this; }
virtual Item** addr(uint i) { return 0; }
virtual bool check_cols(uint c);
// It is not row => null inside is impossible
@@ -916,6 +916,7 @@ public:
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *update_value_transformer(uchar *select_arg) { return this; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
@@ -941,6 +942,7 @@ public:
representation is more precise than the string one).
*/
virtual bool result_as_longlong() { return FALSE; }
+ bool is_datetime();
};
@@ -1039,7 +1041,7 @@ class Item_splocal :public Item_sp_variable,
Type m_type;
Item_result m_result_type;
-
+ enum_field_types m_field_type;
public:
/*
Position of this reference to SP variable in the statement (the
@@ -1071,6 +1073,7 @@ public:
inline enum Type type() const;
inline Item_result result_type() const;
+ inline enum_field_types field_type() const { return m_field_type; }
private:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
@@ -1114,7 +1117,7 @@ inline Item_result Item_splocal::result_type() const
class Item_case_expr :public Item_sp_variable
{
public:
- Item_case_expr(int case_expr_id);
+ Item_case_expr(uint case_expr_id);
public:
Item *this_item();
@@ -1133,7 +1136,7 @@ public:
void print(String *str);
private:
- int m_case_expr_id;
+ uint m_case_expr_id;
};
/*****************************************************************************
@@ -1170,7 +1173,8 @@ class Item_name_const : public Item
Item *value_item;
Item *name_item;
public:
- Item_name_const(Item *name, Item *val): value_item(val), name_item(name)
+ Item_name_const(Item *name_arg, Item *val):
+ value_item(val), name_item(name_arg)
{
Item::maybe_null= TRUE;
}
@@ -1220,7 +1224,7 @@ public:
Item_num() {} /* Remove gcc warning */
virtual Item_num *neg()= 0;
Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool check_partition_func_processor(byte *int_arg) { return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) { return FALSE;}
};
#define NO_CACHED_FIELD_INDEX ((uint)(-1))
@@ -1264,9 +1268,9 @@ public:
Item_ident(THD *thd, Item_ident *item);
const char *full_name() const;
void cleanup();
- bool remove_dependence_processor(byte * arg);
+ bool remove_dependence_processor(uchar * arg);
void print(String *str);
- virtual bool change_context_processor(byte *cntx)
+ virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
friend bool insert_fields(THD *thd, Name_resolution_context *context,
const char *db_name,
@@ -1314,7 +1318,6 @@ public:
uint have_privileges;
/* field need any privileges (for VIEW creation) */
bool any_privileges;
-
Item_field(Name_resolution_context *context_arg,
const char *db_arg,const char *table_name_arg,
const char *field_name_arg);
@@ -1370,30 +1373,32 @@ public:
}
Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
- bool get_date(TIME *ltime,uint fuzzydate);
- bool get_date_result(TIME *ltime,uint fuzzydate);
- bool get_time(TIME *ltime);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
+ bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate);
+ bool get_time(MYSQL_TIME *ltime);
bool is_null() { return field->is_null(); }
void update_null_value();
Item *get_tmp_table_item(THD *thd);
- bool collect_item_field_processor(byte * arg);
- bool find_item_in_field_list_processor(byte *arg);
- bool register_field_in_read_map(byte *arg);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool collect_item_field_processor(uchar * arg);
+ bool find_item_in_field_list_processor(uchar *arg);
+ bool register_field_in_read_map(uchar *arg);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
void cleanup();
bool result_as_longlong()
{
return field->can_be_compared_as_longlong();
}
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
- bool subst_argument_checker(byte **arg);
- Item *equal_fields_propagator(byte *arg);
- bool set_no_const_sub(byte *arg);
- Item *replace_equal_field(byte *arg);
- inline uint32 max_disp_length() { return field->max_length(); }
+ bool subst_argument_checker(uchar **arg);
+ Item *equal_fields_propagator(uchar *arg);
+ bool set_no_const_sub(uchar *arg);
+ Item *replace_equal_field(uchar *arg);
+ inline uint32 max_disp_length() { return field->max_display_length(); }
Item_field *filed_for_view_update() { return this; }
Item *safe_charset_converter(CHARSET_INFO *tocs);
int fix_outer_field(THD *thd, Field **field, Item **reference);
+ virtual Item *update_value_transformer(uchar *select_arg);
+ void print(String *str);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -1424,11 +1429,11 @@ public:
/* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup() {}
bool basic_const_item() const { return 1; }
- Item *new_item() { return new Item_null(name); }
+ Item *clone_item() { return new Item_null(name); }
bool is_null() { return 1; }
void print(String *str) { str->append(STRING_WITH_LEN("NULL")); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_null_result :public Item_null
@@ -1441,7 +1446,7 @@ public:
{
save_in_field(result_field, no_conversions);
}
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
/* Item represents one placeholder ('?') of prepared statement */
@@ -1494,7 +1499,7 @@ public:
*/
CHARSET_INFO *final_character_set_of_str_value;
} cs_info;
- TIME time;
+ MYSQL_TIME time;
} value;
/* Cached values for virtual methods to save us one switch. */
@@ -1526,8 +1531,8 @@ public:
longlong val_int();
my_decimal *val_decimal(my_decimal*);
String *val_str(String*);
- bool get_time(TIME *tm);
- bool get_date(TIME *tm, uint fuzzydate);
+ bool get_time(MYSQL_TIME *tm);
+ bool get_date(MYSQL_TIME *tm, uint fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void set_null();
@@ -1536,7 +1541,7 @@ public:
void set_decimal(const char *str, ulong length);
bool set_str(const char *str, ulong length);
bool set_longdata(const char *str, ulong length);
- void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg);
+ void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
bool set_from_user_var(THD *thd, const user_var_entry *entry);
void reset();
/*
@@ -1573,7 +1578,7 @@ public:
basic_const_item returned TRUE.
*/
Item *safe_charset_converter(CHARSET_INFO *tocs);
- Item *new_item();
+ Item *clone_item();
/*
Implement by-value equality evaluation if parameter value
is set and is a basic constant (integer, real or string).
@@ -1587,11 +1592,14 @@ class Item_int :public Item_num
{
public:
longlong value;
- Item_int(int32 i,uint length=11) :value((longlong) i)
+ Item_int(int32 i,uint length= MY_INT32_NUM_DECIMAL_DIGITS)
+ :value((longlong) i)
{ max_length=length; fixed= 1; }
- Item_int(longlong i,uint length=21) :value(i)
+ Item_int(longlong i,uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+ :value(i)
{ max_length=length; fixed= 1; }
- Item_int(ulonglong i, uint length= 21) :value((longlong)i)
+ Item_int(ulonglong i, uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+ :value((longlong)i)
{ max_length=length; fixed= 1; unsigned_flag= 1; }
Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; }
@@ -1605,7 +1613,7 @@ public:
String *val_str(String*);
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
- Item *new_item() { return new Item_int(name,value,max_length); }
+ Item *clone_item() { return new Item_int(name,value,max_length); }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
void print(String *str);
@@ -1625,7 +1633,7 @@ public:
double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
- Item *new_item() { return new Item_uint(name,max_length); }
+ Item *clone_item() { return new Item_uint(name,max_length); }
int save_in_field(Field *field, bool no_conversions);
void print(String *str);
Item_num *neg ();
@@ -1645,7 +1653,7 @@ public:
Item_decimal(my_decimal *value_par);
Item_decimal(longlong val, bool unsig);
Item_decimal(double val, int precision, int scale);
- Item_decimal(const char *bin, int precision, int scale);
+ Item_decimal(const uchar *bin, int precision, int scale);
enum Type type() const { return DECIMAL_ITEM; }
enum Item_result result_type () const { return DECIMAL_RESULT; }
@@ -1656,7 +1664,7 @@ public:
my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
- Item *new_item()
+ Item *clone_item()
{
return new Item_decimal(name, &decimal_value, decimals, max_length);
}
@@ -1714,7 +1722,7 @@ public:
bool basic_const_item() const { return 1; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
- Item *new_item()
+ Item *clone_item()
{ return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
void print(String *str);
@@ -1732,7 +1740,7 @@ public:
{}
void print(String *str) { str->append(func_name); }
Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1800,17 +1808,21 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const;
- Item *new_item()
+ Item *clone_item()
{
return new Item_string(name, str_value.ptr(),
str_value.length(), collation.collation);
}
Item *safe_charset_converter(CHARSET_INFO *tocs);
- inline void append(char *str, uint length) { str_value.append(str, length); }
+ inline void append(char *str, uint length)
+ {
+ str_value.append(str, length);
+ max_length= str_value.numchars() * collation.collation->mbmaxlen;
+ }
void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1825,43 +1837,67 @@ public:
{}
Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
/* for show tables */
+class Item_partition_func_safe_string: public Item_string
+{
+public:
+ Item_partition_func_safe_string(const char *name, uint length,
+ CHARSET_INFO *cs= NULL):
+ Item_string(name, length, cs)
+ {}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
+};
+
+
+class Item_return_date_time :public Item_partition_func_safe_string
+{
+ enum_field_types date_time_field_type;
+public:
+ Item_return_date_time(const char *name_arg, enum_field_types field_type_arg)
+ :Item_partition_func_safe_string(name_arg, 0, &my_charset_bin),
+ date_time_field_type(field_type_arg)
+ { }
+ enum_field_types field_type() const { return date_time_field_type; }
+};
+
-class Item_datetime :public Item_string
+class Item_blob :public Item_partition_func_safe_string
{
public:
- Item_datetime(const char *item_name): Item_string(item_name,"",0,
- &my_charset_bin)
- { max_length=19;}
- enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ Item_blob(const char *name, uint length) :
+ Item_partition_func_safe_string(name, length, &my_charset_bin)
+ { max_length= length; }
+ enum Type type() const { return TYPE_HOLDER; }
+ enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
};
-class Item_empty_string :public Item_string
+
+class Item_empty_string :public Item_partition_func_safe_string
{
public:
Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) :
- Item_string("",0, cs ? cs : &my_charset_bin)
+ Item_partition_func_safe_string("",0, cs ? cs : &my_charset_bin)
{ name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; }
void make_field(Send_field *field);
};
+
class Item_return_int :public Item_int
{
enum_field_types int_field_type;
public:
- Item_return_int(const char *name, uint length,
- enum_field_types field_type_arg)
- :Item_int(name, 0, length), int_field_type(field_type_arg)
+ Item_return_int(const char *name_arg, uint length,
+ enum_field_types field_type_arg, longlong value= 0)
+ :Item_int(name_arg, value, length), int_field_type(field_type_arg)
{
unsigned_flag=1;
}
enum_field_types field_type() const { return int_field_type; }
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1872,7 +1908,10 @@ public:
Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
double val_real()
- { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); }
+ {
+ DBUG_ASSERT(fixed == 1);
+ return (double) (ulonglong) Item_hex_string::val_int();
+ }
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
@@ -1885,7 +1924,7 @@ public:
void cleanup() {}
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1924,7 +1963,7 @@ class Item_ref :public Item_ident
protected:
void set_properties();
public:
- enum Ref_Type { REF, DIRECT_REF, VIEW_REF };
+ enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF };
Field *result_field; /* Save result here */
Item **ref;
Item_ref(Name_resolution_context *context_arg,
@@ -1947,7 +1986,8 @@ public:
with Bar, and if we have a more broader set of problems like this.
*/
Item_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg);
+ const char *table_name_arg, const char *field_name_arg,
+ bool alias_name_used_arg= FALSE);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
@@ -1964,7 +2004,7 @@ public:
bool val_bool();
String *val_str(String* tmp);
bool is_null();
- bool get_date(TIME *ltime,uint fuzzydate);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
@@ -1985,9 +2025,14 @@ public:
(*ref)->get_tmp_table_item(thd));
}
table_map used_tables() const
- {
+ {
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
+ void update_used_tables()
+ {
+ if (!depended_from)
+ (*ref)->update_used_tables();
+ }
table_map not_null_tables() const { return (*ref)->not_null_tables(); }
void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return 1; }
@@ -1999,7 +2044,7 @@ public:
{
return ref ? (*ref)->real_item() : this;
}
- bool walk(Item_processor processor, bool walk_subquery, byte *arg)
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{ return (*ref)->walk(processor, walk_subquery, arg); }
void print(String *str);
bool result_as_longlong()
@@ -2022,8 +2067,11 @@ class Item_direct_ref :public Item_ref
public:
Item_direct_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg,
- const char *field_name_arg)
- :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ const char *field_name_arg,
+ bool alias_name_used_arg= FALSE)
+ :Item_ref(context_arg, item, table_name_arg,
+ field_name_arg, alias_name_used_arg)
+ {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
@@ -2033,7 +2081,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool is_null();
- bool get_date(TIME *ltime,uint fuzzydate);
+ bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
virtual Ref_Type ref_type() { return DIRECT_REF; }
};
@@ -2058,6 +2106,59 @@ public:
};
+/*
+ Class for outer fields.
+ An object of this class is created when the select where the outer field was
+ resolved is a grouping one. After it has been fixed the ref field will point
+ to either an Item_ref or an Item_direct_ref object which will be used to
+ access the field.
+ See also comments for the fix_inner_refs() and the
+ Item_field::fix_outer_field() functions.
+*/
+
+class Item_sum;
+class Item_outer_ref :public Item_direct_ref
+{
+public:
+ Item *outer_ref;
+ /* The aggregate function under which this outer ref is used, if any. */
+ Item_sum *in_sum_func;
+ /*
+ TRUE <=> that the outer_ref is already present in the select list
+ of the outer select.
+ */
+ bool found_in_select_list;
+ Item_outer_ref(Name_resolution_context *context_arg,
+ Item_field *outer_field_arg)
+ :Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
+ outer_field_arg->field_name),
+ outer_ref(outer_field_arg), in_sum_func(0),
+ found_in_select_list(0)
+ {
+ ref= &outer_ref;
+ set_properties();
+ fixed= 0;
+ }
+ Item_outer_ref(Name_resolution_context *context_arg, Item **item,
+ const char *table_name_arg, const char *field_name_arg,
+ bool alias_name_used_arg)
+ :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg,
+ alias_name_used_arg),
+ outer_ref(0), in_sum_func(0), found_in_select_list(1)
+ {}
+ void save_in_result_field(bool no_conversions)
+ {
+ outer_ref->save_org_in_field(result_field);
+ }
+ bool fix_fields(THD *, Item **);
+ table_map used_tables() const
+ {
+ return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT;
+ }
+ virtual Ref_Type ref_type() { return OUTER_REF; }
+};
+
+
class Item_in_subselect;
@@ -2085,7 +2186,7 @@ public:
String* val_str(String* s);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(TIME *ltime, uint fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
void print(String *str);
/*
we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
@@ -2120,9 +2221,9 @@ public:
{
return ref->save_in_field(field, no_conversions);
}
- Item *new_item();
+ Item *clone_item();
virtual Item *real_item() { return ref; }
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
#ifdef MYSQL_SERVER
@@ -2135,7 +2236,6 @@ public:
#include "item_strfunc.h"
#include "item_geofunc.h"
#include "item_timefunc.h"
-#include "item_uniq.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
#endif
@@ -2232,7 +2332,7 @@ public:
class Cached_item_field :public Cached_item
{
- char *buff;
+ uchar *buff;
Field *field;
uint length;
@@ -2240,7 +2340,7 @@ public:
Cached_item_field(Item_field *item)
{
field= item->field;
- buff= (char*) sql_calloc(length=field->pack_length());
+ buff= (uchar*) sql_calloc(length=field->pack_length());
}
bool cmp(void);
};
@@ -2264,13 +2364,13 @@ public:
int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
- bool walk(Item_processor processor, bool walk_subquery, byte *args)
+ bool walk(Item_processor processor, bool walk_subquery, uchar *args)
{
return arg->walk(processor, walk_subquery, args) ||
(this->*processor)(args);
}
- Item *transform(Item_transformer transformer, byte *args);
+ Item *transform(Item_transformer transformer, uchar *args);
};
/*
@@ -2304,7 +2404,7 @@ public:
*/
table_map used_tables() const { return RAND_TABLE_BIT; }
- bool walk(Item_processor processor, bool walk_subquery, byte *args)
+ bool walk(Item_processor processor, bool walk_subquery, uchar *args)
{
return arg->walk(processor, walk_subquery, args) ||
(this->*processor)(args);
@@ -2374,6 +2474,9 @@ public:
bool fix_fields(THD *, Item **);
void print(String *str);
table_map used_tables() const { return (table_map)0L; }
+ Field *get_tmp_table_field() { return 0; }
+ Item *copy_or_same(THD *thd) { return this; }
+ Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
void cleanup();
private:
@@ -2452,11 +2555,13 @@ public:
Item_cache_int(): Item_cache(), value(0) {}
void store(Item *item);
+ void store(Item *item, longlong val_arg);
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
+ bool result_as_longlong() { return TRUE; }
};
@@ -2556,8 +2661,8 @@ public:
enum Item_result result_type() const { return ROW_RESULT; }
uint cols() { return item_count; }
- Item* el(uint i) { return values[i]; }
- Item** addr(uint i) { return (Item **) (values + i); }
+ Item *element_index(uint i) { return values[i]; }
+ Item **addr(uint i) { return (Item **) (values + i); }
bool check_cols(uint c);
bool null_inside();
void bring_value();
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 37f9ca7ce6c..c162b84f457 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index b1b73a523be..b8117f53d6b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,13 +26,17 @@
static bool convert_constant_item(THD *thd, Field *field, Item **item);
-static Item_result item_store_type(Item_result a,Item_result b)
+static Item_result item_store_type(Item_result a, Item *item,
+ my_bool unsigned_flag)
{
+ Item_result b= item->result_type();
+
if (a == STRING_RESULT || b == STRING_RESULT)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
- else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT)
+ else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT ||
+ unsigned_flag != item->unsigned_flag)
return DECIMAL_RESULT;
else
return INT_RESULT;
@@ -42,6 +45,7 @@ static Item_result item_store_type(Item_result a,Item_result b)
static void agg_result_type(Item_result *type, Item **items, uint nitems)
{
Item **item, **item_end;
+ my_bool unsigned_flag= 0;
*type= STRING_RESULT;
/* Skip beginning NULL items */
@@ -50,6 +54,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
if ((*item)->type() != Item::NULL_ITEM)
{
*type= (*item)->result_type();
+ unsigned_flag= (*item)->unsigned_flag;
item++;
break;
}
@@ -58,32 +63,86 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
for (; item < item_end; item++)
{
if ((*item)->type() != Item::NULL_ITEM)
- *type= item_store_type(type[0], (*item)->result_type());
+ *type= item_store_type(*type, *item, unsigned_flag);
+ }
+}
+
+
+/*
+ Compare row signature of two expressions
+
+ SYNOPSIS:
+ cmp_row_type()
+ item1 the first expression
+ item2 the second expression
+
+ DESCRIPTION
+ The function checks that two expressions have compatible row signatures
+ i.e. that the number of columns they return are the same and that if they
+ are both row expressions then each component from the first expression has
+ a row signature compatible with the signature of the corresponding component
+ of the second expression.
+
+ RETURN VALUES
+ 1 type incompatibility has been detected
+ 0 otherwise
+*/
+
+static int cmp_row_type(Item* item1, Item* item2)
+{
+ uint n= item1->cols();
+ if (item2->check_cols(n))
+ return 1;
+ for (uint i=0; i<n; i++)
+ {
+ if (item2->element_index(i)->check_cols(item1->element_index(i)->cols()) ||
+ (item1->element_index(i)->result_type() == ROW_RESULT &&
+ cmp_row_type(item1->element_index(i), item2->element_index(i))))
+ return 1;
}
+ return 0;
}
/*
Aggregates result types from the array of items.
- SYNOPSIS
+ SYNOPSIS:
agg_cmp_type()
- items array of items to aggregate the type from
- nitems number of items in the array
+ type [out] the aggregated type
+ items array of items to aggregate the type from
+ nitems number of items in the array
DESCRIPTION
This function aggregates result types from the array of items. Found type
supposed to be used later for comparison of values of these items.
Aggregation itself is performed by the item_cmp_type() function.
+ The function also checks compatibility of row signatures for the
+ submitted items (see the spec for the cmp_row_type function).
+
+ RETURN VALUES
+ 1 type incompatibility has been detected
+ 0 otherwise
*/
-static Item_result agg_cmp_type(Item **items, uint nitems)
+static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
{
uint i;
- Item_result type= items[0]->result_type();
+ type[0]= items[0]->result_type();
for (i= 1 ; i < nitems ; i++)
- type= item_cmp_type(type, items[i]->result_type());
- return type;
+ {
+ type[0]= item_cmp_type(type[0], items[i]->result_type());
+ /*
+ When aggregating types of two row expressions we have to check
+ that they have the same cardinality and that each component
+ of the first row expression has a compatible row signature with
+ the signature of the corresponding component of the second row
+ expression.
+ */
+ if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i]))
+ return 1; // error found: invalid usage of rows
+ }
+ return 0;
}
@@ -100,7 +159,8 @@ static Item_result agg_cmp_type(Item **items, uint nitems)
item in the list with each of the remaining items in the 'items' array.
RETURN
- Bitmap of collected types
+ 0 - if row type incompatibility has been detected (see cmp_row_type)
+ Bitmap of collected types - otherwise
*/
static uint collect_cmp_types(Item **items, uint nitems)
@@ -111,12 +171,17 @@ static uint collect_cmp_types(Item **items, uint nitems)
DBUG_ASSERT(nitems > 1);
found_types= 0;
for (i= 1; i < nitems ; i++)
+ {
+ if ((left_result == ROW_RESULT ||
+ items[i]->result_type() == ROW_RESULT) &&
+ cmp_row_type(items[0], items[i]))
+ return 0;
found_types|= 1<< (uint)item_cmp_type(left_result,
items[i]->result_type());
+ }
return found_types;
}
-
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
@@ -177,6 +242,22 @@ longlong Item_func_not::val_int()
}
/*
+ We put any NOT expression into parenthesis to avoid
+ possible problems with internal view representations where
+ any '!' is converted to NOT. It may cause a problem if
+ '!' is used in an expression together with other operators
+ whose precedence is lower than the precedence of '!' yet
+ higher than the precedence of NOT.
+*/
+
+void Item_func_not::print(String *str)
+{
+ str->append('(');
+ Item_func::print(str);
+ str->append(')');
+}
+
+/*
special NOT for ALL subquery
*/
@@ -272,6 +353,7 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
{
TABLE *table= field->table;
ulong orig_sql_mode= thd->variables.sql_mode;
+ enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields;
my_bitmap_map *old_write_map;
my_bitmap_map *old_read_map;
@@ -284,7 +366,9 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
old_read_map= dbug_tmp_use_all_columns(table, table->read_set);
}
/* For comparison purposes allow invalid dates like 2000-01-32 */
- thd->variables.sql_mode|= MODE_INVALID_DATES;
+ thd->variables.sql_mode= (orig_sql_mode & ~MODE_NO_ZERO_DATE) |
+ MODE_INVALID_DATES;
+ thd->count_cuted_fields= CHECK_FIELD_IGNORE;
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
Item *tmp= new Item_int_with_ref(field->val_int(), *item,
@@ -294,6 +378,7 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
result= 1; // Item was replaced
}
thd->variables.sql_mode= orig_sql_mode;
+ thd->count_cuted_fields= orig_count_cuted_fields;
if (table)
{
dbug_tmp_restore_column_map(table->write_set, old_write_map);
@@ -307,7 +392,7 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
void Item_bool_func2::fix_length_and_dec()
{
max_length= 1; // Function returns 0 or 1
- THD *thd= current_thd;
+ THD *thd;
/*
As some compare functions are generated after sql_yacc,
@@ -345,13 +430,16 @@ void Item_bool_func2::fix_length_and_dec()
return;
}
+ thd= current_thd;
if (!thd->is_context_analysis_only())
{
- Item *real_item= args[0]->real_item();
- if (real_item->type() == FIELD_ITEM)
+ Item *arg_real_item= args[0]->real_item();
+ if (arg_real_item->type() == FIELD_ITEM)
{
- Field *field=((Item_field*) real_item)->field;
- if (field->can_be_compared_as_longlong())
+ Field *field=((Item_field*) arg_real_item)->field;
+ if (field->can_be_compared_as_longlong() &&
+ !(arg_real_item->is_datetime() &&
+ args[1]->result_type() == STRING_RESULT))
{
if (convert_constant_item(thd, field,&args[1]))
{
@@ -362,11 +450,13 @@ void Item_bool_func2::fix_length_and_dec()
}
}
}
- real_item= args[1]->real_item();
- if (real_item->type() == FIELD_ITEM /* && !real_item->const_item() */)
+ arg_real_item= args[1]->real_item();
+ if (arg_real_item->type() == FIELD_ITEM)
{
- Field *field=((Item_field*) real_item)->field;
- if (field->can_be_compared_as_longlong())
+ Field *field=((Item_field*) arg_real_item)->field;
+ if (field->can_be_compared_as_longlong() &&
+ !(arg_real_item->is_datetime() &&
+ args[0]->result_type() == STRING_RESULT))
{
if (convert_constant_item(thd, field,&args[0]))
{
@@ -401,9 +491,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
return 1;
for (uint i=0; i < n; i++)
{
- if ((*a)->el(i)->cols() != (*b)->el(i)->cols())
+ if ((*a)->element_index(i)->cols() != (*b)->element_index(i)->cols())
{
- my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->el(i)->cols());
+ my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
return 1;
}
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
@@ -441,8 +531,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
which would be transformed to:
WHERE col= 'j'
*/
- (*a)->walk(&Item::set_no_const_sub, FALSE, (byte*) 0);
- (*b)->walk(&Item::set_no_const_sub, FALSE, (byte*) 0);
+ (*a)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
+ (*b)->walk(&Item::set_no_const_sub, FALSE, (uchar*) 0);
}
break;
}
@@ -465,8 +555,19 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
break;
}
case DECIMAL_RESULT:
+ break;
case REAL_RESULT:
+ {
+ if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC)
+ {
+ precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)];
+ if (func == &Arg_comparator::compare_real)
+ func= &Arg_comparator::compare_real_fixed;
+ else if (func == &Arg_comparator::compare_e_real)
+ func= &Arg_comparator::compare_e_real_fixed;
+ }
break;
+ }
default:
DBUG_ASSERT(0);
}
@@ -474,6 +575,350 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
}
+/*
+ Convert date provided in a string to the int representation.
+
+ SYNOPSIS
+ get_date_from_str()
+ thd Thread handle
+ str a string to convert
+ warn_type type of the timestamp for issuing the warning
+ warn_name field name for issuing the warning
+ error_arg [out] TRUE if string isn't a DATETIME or clipping occur
+
+ DESCRIPTION
+ Convert date provided in the string str to the int representation.
+ if the string contains wrong date or doesn't contain it at all
+ then the warning is issued and TRUE returned in the error_arg argument.
+ The warn_type and the warn_name arguments are used as the name and the
+ type of the field when issuing the warning.
+
+ RETURN
+ converted value.
+*/
+
+static ulonglong
+get_date_from_str(THD *thd, String *str, timestamp_type warn_type,
+ char *warn_name, bool *error_arg)
+{
+ ulonglong value= 0;
+ int error;
+ MYSQL_TIME l_time;
+ enum_mysql_timestamp_type ret;
+ *error_arg= TRUE;
+
+ ret= str_to_datetime(str->ptr(), str->length(), &l_time,
+ (TIME_FUZZY_DATE | MODE_INVALID_DATES |
+ (thd->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))),
+ &error);
+ if ((ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE))
+ {
+ value= TIME_to_ulonglong_datetime(&l_time);
+ *error_arg= FALSE;
+ }
+
+ if (error || *error_arg)
+ {
+ make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ str->ptr(), str->length(),
+ warn_type, warn_name);
+ *error_arg= TRUE;
+ }
+ return value;
+}
+
+
+/*
+ Check whether compare_datetime() can be used to compare items.
+
+ SYNOPSIS
+ Arg_comparator::can_compare_as_dates()
+ a, b [in] items to be compared
+ const_value [out] converted value of the string constant, if any
+
+ DESCRIPTION
+ Check several cases when the DATE/DATETIME comparator should be used.
+ The following cases are checked:
+ 1. Both a and b is a DATE/DATETIME field/function returning string or
+ int result.
+ 2. Only a or b is a DATE/DATETIME field/function returning string or
+ int result and the other item (b or a) is an item with string result.
+ If the second item is a constant one then it's checked to be
+ convertible to the DATE/DATETIME type. If the constant can't be
+ converted to a DATE/DATETIME then the compare_datetime() comparator
+ isn't used and the warning about wrong DATE/DATETIME value is issued.
+ In all other cases (date-[int|real|decimal]/[int|real|decimal]-date)
+ the comparison is handled by other comparators.
+ If the datetime comparator can be used and one the operands of the
+ comparison is a string constant that was successfully converted to a
+ DATE/DATETIME type then the result of the conversion is returned in the
+ const_value if it is provided. If there is no constant or
+ compare_datetime() isn't applicable then the *const_value remains
+ unchanged.
+
+ RETURN
+ the found type of date comparison
+*/
+
+enum Arg_comparator::enum_date_cmp_type
+Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
+{
+ enum enum_date_cmp_type cmp_type= CMP_DATE_DFLT;
+ Item *str_arg= 0, *date_arg= 0;
+
+ if (a->type() == Item::ROW_ITEM || b->type() == Item::ROW_ITEM)
+ return CMP_DATE_DFLT;
+
+ if (a->is_datetime())
+ {
+ if (b->is_datetime())
+ cmp_type= CMP_DATE_WITH_DATE;
+ else if (b->result_type() == STRING_RESULT)
+ {
+ cmp_type= CMP_DATE_WITH_STR;
+ date_arg= a;
+ str_arg= b;
+ }
+ }
+ else if (b->is_datetime() && a->result_type() == STRING_RESULT)
+ {
+ cmp_type= CMP_STR_WITH_DATE;
+ date_arg= b;
+ str_arg= a;
+ }
+
+ if (cmp_type != CMP_DATE_DFLT)
+ {
+ /*
+ Do not cache GET_USER_VAR() function as its const_item() may return TRUE
+ for the current thread but it still may change during the execution.
+ */
+ if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
+ (str_arg->type() != Item::FUNC_ITEM ||
+ ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
+ {
+ THD *thd= current_thd;
+ ulonglong value;
+ bool error;
+ String tmp, *str_val= 0;
+ timestamp_type t_type= (date_arg->field_type() == MYSQL_TYPE_DATE ?
+ MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME);
+
+ str_val= str_arg->val_str(&tmp);
+ if (str_arg->null_value)
+ return CMP_DATE_DFLT;
+ value= get_date_from_str(thd, str_val, t_type, date_arg->name, &error);
+ if (error)
+ return CMP_DATE_DFLT;
+ if (const_value)
+ *const_value= value;
+ }
+ }
+ return cmp_type;
+}
+
+
+int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
+ Item **a1, Item **a2,
+ Item_result type)
+{
+ enum enum_date_cmp_type cmp_type;
+ ulonglong const_value= (ulonglong)-1;
+ a= a1;
+ b= a2;
+
+ if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
+ {
+ thd= current_thd;
+ owner= owner_arg;
+ a_type= (*a)->field_type();
+ b_type= (*b)->field_type();
+ a_cache= 0;
+ b_cache= 0;
+
+ if (const_value != (ulonglong)-1)
+ {
+ Item_cache_int *cache= new Item_cache_int();
+ /* Mark the cache as non-const to prevent re-caching. */
+ cache->set_used_tables(1);
+ if (!(*a)->is_datetime())
+ {
+ cache->store((*a), const_value);
+ a_cache= cache;
+ a= (Item **)&a_cache;
+ }
+ else
+ {
+ cache->store((*b), const_value);
+ b_cache= cache;
+ b= (Item **)&b_cache;
+ }
+ }
+ is_nulls_eq= test(owner && owner->functype() == Item_func::EQUAL_FUNC);
+ func= &Arg_comparator::compare_datetime;
+ return 0;
+ }
+ return set_compare_func(owner_arg, type);
+}
+
+
+void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
+{
+ thd= current_thd;
+ /* A caller will handle null values by itself. */
+ owner= NULL;
+ a= a1;
+ b= b1;
+ a_type= (*a)->field_type();
+ b_type= (*b)->field_type();
+ a_cache= 0;
+ b_cache= 0;
+ is_nulls_eq= FALSE;
+ func= &Arg_comparator::compare_datetime;
+}
+
+/*
+ Retrieves correct DATETIME value from given item.
+
+ SYNOPSIS
+ get_datetime_value()
+ thd thread handle
+ item_arg [in/out] item to retrieve DATETIME value from
+ cache_arg [in/out] pointer to place to store the caching item to
+ warn_item [in] item for issuing the conversion warning
+ is_null [out] TRUE <=> the item_arg is null
+
+ DESCRIPTION
+ Retrieves the correct DATETIME value from given item for comparison by the
+ compare_datetime() function.
+ If item's result can be compared as longlong then its int value is used
+ and its string value is used otherwise. Strings are always parsed and
+ converted to int values by the get_date_from_str() function.
+ This allows us to compare correctly string dates with missed insignificant
+ zeros. If an item is a constant one then its value is cached and it isn't
+ get parsed again. An Item_cache_int object is used for caching values. It
+ seamlessly substitutes the original item. The cache item is marked as
+ non-constant to prevent re-caching it again. In order to compare
+ correctly DATE and DATETIME items the result of the former are treated as
+ a DATETIME with zero time (00:00:00).
+
+ RETURN
+ obtained value
+*/
+
+ulonglong
+get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null)
+{
+ ulonglong value= 0;
+ String buf, *str= 0;
+ Item *item= **item_arg;
+
+ if (item->result_as_longlong())
+ {
+ value= item->val_int();
+ *is_null= item->null_value;
+ /*
+ Item_date_add_interval may return MYSQL_TYPE_STRING as the result
+ field type. To detect that the DATE value has been returned we
+ compare it with 1000000L - any DATE value should be less than it.
+ */
+ if (item->field_type() == MYSQL_TYPE_DATE || value < 100000000L)
+ value*= 1000000L;
+ }
+ else
+ {
+ str= item->val_str(&buf);
+ *is_null= item->null_value;
+ }
+ if (*is_null)
+ return -1;
+ /*
+ Convert strings to the integer DATE/DATETIME representation.
+ Even if both dates provided in strings we can't compare them directly as
+ strings as there is no warranty that they are correct and do not miss
+ some insignificant zeros.
+ */
+ if (str)
+ {
+ bool error;
+ enum_field_types f_type= warn_item->field_type();
+ timestamp_type t_type= f_type ==
+ MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME;
+ value= get_date_from_str(thd, str, t_type, warn_item->name, &error);
+ }
+ /*
+ Do not cache GET_USER_VAR() function as its const_item() may return TRUE
+ for the current thread but it still may change during the execution.
+ */
+ if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM ||
+ ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC))
+ {
+ Item_cache_int *cache= new Item_cache_int();
+ /* Mark the cache as non-const to prevent re-caching. */
+ cache->set_used_tables(1);
+ cache->store(item, value);
+ *cache_arg= cache;
+ *item_arg= cache_arg;
+ }
+ return value;
+}
+
+/*
+ Compare items values as dates.
+
+ SYNOPSIS
+ Arg_comparator::compare_datetime()
+
+ DESCRIPTION
+ Compare items values as DATE/DATETIME for both EQUAL_FUNC and from other
+ comparison functions. The correct DATETIME values are obtained
+ with help of the get_datetime_value() function.
+
+ RETURN
+ If is_nulls_eq is TRUE:
+ 1 if items are equal or both are null
+ 0 otherwise
+ If is_nulls_eq is FALSE:
+ -1 a < b or one of items is null
+ 0 a == b
+ 1 a > b
+*/
+
+int Arg_comparator::compare_datetime()
+{
+ bool is_null= FALSE;
+ ulonglong a_value, b_value;
+
+ /* Get DATE/DATETIME value of the 'a' item. */
+ a_value= get_datetime_value(thd, &a, &a_cache, *b, &is_null);
+ if (!is_nulls_eq && is_null)
+ {
+ if (owner)
+ owner->null_value= 1;
+ return -1;
+ }
+
+ /* Get DATE/DATETIME value of the 'b' item. */
+ b_value= get_datetime_value(thd, &b, &b_cache, *a, &is_null);
+ if (is_null)
+ {
+ if (owner)
+ owner->null_value= is_nulls_eq ? 0 : 1;
+ return is_nulls_eq ? 1 : -1;
+ }
+
+ if (owner)
+ owner->null_value= 0;
+
+ /* Compare values. */
+ if (is_nulls_eq)
+ return (a_value == b_value);
+ return a_value < b_value ? -1 : (a_value > b_value ? 1 : 0);
+}
+
+
int Arg_comparator::compare_string()
{
String *res1,*res2;
@@ -605,6 +1050,44 @@ int Arg_comparator::compare_e_decimal()
return test(my_decimal_cmp(val1, val2) == 0);
}
+
+int Arg_comparator::compare_real_fixed()
+{
+ /*
+ Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
+ gcc to flush double values out of 80-bit Intel FPU registers before
+ performing the comparison.
+ */
+ volatile double val1, val2;
+ val1= (*a)->val_real();
+ if (!(*a)->null_value)
+ {
+ val2= (*b)->val_real();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (val1 == val2 || fabs(val1 - val2) < precision)
+ return 0;
+ if (val1 < val2)
+ return -1;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+int Arg_comparator::compare_e_real_fixed()
+{
+ double val1= (*a)->val_real();
+ double val2= (*b)->val_real();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2 || fabs(val1 - val2) < precision);
+}
+
+
int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
@@ -733,8 +1216,18 @@ int Arg_comparator::compare_row()
if (owner->null_value)
{
// NULL was compared
- if (owner->abort_on_null)
- return -1; // We do not need correct NULL returning
+ switch (owner->functype()) {
+ case Item_func::NE_FUNC:
+ break; // NE never aborts on NULL even if abort_on_null is set
+ case Item_func::LT_FUNC:
+ case Item_func::LE_FUNC:
+ case Item_func::GT_FUNC:
+ case Item_func::GE_FUNC:
+ return -1; // <, <=, > and >= always fail on NULL
+ default: // EQ_FUNC
+ if (owner->abort_on_null)
+ return -1; // We do not need correct NULL returning
+ }
was_null= 1;
owner->null_value= 0;
res= 0; // continue comparison (maybe we will meet explicit difference)
@@ -745,8 +1238,8 @@ int Arg_comparator::compare_row()
if (was_null)
{
/*
- There was NULL(s) in comparison in some parts, but there was not
- explicit difference in other parts, so we have to return NULL
+ There was NULL(s) in comparison in some parts, but there was no
+ explicit difference in other parts, so we have to return NULL.
*/
owner->null_value= 1;
return -1;
@@ -769,6 +1262,59 @@ int Arg_comparator::compare_e_row()
}
+void Item_func_truth::fix_length_and_dec()
+{
+ maybe_null= 0;
+ null_value= 0;
+ decimals= 0;
+ max_length= 1;
+}
+
+
+void Item_func_truth::print(String *str)
+{
+ str->append('(');
+ args[0]->print(str);
+ str->append(STRING_WITH_LEN(" is "));
+ if (! affirmative)
+ str->append(STRING_WITH_LEN("not "));
+ if (value)
+ str->append(STRING_WITH_LEN("true"));
+ else
+ str->append(STRING_WITH_LEN("false"));
+ str->append(')');
+}
+
+
+bool Item_func_truth::val_bool()
+{
+ bool val= args[0]->val_bool();
+ if (args[0]->null_value)
+ {
+ /*
+ NULL val IS {TRUE, FALSE} --> FALSE
+ NULL val IS NOT {TRUE, FALSE} --> TRUE
+ */
+ return (! affirmative);
+ }
+
+ if (affirmative)
+ {
+ /* {TRUE, FALSE} val IS {TRUE, FALSE} value */
+ return (val == value);
+ }
+
+ /* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
+ return (val != value);
+}
+
+
+longlong Item_func_truth::val_int()
+{
+ return (val_bool() ? 1 : 0);
+}
+
+
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
@@ -788,16 +1334,17 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
uint n= cache->cols();
for (uint i= 0; i < n; i++)
{
- if (args[0]->el(i)->used_tables())
- ((Item_cache *)cache->el(i))->set_used_tables(OUTER_REF_TABLE_BIT);
+ if (args[0]->element_index(i)->used_tables())
+ ((Item_cache *)cache->element_index(i))->set_used_tables(OUTER_REF_TABLE_BIT);
else
- ((Item_cache *)cache->el(i))->set_used_tables(0);
+ ((Item_cache *)cache->element_index(i))->set_used_tables(0);
}
used_tables_cache= args[0]->used_tables();
}
not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func;
- const_item_cache= args[0]->const_item();
+ if ((const_item_cache= args[0]->const_item()))
+ cache->store(args[0]);
return 0;
}
@@ -831,6 +1378,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
longlong Item_in_optimizer::val_int()
{
+ bool tmp;
DBUG_ASSERT(fixed == 1);
cache->store(args[0]);
@@ -861,16 +1409,40 @@ longlong Item_in_optimizer::val_int()
We disable the predicates we've pushed down into subselect, run the
subselect and see if it has produced any rows.
*/
- ((Item_in_subselect*)args[1])->enable_pushed_conds= FALSE;
- longlong tmp= args[1]->val_bool_result();
- result_for_null_param= null_value=
- !((Item_in_subselect*)args[1])->engine->no_rows();
- ((Item_in_subselect*)args[1])->enable_pushed_conds= TRUE;
+ Item_in_subselect *item_subs=(Item_in_subselect*)args[1];
+ if (cache->cols() == 1)
+ {
+ item_subs->set_cond_guard_var(0, FALSE);
+ (void) args[1]->val_bool_result();
+ result_for_null_param= null_value= !item_subs->engine->no_rows();
+ item_subs->set_cond_guard_var(0, TRUE);
+ }
+ else
+ {
+ uint i;
+ uint ncols= cache->cols();
+ /*
+ Turn off the predicates that are based on column compares for
+ which the left part is currently NULL
+ */
+ for (i= 0; i < ncols; i++)
+ {
+ if (cache->element_index(i)->null_value)
+ item_subs->set_cond_guard_var(i, FALSE);
+ }
+
+ (void) args[1]->val_bool_result();
+ result_for_null_param= null_value= !item_subs->engine->no_rows();
+
+ /* Turn all predicates back on */
+ for (i= 0; i < ncols; i++)
+ item_subs->set_cond_guard_var(i, TRUE);
+ }
}
}
return 0;
}
- bool tmp= args[1]->val_bool_result();
+ tmp= args[1]->val_bool_result();
null_value= args[1]->null_value;
return tmp;
}
@@ -977,17 +1549,39 @@ longlong Item_func_strcmp::val_int()
}
+bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
+{
+ /* Assume we don't have rtti */
+ if (this == item)
+ return 1;
+ if (item->type() != FUNC_ITEM)
+ return 0;
+ Item_func *item_func=(Item_func*) item;
+ if (arg_count != item_func->arg_count ||
+ functype() != item_func->functype())
+ return 0;
+ if (negated != ((Item_func_opt_neg *) item_func)->negated)
+ return 0;
+ for (uint i=0; i < arg_count ; i++)
+ if (!args[i]->eq(item_func->arguments()[i], binary_cmp))
+ return 0;
+ return 1;
+}
+
+
void Item_func_interval::fix_length_and_dec()
{
- use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) ||
- (row->el(0)->result_type() == INT_RESULT);
+ use_decimal_comparison= ((row->element_index(0)->result_type() ==
+ DECIMAL_RESULT) ||
+ (row->element_index(0)->result_type() ==
+ INT_RESULT));
if (row->cols() > 8)
{
bool consts=1;
for (uint i=1 ; consts && i < row->cols() ; i++)
{
- consts&= row->el(i)->const_item();
+ consts&= row->element_index(i)->const_item();
}
if (consts &&
@@ -998,7 +1592,7 @@ void Item_func_interval::fix_length_and_dec()
{
for (uint i=1 ; i < row->cols(); i++)
{
- Item *el= row->el(i);
+ Item *el= row->element_index(i);
interval_range *range= intervals + (i-1);
if ((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT))
@@ -1023,7 +1617,7 @@ void Item_func_interval::fix_length_and_dec()
{
for (uint i=1 ; i < row->cols(); i++)
{
- intervals[i-1].dbl= row->el(i)->val_real();
+ intervals[i-1].dbl= row->element_index(i)->val_real();
}
}
}
@@ -1063,15 +1657,15 @@ longlong Item_func_interval::val_int()
if (use_decimal_comparison)
{
- dec= row->el(0)->val_decimal(&dec_buf);
- if (row->el(0)->null_value)
+ dec= row->element_index(0)->val_decimal(&dec_buf);
+ if (row->element_index(0)->null_value)
return -1;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &value);
}
else
{
- value= row->el(0)->val_real();
- if (row->el(0)->null_value)
+ value= row->element_index(0)->val_real();
+ if (row->element_index(0)->null_value)
return -1;
}
@@ -1107,16 +1701,16 @@ longlong Item_func_interval::val_int()
for (i=1 ; i < row->cols() ; i++)
{
- Item *el= row->el(i);
+ Item *el= row->element_index(i);
if (use_decimal_comparison &&
((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT)))
{
- my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf);
+ my_decimal e_dec_buf, *e_dec= row->element_index(i)->val_decimal(&e_dec_buf);
if (my_decimal_cmp(e_dec, dec) > 0)
return i-1;
}
- else if (row->el(i)->val_real() > value)
+ else if (row->element_index(i)->val_real() > value)
return i-1;
}
return i-1;
@@ -1174,8 +1768,10 @@ bool Item_func_between::fix_fields(THD *thd, Item **ref)
void Item_func_between::fix_length_and_dec()
{
- max_length= 1;
- THD *thd= current_thd;
+ max_length= 1;
+ int i;
+ bool datetime_found= FALSE;
+ compare_as_dates= TRUE;
/*
As some compare functions are generated after sql_yacc,
@@ -1183,32 +1779,36 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- cmp_type= agg_cmp_type(args, 3);
+ if ( agg_cmp_type(&cmp_type, args, 3))
+ return;
if (cmp_type == STRING_RESULT &&
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1))
return;
/*
- Make a special case of compare with date/time and longlong fields.
- They are compared as integers, so for const item this time-consuming
- conversion can be done only once, not for every single comparison
+ Detect the comparison of DATE/DATETIME items.
+ At least one of items should be a DATE/DATETIME item and other items
+ should return the STRING result.
*/
- if (args[0]->type() == FIELD_ITEM &&
- thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
- thd->lex->sql_command != SQLCOM_SHOW_CREATE)
+ for (i= 0; i < 3; i++)
{
- Field *field=((Item_field*) args[0])->field;
- if (field->can_be_compared_as_longlong())
+ if (args[i]->is_datetime())
{
- /*
- The following can't be recoded with || as convert_constant_item
- changes the argument
- */
- if (convert_constant_item(thd, field,&args[1]))
- cmp_type=INT_RESULT; // Works for all types.
- if (convert_constant_item(thd, field,&args[2]))
- cmp_type=INT_RESULT; // Works for all types.
+ datetime_found= TRUE;
+ continue;
}
+ if (args[i]->result_type() == STRING_RESULT)
+ continue;
+ compare_as_dates= FALSE;
+ break;
+ }
+ if (!datetime_found)
+ compare_as_dates= FALSE;
+
+ if (compare_as_dates)
+ {
+ ge_cmp.set_datetime_cmp_func(args, args + 1);
+ le_cmp.set_datetime_cmp_func(args, args + 2);
}
}
@@ -1216,7 +1816,27 @@ void Item_func_between::fix_length_and_dec()
longlong Item_func_between::val_int()
{ // ANSI BETWEEN
DBUG_ASSERT(fixed == 1);
- if (cmp_type == STRING_RESULT)
+ if (compare_as_dates)
+ {
+ int ge_res, le_res;
+
+ ge_res= ge_cmp.compare();
+ if ((null_value= args[0]->null_value))
+ return 0;
+ le_res= le_cmp.compare();
+
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (longlong) ((ge_res >= 0 && le_res <=0) != negated);
+ else if (args[1]->null_value)
+ {
+ null_value= le_res > 0; // not null if false range.
+ }
+ else
+ {
+ null_value= ge_res < 0;
+ }
+ }
+ else if (cmp_type == STRING_RESULT)
{
String *value,*a,*b;
value=args[0]->val_str(&value0);
@@ -1480,6 +2100,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
+ unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
@@ -1509,12 +2130,20 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
- max_length=
- (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
- (max(args[1]->max_length - args[1]->decimals,
- args[2]->max_length - args[2]->decimals) + decimals +
- (unsigned_flag ? 0 : 1) ) :
- max(args[1]->max_length, args[2]->max_length);
+
+ if ((cached_result_type == DECIMAL_RESULT )
+ || (cached_result_type == INT_RESULT))
+ {
+ int len1= args[1]->max_length - args[1]->decimals
+ - (args[1]->unsigned_flag ? 0 : 1);
+
+ int len2= args[2]->max_length - args[2]->decimals
+ - (args[2]->unsigned_flag ? 0 : 1);
+
+ max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
+ }
+ else
+ max_length= max(args[1]->max_length, args[2]->max_length);
}
@@ -1810,7 +2439,9 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
buff should match stack usage from
Item_func_case::val_int() -> Item_func_case::find_item()
*/
- char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
+#ifndef EMBEDDED_LIBRARY
+ uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
+#endif
bool res= Item_func::fix_fields(thd, ref);
/*
Call check_stack_overrun after fix_fields to be sure that stack variable
@@ -1827,7 +2458,6 @@ void Item_func_case::fix_length_and_dec()
{
Item **agg;
uint nagg;
- THD *thd= current_thd;
uint found_types= 0;
if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1))))
return;
@@ -1862,7 +2492,8 @@ void Item_func_case::fix_length_and_dec()
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
- found_types= collect_cmp_types(agg, nagg);
+ if (!(found_types= collect_cmp_types(agg, nagg)))
+ return;
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
@@ -2028,9 +2659,100 @@ void Item_func_coalesce::fix_length_and_dec()
Classes and function for the IN operator
****************************************************************************/
-static int cmp_longlong(void *cmp_arg, longlong *a,longlong *b)
+/*
+ Determine which of the signed longlong arguments is bigger
+
+ SYNOPSIS
+ cmp_longs()
+ a_val left argument
+ b_val right argument
+
+ DESCRIPTION
+ This function will compare two signed longlong arguments
+ and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+static inline int cmp_longs (longlong a_val, longlong b_val)
{
- return *a < *b ? -1 : *a == *b ? 0 : 1;
+ return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
+}
+
+
+/*
+ Determine which of the unsigned longlong arguments is bigger
+
+ SYNOPSIS
+ cmp_ulongs()
+ a_val left argument
+ b_val right argument
+
+ DESCRIPTION
+ This function will compare two unsigned longlong arguments
+ and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val)
+{
+ return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
+}
+
+
+/*
+ Compare two integers in IN value list format (packed_longlong)
+
+ SYNOPSIS
+ cmp_longlong()
+ cmp_arg an argument passed to the calling function (qsort2)
+ a left argument
+ b right argument
+
+ DESCRIPTION
+ This function will compare two integer arguments in the IN value list
+ format and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+ It's used in sorting the IN values list and finding an element in it.
+ Depending on the signedness of the arguments cmp_longlong() will
+ compare them as either signed (using cmp_longs()) or unsigned (using
+ cmp_ulongs()).
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+int cmp_longlong(void *cmp_arg,
+ in_longlong::packed_longlong *a,
+ in_longlong::packed_longlong *b)
+{
+ if (a->unsigned_flag != b->unsigned_flag)
+ {
+ /*
+ One of the args is unsigned and is too big to fit into the
+ positive signed range. Report no match.
+ */
+ if (a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX ||
+ b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX)
+ return a->unsigned_flag ? 1 : -1;
+ /*
+ Although the signedness differs both args can fit into the signed
+ positive range. Make them signed and compare as usual.
+ */
+ return cmp_longs (a->val, b->val);
+ }
+ if (a->unsigned_flag)
+ return cmp_ulongs ((ulonglong) a->val, (ulonglong) b->val);
+ else
+ return cmp_longs (a->val, b->val);
}
static int cmp_double(void *cmp_arg, double *a,double *b)
@@ -2058,7 +2780,7 @@ static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b)
int in_vector::find(Item *item)
{
- byte *result=get_value(item);
+ uchar *result=get_value(item);
if (!result || !used_count)
return 0; // Null value
@@ -2113,9 +2835,9 @@ void in_string::set(uint pos,Item *item)
}
-byte *in_string::get_value(Item *item)
+uchar *in_string::get_value(Item *item)
{
- return (byte*) item->val_str(&tmp);
+ return (uchar*) item->val_str(&tmp);
}
in_row::in_row(uint elements, Item * item)
@@ -2123,7 +2845,6 @@ in_row::in_row(uint elements, Item * item)
base= (char*) new cmp_item_row[count= elements];
size= sizeof(cmp_item_row);
compare= (qsort2_cmp) cmp_row;
- tmp.store_value(item);
/*
We need to reset these as otherwise we will call sort() with
uninitialized (even if not used) elements
@@ -2138,37 +2859,62 @@ in_row::~in_row()
delete [] (cmp_item_row*) base;
}
-byte *in_row::get_value(Item *item)
+uchar *in_row::get_value(Item *item)
{
tmp.store_value(item);
if (item->is_null())
return 0;
- return (byte *)&tmp;
+ return (uchar *)&tmp;
}
void in_row::set(uint pos, Item *item)
{
DBUG_ENTER("in_row::set");
- DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item));
+ DBUG_PRINT("enter", ("pos: %u item: 0x%lx", pos, (ulong) item));
((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item);
DBUG_VOID_RETURN;
}
in_longlong::in_longlong(uint elements)
- :in_vector(elements,sizeof(longlong),(qsort2_cmp) cmp_longlong, 0)
+ :in_vector(elements,sizeof(packed_longlong),(qsort2_cmp) cmp_longlong, 0)
{}
void in_longlong::set(uint pos,Item *item)
{
- ((longlong*) base)[pos]=item->val_int();
+ struct packed_longlong *buff= &((packed_longlong*) base)[pos];
+
+ buff->val= item->val_int();
+ buff->unsigned_flag= item->unsigned_flag;
}
-byte *in_longlong::get_value(Item *item)
+uchar *in_longlong::get_value(Item *item)
{
- tmp= item->val_int();
+ tmp.val= item->val_int();
if (item->null_value)
return 0;
- return (byte*) &tmp;
+ tmp.unsigned_flag= item->unsigned_flag;
+ return (uchar*) &tmp;
+}
+
+void in_datetime::set(uint pos,Item *item)
+{
+ Item **tmp= &item;
+ bool is_null;
+ struct packed_longlong *buff= &((packed_longlong*) base)[pos];
+
+ buff->val= get_datetime_value(thd, &tmp, 0, warn_item, &is_null);
+ buff->unsigned_flag= 1L;
+}
+
+uchar *in_datetime::get_value(Item *item)
+{
+ bool is_null;
+ Item **tmp_item= lval_cache ? &lval_cache : &item;
+ tmp.val= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
+ if (item->null_value)
+ return 0;
+ tmp.unsigned_flag= 1L;
+ return (uchar*) &tmp;
}
in_double::in_double(uint elements)
@@ -2180,12 +2926,12 @@ void in_double::set(uint pos,Item *item)
((double*) base)[pos]= item->val_real();
}
-byte *in_double::get_value(Item *item)
+uchar *in_double::get_value(Item *item)
{
tmp= item->val_real();
if (item->null_value)
return 0; /* purecov: inspected */
- return (byte*) &tmp;
+ return (uchar*) &tmp;
}
@@ -2201,17 +2947,18 @@ void in_decimal::set(uint pos, Item *item)
dec->len= DECIMAL_BUFF_LENGTH;
dec->fix_buffer_pointer();
my_decimal *res= item->val_decimal(dec);
- if (res != dec)
+ /* if item->val_decimal() is evaluated to NULL then res == 0 */
+ if (!item->null_value && res != dec)
my_decimal2decimal(res, dec);
}
-byte *in_decimal::get_value(Item *item)
+uchar *in_decimal::get_value(Item *item)
{
my_decimal *result= item->val_decimal(&val);
if (item->null_value)
return 0;
- return (byte *)result;
+ return (uchar *)result;
}
@@ -2274,12 +3021,18 @@ cmp_item_row::~cmp_item_row()
}
+void cmp_item_row::alloc_comparators()
+{
+ if (!comparators)
+ comparators= (cmp_item **) current_thd->calloc(sizeof(cmp_item *)*n);
+}
+
+
void cmp_item_row::store_value(Item *item)
{
DBUG_ENTER("cmp_item_row::store_value");
n= item->cols();
- if (!comparators)
- comparators= (cmp_item **) current_thd->calloc(sizeof(cmp_item *)*n);
+ alloc_comparators();
if (comparators)
{
item->bring_value();
@@ -2288,11 +3041,11 @@ void cmp_item_row::store_value(Item *item)
{
if (!comparators[i])
if (!(comparators[i]=
- cmp_item::get_comparator(item->el(i)->result_type(),
- item->el(i)->collation.collation)))
+ cmp_item::get_comparator(item->element_index(i)->result_type(),
+ item->element_index(i)->collation.collation)))
break; // new failed
- comparators[i]->store_value(item->el(i));
- item->null_value|= item->el(i)->null_value;
+ comparators[i]->store_value(item->element_index(i));
+ item->null_value|= item->element_index(i)->null_value;
}
}
DBUG_VOID_RETURN;
@@ -2317,8 +3070,8 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item)
if (!(comparators[i]= tmpl->comparators[i]->make_same()))
break; // new failed
comparators[i]->store_value_by_template(tmpl->comparators[i],
- item->el(i));
- item->null_value|= item->el(i)->null_value;
+ item->element_index(i));
+ item->null_value|= item->element_index(i)->null_value;
}
}
}
@@ -2336,9 +3089,9 @@ int cmp_item_row::cmp(Item *arg)
arg->bring_value();
for (uint i=0; i < n; i++)
{
- if (comparators[i]->cmp(arg->el(i)))
+ if (comparators[i]->cmp(arg->element_index(i)))
{
- if (!arg->el(i)->null_value)
+ if (!arg->element_index(i)->null_value)
return 1;
was_null= 1;
}
@@ -2349,11 +3102,11 @@ int cmp_item_row::cmp(Item *arg)
int cmp_item_row::compare(cmp_item *c)
{
- cmp_item_row *cmp= (cmp_item_row *) c;
+ cmp_item_row *l_cmp= (cmp_item_row *) c;
for (uint i=0; i < n; i++)
{
int res;
- if ((res= comparators[i]->compare(cmp->comparators[i])))
+ if ((res= comparators[i]->compare(l_cmp->comparators[i])))
return res;
}
return 0;
@@ -2380,8 +3133,8 @@ int cmp_item_decimal::cmp(Item *arg)
int cmp_item_decimal::compare(cmp_item *arg)
{
- cmp_item_decimal *cmp= (cmp_item_decimal*) arg;
- return my_decimal_cmp(&value, &cmp->value);
+ cmp_item_decimal *l_cmp= (cmp_item_decimal*) arg;
+ return my_decimal_cmp(&value, &l_cmp->value);
}
@@ -2391,6 +3144,36 @@ cmp_item* cmp_item_decimal::make_same()
}
+void cmp_item_datetime::store_value(Item *item)
+{
+ bool is_null;
+ Item **tmp_item= lval_cache ? &lval_cache : &item;
+ value= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
+}
+
+
+int cmp_item_datetime::cmp(Item *arg)
+{
+ bool is_null;
+ Item **tmp_item= &arg;
+ return value !=
+ get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null);
+}
+
+
+int cmp_item_datetime::compare(cmp_item *ci)
+{
+ cmp_item_datetime *l_cmp= (cmp_item_datetime *)ci;
+ return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1);
+}
+
+
+cmp_item *cmp_item_datetime::make_same()
+{
+ return new cmp_item_datetime(warn_item);
+}
+
+
bool Item_func_in::nulls_in_row()
{
Item **arg,**arg_end;
@@ -2466,10 +3249,16 @@ void Item_func_in::fix_length_and_dec()
Item **arg, **arg_end;
bool const_itm= 1;
THD *thd= current_thd;
+ bool datetime_found= FALSE;
+ /* TRUE <=> arguments values will be compared as DATETIMEs. */
+ bool compare_as_datetime= FALSE;
+ Item *date_arg= 0;
uint found_types= 0;
uint type_cnt= 0, i;
+ Item_result cmp_type= STRING_RESULT;
left_result_type= args[0]->result_type();
- found_types= collect_cmp_types(args, arg_count);
+ if (!(found_types= collect_cmp_types(args, arg_count)))
+ return;
for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++)
{
@@ -2482,7 +3271,102 @@ void Item_func_in::fix_length_and_dec()
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & 1 << i)
+ {
(type_cnt)++;
+ cmp_type= (Item_result) i;
+ }
+ }
+
+ if (type_cnt == 1)
+ {
+ if (cmp_type == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ return;
+ arg_types_compatible= TRUE;
+ }
+ if (type_cnt == 1)
+ {
+ /*
+ When comparing rows create the row comparator object beforehand to ease
+ the DATETIME comparison detection procedure.
+ */
+ if (cmp_type == ROW_RESULT)
+ {
+ cmp_item_row *cmp= 0;
+ if (const_itm && !nulls_in_row())
+ {
+ array= new in_row(arg_count-1, 0);
+ cmp= &((in_row*)array)->tmp;
+ }
+ else
+ {
+ if (!(cmp= new cmp_item_row))
+ return;
+ cmp_items[ROW_RESULT]= cmp;
+ }
+ cmp->n= args[0]->cols();
+ cmp->alloc_comparators();
+ }
+ /* All DATE/DATETIME fields/functions has the STRING result type. */
+ if (cmp_type == STRING_RESULT || cmp_type == ROW_RESULT)
+ {
+ uint col, cols= args[0]->cols();
+
+ for (col= 0; col < cols; col++)
+ {
+ bool skip_column= FALSE;
+ /*
+ Check that all items to be compared has the STRING result type and at
+ least one of them is a DATE/DATETIME item.
+ */
+ for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
+ {
+ Item *itm= ((cmp_type == STRING_RESULT) ? arg[0] :
+ arg[0]->element_index(col));
+ if (itm->result_type() != STRING_RESULT)
+ {
+ skip_column= TRUE;
+ break;
+ }
+ else if (itm->is_datetime())
+ {
+ datetime_found= TRUE;
+ /*
+ Internally all DATE/DATETIME values are converted to the DATETIME
+ type. So try to find a DATETIME item to issue correct warnings.
+ */
+ if (!date_arg)
+ date_arg= itm;
+ else if (itm->field_type() == MYSQL_TYPE_DATETIME)
+ {
+ date_arg= itm;
+ /* All arguments are already checked to have the STRING result. */
+ if (cmp_type == STRING_RESULT)
+ break;
+ }
+ }
+ }
+ if (skip_column)
+ continue;
+ if (datetime_found)
+ {
+ if (cmp_type == ROW_RESULT)
+ {
+ cmp_item **cmp= 0;
+ if (array)
+ cmp= ((in_row*)array)->tmp.comparators + col;
+ else
+ cmp= ((cmp_item_row*)cmp_items[ROW_RESULT])->comparators + col;
+ *cmp= new cmp_item_datetime(date_arg);
+ /* Reset variables for the next column. */
+ date_arg= 0;
+ datetime_found= FALSE;
+ }
+ else
+ compare_as_datetime= TRUE;
+ }
+ }
+ }
}
/*
Row item with NULLs inside can return NULL or FALSE =>
@@ -2490,35 +3374,61 @@ void Item_func_in::fix_length_and_dec()
*/
if (type_cnt == 1 && const_itm && !nulls_in_row())
{
- uint tmp_type;
- Item_result cmp_type;
- /* Only one cmp type was found. Extract it here */
- for (tmp_type= 0; found_types - 1; found_types>>= 1)
- tmp_type++;
- cmp_type= (Item_result)tmp_type;
-
- switch (cmp_type) {
- case STRING_RESULT:
- if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
+ if (compare_as_datetime)
+ array= new in_datetime(date_arg, arg_count - 1);
+ else
+ {
+ /*
+ IN must compare INT columns and constants as int values (the same
+ way as equality does).
+ So we must check here if the column on the left and all the constant
+ values on the right can be compared as integers and adjust the
+ comparison type accordingly.
+ */
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
+ thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
+ thd->lex->sql_command != SQLCOM_SHOW_CREATE &&
+ cmp_type != INT_RESULT)
+ {
+ Field *field= ((Item_field*) (args[0]->real_item()))->field;
+ if (field->can_be_compared_as_longlong())
+ {
+ bool all_converted= TRUE;
+ for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if (!convert_constant_item (thd, field, &arg[0]))
+ all_converted= FALSE;
+ }
+ if (all_converted)
+ cmp_type= INT_RESULT;
+ }
+ }
+ switch (cmp_type) {
+ case STRING_RESULT:
+ array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
+ cmp_collation.collation);
+ break;
+ case INT_RESULT:
+ array= new in_longlong(arg_count-1);
+ break;
+ case REAL_RESULT:
+ array= new in_double(arg_count-1);
+ break;
+ case ROW_RESULT:
+ /*
+ The row comparator was created at the beginning but only DATETIME
+ items comparators were initialized. Call store_value() to setup
+ others.
+ */
+ ((in_row*)array)->tmp.store_value(args[0]);
+ break;
+ case DECIMAL_RESULT:
+ array= new in_decimal(arg_count - 1);
+ break;
+ default:
+ DBUG_ASSERT(0);
return;
- array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in,
- cmp_collation.collation);
- break;
- case INT_RESULT:
- array= new in_longlong(arg_count - 1);
- break;
- case REAL_RESULT:
- array= new in_double(arg_count - 1);
- break;
- case ROW_RESULT:
- array= new in_row(arg_count - 1, args[0]);
- break;
- case DECIMAL_RESULT:
- array= new in_decimal(arg_count - 1);
- break;
- default:
- DBUG_ASSERT(0);
- return;
+ }
}
if (array && !(thd->is_fatal_error)) // If not EOM
{
@@ -2537,17 +3447,23 @@ void Item_func_in::fix_length_and_dec()
}
else
{
- for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
+ if (compare_as_datetime)
+ cmp_items[STRING_RESULT]= new cmp_item_datetime(date_arg);
+ else
{
- if (found_types & (1 << i) && !cmp_items[i])
+ for (i= 0; i <= (uint) DECIMAL_RESULT; i++)
{
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1))
- return;
- if (!(cmp_items[i]=
- cmp_item::get_comparator((Item_result)i,
- cmp_collation.collation)))
- return;
+ if (found_types & (1 << i) && !cmp_items[i])
+ {
+ if ((Item_result)i == STRING_RESULT &&
+ agg_arg_charsets(cmp_collation, args, arg_count,
+ MY_COLL_CMP_CONV, 1))
+ return;
+ if (!cmp_items[i] && !(cmp_items[i]=
+ cmp_item::get_comparator((Item_result)i,
+ cmp_collation.collation)))
+ return;
+ }
}
}
}
@@ -2692,7 +3608,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
List_iterator<Item> li(list);
Item *item;
#ifndef EMBEDDED_LIBRARY
- char buff[sizeof(char*)]; // Max local vars in function
+ uchar buff[sizeof(char*)]; // Max local vars in function
#endif
not_null_tables_cache= used_tables_cache= 0;
const_item_cache= 1;
@@ -2759,7 +3675,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
return FALSE;
}
-bool Item_cond::walk(Item_processor processor, bool walk_subquery, byte *arg)
+bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
List_iterator_fast<Item> li(list);
Item *item;
@@ -2791,7 +3707,7 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, byte *arg)
Item returned as the result of transformation of the root node
*/
-Item *Item_cond::transform(Item_transformer transformer, byte *arg)
+Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -2842,8 +3758,8 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
Item returned as the result of transformation of the root node
*/
-Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t)
+Item *Item_cond::compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
@@ -2856,7 +3772,7 @@ Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p,
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
- byte *arg_v= *arg_p;
+ uchar *arg_v= *arg_p;
Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && new_item != item)
li.replace(new_item);
@@ -3080,7 +3996,7 @@ longlong Item_func_isnull::val_int()
Handle optimization if the argument can't be null
This has to be here because of the test in update_used_tables().
*/
- if (!used_tables_cache)
+ if (!used_tables_cache && !with_subselect)
return cached_value;
return args[0]->is_null() ? 1: 0;
}
@@ -3089,7 +4005,7 @@ longlong Item_is_not_null_test::val_int()
{
DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_is_not_null_test::val_int");
- if (!used_tables_cache)
+ if (!used_tables_cache && !with_subselect)
{
owner->was_null|= (!cached_value);
DBUG_PRINT("info", ("cached: %ld", (long) cached_value));
@@ -3116,7 +4032,7 @@ void Item_is_not_null_test::update_used_tables()
else
{
args[0]->update_used_tables();
- if (!(used_tables_cache=args[0]->used_tables()))
+ if (!(used_tables_cache=args[0]->used_tables()) && !with_subselect)
{
/* Remember if the value is always NULL or never NULL */
cached_value= (longlong) !args[0]->is_null();
@@ -4085,14 +5001,12 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
- Item *item= const_item ? const_item : get_first();
+ Item *item= get_first();
eval_item= cmp_item::get_comparator(item->result_type(),
item->collation.collation);
- if (item->result_type() == STRING_RESULT)
- eval_item->cmp_charset= cmp_collation.collation;
}
-bool Item_equal::walk(Item_processor processor, bool walk_subquery, byte *arg)
+bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
List_iterator_fast<Item_field> it(fields);
Item *item;
@@ -4104,7 +5018,7 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, byte *arg)
return Item_func::walk(processor, walk_subquery, arg);
}
-Item *Item_equal::transform(Item_transformer transformer, byte *arg)
+Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 51cf5667c95..60f2ac6321d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,12 +34,20 @@ class Arg_comparator: public Sql_alloc
arg_cmp_func func;
Item_bool_func2 *owner;
Arg_comparator *comparators; // used only for compare_row()
-
+ double precision;
+ /* Fields used in DATE/DATETIME comparison. */
+ THD *thd;
+ enum_field_types a_type, b_type; // Types of a and b items
+ Item *a_cache, *b_cache; // Cached values of a and b items
+ bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC
+ enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
+ CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
public:
DTCollation cmp_collation;
- Arg_comparator() {};
- Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {};
+ Arg_comparator(): thd(0), a_cache(0), b_cache(0) {};
+ Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0),
+ a_cache(0), b_cache(0) {};
int set_compare_func(Item_bool_func2 *owner, Item_result type);
inline int set_compare_func(Item_bool_func2 *owner_arg)
@@ -48,14 +55,10 @@ public:
return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
(*b)->result_type()));
}
- inline int set_cmp_func(Item_bool_func2 *owner_arg,
+ int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2,
- Item_result type)
- {
- a= a1;
- b= a2;
- return set_compare_func(owner_arg, type);
- }
+ Item_result type);
+
inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2)
{
@@ -81,7 +84,14 @@ public:
int compare_e_int(); // compare args[0] & args[1]
int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
+ int compare_real_fixed();
+ int compare_e_real_fixed();
+ int compare_datetime(); // compare args[0] & args[1] as DATETIMEs
+ static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b,
+ ulonglong *const_val_arg);
+
+ void set_datetime_cmp_func(Item **a1, Item **b1);
static arg_cmp_func comparator_matrix [5][2];
friend class Item_func;
@@ -99,6 +109,92 @@ public:
uint decimal_precision() const { return 1; }
};
+
+/**
+ Abstract Item class, to represent <code>X IS [NOT] (TRUE | FALSE)</code>
+ boolean predicates.
+*/
+
+class Item_func_truth : public Item_bool_func
+{
+public:
+ virtual bool val_bool();
+ virtual longlong val_int();
+ virtual void fix_length_and_dec();
+ virtual void print(String *str);
+
+protected:
+ Item_func_truth(Item *a, bool a_value, bool a_affirmative)
+ : Item_bool_func(a), value(a_value), affirmative(a_affirmative)
+ {}
+
+ ~Item_func_truth()
+ {}
+private:
+ /**
+ True for <code>X IS [NOT] TRUE</code>,
+ false for <code>X IS [NOT] FALSE</code> predicates.
+ */
+ const bool value;
+ /**
+ True for <code>X IS Y</code>, false for <code>X IS NOT Y</code> predicates.
+ */
+ const bool affirmative;
+};
+
+
+/**
+ This Item represents a <code>X IS TRUE</code> boolean predicate.
+*/
+
+class Item_func_istrue : public Item_func_truth
+{
+public:
+ Item_func_istrue(Item *a) : Item_func_truth(a, true, true) {}
+ ~Item_func_istrue() {}
+ virtual const char* func_name() const { return "istrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT TRUE</code> boolean predicate.
+*/
+
+class Item_func_isnottrue : public Item_func_truth
+{
+public:
+ Item_func_isnottrue(Item *a) : Item_func_truth(a, true, false) {}
+ ~Item_func_isnottrue() {}
+ virtual const char* func_name() const { return "isnottrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS FALSE</code> boolean predicate.
+*/
+
+class Item_func_isfalse : public Item_func_truth
+{
+public:
+ Item_func_isfalse(Item *a) : Item_func_truth(a, false, true) {}
+ ~Item_func_isfalse() {}
+ virtual const char* func_name() const { return "isfalse"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT FALSE</code> boolean predicate.
+*/
+
+class Item_func_isnotfalse : public Item_func_truth
+{
+public:
+ Item_func_isnotfalse(Item *a) : Item_func_truth(a, false, false) {}
+ ~Item_func_isnotfalse() {}
+ virtual const char* func_name() const { return "isnotfalse"; }
+};
+
+
class Item_cache;
#define UNKNOWN ((my_bool)-1)
@@ -245,7 +341,7 @@ public:
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
uint decimal_precision() const { return 1; }
- void top_level_item() { abort_on_null=1; }
+ void top_level_item() { abort_on_null= TRUE; }
friend class Arg_comparator;
};
@@ -259,8 +355,8 @@ public:
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
- bool subst_argument_checker(byte **arg) { return TRUE; }
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ bool subst_argument_checker(uchar **arg) { return TRUE; }
};
class Item_func_not :public Item_bool_func
@@ -271,7 +367,8 @@ public:
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ void print(String *str);
};
class Item_maxmin_subselect;
@@ -314,6 +411,7 @@ public:
enum Functype functype() const { return TRIG_COND_FUNC; };
const char *func_name() const { return "trigcond"; };
bool const_item() const { return FALSE; }
+ bool *get_trig_var() { return trig_var; }
};
class Item_func_not_all :public Item_func_not
@@ -473,7 +571,8 @@ public:
negated= !negated;
return this;
}
- bool subst_argument_checker(byte **arg) { return TRUE; }
+ bool eq(const Item *item, bool binary_cmp) const;
+ bool subst_argument_checker(uchar **arg) { return TRUE; }
};
@@ -483,8 +582,12 @@ class Item_func_between :public Item_func_opt_neg
public:
Item_result cmp_type;
String value0,value1,value2;
+ /* TRUE <=> arguments will be compared as dates. */
+ bool compare_as_dates;
+ /* Comparators used for DATE/DATETIME comparison. */
+ Arg_comparator ge_cmp, le_cmp;
Item_func_between(Item *a, Item *b, Item *c)
- :Item_func_opt_neg(a, b, c) {}
+ :Item_func_opt_neg(a, b, c), compare_as_dates(FALSE) {}
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_KEY; }
enum Functype functype() const { return BETWEEN; }
@@ -495,7 +598,7 @@ public:
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -507,7 +610,7 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "strcmp"; }
void print(String *str) { Item_func::print(str); }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -570,7 +673,7 @@ public:
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
uint decimal_precision() const;
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -611,7 +714,7 @@ public:
void print(String *str) { Item_func::print(str); }
table_map not_null_tables() const { return 0; }
bool is_null();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Functions to handle the optimized IN */
@@ -636,7 +739,7 @@ public:
count(elements), used_count(elements) {}
virtual ~in_vector() {}
virtual void set(uint pos,Item *item)=0;
- virtual byte *get_value(Item *item)=0;
+ virtual uchar *get_value(Item *item)=0;
void sort()
{
qsort2(base,used_count,size,compare,collation);
@@ -679,7 +782,7 @@ public:
in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs);
~in_string();
void set(uint pos,Item *item);
- byte *get_value(Item *item);
+ uchar *get_value(Item *item);
Item* create_item()
{
return new Item_string(collation);
@@ -695,11 +798,21 @@ public:
class in_longlong :public in_vector
{
- longlong tmp;
+protected:
+ /*
+ Here we declare a temporary variable (tmp) of the same type as the
+ elements of this vector. tmp is used in finding if a given value is in
+ the list.
+ */
+ struct packed_longlong
+ {
+ longlong val;
+ longlong unsigned_flag; // Use longlong, not bool, to preserve alignment
+ } tmp;
public:
in_longlong(uint elements);
void set(uint pos,Item *item);
- byte *get_value(Item *item);
+ uchar *get_value(Item *item);
Item* create_item()
{
@@ -711,9 +824,37 @@ public:
}
void value_to_item(uint pos, Item *item)
{
- ((Item_int*)item)->value= ((longlong*)base)[pos];
+ ((Item_int*) item)->value= ((packed_longlong*) base)[pos].val;
+ ((Item_int*) item)->unsigned_flag= (my_bool)
+ ((packed_longlong*) base)[pos].unsigned_flag;
}
Item_result result_type() { return INT_RESULT; }
+
+ friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
+};
+
+
+/*
+ Class to represent a vector of constant DATE/DATETIME values.
+ Values are obtained with help of the get_datetime_value() function.
+ If the left item is a constant one then its value is cached in the
+ lval_cache variable.
+*/
+class in_datetime :public in_longlong
+{
+public:
+ THD *thd;
+ /* An item used to issue warnings. */
+ Item *warn_item;
+ /* Cache for the left item. */
+ Item *lval_cache;
+
+ in_datetime(Item *warn_item_arg, uint elements)
+ :in_longlong(elements), thd(current_thd), warn_item(warn_item_arg),
+ lval_cache(0) {};
+ void set(uint pos,Item *item);
+ uchar *get_value(Item *item);
+ friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
class in_double :public in_vector
@@ -722,7 +863,7 @@ class in_double :public in_vector
public:
in_double(uint elements);
void set(uint pos,Item *item);
- byte *get_value(Item *item);
+ uchar *get_value(Item *item);
Item *create_item()
{
return new Item_float(0.0);
@@ -741,7 +882,7 @@ class in_decimal :public in_vector
public:
in_decimal(uint elements);
void set(uint pos, Item *item);
- byte *get_value(Item *item);
+ uchar *get_value(Item *item);
Item *create_item()
{
return new Item_decimal(0, FALSE);
@@ -814,10 +955,10 @@ public:
return (value_res ? (res ? sortcmp(value_res, res, cmp_charset) : 1) :
(res ? -1 : 0));
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_string *cmp= (cmp_item_string *)c;
- return sortcmp(value_res, cmp->value_res, cmp_charset);
+ cmp_item_string *l_cmp= (cmp_item_string *) ci;
+ return sortcmp(value_res, l_cmp->value_res, cmp_charset);
}
cmp_item *make_same();
void set_charset(CHARSET_INFO *cs)
@@ -840,14 +981,38 @@ public:
{
return value != arg->val_int();
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_int *cmp= (cmp_item_int *)c;
- return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1);
+ cmp_item_int *l_cmp= (cmp_item_int *)ci;
+ return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1);
}
cmp_item *make_same();
};
+/*
+ Compare items in the DATETIME context.
+ Values are obtained with help of the get_datetime_value() function.
+ If the left item is a constant one then its value is cached in the
+ lval_cache variable.
+*/
+class cmp_item_datetime :public cmp_item
+{
+ ulonglong value;
+public:
+ THD *thd;
+ /* Item used for issuing warnings. */
+ Item *warn_item;
+ /* Cache for the left item. */
+ Item *lval_cache;
+
+ cmp_item_datetime(Item *warn_item_arg)
+ :thd(current_thd), warn_item(warn_item_arg), lval_cache(0) {}
+ void store_value(Item *item);
+ int cmp(Item *arg);
+ int compare(cmp_item *ci);
+ cmp_item *make_same();
+};
+
class cmp_item_real :public cmp_item
{
double value;
@@ -861,10 +1026,10 @@ public:
{
return value != arg->val_real();
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_real *cmp= (cmp_item_real *)c;
- return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1);
+ cmp_item_real *l_cmp= (cmp_item_real *) ci;
+ return (value < l_cmp->value)? -1 : ((value == l_cmp->value) ? 0 : 1);
}
cmp_item *make_same();
};
@@ -882,32 +1047,6 @@ public:
};
-class cmp_item_row :public cmp_item
-{
- cmp_item **comparators;
- uint n;
-public:
- cmp_item_row(): comparators(0), n(0) {}
- ~cmp_item_row();
- void store_value(Item *item);
- int cmp(Item *arg);
- int compare(cmp_item *arg);
- cmp_item *make_same();
- void store_value_by_template(cmp_item *tmpl, Item *);
-};
-
-
-class in_row :public in_vector
-{
- cmp_item_row tmp;
-public:
- in_row(uint elements, Item *);
- ~in_row();
- void set(uint pos,Item *item);
- byte *get_value(Item *item);
- Item_result result_type() { return ROW_RESULT; }
-};
-
/*
cmp_item for optimized IN with row (right part string, which never
be changed)
@@ -930,10 +1069,10 @@ public:
DBUG_ASSERT(0);
return 1;
}
- int compare(cmp_item *c)
+ int compare(cmp_item *ci)
{
- cmp_item_string *cmp= (cmp_item_string *)c;
- return sortcmp(value_res, cmp->value_res, cmp_charset);
+ cmp_item_string *l_cmp= (cmp_item_string *) ci;
+ return sortcmp(value_res, l_cmp->value_res, cmp_charset);
}
cmp_item *make_same()
{
@@ -1002,7 +1141,7 @@ public:
void print(String *str);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(byte *bool_arg) { return FALSE;}
+ bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
void cleanup()
{
uint i;
@@ -1034,14 +1173,25 @@ public:
class Item_func_in :public Item_func_opt_neg
{
public:
+ Item_result cmp_type;
+ /*
+ an array of values when the right hand arguments of IN
+ are all SQL constant and there are no nulls
+ */
in_vector *array;
bool have_null;
+ /*
+ true when all arguments of the IN clause are of compatible types
+ and can be used safely as comparisons for key conditions
+ */
+ bool arg_types_compatible;
Item_result left_result_type;
- cmp_item *cmp_items[5]; /* One cmp_item for each result type */
+ cmp_item *cmp_items[6]; /* One cmp_item for each result type */
DTCollation cmp_collation;
Item_func_in(List<Item> &list)
- :Item_func_opt_neg(list), array(0), have_null(0)
+ :Item_func_opt_neg(list), array(0), have_null(0),
+ arg_types_compatible(FALSE)
{
bzero(&cmp_items, sizeof(cmp_items));
allowed_arg_cols= 0; // Fetch this value from first argument
@@ -1057,7 +1207,7 @@ public:
Item_int_func::cleanup();
delete array;
array= 0;
- for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
+ for (i= 0; i <= (uint)DECIMAL_RESULT + 1; i++)
{
delete cmp_items[i];
cmp_items[i]= 0;
@@ -1065,14 +1215,43 @@ public:
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
- { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
+ { return OPTIMIZE_KEY; }
void print(String *str);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+};
+
+class cmp_item_row :public cmp_item
+{
+ cmp_item **comparators;
+ uint n;
+public:
+ cmp_item_row(): comparators(0), n(0) {}
+ ~cmp_item_row();
+ void store_value(Item *item);
+ inline void alloc_comparators();
+ int cmp(Item *arg);
+ int compare(cmp_item *arg);
+ cmp_item *make_same();
+ void store_value_by_template(cmp_item *tmpl, Item *);
+ friend void Item_func_in::fix_length_and_dec();
+};
+
+
+class in_row :public in_vector
+{
+ cmp_item_row tmp;
+public:
+ in_row(uint elements, Item *);
+ ~in_row();
+ void set(uint pos,Item *item);
+ uchar *get_value(Item *item);
+ friend void Item_func_in::fix_length_and_dec();
+ Item_result result_type() { return ROW_RESULT; }
};
/* Functions used by where clause */
@@ -1103,7 +1282,8 @@ public:
else
{
args[0]->update_used_tables();
- if ((const_item_cache= !(used_tables_cache= args[0]->used_tables())))
+ if ((const_item_cache= !(used_tables_cache= args[0]->used_tables())) &&
+ !with_subselect)
{
/* Remember if the value is always NULL or never NULL */
cached_value= (longlong) args[0]->is_null();
@@ -1114,7 +1294,7 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
Item *neg_transformer(THD *thd);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Functions used by HAVING for rewriting IN subquery */
@@ -1141,7 +1321,7 @@ public:
*/
table_map used_tables() const
{ return used_tables_cache | RAND_TABLE_BIT; }
- bool check_partition_func_processor(byte *int_arg) {return TRUE;}
+ bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -1164,7 +1344,7 @@ public:
void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
void top_level_item() { abort_on_null=1; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1203,7 +1383,7 @@ public:
const char *func_name() const { return "like"; }
bool fix_fields(THD *thd, Item **ref);
void cleanup();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
#ifdef USE_REGEX
@@ -1226,7 +1406,7 @@ public:
const char *func_name() const { return "regexp"; }
void print(String *str) { print_op(str); }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
#else
@@ -1279,14 +1459,14 @@ public:
COND **conds);
void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item);
- bool walk(Item_processor processor, bool walk_subquery, byte *arg);
- Item *transform(Item_transformer transformer, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
+ Item *transform(Item_transformer transformer, uchar *arg);
void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
- bool subst_argument_checker(byte **arg) { return TRUE; }
- Item *compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ bool subst_argument_checker(uchar **arg) { return TRUE; }
+ Item *compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t);
};
@@ -1371,7 +1551,6 @@ class Item_equal: public Item_bool_func
Item *const_item; /* optional constant item equal to fields items */
cmp_item *eval_item;
bool cond_false;
- DTCollation cmp_collation;
public:
inline Item_equal()
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
@@ -1396,8 +1575,8 @@ public:
void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
void update_used_tables();
- bool walk(Item_processor processor, bool walk_subquery, byte *arg);
- Item *transform(Item_transformer transformer, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
+ Item *transform(Item_transformer transformer, uchar *arg);
void print(String *str);
CHARSET_INFO *compare_collation()
{ return fields.head()->collation.collation; }
@@ -1445,7 +1624,7 @@ public:
Item_cond_and() :Item_cond() {}
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
Item_cond_and(THD *thd, Item_cond_and *item) :Item_cond(thd, item) {}
- Item_cond_and(List<Item> &list): Item_cond(list) {}
+ Item_cond_and(List<Item> &list_arg): Item_cond(list_arg) {}
enum Functype functype() const { return COND_AND_FUNC; }
longlong val_int();
const char *func_name() const { return "and"; }
@@ -1467,7 +1646,7 @@ public:
Item_cond_or() :Item_cond() {}
Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {}
Item_cond_or(THD *thd, Item_cond_or *item) :Item_cond(thd, item) {}
- Item_cond_or(List<Item> &list): Item_cond(list) {}
+ Item_cond_or(List<Item> &list_arg): Item_cond(list_arg) {}
enum Functype functype() const { return COND_OR_FUNC; }
longlong val_int();
const char *func_name() const { return "or"; }
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 2f8b911a0cf..0daba3e23a8 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -168,7 +167,7 @@ class Create_sp_func : public Create_qfunc
{
public:
virtual Item* create(THD *thd, LEX_STRING db, LEX_STRING name,
- List<Item> *item_list);
+ bool use_explicit_name, List<Item> *item_list);
static Create_sp_func s_singleton;
@@ -2142,6 +2141,19 @@ protected:
};
+class Create_func_uuid_short : public Create_func_arg0
+{
+public:
+ virtual Item *create(THD *thd);
+
+ static Create_func_uuid_short s_singleton;
+
+protected:
+ Create_func_uuid_short() {}
+ virtual ~Create_func_uuid_short() {}
+};
+
+
class Create_func_version : public Create_func_arg0
{
public:
@@ -2317,7 +2329,7 @@ Create_qfunc::create(THD *thd, LEX_STRING name, List<Item> *item_list)
if (thd->copy_db_to(&db.str, &db.length))
return NULL;
- return create(thd, db, name, item_list);
+ return create(thd, db, name, false, item_list);
}
@@ -2342,7 +2354,7 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
if (item_list != NULL)
arg_count= item_list->elements;
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
DBUG_ASSERT( (udf->type == UDFTYPE_FUNCTION)
|| (udf->type == UDFTYPE_AGGREGATE));
@@ -2434,7 +2446,7 @@ Create_sp_func Create_sp_func::s_singleton;
Item*
Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name,
- List<Item> *item_list)
+ bool use_explicit_name, List<Item> *item_list)
{
int arg_count= 0;
Item *func= NULL;
@@ -2459,7 +2471,7 @@ Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name,
if (item_list != NULL)
arg_count= item_list->elements;
- qname= new (thd->mem_root) sp_name(db, name);
+ qname= new (thd->mem_root) sp_name(db, name, use_explicit_name);
qname->init_qname(thd);
sp_add_used_routine(lex, thd, qname, TYPE_ENUM_FUNCTION);
@@ -2878,9 +2890,6 @@ Create_func_convert_tz Create_func_convert_tz::s_singleton;
Item*
Create_func_convert_tz::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
- if (thd->lex->add_time_zone_tables_to_query_tables(thd))
- return NULL;
-
return new (thd->mem_root) Item_func_convert_tz(arg1, arg2, arg3);
}
@@ -3920,6 +3929,7 @@ Create_func_master_pos_wait Create_func_master_pos_wait::s_singleton;
Item*
Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name,
List<Item> *item_list)
+
{
Item *func= NULL;
int arg_count= 0;
@@ -4531,11 +4541,21 @@ Create_func_uuid Create_func_uuid::s_singleton;
Item*
Create_func_uuid::create(THD *thd)
{
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
return new (thd->mem_root) Item_func_uuid();
}
+Create_func_uuid_short Create_func_uuid_short::s_singleton;
+
+Item*
+Create_func_uuid_short::create(THD *thd)
+{
+ thd->lex->set_stmt_unsafe();
+ return new (thd->mem_root) Item_func_uuid_short();
+}
+
+
Create_func_version Create_func_version::s_singleton;
Item*
@@ -4685,209 +4705,217 @@ struct Native_func_registry
static Native_func_registry func_array[] =
{
- { C_STRING_WITH_LEN("ABS"), BUILDER(Create_func_abs)},
- { C_STRING_WITH_LEN("ACOS"), BUILDER(Create_func_acos)},
- { C_STRING_WITH_LEN("ADDTIME"), BUILDER(Create_func_addtime)},
- { C_STRING_WITH_LEN("AES_DECRYPT"), BUILDER(Create_func_aes_decrypt)},
- { C_STRING_WITH_LEN("AES_ENCRYPT"), BUILDER(Create_func_aes_encrypt)},
- { C_STRING_WITH_LEN("AREA"), GEOM_BUILDER(Create_func_area)},
- { C_STRING_WITH_LEN("ASBINARY"), GEOM_BUILDER(Create_func_as_wkb)},
- { C_STRING_WITH_LEN("ASIN"), BUILDER(Create_func_asin)},
- { C_STRING_WITH_LEN("ASTEXT"), GEOM_BUILDER(Create_func_as_wkt)},
- { C_STRING_WITH_LEN("ASWKB"), GEOM_BUILDER(Create_func_as_wkb)},
- { C_STRING_WITH_LEN("ASWKT"), GEOM_BUILDER(Create_func_as_wkt)},
- { C_STRING_WITH_LEN("ATAN"), BUILDER(Create_func_atan)},
- { C_STRING_WITH_LEN("ATAN2"), BUILDER(Create_func_atan)},
- { C_STRING_WITH_LEN("BENCHMARK"), BUILDER(Create_func_benchmark)},
- { C_STRING_WITH_LEN("BIN"), BUILDER(Create_func_bin)},
- { C_STRING_WITH_LEN("BIT_COUNT"), BUILDER(Create_func_bit_count)},
- { C_STRING_WITH_LEN("BIT_LENGTH"), BUILDER(Create_func_bit_length)},
- { C_STRING_WITH_LEN("CEIL"), BUILDER(Create_func_ceiling)},
- { C_STRING_WITH_LEN("CEILING"), BUILDER(Create_func_ceiling)},
- { C_STRING_WITH_LEN("CENTROID"), GEOM_BUILDER(Create_func_centroid)},
- { C_STRING_WITH_LEN("CHARACTER_LENGTH"), BUILDER(Create_func_char_length)},
- { C_STRING_WITH_LEN("CHAR_LENGTH"), BUILDER(Create_func_char_length)},
- { C_STRING_WITH_LEN("COERCIBILITY"), BUILDER(Create_func_coercibility)},
- { C_STRING_WITH_LEN("COMPRESS"), BUILDER(Create_func_compress)},
- { C_STRING_WITH_LEN("CONCAT"), BUILDER(Create_func_concat)},
- { C_STRING_WITH_LEN("CONCAT_WS"), BUILDER(Create_func_concat_ws)},
- { C_STRING_WITH_LEN("CONNECTION_ID"), BUILDER(Create_func_connection_id)},
- { C_STRING_WITH_LEN("CONV"), BUILDER(Create_func_conv)},
- { C_STRING_WITH_LEN("CONVERT_TZ"), BUILDER(Create_func_convert_tz)},
- { C_STRING_WITH_LEN("COS"), BUILDER(Create_func_cos)},
- { C_STRING_WITH_LEN("COT"), BUILDER(Create_func_cot)},
- { C_STRING_WITH_LEN("CRC32"), BUILDER(Create_func_crc32)},
- { C_STRING_WITH_LEN("CROSSES"), GEOM_BUILDER(Create_func_crosses)},
- { C_STRING_WITH_LEN("DATEDIFF"), BUILDER(Create_func_datediff)},
- { C_STRING_WITH_LEN("DATE_FORMAT"), BUILDER(Create_func_date_format)},
- { C_STRING_WITH_LEN("DAYNAME"), BUILDER(Create_func_dayname)},
- { C_STRING_WITH_LEN("DAYOFMONTH"), BUILDER(Create_func_dayofmonth)},
- { C_STRING_WITH_LEN("DAYOFWEEK"), BUILDER(Create_func_dayofweek)},
- { C_STRING_WITH_LEN("DAYOFYEAR"), BUILDER(Create_func_dayofyear)},
- { C_STRING_WITH_LEN("DECODE"), BUILDER(Create_func_decode)},
- { C_STRING_WITH_LEN("DEGREES"), BUILDER(Create_func_degrees)},
- { C_STRING_WITH_LEN("DES_DECRYPT"), BUILDER(Create_func_des_decrypt)},
- { C_STRING_WITH_LEN("DES_ENCRYPT"), BUILDER(Create_func_des_encrypt)},
- { C_STRING_WITH_LEN("DIMENSION"), GEOM_BUILDER(Create_func_dimension)},
- { C_STRING_WITH_LEN("DISJOINT"), GEOM_BUILDER(Create_func_disjoint)},
- { C_STRING_WITH_LEN("ELT"), BUILDER(Create_func_elt)},
- { C_STRING_WITH_LEN("ENCODE"), BUILDER(Create_func_encode)},
- { C_STRING_WITH_LEN("ENCRYPT"), BUILDER(Create_func_encrypt)},
- { C_STRING_WITH_LEN("ENDPOINT"), GEOM_BUILDER(Create_func_endpoint)},
- { C_STRING_WITH_LEN("ENVELOPE"), GEOM_BUILDER(Create_func_envelope)},
- { C_STRING_WITH_LEN("EQUALS"), GEOM_BUILDER(Create_func_equals)},
- { C_STRING_WITH_LEN("EXP"), BUILDER(Create_func_exp)},
- { C_STRING_WITH_LEN("EXPORT_SET"), BUILDER(Create_func_export_set)},
- { C_STRING_WITH_LEN("EXTERIORRING"), GEOM_BUILDER(Create_func_exteriorring)},
- { C_STRING_WITH_LEN("EXTRACTVALUE"), BUILDER(Create_func_xml_extractvalue)},
- { C_STRING_WITH_LEN("FIELD"), BUILDER(Create_func_field)},
- { C_STRING_WITH_LEN("FIND_IN_SET"), BUILDER(Create_func_find_in_set)},
- { C_STRING_WITH_LEN("FLOOR"), BUILDER(Create_func_floor)},
- { C_STRING_WITH_LEN("FORMAT"), BUILDER(Create_func_format)},
- { C_STRING_WITH_LEN("FOUND_ROWS"), BUILDER(Create_func_found_rows)},
- { C_STRING_WITH_LEN("FROM_DAYS"), BUILDER(Create_func_from_days)},
- { C_STRING_WITH_LEN("FROM_UNIXTIME"), BUILDER(Create_func_from_unixtime)},
- { C_STRING_WITH_LEN("GEOMCOLLFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("GEOMCOLLFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("GEOMETRYFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("GEOMETRYFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("GEOMETRYN"), GEOM_BUILDER(Create_func_geometryn)},
- { C_STRING_WITH_LEN("GEOMETRYTYPE"), GEOM_BUILDER(Create_func_geometry_type)},
- { C_STRING_WITH_LEN("GEOMFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("GEOMFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("GET_LOCK"), BUILDER(Create_func_get_lock)},
- { C_STRING_WITH_LEN("GLENGTH"), GEOM_BUILDER(Create_func_glength)},
- { C_STRING_WITH_LEN("GREATEST"), BUILDER(Create_func_greatest)},
- { C_STRING_WITH_LEN("HEX"), BUILDER(Create_func_hex)},
- { C_STRING_WITH_LEN("IFNULL"), BUILDER(Create_func_ifnull)},
- { C_STRING_WITH_LEN("INET_ATON"), BUILDER(Create_func_inet_aton)},
- { C_STRING_WITH_LEN("INET_NTOA"), BUILDER(Create_func_inet_ntoa)},
- { C_STRING_WITH_LEN("INSTR"), BUILDER(Create_func_instr)},
- { C_STRING_WITH_LEN("INTERIORRINGN"), GEOM_BUILDER(Create_func_interiorringn)},
- { C_STRING_WITH_LEN("INTERSECTS"), GEOM_BUILDER(Create_func_intersects)},
- { C_STRING_WITH_LEN("ISCLOSED"), GEOM_BUILDER(Create_func_isclosed)},
- { C_STRING_WITH_LEN("ISEMPTY"), GEOM_BUILDER(Create_func_isempty)},
- { C_STRING_WITH_LEN("ISNULL"), BUILDER(Create_func_isnull)},
- { C_STRING_WITH_LEN("ISSIMPLE"), GEOM_BUILDER(Create_func_issimple)},
- { C_STRING_WITH_LEN("IS_FREE_LOCK"), BUILDER(Create_func_is_free_lock)},
- { C_STRING_WITH_LEN("IS_USED_LOCK"), BUILDER(Create_func_is_used_lock)},
- { C_STRING_WITH_LEN("LAST_DAY"), BUILDER(Create_func_last_day)},
- { C_STRING_WITH_LEN("LAST_INSERT_ID"), BUILDER(Create_func_last_insert_id)},
- { C_STRING_WITH_LEN("LCASE"), BUILDER(Create_func_lcase)},
- { C_STRING_WITH_LEN("LEAST"), BUILDER(Create_func_least)},
- { C_STRING_WITH_LEN("LENGTH"), BUILDER(Create_func_length)},
- { C_STRING_WITH_LEN("LINEFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("LINEFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("LINESTRINGFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("LINESTRINGFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("LN"), BUILDER(Create_func_ln)},
- { C_STRING_WITH_LEN("LOAD_FILE"), BUILDER(Create_func_load_file)},
- { C_STRING_WITH_LEN("LOCATE"), BUILDER(Create_func_locate)},
- { C_STRING_WITH_LEN("LOG"), BUILDER(Create_func_log)},
- { C_STRING_WITH_LEN("LOG10"), BUILDER(Create_func_log10)},
- { C_STRING_WITH_LEN("LOG2"), BUILDER(Create_func_log2)},
- { C_STRING_WITH_LEN("LOWER"), BUILDER(Create_func_lcase)},
- { C_STRING_WITH_LEN("LPAD"), BUILDER(Create_func_lpad)},
- { C_STRING_WITH_LEN("LTRIM"), BUILDER(Create_func_ltrim)},
- { C_STRING_WITH_LEN("MAKEDATE"), BUILDER(Create_func_makedate)},
- { C_STRING_WITH_LEN("MAKETIME"), BUILDER(Create_func_maketime)},
- { C_STRING_WITH_LEN("MAKE_SET"), BUILDER(Create_func_make_set)},
- { C_STRING_WITH_LEN("MASTER_POS_WAIT"), BUILDER(Create_func_master_pos_wait)},
- { C_STRING_WITH_LEN("MBRCONTAINS"), GEOM_BUILDER(Create_func_contains)},
- { C_STRING_WITH_LEN("MD5"), BUILDER(Create_func_md5)},
- { C_STRING_WITH_LEN("MLINEFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MLINEFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("MONTHNAME"), BUILDER(Create_func_monthname)},
- { C_STRING_WITH_LEN("MPOINTFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MPOINTFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("MPOLYFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MPOLYFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("MULTILINESTRINGFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MULTILINESTRINGFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("MULTIPOINTFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MULTIPOINTFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("MULTIPOLYGONFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("MULTIPOLYGONFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("NAME_CONST"), BUILDER(Create_func_name_const)},
- { C_STRING_WITH_LEN("NULLIF"), BUILDER(Create_func_nullif)},
- { C_STRING_WITH_LEN("NUMGEOMETRIES"), GEOM_BUILDER(Create_func_numgeometries)},
- { C_STRING_WITH_LEN("NUMINTERIORRINGS"), GEOM_BUILDER(Create_func_numinteriorring)},
- { C_STRING_WITH_LEN("NUMPOINTS"), GEOM_BUILDER(Create_func_numpoints)},
- { C_STRING_WITH_LEN("OCT"), BUILDER(Create_func_oct)},
- { C_STRING_WITH_LEN("OCTET_LENGTH"), BUILDER(Create_func_length)},
- { C_STRING_WITH_LEN("ORD"), BUILDER(Create_func_ord)},
- { C_STRING_WITH_LEN("OVERLAPS"), GEOM_BUILDER(Create_func_overlaps)},
- { C_STRING_WITH_LEN("PERIOD_ADD"), BUILDER(Create_func_period_add)},
- { C_STRING_WITH_LEN("PERIOD_DIFF"), BUILDER(Create_func_period_diff)},
- { C_STRING_WITH_LEN("PI"), BUILDER(Create_func_pi)},
- { C_STRING_WITH_LEN("POINTFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("POINTFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("POINTN"), GEOM_BUILDER(Create_func_pointn)},
- { C_STRING_WITH_LEN("POLYFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("POLYFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("POLYGONFROMTEXT"), GEOM_BUILDER(Create_func_geometry_from_text)},
- { C_STRING_WITH_LEN("POLYGONFROMWKB"), GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { C_STRING_WITH_LEN("POW"), BUILDER(Create_func_pow)},
- { C_STRING_WITH_LEN("POWER"), BUILDER(Create_func_pow)},
- { C_STRING_WITH_LEN("QUOTE"), BUILDER(Create_func_quote)},
- { C_STRING_WITH_LEN("RADIANS"), BUILDER(Create_func_radians)},
- { C_STRING_WITH_LEN("RAND"), BUILDER(Create_func_rand)},
- { C_STRING_WITH_LEN("RELEASE_LOCK"), BUILDER(Create_func_release_lock)},
- { C_STRING_WITH_LEN("REVERSE"), BUILDER(Create_func_reverse)},
- { C_STRING_WITH_LEN("ROUND"), BUILDER(Create_func_round)},
- { C_STRING_WITH_LEN("ROW_COUNT"), BUILDER(Create_func_row_count)},
- { C_STRING_WITH_LEN("RPAD"), BUILDER(Create_func_rpad)},
- { C_STRING_WITH_LEN("RTRIM"), BUILDER(Create_func_rtrim)},
- { C_STRING_WITH_LEN("SEC_TO_TIME"), BUILDER(Create_func_sec_to_time)},
- { C_STRING_WITH_LEN("SHA"), BUILDER(Create_func_sha)},
- { C_STRING_WITH_LEN("SHA1"), BUILDER(Create_func_sha)},
- { C_STRING_WITH_LEN("SIGN"), BUILDER(Create_func_sign)},
- { C_STRING_WITH_LEN("SIN"), BUILDER(Create_func_sin)},
- { C_STRING_WITH_LEN("SLEEP"), BUILDER(Create_func_sleep)},
- { C_STRING_WITH_LEN("SOUNDEX"), BUILDER(Create_func_soundex)},
- { C_STRING_WITH_LEN("SPACE"), BUILDER(Create_func_space)},
- { C_STRING_WITH_LEN("SQRT"), BUILDER(Create_func_sqrt)},
- { C_STRING_WITH_LEN("SRID"), GEOM_BUILDER(Create_func_srid)},
- { C_STRING_WITH_LEN("STARTPOINT"), GEOM_BUILDER(Create_func_startpoint)},
- { C_STRING_WITH_LEN("STRCMP"), BUILDER(Create_func_strcmp)},
- { C_STRING_WITH_LEN("STR_TO_DATE"), BUILDER(Create_func_str_to_date)},
- { C_STRING_WITH_LEN("SUBSTRING_INDEX"), BUILDER(Create_func_substr_index)},
- { C_STRING_WITH_LEN("SUBTIME"), BUILDER(Create_func_subtime)},
- { C_STRING_WITH_LEN("TAN"), BUILDER(Create_func_tan)},
- { C_STRING_WITH_LEN("TIMEDIFF"), BUILDER(Create_func_timediff)},
- { C_STRING_WITH_LEN("TIME_FORMAT"), BUILDER(Create_func_time_format)},
- { C_STRING_WITH_LEN("TIME_TO_SEC"), BUILDER(Create_func_time_to_sec)},
- { C_STRING_WITH_LEN("TOUCHES"), GEOM_BUILDER(Create_func_touches)},
- { C_STRING_WITH_LEN("TO_DAYS"), BUILDER(Create_func_to_days)},
- { C_STRING_WITH_LEN("UCASE"), BUILDER(Create_func_ucase)},
- { C_STRING_WITH_LEN("UNCOMPRESS"), BUILDER(Create_func_uncompress)},
- { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH"), BUILDER(Create_func_uncompressed_length)},
- { C_STRING_WITH_LEN("UNHEX"), BUILDER(Create_func_unhex)},
- { C_STRING_WITH_LEN("UNIX_TIMESTAMP"), BUILDER(Create_func_unix_timestamp)},
- { C_STRING_WITH_LEN("UPDATEXML"), BUILDER(Create_func_xml_update)},
- { C_STRING_WITH_LEN("UPPER"), BUILDER(Create_func_ucase)},
- { C_STRING_WITH_LEN("UUID"), BUILDER(Create_func_uuid)},
- { C_STRING_WITH_LEN("VERSION"), BUILDER(Create_func_version)},
- { C_STRING_WITH_LEN("WEEKDAY"), BUILDER(Create_func_weekday)},
- { C_STRING_WITH_LEN("WEEKOFYEAR"), BUILDER(Create_func_weekofyear)},
- { C_STRING_WITH_LEN("WITHIN"), GEOM_BUILDER(Create_func_within)},
- { C_STRING_WITH_LEN("X"), GEOM_BUILDER(Create_func_x)},
- { C_STRING_WITH_LEN("Y"), GEOM_BUILDER(Create_func_y)},
- { C_STRING_WITH_LEN("YEARWEEK"), BUILDER(Create_func_year_week)},
+ { { C_STRING_WITH_LEN("ABS") }, BUILDER(Create_func_abs)},
+ { { C_STRING_WITH_LEN("ACOS") }, BUILDER(Create_func_acos)},
+ { { C_STRING_WITH_LEN("ADDTIME") }, BUILDER(Create_func_addtime)},
+ { { C_STRING_WITH_LEN("AES_DECRYPT") }, BUILDER(Create_func_aes_decrypt)},
+ { { C_STRING_WITH_LEN("AES_ENCRYPT") }, BUILDER(Create_func_aes_encrypt)},
+ { { C_STRING_WITH_LEN("AREA") }, GEOM_BUILDER(Create_func_area)},
+ { { C_STRING_WITH_LEN("ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { C_STRING_WITH_LEN("ASIN") }, BUILDER(Create_func_asin)},
+ { { C_STRING_WITH_LEN("ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { C_STRING_WITH_LEN("ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { C_STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { C_STRING_WITH_LEN("ATAN") }, BUILDER(Create_func_atan)},
+ { { C_STRING_WITH_LEN("ATAN2") }, BUILDER(Create_func_atan)},
+ { { C_STRING_WITH_LEN("BENCHMARK") }, BUILDER(Create_func_benchmark)},
+ { { C_STRING_WITH_LEN("BIN") }, BUILDER(Create_func_bin)},
+ { { C_STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)},
+ { { C_STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)},
+ { { C_STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)},
+ { { C_STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)},
+ { { C_STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
+ { { C_STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)},
+ { { C_STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)},
+ { { C_STRING_WITH_LEN("COERCIBILITY") }, BUILDER(Create_func_coercibility)},
+ { { C_STRING_WITH_LEN("COMPRESS") }, BUILDER(Create_func_compress)},
+ { { C_STRING_WITH_LEN("CONCAT") }, BUILDER(Create_func_concat)},
+ { { C_STRING_WITH_LEN("CONCAT_WS") }, BUILDER(Create_func_concat_ws)},
+ { { C_STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)},
+ { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
+ { { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
+ { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
+ { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)},
+ { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)},
+ { { C_STRING_WITH_LEN("CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
+ { { C_STRING_WITH_LEN("DATEDIFF") }, BUILDER(Create_func_datediff)},
+ { { C_STRING_WITH_LEN("DATE_FORMAT") }, BUILDER(Create_func_date_format)},
+ { { C_STRING_WITH_LEN("DAYNAME") }, BUILDER(Create_func_dayname)},
+ { { C_STRING_WITH_LEN("DAYOFMONTH") }, BUILDER(Create_func_dayofmonth)},
+ { { C_STRING_WITH_LEN("DAYOFWEEK") }, BUILDER(Create_func_dayofweek)},
+ { { C_STRING_WITH_LEN("DAYOFYEAR") }, BUILDER(Create_func_dayofyear)},
+ { { C_STRING_WITH_LEN("DECODE") }, BUILDER(Create_func_decode)},
+ { { C_STRING_WITH_LEN("DEGREES") }, BUILDER(Create_func_degrees)},
+ { { C_STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)},
+ { { C_STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)},
+ { { C_STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
+ { { C_STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
+ { { C_STRING_WITH_LEN("ELT") }, BUILDER(Create_func_elt)},
+ { { C_STRING_WITH_LEN("ENCODE") }, BUILDER(Create_func_encode)},
+ { { C_STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)},
+ { { C_STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
+ { { C_STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
+ { { C_STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { C_STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)},
+ { { C_STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)},
+ { { C_STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
+ { { C_STRING_WITH_LEN("EXTRACTVALUE") }, BUILDER(Create_func_xml_extractvalue)},
+ { { C_STRING_WITH_LEN("FIELD") }, BUILDER(Create_func_field)},
+ { { C_STRING_WITH_LEN("FIND_IN_SET") }, BUILDER(Create_func_find_in_set)},
+ { { C_STRING_WITH_LEN("FLOOR") }, BUILDER(Create_func_floor)},
+ { { C_STRING_WITH_LEN("FORMAT") }, BUILDER(Create_func_format)},
+ { { C_STRING_WITH_LEN("FOUND_ROWS") }, BUILDER(Create_func_found_rows)},
+ { { C_STRING_WITH_LEN("FROM_DAYS") }, BUILDER(Create_func_from_days)},
+ { { C_STRING_WITH_LEN("FROM_UNIXTIME") }, BUILDER(Create_func_from_unixtime)},
+ { { C_STRING_WITH_LEN("GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
+ { { C_STRING_WITH_LEN("GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
+ { { C_STRING_WITH_LEN("GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("GET_LOCK") }, BUILDER(Create_func_get_lock)},
+ { { C_STRING_WITH_LEN("GLENGTH") }, GEOM_BUILDER(Create_func_glength)},
+ { { C_STRING_WITH_LEN("GREATEST") }, BUILDER(Create_func_greatest)},
+ { { C_STRING_WITH_LEN("HEX") }, BUILDER(Create_func_hex)},
+ { { C_STRING_WITH_LEN("IFNULL") }, BUILDER(Create_func_ifnull)},
+ { { C_STRING_WITH_LEN("INET_ATON") }, BUILDER(Create_func_inet_aton)},
+ { { C_STRING_WITH_LEN("INET_NTOA") }, BUILDER(Create_func_inet_ntoa)},
+ { { C_STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)},
+ { { C_STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
+ { { C_STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
+ { { C_STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
+ { { C_STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
+ { { C_STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)},
+ { { C_STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
+ { { C_STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)},
+ { { C_STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)},
+ { { C_STRING_WITH_LEN("LAST_DAY") }, BUILDER(Create_func_last_day)},
+ { { C_STRING_WITH_LEN("LAST_INSERT_ID") }, BUILDER(Create_func_last_insert_id)},
+ { { C_STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)},
+ { { C_STRING_WITH_LEN("LEAST") }, BUILDER(Create_func_least)},
+ { { C_STRING_WITH_LEN("LENGTH") }, BUILDER(Create_func_length)},
+ { { C_STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("LN") }, BUILDER(Create_func_ln)},
+ { { C_STRING_WITH_LEN("LOAD_FILE") }, BUILDER(Create_func_load_file)},
+ { { C_STRING_WITH_LEN("LOCATE") }, BUILDER(Create_func_locate)},
+ { { C_STRING_WITH_LEN("LOG") }, BUILDER(Create_func_log)},
+ { { C_STRING_WITH_LEN("LOG10") }, BUILDER(Create_func_log10)},
+ { { C_STRING_WITH_LEN("LOG2") }, BUILDER(Create_func_log2)},
+ { { C_STRING_WITH_LEN("LOWER") }, BUILDER(Create_func_lcase)},
+ { { C_STRING_WITH_LEN("LPAD") }, BUILDER(Create_func_lpad)},
+ { { C_STRING_WITH_LEN("LTRIM") }, BUILDER(Create_func_ltrim)},
+ { { C_STRING_WITH_LEN("MAKEDATE") }, BUILDER(Create_func_makedate)},
+ { { C_STRING_WITH_LEN("MAKETIME") }, BUILDER(Create_func_maketime)},
+ { { C_STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)},
+ { { C_STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)},
+ { { C_STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_contains)},
+ { { C_STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
+ { { C_STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_equals)},
+ { { C_STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
+ { { C_STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
+ { { C_STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { C_STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { C_STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)},
+ { { C_STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("MONTHNAME") }, BUILDER(Create_func_monthname)},
+ { { C_STRING_WITH_LEN("MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("NAME_CONST") }, BUILDER(Create_func_name_const)},
+ { { C_STRING_WITH_LEN("NULLIF") }, BUILDER(Create_func_nullif)},
+ { { C_STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
+ { { C_STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
+ { { C_STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
+ { { C_STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)},
+ { { C_STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_length)},
+ { { C_STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)},
+ { { C_STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
+ { { C_STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)},
+ { { C_STRING_WITH_LEN("PERIOD_DIFF") }, BUILDER(Create_func_period_diff)},
+ { { C_STRING_WITH_LEN("PI") }, BUILDER(Create_func_pi)},
+ { { C_STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)},
+ { { C_STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { C_STRING_WITH_LEN("POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { C_STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)},
+ { { C_STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)},
+ { { C_STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)},
+ { { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)},
+ { { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)},
+ { { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)},
+ { { C_STRING_WITH_LEN("REVERSE") }, BUILDER(Create_func_reverse)},
+ { { C_STRING_WITH_LEN("ROUND") }, BUILDER(Create_func_round)},
+ { { C_STRING_WITH_LEN("ROW_COUNT") }, BUILDER(Create_func_row_count)},
+ { { C_STRING_WITH_LEN("RPAD") }, BUILDER(Create_func_rpad)},
+ { { C_STRING_WITH_LEN("RTRIM") }, BUILDER(Create_func_rtrim)},
+ { { C_STRING_WITH_LEN("SEC_TO_TIME") }, BUILDER(Create_func_sec_to_time)},
+ { { C_STRING_WITH_LEN("SHA") }, BUILDER(Create_func_sha)},
+ { { C_STRING_WITH_LEN("SHA1") }, BUILDER(Create_func_sha)},
+ { { C_STRING_WITH_LEN("SIGN") }, BUILDER(Create_func_sign)},
+ { { C_STRING_WITH_LEN("SIN") }, BUILDER(Create_func_sin)},
+ { { C_STRING_WITH_LEN("SLEEP") }, BUILDER(Create_func_sleep)},
+ { { C_STRING_WITH_LEN("SOUNDEX") }, BUILDER(Create_func_soundex)},
+ { { C_STRING_WITH_LEN("SPACE") }, BUILDER(Create_func_space)},
+ { { C_STRING_WITH_LEN("SQRT") }, BUILDER(Create_func_sqrt)},
+ { { C_STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
+ { { C_STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
+ { { C_STRING_WITH_LEN("STRCMP") }, BUILDER(Create_func_strcmp)},
+ { { C_STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)},
+ { { C_STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
+ { { C_STRING_WITH_LEN("SUBTIME") }, BUILDER(Create_func_subtime)},
+ { { C_STRING_WITH_LEN("TAN") }, BUILDER(Create_func_tan)},
+ { { C_STRING_WITH_LEN("TIMEDIFF") }, BUILDER(Create_func_timediff)},
+ { { C_STRING_WITH_LEN("TIME_FORMAT") }, BUILDER(Create_func_time_format)},
+ { { C_STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
+ { { C_STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { C_STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
+ { { C_STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)},
+ { { C_STRING_WITH_LEN("UNCOMPRESS") }, BUILDER(Create_func_uncompress)},
+ { { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH") }, BUILDER(Create_func_uncompressed_length)},
+ { { C_STRING_WITH_LEN("UNHEX") }, BUILDER(Create_func_unhex)},
+ { { C_STRING_WITH_LEN("UNIX_TIMESTAMP") }, BUILDER(Create_func_unix_timestamp)},
+ { { C_STRING_WITH_LEN("UPDATEXML") }, BUILDER(Create_func_xml_update)},
+ { { C_STRING_WITH_LEN("UPPER") }, BUILDER(Create_func_ucase)},
+ { { C_STRING_WITH_LEN("UUID") }, BUILDER(Create_func_uuid)},
+ { { C_STRING_WITH_LEN("UUID_SHORT") }, BUILDER(Create_func_uuid_short)},
+ { { C_STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)},
+ { { C_STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)},
+ { { C_STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)},
+ { { C_STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { C_STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
+ { { C_STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
+ { { C_STRING_WITH_LEN("YEARWEEK") }, BUILDER(Create_func_year_week)},
{ {0, 0}, NULL}
};
static HASH native_functions_hash;
-extern "C" byte*
-get_native_fct_hash_key(const byte *buff, uint *length, my_bool /* unused */)
+extern "C" uchar*
+get_native_fct_hash_key(const uchar *buff, size_t *length,
+ my_bool /* unused */)
{
Native_func_registry *func= (Native_func_registry*) buff;
*length= func->name.length;
- return (byte*) func->name.str;
+ return (uchar*) func->name.str;
}
/*
@@ -4914,7 +4942,7 @@ int item_create_init()
for (func= func_array; func->builder != NULL; func++)
{
- if (my_hash_insert(& native_functions_hash, (byte*) func))
+ if (my_hash_insert(& native_functions_hash, (uchar*) func))
DBUG_RETURN(1);
}
@@ -4922,8 +4950,8 @@ int item_create_init()
for (uint i=0 ; i < native_functions_hash.records ; i++)
{
func= (Native_func_registry*) hash_element(& native_functions_hash, i);
- DBUG_PRINT("info", ("native function %s, length %d",
- func->name.str, func->name.length));
+ DBUG_PRINT("info", ("native function: %s length: %u",
+ func->name.str, (uint) func->name.length));
}
#endif
@@ -4951,7 +4979,7 @@ find_native_function_builder(THD *thd, LEX_STRING name)
/* Thread safe */
func= (Native_func_registry*) hash_search(& native_functions_hash,
- (byte*) name.str,
+ (uchar*) name.str,
name.length);
if (func)
@@ -4968,11 +4996,15 @@ find_qualified_function_builder(THD *thd)
return & Create_sp_func::s_singleton;
}
-Item*
-create_func_cast(THD *thd, Item *a, Cast_target cast_type, int len, int dec,
+
+Item *
+create_func_cast(THD *thd, Item *a, Cast_target cast_type,
+ const char *c_len, const char *c_dec,
CHARSET_INFO *cs)
{
Item *res;
+ ulong len;
+ uint dec;
LINT_INIT(res);
switch (cast_type) {
@@ -4996,18 +5028,21 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, int len, int dec,
break;
case ITEM_CAST_DECIMAL:
{
- int tmp_len= (len>0) ? len : 10;
- if (tmp_len < dec)
+ len= c_len ? atoi(c_len) : 0;
+ dec= c_dec ? atoi(c_dec) : 0;
+ my_decimal_trim(&len, &dec);
+ if (len < dec)
{
my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
return 0;
}
- res= new (thd->mem_root) Item_decimal_typecast(a, tmp_len, dec);
+ res= new (thd->mem_root) Item_decimal_typecast(a, len, dec);
break;
}
case ITEM_CAST_CHAR:
{
CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection);
+ len= c_len ? atoi(c_len) : -1;
res= new (thd->mem_root) Item_char_typecast(a, len, real_cs);
break;
}
@@ -5020,4 +5055,3 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, int len, int dec,
}
return res;
}
-
diff --git a/sql/item_create.h b/sql/item_create.h
index c20e36af04f..7ace4032515 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -88,11 +87,12 @@ public:
@param thd The current thread
@param db The database name
@param name The function name
+ @param use_explicit_name Should the function be represented as 'db.name'?
@param item_list The list of arguments to the function, can be NULL
@return An item representing the parsed function call
*/
virtual Item* create(THD *thd, LEX_STRING db, LEX_STRING name,
- List<Item> *item_list) = 0;
+ bool use_explicit_name, List<Item> *item_list) = 0;
protected:
/** Constructor. */
@@ -159,9 +159,9 @@ protected:
@param dec TODO
@param cs The character set
*/
-Item*
-create_func_cast(THD *thd, Item *a, Cast_target cast_type, int len, int dec,
+Item *
+create_func_cast(THD *thd, Item *a, Cast_target cast_type,
+ const char *len, const char *dec,
CHARSET_INFO *cs);
-
#endif
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0f5faf93cc3..b0346cc5224 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,6 +22,7 @@
#include "mysql_priv.h"
#include "slave.h" // for wait_for_master_pos
+#include "rpl_mi.h"
#include <m_ctype.h>
#include <hash.h>
#include <time.h>
@@ -36,7 +36,6 @@
#define sp_restore_security_context(A,B) while (0) {}
#endif
-
bool check_reserved_words(LEX_STRING *name)
{
if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") ||
@@ -143,7 +142,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end;
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
- char buff[STACK_BUFF_ALLOC]; // Max argument in function
+ uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
#endif
used_tables_cache= not_null_tables_cache= 0;
@@ -196,7 +195,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
bool Item_func::walk(Item_processor processor, bool walk_subquery,
- byte *argument)
+ uchar *argument)
{
if (arg_count)
{
@@ -233,6 +232,8 @@ void Item_func::traverse_cond(Cond_traverser traverser,
(*traverser)(this, argument);
}
}
+ else
+ (*traverser)(this, argument);
}
@@ -257,7 +258,7 @@ void Item_func::traverse_cond(Cond_traverser traverser,
Item returned as the result of transformation of the root node
*/
-Item *Item_func::transform(Item_transformer transformer, byte *argument)
+Item *Item_func::transform(Item_transformer transformer, uchar *argument)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -310,8 +311,8 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument)
Item returned as the result of transformation of the root node
*/
-Item *Item_func::compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t)
+Item *Item_func::compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
@@ -324,7 +325,7 @@ Item *Item_func::compile(Item_analyzer analyzer, byte **arg_p,
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
- byte *arg_v= *arg_p;
+ uchar *arg_v= *arg_p;
Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *arg != new_item)
current_thd->change_item_tree(arg, new_item);
@@ -412,8 +413,13 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
if (item->type() != FUNC_ITEM)
return 0;
Item_func *item_func=(Item_func*) item;
- if (arg_count != item_func->arg_count ||
- func_name() != item_func->func_name())
+ Item_func::Functype func_type;
+ if ((func_type= functype()) != item_func->functype() ||
+ arg_count != item_func->arg_count ||
+ (func_type != Item_func::FUNC_SP &&
+ func_name() != item_func->func_name()) ||
+ (func_type == Item_func::FUNC_SP &&
+ my_strcasecmp(system_charset_info, func_name(), item_func->func_name())))
return 0;
for (uint i=0; i < arg_count ; i++)
if (!args[i]->eq(item_func->args[i], binary_cmp))
@@ -429,7 +435,7 @@ Field *Item_func::tmp_table_field(TABLE *table)
switch (result_type()) {
case INT_RESULT:
- if (max_length > 11)
+ if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
else
field= new Field_long(max_length, maybe_null, name, unsigned_flag);
@@ -459,7 +465,7 @@ Field *Item_func::tmp_table_field(TABLE *table)
}
-bool Item_func::is_expensive_processor(byte *arg)
+bool Item_func::is_expensive_processor(uchar *arg)
{
return is_expensive();
}
@@ -613,6 +619,14 @@ Item *Item_func::get_tmp_table_item(THD *thd)
return copy_or_same(thd);
}
+double Item_int_func::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+
+ return unsigned_flag ? (double) ((ulonglong) val_int()) : (double) val_int();
+}
+
+
String *Item_int_func::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -795,7 +809,10 @@ double Item_func_numhybrid::val_real()
return result;
}
case INT_RESULT:
- return (double)int_op();
+ {
+ longlong result= int_op();
+ return unsigned_flag ? (double) ((ulonglong) result) : (double) result;
+ }
case REAL_RESULT:
return real_op();
case STRING_RESULT:
@@ -938,7 +955,8 @@ longlong Item_func_signed::val_int()
longlong value;
int error;
- if (args[0]->cast_to_int_type() != STRING_RESULT)
+ if (args[0]->cast_to_int_type() != STRING_RESULT ||
+ args[0]->result_as_longlong())
{
value= args[0]->val_int();
null_value= args[0]->null_value;
@@ -975,9 +993,12 @@ longlong Item_func_unsigned::val_int()
my_decimal tmp, *dec= args[0]->val_decimal(&tmp);
if (!(null_value= args[0]->null_value))
my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &value);
+ else
+ value= 0;
return value;
}
- else if (args[0]->cast_to_int_type() != STRING_RESULT)
+ else if (args[0]->cast_to_int_type() != STRING_RESULT ||
+ args[0]->result_as_longlong())
{
value= args[0]->val_int();
null_value= args[0]->null_value;
@@ -998,7 +1019,7 @@ String *Item_decimal_typecast::val_str(String *str)
my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
if (null_value)
return NULL;
- my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
+ my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str);
return str;
}
@@ -1029,6 +1050,8 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
{
my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
bool sign;
+ uint precision;
+
if ((null_value= args[0]->null_value))
return NULL;
my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
@@ -1041,9 +1064,11 @@ my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
goto err;
}
}
- if (max_length - 2 - decimals < (uint) my_decimal_intg(dec))
+ precision= my_decimal_length_to_precision(max_length,
+ decimals, unsigned_flag);
+ if (precision - decimals < (uint) my_decimal_intg(dec))
{
- max_my_decimal(dec, max_length - 2, decimals);
+ max_my_decimal(dec, precision, decimals);
dec->sign(sign);
goto err;
}
@@ -1060,9 +1085,25 @@ err:
void Item_decimal_typecast::print(String *str)
{
+ char len_buf[20*3 + 1];
+ char *end;
+
+ uint precision= my_decimal_length_to_precision(max_length, decimals,
+ unsigned_flag);
str->append(STRING_WITH_LEN("cast("));
args[0]->print(str);
- str->append(STRING_WITH_LEN(" as decimal)"));
+ str->append(STRING_WITH_LEN(" as decimal("));
+
+ end=int10_to_str(precision, len_buf,10);
+ str->append(len_buf, (uint32) (end - len_buf));
+
+ str->append(',');
+
+ end=int10_to_str(decimals, len_buf,10);
+ str->append(len_buf, (uint32) (end - len_buf));
+
+ str->append(')');
+ str->append(')');
}
@@ -1355,6 +1396,8 @@ longlong Item_func_mod::int_op()
DBUG_ASSERT(fixed == 1);
longlong value= args[0]->val_int();
longlong val2= args[1]->val_int();
+ longlong result;
+
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0; /* purecov: inspected */
if (val2 == 0)
@@ -1364,9 +1407,13 @@ longlong Item_func_mod::int_op()
}
if (args[0]->unsigned_flag)
- return ((ulonglong) value) % val2;
+ result= args[1]->unsigned_flag ?
+ ((ulonglong) value) % ((ulonglong) val2) : ((ulonglong) value) % val2;
+ else
+ result= args[1]->unsigned_flag ?
+ value % ((ulonglong) val2) : value % val2;
- return value % val2;
+ return result;
}
double Item_func_mod::real_op()
@@ -1421,6 +1468,7 @@ void Item_func_mod::fix_length_and_dec()
{
Item_num_op::fix_length_and_dec();
maybe_null= 1;
+ unsigned_flag= args[0]->unsigned_flag;
}
@@ -1474,7 +1522,7 @@ void Item_func_neg::fix_length_and_dec()
*/
if (hybrid_type == INT_RESULT &&
args[0]->type() == INT_ITEM &&
- ((ulonglong) args[0]->val_int() >= (ulonglong) LONGLONG_MIN))
+ ((ulonglong) args[0]->val_int() > (ulonglong) LONGLONG_MIN))
{
/*
Ensure that result is converted to DECIMAL, as longlong can't hold
@@ -1499,8 +1547,9 @@ double Item_func_abs::real_op()
longlong Item_func_abs::int_op()
{
longlong value= args[0]->val_int();
- null_value= args[0]->null_value;
- return value >= 0 ? value : -value;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ return (value >= 0) || unsigned_flag ? value : -value;
}
@@ -1521,6 +1570,7 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
void Item_func_abs::fix_length_and_dec()
{
Item_func_num1::fix_length_and_dec();
+ unsigned_flag= args[0]->unsigned_flag;
}
@@ -1895,6 +1945,10 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
void Item_func_round::fix_length_and_dec()
{
+ int decimals_to_set;
+ longlong val1;
+ bool val1_unsigned;
+
unsigned_flag= args[0]->unsigned_flag;
if (!args[1]->const_item())
{
@@ -1903,8 +1957,14 @@ void Item_func_round::fix_length_and_dec()
hybrid_type= REAL_RESULT;
return;
}
-
- int decimals_to_set= max((int)args[1]->val_int(), 0);
+
+ val1= args[1]->val_int();
+ val1_unsigned= args[1]->unsigned_flag;
+ if (val1 < 0)
+ decimals_to_set= val1_unsigned ? INT_MAX : 0;
+ else
+ decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1;
+
if (args[0]->decimals == NOT_FIXED_DEC)
{
max_length= args[0]->max_length;
@@ -1921,10 +1981,9 @@ void Item_func_round::fix_length_and_dec()
max_length= float_length(decimals);
break;
case INT_RESULT:
- if (!decimals_to_set &&
- (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)))
+ if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
{
- int length_can_increase= test(!truncate && (args[1]->val_int() < 0));
+ int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned);
max_length= args[0]->max_length + length_can_increase;
/* Here we can keep INT_RESULT */
hybrid_type= INT_RESULT;
@@ -1950,10 +2009,12 @@ void Item_func_round::fix_length_and_dec()
}
}
-double my_double_round(double value, int dec, bool truncate)
+double my_double_round(double value, longlong dec, bool dec_unsigned,
+ bool truncate)
{
double tmp;
- uint abs_dec= abs(dec);
+ bool dec_negative= (dec < 0) && !dec_unsigned;
+ ulonglong abs_dec= dec_negative ? -dec : dec;
/*
tmp2 is here to avoid return the value with 80 bit precision
This will fix that the test round(0.1,1) = round(0.1,1) is true
@@ -1963,7 +2024,11 @@ double my_double_round(double value, int dec, bool truncate)
tmp=(abs_dec < array_elements(log_10) ?
log_10[abs_dec] : pow(10.0,(double) abs_dec));
- if (truncate)
+ if (dec_negative && my_isinf(tmp))
+ tmp2= 0;
+ else if (!dec_negative && my_isinf(value * tmp))
+ tmp2= value;
+ else if (truncate)
{
if (value >= 0)
tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
@@ -1979,24 +2044,35 @@ double my_double_round(double value, int dec, bool truncate)
double Item_func_round::real_op()
{
double value= args[0]->val_real();
- int dec= (int) args[1]->val_int();
if (!(null_value= args[0]->null_value || args[1]->null_value))
- return my_double_round(value, dec, truncate);
+ return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag,
+ truncate);
return 0.0;
}
+/*
+ Rounds a given value to a power of 10 specified as the 'to' argument,
+ avoiding overflows when the value is close to the ulonglong range boundary.
+*/
+
+static inline ulonglong my_unsigned_round(ulonglong value, ulonglong to)
+{
+ ulonglong tmp= value / to * to;
+ return (value - tmp < (to >> 1)) ? tmp : tmp + to;
+}
+
longlong Item_func_round::int_op()
{
longlong value= args[0]->val_int();
- int dec=(int) args[1]->val_int();
+ longlong dec= args[1]->val_int();
decimals= 0;
- uint abs_dec;
+ ulonglong abs_dec;
if ((null_value= args[0]->null_value || args[1]->null_value))
return 0;
- if (dec >= 0)
+ if ((dec >= 0) || args[1]->unsigned_flag)
return value; // integer have not digits after point
abs_dec= -dec;
@@ -2008,21 +2084,12 @@ longlong Item_func_round::int_op()
tmp= log_10_int[abs_dec];
if (truncate)
- {
- if (unsigned_flag)
- value= (ulonglong(value)/tmp)*tmp;
- else
- value= (value/tmp)*tmp;
- }
+ value= (unsigned_flag) ?
+ ((ulonglong) value / tmp) * tmp : (value / tmp) * tmp;
else
- {
- if (unsigned_flag)
- value= ((ulonglong(value)+(tmp>>1))/tmp)*tmp;
- else if ( value >= 0)
- value= ((value+(tmp>>1))/tmp)*tmp;
- else
- value= ((value-(tmp>>1))/tmp)*tmp;
- }
+ value= (unsigned_flag || value >= 0) ?
+ my_unsigned_round((ulonglong) value, tmp) :
+ -(longlong) my_unsigned_round((ulonglong) -value, tmp);
return value;
}
@@ -2030,19 +2097,35 @@ longlong Item_func_round::int_op()
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
- int dec=(int) args[1]->val_int();
- if (dec > 0)
+ longlong dec= args[1]->val_int();
+ if (dec > 0 || (dec < 0 && args[1]->unsigned_flag))
{
- decimals= min(dec, DECIMAL_MAX_SCALE); // to get correct output
+ dec= min((ulonglong) dec, DECIMAL_MAX_SCALE);
+ decimals= (uint8) dec; // to get correct output
}
+ else if (dec < INT_MIN)
+ dec= INT_MIN;
+
if (!(null_value= (args[0]->null_value || args[1]->null_value ||
- my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
- decimal_value) > 1)))
+ my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
+ truncate, decimal_value) > 1)))
return decimal_value;
return 0;
}
+void Item_func_rand::seed_random(Item *arg)
+{
+ /*
+ TODO: do not do reinit 'rand' for every execute of PS/SP if
+ args[0] is a constant.
+ */
+ uint32 tmp= (uint32) arg->val_int();
+ randominit(rand, (uint32) (tmp*0x10001L+55555555L),
+ (uint32) (tmp*0x10000001L));
+}
+
+
bool Item_func_rand::fix_fields(THD *thd,Item **ref)
{
if (Item_real_func::fix_fields(thd, ref))
@@ -2050,11 +2133,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
used_tables_cache|= RAND_TABLE_BIT;
if (arg_count)
{ // Only use argument once in query
- if (!args[0]->const_during_execution())
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND");
- return TRUE;
- }
/*
Allocate rand structure once: we must use thd->stmt_arena
to create rand in proper mem_root if it's a prepared statement or
@@ -2066,20 +2144,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
if (!rand && !(rand= (struct rand_struct*)
thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE;
- /*
- PARAM_ITEM is returned if we're in statement prepare and consequently
- no placeholder value is set yet.
- */
- if (args[0]->type() != PARAM_ITEM)
- {
- /*
- TODO: do not do reinit 'rand' for every execute of PS/SP if
- args[0] is a constant.
- */
- uint32 tmp= (uint32) args[0]->val_int();
- randominit(rand, (uint32) (tmp*0x10001L+55555555L),
- (uint32) (tmp*0x10000001L));
- }
+
+ if (args[0]->const_item())
+ seed_random (args[0]);
}
else
{
@@ -2109,6 +2176,8 @@ void Item_func_rand::update_used_tables()
double Item_func_rand::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (arg_count && !args[0]->const_item())
+ seed_random (args[0]);
return my_rnd(rand);
}
@@ -2134,6 +2203,7 @@ double Item_func_units::val_real()
void Item_func_min_max::fix_length_and_dec()
{
int max_int_part=0;
+ bool datetime_found= FALSE;
decimals=0;
max_length=0;
maybe_null=0;
@@ -2147,18 +2217,88 @@ void Item_func_min_max::fix_length_and_dec()
if (args[i]->maybe_null)
maybe_null=1;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
+ if (args[i]->result_type() != ROW_RESULT && args[i]->is_datetime())
+ {
+ datetime_found= TRUE;
+ if (!datetime_item || args[i]->field_type() == MYSQL_TYPE_DATETIME)
+ datetime_item= args[i];
+ }
}
if (cmp_type == STRING_RESULT)
+ {
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1);
+ if (datetime_found)
+ {
+ thd= current_thd;
+ compare_as_dates= TRUE;
+ }
+ }
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
unsigned_flag);
}
+/*
+ Compare item arguments in the DATETIME context.
+
+ SYNOPSIS
+ cmp_datetimes()
+ value [out] found least/greatest DATE/DATETIME value
+
+ DESCRIPTION
+ Compare item arguments as DATETIME values and return the index of the
+ least/greatest argument in the arguments array.
+ The correct integer DATE/DATETIME value of the found argument is
+ stored to the value pointer, if latter is provided.
+
+ RETURN
+ 0 If one of arguments is NULL
+ # index of the least/greatest argument
+*/
+
+uint Item_func_min_max::cmp_datetimes(ulonglong *value)
+{
+ ulonglong min_max;
+ uint min_max_idx= 0;
+ LINT_INIT(min_max);
+
+ for (uint i=0; i < arg_count ; i++)
+ {
+ Item **arg= args + i;
+ bool is_null;
+ ulonglong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
+ if ((null_value= args[i]->null_value))
+ return 0;
+ if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
+ {
+ min_max= res;
+ min_max_idx= i;
+ }
+ }
+ if (value)
+ {
+ *value= min_max;
+ if (datetime_item->field_type() == MYSQL_TYPE_DATE)
+ *value/= 1000000L;
+ }
+ return min_max_idx;
+}
+
+
String *Item_func_min_max::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
+ if (compare_as_dates)
+ {
+ String *str_res;
+ uint min_max_idx= cmp_datetimes(NULL);
+ if (null_value)
+ return 0;
+ str_res= args[min_max_idx]->val_str(str);
+ str_res->set_charset(collation.collation);
+ return str_res;
+ }
switch (cmp_type) {
case INT_RESULT:
{
@@ -2223,6 +2363,12 @@ double Item_func_min_max::val_real()
{
DBUG_ASSERT(fixed == 1);
double value=0.0;
+ if (compare_as_dates)
+ {
+ ulonglong result= 0;
+ (void)cmp_datetimes(&result);
+ return (double)result;
+ }
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2244,6 +2390,12 @@ longlong Item_func_min_max::val_int()
{
DBUG_ASSERT(fixed == 1);
longlong value=0;
+ if (compare_as_dates)
+ {
+ ulonglong result= 0;
+ (void)cmp_datetimes(&result);
+ return (longlong)result;
+ }
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2267,6 +2419,13 @@ my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
my_decimal tmp_buf, *tmp, *res;
LINT_INIT(res);
+ if (compare_as_dates)
+ {
+ ulonglong value= 0;
+ (void)cmp_datetimes(&value);
+ ulonglong2decimal(value, dec);
+ return dec;
+ }
for (uint i=0; i < arg_count ; i++)
{
if (i == 0)
@@ -2334,7 +2493,8 @@ longlong Item_func_coercibility::val_int()
void Item_func_locate::fix_length_and_dec()
{
- maybe_null=0; max_length=11;
+ maybe_null= 0;
+ max_length= MY_INT32_NUM_DECIMAL_DIGITS;
agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
}
@@ -2378,7 +2538,7 @@ longlong Item_func_locate::val_int()
b->ptr(), b->length(),
&match, 1))
return 0;
- return (longlong) match.mblen + start0 + 1;
+ return (longlong) match.mb_len + start0 + 1;
}
@@ -2513,7 +2673,7 @@ void Item_func_find_in_set::fix_length_and_dec()
if (args[0]->const_item() && args[1]->type() == FIELD_ITEM)
{
Field *field= ((Item_field*) args[1])->field;
- if (field->real_type() == FIELD_TYPE_SET)
+ if (field->real_type() == MYSQL_TYPE_SET)
{
String *find=args[0]->val_str(&value);
if (find)
@@ -2643,7 +2803,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
uint arg_count, Item **arguments)
{
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
- char buff[STACK_BUFF_ALLOC]; // Max argument in function
+ uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
#endif
DBUG_ENTER("Item_udf_func::fix_fields");
@@ -2747,25 +2907,28 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
if (arguments[i]->const_item())
{
- if (arguments[i]->null_value)
- continue;
-
switch (arguments[i]->result_type())
{
case STRING_RESULT:
case DECIMAL_RESULT:
{
String *res= arguments[i]->val_str(&buffers[i]);
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= (char*) res->ptr();
break;
}
case INT_RESULT:
*((longlong*) to)= arguments[i]->val_int();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(longlong));
break;
case REAL_RESULT:
*((double*) to)= arguments[i]->val_real();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(double));
break;
@@ -3078,26 +3241,26 @@ static HASH hash_user_locks;
class User_level_lock
{
- char *key;
- uint key_length;
+ uchar *key;
+ size_t key_length;
public:
int count;
bool locked;
pthread_cond_t cond;
- pthread_t thread;
- ulong thread_id;
+ my_thread_id thread_id;
+ void set_thread(THD *thd) { thread_id= thd->thread_id; }
- User_level_lock(const char *key_arg,uint length, ulong id)
+ User_level_lock(const uchar *key_arg,uint length, ulong id)
:key_length(length),count(1),locked(1), thread_id(id)
{
- key=(char*) my_memdup((byte*) key_arg,length,MYF(0));
+ key= (uchar*) my_memdup(key_arg,length,MYF(0));
pthread_cond_init(&cond,NULL);
if (key)
{
- if (my_hash_insert(&hash_user_locks,(byte*) this))
+ if (my_hash_insert(&hash_user_locks,(uchar*) this))
{
- my_free((gptr) key,MYF(0));
+ my_free(key,MYF(0));
key=0;
}
}
@@ -3106,22 +3269,22 @@ public:
{
if (key)
{
- hash_delete(&hash_user_locks,(byte*) this);
- my_free((gptr) key,MYF(0));
+ hash_delete(&hash_user_locks,(uchar*) this);
+ my_free(key, MYF(0));
}
pthread_cond_destroy(&cond);
}
inline bool initialized() { return key != 0; }
friend void item_user_lock_release(User_level_lock *ull);
- friend char *ull_get_key(const User_level_lock *ull, uint *length,
- my_bool not_used);
+ friend uchar *ull_get_key(const User_level_lock *ull, size_t *length,
+ my_bool not_used);
};
-char *ull_get_key(const User_level_lock *ull, uint *length,
- my_bool not_used __attribute__((unused)))
+uchar *ull_get_key(const User_level_lock *ull, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
- *length=(uint) ull->key_length;
- return (char*) ull->key;
+ *length= ull->key_length;
+ return ull->key;
}
@@ -3173,9 +3336,9 @@ longlong Item_master_pos_wait::val_int()
null_value = 1;
return 0;
}
+#ifdef HAVE_REPLICATION
longlong pos = (ulong)args[1]->val_int();
longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ;
-#ifdef HAVE_REPLICATION
if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
{
null_value = 1;
@@ -3191,8 +3354,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
THD* thd=current_thd;
User_level_lock* ull;
struct timespec abstime;
- int lock_name_len;
- lock_name_len=strlen(lock_name);
+ size_t lock_name_len;
+ lock_name_len= strlen(lock_name);
pthread_mutex_lock(&LOCK_user_locks);
if (thd->ull)
@@ -3207,8 +3370,9 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
this case, we will not be waiting, but rather, just waste CPU and
memory on the whole deal
*/
- if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks, lock_name,
- lock_name_len))))
+ if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
+ (uchar*) lock_name,
+ lock_name_len))))
{
pthread_mutex_unlock(&LOCK_user_locks);
return;
@@ -3239,7 +3403,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
else
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
thd->ull=ull;
}
pthread_mutex_unlock(&LOCK_user_locks);
@@ -3303,10 +3467,11 @@ longlong Item_func_get_lock::val_int()
}
if (!(ull= ((User_level_lock *) hash_search(&hash_user_locks,
- (byte*) res->ptr(),
- res->length()))))
+ (uchar*) res->ptr(),
+ (size_t) res->length()))))
{
- ull=new User_level_lock(res->ptr(),res->length(), thd->thread_id);
+ ull= new User_level_lock((uchar*) res->ptr(), (size_t) res->length(),
+ thd->thread_id);
if (!ull || !ull->initialized())
{
delete ull;
@@ -3314,7 +3479,7 @@ longlong Item_func_get_lock::val_int()
null_value=1; // Probably out of memory
return 0;
}
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
thd->ull=ull;
pthread_mutex_unlock(&LOCK_user_locks);
return 1; // Got new lock
@@ -3355,7 +3520,7 @@ longlong Item_func_get_lock::val_int()
else // We got the lock
{
ull->locked=1;
- ull->thread=thd->real_id;
+ ull->set_thread(thd);
ull->thread_id= thd->thread_id;
thd->ull=ull;
error=0;
@@ -3396,14 +3561,14 @@ longlong Item_func_release_lock::val_int()
result=0;
pthread_mutex_lock(&LOCK_user_locks);
if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks,
- (const byte*) res->ptr(),
- res->length()))))
+ (const uchar*) res->ptr(),
+ (size_t) res->length()))))
{
null_value=1;
}
else
{
- if (ull->locked && pthread_equal(pthread_self(),ull->thread))
+ if (ull->locked && current_thd->thread_id == ull->thread_id)
{
result=1; // Release is ok
item_user_lock_release(ull);
@@ -3445,10 +3610,11 @@ longlong Item_func_benchmark::val_int()
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), &my_charset_bin);
+ my_decimal tmp_decimal;
THD *thd=current_thd;
ulong loop_count;
- loop_count= args[0]->val_int();
+ loop_count= (ulong) args[0]->val_int();
if (args[0]->null_value)
{
@@ -3469,6 +3635,9 @@ longlong Item_func_benchmark::val_int()
case STRING_RESULT:
(void) args[1]->val_str(&tmp);
break;
+ case DECIMAL_RESULT:
+ (void) args[1]->val_decimal(&tmp_decimal);
+ break;
case ROW_RESULT:
default:
// This case should never be chosen
@@ -3538,7 +3707,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
{
user_var_entry *entry;
- if (!(entry = (user_var_entry*) hash_search(hash, (byte*) name.str,
+ if (!(entry = (user_var_entry*) hash_search(hash, (uchar*) name.str,
name.length)) &&
create_if_not_exists)
{
@@ -3568,7 +3737,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->used_query_id=current_thd->query_id;
entry->type=STRING_RESULT;
memcpy(entry->name.str, name.str, name.length+1);
- if (my_hash_insert(hash,(byte*) entry))
+ if (my_hash_insert(hash,(uchar*) entry))
{
my_free((char*) entry,MYF(0));
return 0;
@@ -3630,6 +3799,23 @@ Item_func_set_user_var::fix_length_and_dec()
/*
+ Mark field in read_map
+
+ NOTES
+ This is used by filesort to register used fields in a a temporary
+ column read set or to register used fields in a view
+*/
+
+bool Item_func_set_user_var::register_field_in_read_map(uchar *arg)
+{
+ TABLE *table= (TABLE *) arg;
+ if (result_field->table == table || !table)
+ bitmap_set_bit(result_field->table->read_set, result_field->field_index);
+ return 0;
+}
+
+
+/*
Set value to user variable.
SYNOPSYS
@@ -3683,8 +3869,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
if (entry->value == pos)
entry->value=0;
- if (!(entry->value=(char*) my_realloc(entry->value, length,
- MYF(MY_ALLOW_ZERO_PTR))))
+ entry->value= (char*) my_realloc(entry->value, length,
+ MYF(MY_ALLOW_ZERO_PTR | MY_WME));
+ if (!entry->value)
return 1;
}
}
@@ -3706,7 +3893,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length,
bool
-Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
+Item_func_set_user_var::update_hash(void *ptr, uint length,
+ Item_result res_type,
CHARSET_INFO *cs, Derivation dv,
bool unsigned_arg)
{
@@ -3715,9 +3903,9 @@ Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type,
result type of the variable
*/
if ((null_value= args[0]->null_value) && null_item)
- type= entry->type; // Don't change type of item
+ res_type= entry->type; // Don't change type of item
if (::update_hash(entry, (null_value= args[0]->null_value),
- ptr, length, type, cs, dv, unsigned_arg))
+ ptr, length, res_type, cs, dv, unsigned_arg))
{
current_thd->fatal_error(); // Probably end of memory
null_value= 1;
@@ -3863,7 +4051,8 @@ bool
Item_func_set_user_var::check(bool use_result_field)
{
DBUG_ENTER("Item_func_set_user_var::check");
- DBUG_ASSERT(!use_result_field || result_field);
+ if (use_result_field && !result_field)
+ use_result_field= FALSE;
switch (cached_result_type) {
case REAL_RESULT:
@@ -4007,6 +4196,40 @@ my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
}
+double Item_func_set_user_var::val_result()
+{
+ DBUG_ASSERT(fixed == 1);
+ check(TRUE);
+ update(); // Store expression
+ return entry->val_real(&null_value);
+}
+
+longlong Item_func_set_user_var::val_int_result()
+{
+ DBUG_ASSERT(fixed == 1);
+ check(TRUE);
+ update(); // Store expression
+ return entry->val_int(&null_value);
+}
+
+String *Item_func_set_user_var::str_result(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ check(TRUE);
+ update(); // Store expression
+ return entry->val_str(&null_value, str, decimals);
+}
+
+
+my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ check(TRUE);
+ update(); // Store expression
+ return entry->val_decimal(&null_value, val);
+}
+
+
void Item_func_set_user_var::print(String *str)
{
str->append(STRING_WITH_LEN("(@"));
@@ -4050,6 +4273,107 @@ void Item_func_set_user_var::make_field(Send_field *tmp_field)
Item::make_field(tmp_field);
}
+
+/*
+ Save the value of a user variable into a field
+
+ SYNOPSIS
+ save_in_field()
+ field target field to save the value to
+ no_conversion flag indicating whether conversions are allowed
+
+ DESCRIPTION
+ Save the function value into a field and update the user variable
+ accordingly. If a result field is defined and the target field doesn't
+ coincide with it then the value from the result field will be used as
+ the new value of the user variable.
+
+ The reason to have this method rather than simply using the result
+ field in the val_xxx() methods is that the value from the result field
+ not always can be used when the result field is defined.
+ Let's consider the following cases:
+ 1) when filling a tmp table the result field is defined but the value of it
+ is undefined because it has to be produced yet. Thus we can't use it.
+ 2) on execution of an INSERT ... SELECT statement the save_in_field()
+ function will be called to fill the data in the new record. If the SELECT
+ part uses a tmp table then the result field is defined and should be
+ used in order to get the correct result.
+
+ The difference between the SET_USER_VAR function and regular functions
+ like CONCAT is that the Item_func objects for the regular functions are
+ replaced by Item_field objects after the values of these functions have
+ been stored in a tmp table. Yet an object of the Item_field class cannot
+ be used to update a user variable.
+ Due to this we have to handle the result field in a special way here and
+ in the Item_func_set_user_var::send() function.
+
+ RETURN VALUES
+ FALSE Ok
+ TRUE Error
+*/
+
+int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions,
+ bool can_use_result_field)
+{
+ bool use_result_field= (!can_use_result_field ? 0 :
+ (result_field && result_field != field));
+ int error;
+
+ /* Update the value of the user variable */
+ check(use_result_field);
+ update();
+
+ if (result_type() == STRING_RESULT ||
+ result_type() == REAL_RESULT &&
+ field->result_type() == STRING_RESULT)
+ {
+ String *result;
+ CHARSET_INFO *cs= collation.collation;
+ char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
+ str_value.set_quick(buff, sizeof(buff), cs);
+ result= entry->val_str(&null_value, &str_value, decimals);
+
+ if (null_value)
+ {
+ str_value.set_quick(0, 0, cs);
+ return set_field_to_null_with_conversions(field, no_conversions);
+ }
+
+ /* NOTE: If null_value == FALSE, "result" must be not NULL. */
+
+ field->set_notnull();
+ error=field->store(result->ptr(),result->length(),cs);
+ str_value.set_quick(0, 0, cs);
+ }
+ else if (result_type() == REAL_RESULT)
+ {
+ double nr= entry->val_real(&null_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ error=field->store(nr);
+ }
+ else if (result_type() == DECIMAL_RESULT)
+ {
+ my_decimal decimal_value;
+ my_decimal *value= entry->val_decimal(&null_value, &decimal_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ error=field->store_decimal(value);
+ }
+ else
+ {
+ longlong nr= entry->val_int(&null_value);
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ error=field->store(nr, unsigned_flag);
+ }
+ return error;
+}
+
+
String *
Item_func_get_user_var::val_str(String *str)
{
@@ -4117,7 +4441,14 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
user_var_entry *var_entry;
var_entry= get_variable(&thd->user_vars, name, 0);
- if (!(opt_bin_log && is_update_query(sql_command)))
+ /*
+ Any reference to user-defined variable which is done from stored
+ function or trigger affects their execution and the execution of the
+ calling statement. We must log all such variables even if they are
+ not involved in table-updating statements.
+ */
+ if (!(opt_bin_log &&
+ (is_update_query(sql_command) || thd->in_sub_stmt)))
{
*out_entry= var_entry;
return 0;
@@ -4145,7 +4476,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
List<set_var_base> tmp_var_list;
LEX *sav_lex= thd->lex, lex_tmp;
thd->lex= &lex_tmp;
- lex_start(thd, NULL, 0);
+ lex_start(thd);
tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name,
new Item_null())));
/* Create the variable */
@@ -4177,7 +4508,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
> set @a:=1;
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
We have to write to binlog value @a= 1.
-
+
We allocate the user_var_event on user_var_events_alloc pool, not on
the this-statement-execution pool because in SPs user_var_event objects
may need to be valid after current [SP] statement execution pool is
@@ -4187,7 +4518,7 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
if (!(user_var_event= (BINLOG_USER_VAR_EVENT *)
alloc_root(thd->user_var_events_alloc, size)))
goto err;
-
+
user_var_event->value= (char*) user_var_event +
ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
user_var_event->user_var_event= var_entry;
@@ -4207,9 +4538,9 @@ int get_var_with_binlog(THD *thd, enum_sql_command sql_command,
}
/* Mark that this variable has been used by this query */
var_entry->used_query_id= thd->query_id;
- if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
+ if (insert_dynamic(&thd->user_var_events, (uchar*) &user_var_event))
goto err;
-
+
*out_entry= var_entry;
return 0;
@@ -4218,7 +4549,6 @@ err:
return 1;
}
-
void Item_func_get_user_var::fix_length_and_dec()
{
THD *thd=current_thd;
@@ -4229,10 +4559,19 @@ void Item_func_get_user_var::fix_length_and_dec()
error= get_var_with_binlog(thd, thd->lex->sql_command, name, &var_entry);
+ /*
+ If the variable didn't exist it has been created as a STRING-type.
+ 'var_entry' is NULL only if there occured an error during the call to
+ get_var_with_binlog.
+ */
if (var_entry)
{
+ m_cached_result_type= var_entry->type;
+ unsigned_flag= var_entry->unsigned_flag;
+ max_length= var_entry->length;
+
collation.set(var_entry->collation);
- switch (var_entry->type) {
+ switch(m_cached_result_type) {
case REAL_RESULT:
max_length= DBL_DIG + 8;
break;
@@ -4257,6 +4596,8 @@ void Item_func_get_user_var::fix_length_and_dec()
{
collation.set(&my_charset_bin, DERIVATION_IMPLICIT);
null_value= 1;
+ m_cached_result_type= STRING_RESULT;
+ max_length= MAX_BLOB_WIDTH;
}
if (error)
@@ -4274,12 +4615,7 @@ bool Item_func_get_user_var::const_item() const
enum Item_result Item_func_get_user_var::result_type() const
{
- user_var_entry *entry;
- if (!(entry = (user_var_entry*) hash_search(&current_thd->user_vars,
- (byte*) name.str,
- name.length)))
- return STRING_RESULT;
- return entry->type;
+ return m_cached_result_type;
}
@@ -4488,14 +4824,14 @@ void Item_func_match::init_search(bool no_order)
fields.push_back(new Item_string(" ",1, cmp_collation.collation));
for (uint i=1; i < arg_count; i++)
fields.push_back(args[i]);
- concat=new Item_func_concat_ws(fields);
+ concat_ws=new Item_func_concat_ws(fields);
/*
Above function used only to get value and do not need fix_fields for it:
Item_string - basic constant
fields - fix_fields() was already called for this arguments
Item_func_concat_ws - do not need fix_fields() to produce value
*/
- concat->quick_fix_field();
+ concat_ws->quick_fix_field();
}
if (master)
@@ -4605,7 +4941,7 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr < table->s->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
- (table->keys_in_use_for_query.is_set(keynr)))
+ (table->s->keys_in_use.is_set(keynr)))
{
ft_to_key[fts]=keynr;
ft_cnt[fts]=0;
@@ -4710,11 +5046,11 @@ double Item_func_match::val_real()
if (key == NO_SUCH_KEY)
{
- String *a= concat->val_str(&value);
- if ((null_value= (a == 0)))
+ String *a= concat_ws->val_str(&value);
+ if ((null_value= (a == 0)) || !a->length())
DBUG_RETURN(0);
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
- (byte *)a->ptr(), a->length()));
+ (uchar *)a->ptr(), a->length()));
}
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
table->record[0], 0));
@@ -4756,7 +5092,7 @@ longlong Item_func_bit_xor::val_int()
thd Thread handler
var_type global / session
name Name of base or system variable
- component Component.
+ component Component
NOTES
If component.str = 0 then the variable name is in 'name'
@@ -4784,7 +5120,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
component_name= &component; // Empty string
}
- if (!(var= find_sys_var(base_name->str, base_name->length)))
+ if (!(var= find_sys_var(thd, base_name->str, base_name->length)))
return 0;
if (component.str)
{
@@ -4829,8 +5165,8 @@ longlong Item_func_is_free_lock::val_int()
}
pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
- res->length());
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 1;
@@ -4848,8 +5184,8 @@ longlong Item_func_is_used_lock::val_int()
return 0;
pthread_mutex_lock(&LOCK_user_locks);
- ull= (User_level_lock *) hash_search(&hash_user_locks, (byte*) res->ptr(),
- res->length());
+ ull= (User_level_lock *) hash_search(&hash_user_locks, (uchar*) res->ptr(),
+ (size_t) res->length());
pthread_mutex_unlock(&LOCK_user_locks);
if (!ull || !ull->locked)
return 0;
@@ -4868,9 +5204,10 @@ longlong Item_func_row_count::val_int()
}
+
+
Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
- :Item_func(), context(context_arg), m_name(name), m_sp(NULL),
- result_field(NULL)
+ :Item_func(), context(context_arg), m_name(name), m_sp(NULL), sp_result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
@@ -4881,8 +5218,7 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
sp_name *name, List<Item> &list)
- :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),
- result_field(NULL)
+ :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),sp_result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
@@ -4894,10 +5230,10 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
void
Item_func_sp::cleanup()
{
- if (result_field)
+ if (sp_result_field)
{
- delete result_field;
- result_field= NULL;
+ delete sp_result_field;
+ sp_result_field= NULL;
}
m_sp= NULL;
dummy_table->alias= NULL;
@@ -4909,114 +5245,165 @@ Item_func_sp::func_name() const
{
THD *thd= current_thd;
/* Calculate length to avoid reallocation of string for sure */
- uint len= ((m_name->m_db.length +
+ uint len= (((m_name->m_explicit_name ? m_name->m_db.length : 0) +
m_name->m_name.length)*2 + //characters*quoting
2 + // ` and `
- 1 + // .
+ (m_name->m_explicit_name ?
+ 3 : 0) + // '`', '`' and '.' for the db
1 + // end of string
ALIGN_SIZE(1)); // to avoid String reallocation
String qname((char *)alloc_root(thd->mem_root, len), len,
system_charset_info);
qname.length(0);
- append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length);
- qname.append('.');
+ if (m_name->m_explicit_name)
+ {
+ append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length);
+ qname.append('.');
+ }
append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length);
return qname.ptr();
}
-Field *
-Item_func_sp::sp_result_field(void) const
+
+/**
+ @brief Initialize the result field by creating a temporary dummy table
+ and assign it to a newly created field object. Meta data used to
+ create the field is fetched from the sp_head belonging to the stored
+ proceedure found in the stored procedure functon cache.
+
+ @note This function should be called from fix_fields to init the result
+ field. It is some what related to Item_field.
+
+ @see Item_field
+
+ @param thd A pointer to the session and thread context.
+
+ @return Function return error status.
+ @retval TRUE is returned on an error
+ @retval FALSE is returned on success.
+*/
+
+bool
+Item_func_sp::init_result_field(THD *thd)
{
- Field *field;
- DBUG_ENTER("Item_func_sp::sp_result_field");
- DBUG_PRINT("info", ("sp: %s, flags: %x, level: %lu",
- (m_sp ? "YES" : "NO"),
- (m_sp ? m_sp->m_flags : (uint)0),
- (m_sp ? m_sp->m_recursion_level : (ulong)0)));
+ LEX_STRING empty_name= { C_STRING_WITH_LEN("") };
+ TABLE_SHARE *share;
+ DBUG_ENTER("Item_func_sp::init_result_field");
+
+ DBUG_ASSERT(m_sp == NULL);
+ DBUG_ASSERT(sp_result_field == NULL);
- if (!m_sp)
+ if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
+ &thd->sp_func_cache, TRUE)))
{
- THD *thd= current_thd;
- if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
- &thd->sp_func_cache, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
- DBUG_RETURN(0);
- }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ context->process_error(thd);
+ DBUG_RETURN(TRUE);
}
- if (!dummy_table->alias)
+
+ /*
+ A Field need to be attached to a Table.
+ Below we "create" a dummy table by initializing
+ the needed pointers.
+ */
+
+ share= dummy_table->s;
+ dummy_table->alias = "";
+ dummy_table->maybe_null = maybe_null;
+ dummy_table->in_use= thd;
+ dummy_table->copy_blobs= TRUE;
+ share->table_cache_key = empty_name;
+ share->table_name = empty_name;
+
+ if (!(sp_result_field= m_sp->create_result_field(max_length, name,
+ dummy_table)))
{
- char *empty_name= (char *) "";
- dummy_table->alias= empty_name;
- dummy_table->maybe_null= maybe_null;
- dummy_table->in_use= current_thd;
- dummy_table->copy_blobs= TRUE;
- dummy_table->s->table_cache_key.str = empty_name;
- dummy_table->s->table_name.str= empty_name;
- dummy_table->s->db.str= empty_name;
+ DBUG_RETURN(TRUE);
}
- if (!(field= m_sp->create_result_field(max_length, name, dummy_table)))
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+
+ if (sp_result_field->pack_length() > sizeof(result_buf))
+ {
+ void *tmp;
+ if (!(tmp= sql_alloc(sp_result_field->pack_length())))
+ DBUG_RETURN(TRUE);
+ sp_result_field->move_field((uchar*) tmp);
+ }
+ else
+ sp_result_field->move_field(result_buf);
+
+ sp_result_field->null_ptr= (uchar *) &null_value;
+ sp_result_field->null_bit= 1;
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ @brief Initialize local members with values from the Field interface.
+
+ @note called from Item::fix_fields.
+*/
- DBUG_RETURN(field);
+void Item_func_sp::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_func_sp::fix_length_and_dec");
+
+ DBUG_ASSERT(sp_result_field);
+ decimals= sp_result_field->decimals();
+ max_length= sp_result_field->field_length;
+ collation.set(sp_result_field->charset());
+ maybe_null= 1;
+ unsigned_flag= test(sp_result_field->flags & UNSIGNED_FLAG);
+
+ DBUG_VOID_RETURN;
}
-/*
- Execute function & store value in field
+/**
+ @brief Execute function & store value in field.
- RETURN
- 0 value <> NULL
- 1 value = NULL or error
+ @return Function returns error status.
+ @retval FALSE on success.
+ @retval TRUE if an error occurred.
*/
bool
-Item_func_sp::execute(Field **flp)
+Item_func_sp::execute()
{
THD *thd= current_thd;
- Field *f;
-
- /*
- Get field in virtual tmp table to store result. Create the field if
- invoked first time.
- */
- if (!(f= *flp))
- {
- if (!(*flp= f= sp_result_field()))
- {
- /* Error set by sp_result_field() */
- null_value= 1;
- return TRUE;
- }
-
- f->move_field((f->pack_length() > sizeof(result_buf)) ?
- sql_alloc(f->pack_length()) : result_buf);
- f->null_ptr= (uchar *)&null_value;
- f->null_bit= 1;
- }
-
/* Execute function and store the return value in the field. */
- if (execute_impl(thd, f))
+ if (execute_impl(thd))
{
null_value= 1;
context->process_error(thd);
+ if (thd->killed)
+ thd->send_kill_message();
return TRUE;
}
/* Check that the field (the value) is not NULL. */
- null_value= f->is_null();
+ null_value= sp_result_field->is_null();
return null_value;
}
+/**
+ @brief Execute function and store the return value in the field.
+
+ @note This function was intended to be the concrete implementation of
+ the interface function execute. This was never realized.
+
+ @return The error state.
+ @retval FALSE on success
+ @retval TRUE if an error occurred.
+*/
bool
-Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
+Item_func_sp::execute_impl(THD *thd)
{
bool err_status= TRUE;
Sub_statement_state statement_state;
@@ -5033,7 +5420,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
thd->security_ctx= context->security_ctx;
}
#endif
- if (find_and_check_access(thd))
+ if (sp_check_access(thd))
goto error;
/*
@@ -5054,7 +5441,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
function call into binlog.
*/
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
- err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
+ err_status= m_sp->execute_function(thd, args, arg_count, sp_result_field);
thd->restore_sub_statement_state(&statement_state);
error:
@@ -5069,15 +5456,9 @@ error:
void
Item_func_sp::make_field(Send_field *tmp_field)
{
- Field *field;
DBUG_ENTER("Item_func_sp::make_field");
- if ((field= sp_result_field()))
- {
- field->make_field(tmp_field);
- delete field;
- DBUG_VOID_RETURN;
- }
- init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
+ DBUG_ASSERT(sp_result_field);
+ sp_result_field->make_field(tmp_field);
DBUG_VOID_RETURN;
}
@@ -5085,67 +5466,20 @@ Item_func_sp::make_field(Send_field *tmp_field)
enum enum_field_types
Item_func_sp::field_type() const
{
- Field *field;
DBUG_ENTER("Item_func_sp::field_type");
-
- if (result_field)
- DBUG_RETURN(result_field->type());
- if ((field= sp_result_field()))
- {
- enum_field_types result= field->type();
- delete field;
- DBUG_RETURN(result);
- }
- DBUG_RETURN(MYSQL_TYPE_VARCHAR);
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field->type());
}
-
Item_result
Item_func_sp::result_type() const
{
- Field *field;
DBUG_ENTER("Item_func_sp::result_type");
- DBUG_PRINT("info", ("m_sp: 0x%lx", (long) m_sp));
-
- if (result_field)
- DBUG_RETURN(result_field->result_type());
- if ((field= sp_result_field()))
- {
- Item_result result= field->result_type();
- delete field;
- DBUG_RETURN(result);
- }
- DBUG_RETURN(STRING_RESULT);
-}
-
-void
-Item_func_sp::fix_length_and_dec()
-{
- Field *field;
- DBUG_ENTER("Item_func_sp::fix_length_and_dec");
-
- if (result_field)
- {
- decimals= result_field->decimals();
- max_length= result_field->field_length;
- collation.set(result_field->charset());
- DBUG_VOID_RETURN;
- }
-
- if (!(field= sp_result_field()))
- {
- context->process_error(current_thd);
- DBUG_VOID_RETURN;
- }
- decimals= field->decimals();
- max_length= field->field_length;
- collation.set(field->charset());
- maybe_null= 1;
- delete field;
- DBUG_VOID_RETURN;
+ DBUG_PRINT("info", ("m_sp = %p", m_sp));
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field->result_type());
}
-
longlong Item_func_found_rows::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -5156,57 +5490,39 @@ longlong Item_func_found_rows::val_int()
Field *
Item_func_sp::tmp_table_field(TABLE *t_arg)
{
- Field *field= 0;
DBUG_ENTER("Item_func_sp::tmp_table_field");
- if (m_sp)
- field= m_sp->create_result_field(max_length, (const char*) name, t_arg);
-
- if (!field)
- field= Item_func::tmp_table_field(t_arg);
-
- if (!field)
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-
- DBUG_RETURN(field);
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field);
}
-/*
- Find the function and check access rights to the function
-
- SYNOPSIS
- find_and_check_access()
- thd thread handler
-
- RETURN
- FALSE Access granted
- TRUE Requested access can't be granted or function doesn't exists
-
- NOTES
- Checks if requested access to function can be granted to user.
+/**
+ @brief Checks if requested access to function can be granted to user.
If function isn't found yet, it searches function first.
If function can't be found or user don't have requested access
error is raised.
+
+ @param thd thread handler
+
+ @return Indication if the access was granted or not.
+ @retval FALSE Access is granted.
+ @retval TRUE Requested access can't be granted or function doesn't exists.
+
*/
bool
-Item_func_sp::find_and_check_access(THD *thd)
+Item_func_sp::sp_check_access(THD *thd)
{
- if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
- &thd->sp_func_cache, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
- return TRUE;
- }
-
+ DBUG_ENTER("Item_func_sp::sp_check_access");
+ DBUG_ASSERT(m_sp);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
- return TRUE;
+ DBUG_RETURN(TRUE);
#endif
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -5214,9 +5530,25 @@ bool
Item_func_sp::fix_fields(THD *thd, Item **ref)
{
bool res;
+ DBUG_ENTER("Item_func_sp::fix_fields");
DBUG_ASSERT(fixed == 0);
+
+ /*
+ We must call init_result_field before Item_func::fix_fields()
+ to make m_sp and result_field members available to fix_length_and_dec(),
+ which is called from Item_func::fix_fields().
+ */
+ res= init_result_field(thd);
+
+ if (res)
+ DBUG_RETURN(res);
+
res= Item_func::fix_fields(thd, ref);
- if (!res && thd->lex->view_prepare_mode)
+
+ if (res)
+ DBUG_RETURN(res);
+
+ if (thd->lex->view_prepare_mode)
{
/*
Here we check privileges of the stored routine only during view
@@ -5228,15 +5560,54 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
good idea especially if the view has SQL SECURITY DEFINER and
the used stored procedure has SQL SECURITY DEFINER.
*/
- res= find_and_check_access(thd);
+ res= sp_check_access(thd);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Try to set and restore the security context to see whether it's valid
+ */
Security_context *save_secutiry_ctx;
- if (!res && !(res= set_routine_security_ctx(thd, m_sp, false,
- &save_secutiry_ctx)))
- {
- sp_restore_security_context(thd, save_secutiry_ctx);
- }
+ res= set_routine_security_ctx(thd, m_sp, false, &save_secutiry_ctx);
+ if (!res)
+ m_sp->m_security_ctx.restore_security_context(thd, save_secutiry_ctx);
+
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
}
- return res;
+ DBUG_RETURN(res);
+}
+
+
+/*
+ uuid_short handling.
+
+ The short uuid is defined as a longlong that contains the following bytes:
+
+ Bytes Comment
+ 1 Server_id & 255
+ 4 Startup time of server in seconds
+ 3 Incrementor
+
+ This means that an uuid is guaranteed to be unique
+ even in a replication environment if the following holds:
+
+ - The last byte of the server id is unique
+ - If you between two shutdown of the server don't get more than
+ an average of 2^24 = 16M calls to uuid_short() per second.
+*/
+
+ulonglong uuid_value;
+
+void uuid_short_init()
+{
+ uuid_value= ((((ulonglong) server_id) << 56) +
+ (((ulonglong) server_start_time) << 24));
+}
+
+
+longlong Item_func_uuid_short::val_int()
+{
+ ulonglong val;
+ pthread_mutex_lock(&LOCK_uuid_generator);
+ val= uuid_value++;
+ pthread_mutex_unlock(&LOCK_uuid_generator);
+ return (longlong) val;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 9130ef0a0c4..8fc68f93e12 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -148,11 +147,11 @@ public:
void count_only_length();
void count_real_length();
void count_decimal_length();
- inline bool get_arg0_date(TIME *ltime, uint fuzzy_date)
+ inline bool get_arg0_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
return (null_value=args[0]->get_date(ltime, fuzzy_date));
}
- inline bool get_arg0_time(TIME *ltime)
+ inline bool get_arg0_time(MYSQL_TIME *ltime)
{
return (null_value=args[0]->get_time(ltime));
}
@@ -185,13 +184,13 @@ public:
{
return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep);
}
- bool walk(Item_processor processor, bool walk_subquery, byte *arg);
- Item *transform(Item_transformer transformer, byte *arg);
- Item* compile(Item_analyzer analyzer, byte **arg_p,
- Item_transformer transformer, byte *arg_t);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
+ Item *transform(Item_transformer transformer, uchar *arg);
+ Item* compile(Item_analyzer analyzer, uchar **arg_p,
+ Item_transformer transformer, uchar *arg_t);
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
- bool is_expensive_processor(byte *arg);
+ bool is_expensive_processor(uchar *arg);
virtual bool is_expensive() { return 0; }
};
@@ -254,7 +253,7 @@ public:
void fix_num_length_and_dec();
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -267,7 +266,7 @@ class Item_num_op :public Item_func_numhybrid
void print(String *str) { print_op(str); }
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -281,7 +280,7 @@ public:
{ max_length= 21; }
Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {}
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real();
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() {}
@@ -306,19 +305,13 @@ class Item_func_signed :public Item_int_func
public:
Item_func_signed(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "cast_as_signed"; }
- double val_real()
- {
- double tmp= args[0]->val_real();
- null_value= args[0]->null_value;
- return tmp;
- }
longlong val_int();
longlong val_int_from_str(int *error);
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str);
uint decimal_precision() const { return args[0]->decimal_precision(); }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -340,8 +333,8 @@ class Item_decimal_typecast :public Item_func
public:
Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
{
- max_length= len + 2;
decimals= dec;
+ max_length= my_decimal_precision_to_length(len, dec, unsigned_flag);
}
String *val_str(String *str);
double val_real();
@@ -352,7 +345,7 @@ public:
void fix_length_and_dec() {};
const char *func_name() const { return "decimal_typecast"; }
void print(String *);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -421,7 +414,7 @@ public:
const char *func_name() const { return "DIV"; }
void fix_length_and_dec();
void print(String *str) { print_op(str); }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -495,7 +488,7 @@ public:
Item_func_exp(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "exp"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -505,7 +498,7 @@ public:
Item_func_ln(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "ln"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -516,7 +509,7 @@ public:
Item_func_log(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "log"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -526,7 +519,7 @@ public:
Item_func_log2(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log2"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -536,7 +529,7 @@ public:
Item_func_log10(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "log10"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -546,7 +539,7 @@ public:
Item_func_sqrt(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sqrt"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -556,7 +549,7 @@ public:
Item_func_pow(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "pow"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -566,7 +559,7 @@ public:
Item_func_acos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "acos"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_asin :public Item_dec_func
@@ -575,7 +568,7 @@ public:
Item_func_asin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "asin"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_atan :public Item_dec_func
@@ -585,7 +578,7 @@ public:
Item_func_atan(Item *a,Item *b) :Item_dec_func(a,b) {}
double val_real();
const char *func_name() const { return "atan"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_cos :public Item_dec_func
@@ -594,7 +587,7 @@ public:
Item_func_cos(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "cos"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_sin :public Item_dec_func
@@ -603,7 +596,7 @@ public:
Item_func_sin(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "sin"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_tan :public Item_dec_func
@@ -612,7 +605,7 @@ public:
Item_func_tan(Item *a) :Item_dec_func(a) {}
double val_real();
const char *func_name() const { return "tan"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_integer :public Item_int_func
@@ -680,6 +673,8 @@ public:
bool const_item() const { return 0; }
void update_used_tables();
bool fix_fields(THD *thd, Item **ref);
+private:
+ void seed_random (Item * val);
};
@@ -689,7 +684,7 @@ public:
Item_func_sign(Item *a) :Item_int_func(a) {}
const char *func_name() const { return "sign"; }
longlong val_int();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -704,7 +699,7 @@ public:
const char *func_name() const { return name; }
void fix_length_and_dec()
{ decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -713,16 +708,25 @@ class Item_func_min_max :public Item_func
Item_result cmp_type;
String tmp_value;
int cmp_sign;
+ /* TRUE <=> arguments should be compared in the DATETIME context. */
+ bool compare_as_dates;
+ /* An item used for issuing warnings while string to DATETIME conversion. */
+ Item *datetime_item;
+ THD *thd;
+
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
- cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg) {}
+ cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg), compare_as_dates(FALSE),
+ datetime_item(0) {}
double val_real();
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool result_as_longlong() { return compare_as_dates; };
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ uint cmp_datetimes(ulonglong *value);
};
class Item_func_min :public Item_func_min_max
@@ -740,6 +744,35 @@ public:
};
+/*
+ Objects of this class are used for ROLLUP queries to wrap up
+ each constant item referred to in GROUP BY list.
+*/
+
+class Item_func_rollup_const :public Item_func
+{
+public:
+ Item_func_rollup_const(Item *a) :Item_func(a)
+ {
+ name= a->name;
+ name_length= a->name_length;
+ }
+ double val_real() { return args[0]->val_real(); }
+ longlong val_int() { return args[0]->val_int(); }
+ String *val_str(String *str) { return args[0]->val_str(str); }
+ my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); }
+ const char *func_name() const { return "rollup_const"; }
+ bool const_item() const { return 0; }
+ Item_result result_type() const { return args[0]->result_type(); }
+ void fix_length_and_dec()
+ {
+ collation= args[0]->collation;
+ max_length= args[0]->max_length;
+ decimals=args[0]->decimals;
+ }
+};
+
+
class Item_func_length :public Item_int_func
{
String value;
@@ -748,7 +781,7 @@ public:
longlong val_int();
const char *func_name() const { return "length"; }
void fix_length_and_dec() { max_length=10; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_bit_length :public Item_func_length
@@ -768,7 +801,7 @@ public:
longlong val_int();
const char *func_name() const { return "char_length"; }
void fix_length_and_dec() { max_length=10; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_coercibility :public Item_int_func
@@ -792,7 +825,7 @@ public:
longlong val_int();
void fix_length_and_dec();
void print(String *str);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -817,7 +850,7 @@ public:
longlong val_int();
const char *func_name() const { return "ascii"; }
void fix_length_and_dec() { max_length=3; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_ord :public Item_int_func
@@ -827,7 +860,7 @@ public:
Item_func_ord(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "ord"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_find_in_set :public Item_int_func
@@ -841,7 +874,7 @@ public:
longlong val_int();
const char *func_name() const { return "find_in_set"; }
void fix_length_and_dec();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */
@@ -853,7 +886,7 @@ public:
Item_func_bit(Item *a) :Item_int_func(a) {}
void fix_length_and_dec() { unsigned_flag= 1; }
void print(String *str) { print_op(str); }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_bit_or :public Item_func_bit
@@ -879,7 +912,7 @@ public:
longlong val_int();
const char *func_name() const { return "bit_count"; }
void fix_length_and_dec() { max_length=2; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_shift_left :public Item_func_bit
@@ -1203,6 +1236,10 @@ public:
longlong val_int();
String *val_str(String *str);
my_decimal *val_decimal(my_decimal *);
+ double val_result();
+ longlong val_int_result();
+ String *str_result(String *str);
+ my_decimal *val_decimal_result(my_decimal *);
bool update_hash(void *ptr, uint length, enum Item_result type,
CHARSET_INFO *cs, Derivation dv, bool unsigned_arg);
bool send(Protocol *protocol, String *str_arg);
@@ -1215,6 +1252,14 @@ public:
void print(String *str);
void print_as_stmt(String *str);
const char *func_name() const { return "set_user_var"; }
+ int save_in_field(Field *field, bool no_conversions,
+ bool can_use_result_field);
+ int save_in_field(Field *field, bool no_conversions)
+ {
+ return save_in_field(field, no_conversions, 1);
+ }
+ void save_org_in_field(Field *field) { (void)save_in_field(field, 1, 0); }
+ bool register_field_in_read_map(uchar *arg);
};
@@ -1222,11 +1267,12 @@ class Item_func_get_user_var :public Item_func,
private Settable_routine_parameter
{
user_var_entry *var_entry;
+ Item_result m_cached_result_type;
public:
LEX_STRING name; // keep it public
Item_func_get_user_var(LEX_STRING a):
- Item_func(), name(a) {}
+ Item_func(), m_cached_result_type(STRING_RESULT), name(a) {}
enum Functype functype() const { return GUSERVAR_FUNC; }
LEX_STRING get_name() { return name; }
double val_real();
@@ -1240,13 +1286,11 @@ public:
We must always return variables as strings to guard against selects of type
select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b)
*/
- enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
const char *func_name() const { return "get_user_var"; }
bool const_item() const;
table_map used_tables() const
{ return const_item() ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const;
-
private:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it);
@@ -1319,7 +1363,7 @@ public:
longlong val_int();
const char *func_name() const { return "inet_aton"; }
void fix_length_and_dec() { decimals= 0; max_length= 21; maybe_null= 1; unsigned_flag= 1;}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1335,12 +1379,12 @@ public:
FT_INFO *ft_handler;
TABLE *table;
Item_func_match *master; // for master-slave optimization
- Item *concat; // Item_func_concat_ws
- String value; // value of concat
+ Item *concat_ws; // Item_func_concat_ws
+ String value; // value of concat_ws
String search_value; // key_item()'s value converted to cmp_collation
Item_func_match(List<Item> &a, uint b): Item_real_func(a), key(0), flags(b),
- join_key(0), ft_handler(0), table(0), master(0), concat(0) { }
+ join_key(0), ft_handler(0), table(0), master(0), concat_ws(0) { }
void cleanup()
{
DBUG_ENTER("Item_func_match");
@@ -1348,7 +1392,7 @@ public:
if (!master && ft_handler)
ft_handler->please->close_search(ft_handler);
ft_handler= 0;
- concat= 0;
+ concat_ws= 0;
DBUG_VOID_RETURN;
}
enum Functype functype() const { return FT_FUNC; }
@@ -1432,13 +1476,16 @@ private:
sp_name *m_name;
mutable sp_head *m_sp;
TABLE *dummy_table;
- Field *result_field;
- char result_buf[64];
-
- bool execute(Field **flp);
- bool execute_impl(THD *thd, Field *return_value_fld);
- Field *sp_result_field(void) const;
+ uchar result_buf[64];
+ /*
+ The result field of the concrete stored function.
+ */
+ Field *sp_result_field;
+ bool execute();
+ bool execute_impl(THD *thd);
+ bool init_result_field(THD *thd);
+
public:
Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
@@ -1449,6 +1496,8 @@ public:
virtual ~Item_func_sp()
{}
+ table_map used_tables() const { return RAND_TABLE_BIT; }
+
void cleanup();
const char *func_name() const;
@@ -1463,23 +1512,23 @@ public:
longlong val_int()
{
- if (execute(&result_field))
+ if (execute())
return (longlong) 0;
- return result_field->val_int();
+ return sp_result_field->val_int();
}
double val_real()
{
- if (execute(&result_field))
+ if (execute())
return 0.0;
- return result_field->val_real();
+ return sp_result_field->val_real();
}
my_decimal *val_decimal(my_decimal *dec_buf)
{
- if (execute(&result_field))
+ if (execute())
return NULL;
- return result_field->val_decimal(dec_buf);
+ return sp_result_field->val_decimal(dec_buf);
}
String *val_str(String *str)
@@ -1488,7 +1537,7 @@ public:
char buff[20];
buf.set(buff, 20, str->charset());
buf.length(0);
- if (execute(&result_field))
+ if (execute())
return NULL;
/*
result_field will set buf pointing to internal buffer
@@ -1496,19 +1545,19 @@ public:
when SP is executed. In order to prevent occasional
corruption of returned value, we make here a copy.
*/
- result_field->val_str(&buf);
+ sp_result_field->val_str(&buf);
str->copy(buf);
return str;
}
- virtual bool change_context_processor(byte *cntx)
+ virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
- void fix_length_and_dec();
- bool find_and_check_access(THD * thd);
+ bool sp_check_access(THD * thd);
virtual enum Functype functype() const { return FUNC_SP; }
bool fix_fields(THD *thd, Item **ref);
+ void fix_length_and_dec(void);
bool is_expensive() { return 1; }
};
@@ -1521,3 +1570,18 @@ public:
const char *func_name() const { return "found_rows"; }
void fix_length_and_dec() { decimals= 0; maybe_null=0; }
};
+
+
+void uuid_short_init();
+
+class Item_func_uuid_short :public Item_int_func
+{
+public:
+ Item_func_uuid_short() :Item_int_func() {}
+ const char *func_name() const { return "uuid_short"; }
+ longlong val_int();
+ void fix_length_and_dec()
+ { max_length= 21; unsigned_flag=1; }
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+};
+
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index ef71dc9b8b5..78741483c0b 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2003-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -39,6 +38,7 @@ void Item_geometry_func::fix_length_and_dec()
collation.set(&my_charset_bin);
decimals=0;
max_length=MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
int Item_geometry_func::get_geometry_type() const
@@ -67,11 +67,8 @@ String *Item_func_geometry_from_text::val_str(String *str)
return 0;
str->length(0);
str->q_append(srid);
- if (!Geometry::create_from_wkt(&buffer, &trs, str, 0))
- /* We shouldn't return NULL here as NULL is a legal spatial object */
- /* Geometry::bad_spatial_data will produce error message beeing stored*/
- /* in GEOMETRY field */
- return &Geometry::bad_geometry_data;
+ if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0)))
+ return 0;
return str;
}
@@ -125,6 +122,7 @@ String *Item_func_as_wkt::val_str(String *str)
void Item_func_as_wkt::fix_length_and_dec()
{
max_length=MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
@@ -390,7 +388,8 @@ String *Item_func_spatial_collection::val_str(String *str)
for (i= 0; i < arg_count; ++i)
{
String *res= args[i]->val_str(&arg_value);
- if (args[i]->null_value)
+ uint32 len;
+ if (args[i]->null_value || ((len= res->length()) < WKB_HEADER_SIZE))
goto err;
if (coll_type == Geometry::wkb_geometrycollection)
@@ -399,13 +398,12 @@ String *Item_func_spatial_collection::val_str(String *str)
In the case of GeometryCollection we don't need any checkings
for item types, so just copy them into target collection
*/
- if (str->append(res->ptr(), res->length(), (uint32) 512))
+ if (str->append(res->ptr(), len, (uint32) 512))
goto err;
}
else
{
enum Geometry::wkbType wkb_type;
- uint32 len=res->length();
const char *data= res->ptr() + 1;
/*
@@ -413,8 +411,6 @@ String *Item_func_spatial_collection::val_str(String *str)
are of specific type, let's do this checking now
*/
- if (len < 5)
- goto err;
wkb_type= (Geometry::wkbType) uint4korr(data);
data+= 4;
len-= 5;
@@ -536,9 +532,13 @@ longlong Item_func_spatial_rel::val_int()
longlong Item_func_isempty::val_int()
{
DBUG_ASSERT(fixed == 1);
- String tmp;
- null_value=0;
- return args[0]->null_value ? 1 : 0;
+ String tmp;
+ String *swkb= args[0]->val_str(&tmp);
+ Geometry_buffer buffer;
+
+ null_value= args[0]->null_value ||
+ !(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
+ return null_value ? 1 : 0;
}
@@ -546,10 +546,11 @@ longlong Item_func_issimple::val_int()
{
DBUG_ASSERT(fixed == 1);
String tmp;
- String *wkb=args[0]->val_str(&tmp);
-
- if ((null_value= (!wkb || args[0]->null_value)))
- return 0;
+ String *swkb= args[0]->val_str(&tmp);
+ Geometry_buffer buffer;
+
+ null_value= args[0]->null_value ||
+ !(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
/* TODO: Ramil or Holyfoot, add real IsSimple calculation */
return 0;
}
@@ -702,8 +703,9 @@ double Item_func_glength::val_real()
null_value= (!swkb ||
!(geom= Geometry::construct(&buffer,
- swkb->ptr(), swkb->length())) ||
- geom->length(&res));
+ swkb->ptr(),
+ swkb->length())) ||
+ geom->geom_length(&res));
return res;
}
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 42f11820869..068caa447ef 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,6 +34,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
Field *tmp_table_field(TABLE *t_arg);
virtual int get_geometry_type() const;
+ bool is_null() { (void) val_int(); return null_value; }
};
class Item_func_geometry_from_text: public Item_geometry_func
@@ -82,6 +82,7 @@ public:
void fix_length_and_dec()
{
max_length=20; // "GeometryCollection" is the most long
+ maybe_null= 1;
};
};
@@ -226,6 +227,8 @@ public:
}
}
void print(String *str) { Item_func::print(str); }
+ void fix_length_and_dec() { maybe_null= 1; }
+ bool is_null() { (void) val_int(); return null_value; }
};
class Item_func_isempty: public Item_bool_func
@@ -235,6 +238,7 @@ public:
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "isempty"; }
+ void fix_length_and_dec() { maybe_null= 1; }
};
class Item_func_issimple: public Item_bool_func
@@ -244,6 +248,7 @@ public:
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "issimple"; }
+ void fix_length_and_dec() { maybe_null= 1; }
};
class Item_func_isclosed: public Item_bool_func
@@ -253,6 +258,7 @@ public:
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "isclosed"; }
+ void fix_length_and_dec() { maybe_null= 1; }
};
class Item_func_dimension: public Item_int_func
@@ -262,7 +268,7 @@ 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; }
+ void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
class Item_func_x: public Item_real_func
@@ -272,6 +278,11 @@ public:
Item_func_x(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "x"; }
+ void fix_length_and_dec()
+ {
+ Item_real_func::fix_length_and_dec();
+ maybe_null= 1;
+ }
};
@@ -282,6 +293,11 @@ public:
Item_func_y(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "y"; }
+ void fix_length_and_dec()
+ {
+ Item_real_func::fix_length_and_dec();
+ maybe_null= 1;
+ }
};
@@ -292,7 +308,7 @@ 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; }
+ void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
@@ -303,7 +319,7 @@ public:
Item_func_numinteriorring(Item *a): Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "numinteriorrings"; }
- void fix_length_and_dec() { max_length=10; }
+ void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
@@ -314,7 +330,7 @@ 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; }
+ void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
@@ -325,6 +341,11 @@ public:
Item_func_area(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "area"; }
+ void fix_length_and_dec()
+ {
+ Item_real_func::fix_length_and_dec();
+ maybe_null= 1;
+ }
};
@@ -335,6 +356,11 @@ public:
Item_func_glength(Item *a): Item_real_func(a) {}
double val_real();
const char *func_name() const { return "glength"; }
+ void fix_length_and_dec()
+ {
+ Item_real_func::fix_length_and_dec();
+ maybe_null= 1;
+ }
};
@@ -345,7 +371,7 @@ 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; }
+ void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};
#define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 6e71ae0d4db..d1d1011ab2b 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -143,7 +142,7 @@ void Item_row::print(String *str)
}
-bool Item_row::walk(Item_processor processor, bool walk_subquery, byte *arg)
+bool Item_row::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
for (uint i= 0; i < arg_count; i++)
{
@@ -154,7 +153,7 @@ bool Item_row::walk(Item_processor processor, bool walk_subquery, byte *arg)
}
-Item *Item_row::transform(Item_transformer transformer, byte *arg)
+Item *Item_row::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
diff --git a/sql/item_row.h b/sql/item_row.h
index 39913086e8d..dd7436888f0 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -68,11 +67,11 @@ public:
void update_used_tables();
void print(String *str);
- bool walk(Item_processor processor, bool walk_subquery, byte *arg);
- Item *transform(Item_transformer transformer, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
+ Item *transform(Item_transformer transformer, uchar *arg);
uint cols() { return arg_count; }
- Item* el(uint i) { return items[i]; }
+ Item* element_index(uint i) { return items[i]; }
Item** addr(uint i) { return items + i; }
bool check_cols(uint c);
bool null_inside() { return with_null; };
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e8c87893471..f9ca53a8355 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,27 +25,16 @@
#include "mysql_priv.h"
#include <m_ctype.h>
-#ifdef HAVE_OPENSSL
-#include <openssl/des.h>
-#endif /* HAVE_OPENSSL */
#include "md5.h"
#include "sha1.h"
#include "my_aes.h"
+#include <zlib.h>
C_MODE_START
#include "../mysys/my_static.h" // For soundex_map
C_MODE_END
String my_empty_string("",default_charset_info);
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
- const char *fname)
-{
- my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
- c1.collation->name, c1.derivation_name(),
- c2.collation->name, c2.derivation_name(),
- fname);
-}
-
String *Item_str_func::check_well_formed_result(String *str)
{
@@ -977,18 +965,18 @@ String *Item_func_insert::val_str(String *str)
args[3]->null_value)
goto null; /* purecov: inspected */
- if ((start < 0) || (start > res->length() + 1))
+ if ((start < 0) || (start > res->length()))
return res; // Wrong param; skip insert
- if ((length < 0) || (length > res->length() + 1))
- length= res->length() + 1;
+ if ((length < 0) || (length > res->length()))
+ length= res->length();
/* start and length are now sufficiently valid to pass to charpos function */
start= res->charpos((int) start);
length= res->charpos((int) length, (uint32) start);
/* Re-testing with corrected params */
- if (start > res->length() + 1)
- return res; // Wrong param; skip insert
+ if (start > res->length())
+ return res; /* purecov: inspected */ // Wrong param; skip insert
if (length > res->length() - start)
length= res->length() - start;
@@ -1166,7 +1154,8 @@ String *Item_func_substr::val_str(String *str)
/* if "unsigned_flag" is set, we have a *huge* positive number. */
/* Assumes that the maximum length of a String is < INT_MAX32. */
- if ((args[1]->unsigned_flag) || (start < INT_MIN32) || (start > INT_MAX32))
+ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) ||
+ (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32)))
return &my_empty_string;
start= ((start < 0) ? res->numchars() + start : start - 1);
@@ -1193,11 +1182,10 @@ void Item_func_substr::fix_length_and_dec()
if (args[1]->const_item())
{
int32 start= (int32) args[1]->val_int();
- start= (int32)((start < 0) ? max_length + start : start - 1);
- if (start < 0 || start >= (int32) max_length)
- max_length=0; /* purecov: inspected */
+ if (start < 0)
+ max_length= ((uint)(-start) > max_length) ? 0 : (uint)(-start);
else
- max_length-= (uint) start;
+ max_length-= min((uint)(start - 1), max_length);
}
if (arg_count == 3 && args[2]->const_item())
{
@@ -1811,8 +1799,13 @@ bool Item_func_current_user::fix_fields(THD *thd, Item **ref)
if (Item_func_sysconst::fix_fields(thd, ref))
return TRUE;
- Security_context *ctx= (context->security_ctx
+ Security_context *ctx=
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ (context->security_ctx
? context->security_ctx : thd->security_ctx);
+#else
+ thd->security_ctx;
+#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
return init(ctx->priv_user, ctx->priv_host);
}
@@ -1821,7 +1814,8 @@ void Item_func_soundex::fix_length_and_dec()
{
collation.set(args[0]->collation);
max_length=args[0]->max_length;
- set_if_bigger(max_length,4);
+ set_if_bigger(max_length, 4 * collation.collation->mbminlen);
+ tmp_value.set_charset(collation.collation);
}
@@ -1831,14 +1825,15 @@ void Item_func_soundex::fix_length_and_dec()
else return 0
*/
-static char soundex_toupper(char ch)
+static int soundex_toupper(int ch)
{
return (ch >= 'a' && ch <= 'z') ? ch - 'a' + 'A' : ch;
}
-static char get_scode(char *ptr)
+
+static char get_scode(int wc)
{
- uchar ch= soundex_toupper(*ptr);
+ int ch= soundex_toupper(wc);
if (ch < 'A' || ch > 'Z')
{
// Thread extended alfa (country spec)
@@ -1848,46 +1843,121 @@ static char get_scode(char *ptr)
}
+static bool my_uni_isalpha(int wc)
+{
+ /*
+ Return true for all Basic Latin letters: a..z A..Z.
+ Return true for all Unicode characters with code higher than U+00C0:
+ - characters between 'z' and U+00C0 are controls and punctuations.
+ - "U+00C0 LATIN CAPITAL LETTER A WITH GRAVE" is the first letter after 'z'.
+ */
+ return (wc >= 'a' && wc <= 'z') ||
+ (wc >= 'A' && wc <= 'Z') ||
+ (wc >= 0xC0);
+}
+
+
String *Item_func_soundex::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res =args[0]->val_str(str);
char last_ch,ch;
CHARSET_INFO *cs= collation.collation;
+ my_wc_t wc;
+ uint nchars;
+ int rc;
- if ((null_value=args[0]->null_value))
+ if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
- if (tmp_value.alloc(max(res->length(),4)))
+ if (tmp_value.alloc(max(res->length(), 4 * cs->mbminlen)))
return str; /* purecov: inspected */
char *to= (char *) tmp_value.ptr();
- char *from= (char *) res->ptr(), *end=from+res->length();
- tmp_value.set_charset(cs);
+ char *to_end= to + tmp_value.alloced_length();
+ char *from= (char *) res->ptr(), *end= from + res->length();
- while (from != end && !my_isalpha(cs,*from)) // Skip pre-space
- from++; /* purecov: inspected */
- if (from == end)
- return &my_empty_string; // No alpha characters.
- *to++ = soundex_toupper(*from); // Copy first letter
- last_ch = get_scode(from); // code of the first letter
- // for the first 'double-letter check.
- // Loop on input letters until
- // end of input (null) or output
- // letter code count = 3
- for (from++ ; from < end ; from++)
- {
- if (!my_isalpha(cs,*from))
- continue;
- ch=get_scode(from);
+ for ( ; ; ) /* Skip pre-space */
+ {
+ if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0)
+ return &my_empty_string; /* EOL or invalid byte sequence */
+
+ if (rc == 1 && cs->ctype)
+ {
+ /* Single byte letter found */
+ if (my_isalpha(cs, *from))
+ {
+ last_ch= get_scode(*from); // Code of the first letter
+ *to++= soundex_toupper(*from++); // Copy first letter
+ break;
+ }
+ from++;
+ }
+ else
+ {
+ from+= rc;
+ if (my_uni_isalpha(wc))
+ {
+ /* Multibyte letter found */
+ wc= soundex_toupper(wc);
+ last_ch= get_scode(wc); // Code of the first letter
+ if ((rc= cs->cset->wc_mb(cs, wc, (uchar*) to, (uchar*) to_end)) <= 0)
+ {
+ /* Extra safety - should not really happen */
+ DBUG_ASSERT(false);
+ return &my_empty_string;
+ }
+ to+= rc;
+ break;
+ }
+ }
+ }
+
+ /*
+ last_ch is now set to the first 'double-letter' check.
+ loop on input letters until end of input
+ */
+ for (nchars= 1 ; ; )
+ {
+ if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0)
+ break; /* EOL or invalid byte sequence */
+
+ if (rc == 1 && cs->ctype)
+ {
+ if (!my_isalpha(cs, *from++))
+ continue;
+ }
+ else
+ {
+ from+= rc;
+ if (!my_uni_isalpha(wc))
+ continue;
+ }
+
+ ch= get_scode(wc);
if ((ch != '0') && (ch != last_ch)) // if not skipped or double
{
- *to++ = ch; // letter, copy to output
- last_ch = ch; // save code of last input letter
- } // for next double-letter check
+ // letter, copy to output
+ if ((rc= cs->cset->wc_mb(cs, (my_wc_t) ch,
+ (uchar*) to, (uchar*) to_end)) <= 0)
+ {
+ // Extra safety - should not really happen
+ DBUG_ASSERT(false);
+ break;
+ }
+ to+= rc;
+ nchars++;
+ last_ch= ch; // save code of last input letter
+ } // for next double-letter check
}
- for (end=(char*) tmp_value.ptr()+4 ; to < end ; to++)
- *to = '0';
- *to=0; // end string
+
+ /* Pad up to 4 characters with DIGIT ZERO, if the string is shorter */
+ if (nchars < 4)
+ {
+ uint nbytes= (4 - nchars) * cs->mbminlen;
+ cs->cset->fill(cs, to, nbytes, '0');
+ to+= nbytes;
+ }
+
tmp_value.length((uint) (to-tmp_value.ptr()));
return &tmp_value;
}
@@ -1930,7 +2000,7 @@ String *Item_func_format::val_str(String *str)
int diff;
DBUG_ASSERT(fixed == 1);
- dec= args[1]->val_int();
+ dec= (int) args[1]->val_int();
if (args[1]->null_value)
{
null_value=1;
@@ -1959,7 +2029,7 @@ String *Item_func_format::val_str(String *str)
double nr= args[0]->val_real();
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- nr= my_double_round(nr, dec, FALSE);
+ nr= my_double_round(nr, (longlong) dec, FALSE, FALSE);
/* Here default_charset() is right as this is not an automatic conversion */
str->set_real(nr, dec, default_charset());
if (isnan(nr))
@@ -2151,7 +2221,7 @@ String *Item_func_make_set::val_str(String *str)
}
-Item *Item_func_make_set::transform(Item_transformer transformer, byte *arg)
+Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
@@ -2272,25 +2342,25 @@ String *Item_func_repeat::val_str(String *str)
uint length,tot_length;
char *to;
/* must be longlong to avoid truncation */
- longlong tmp_count= args[1]->val_int();
- long count= (long) tmp_count;
+ longlong count= args[1]->val_int();
String *res= args[0]->val_str(str);
- /* Assumes that the maximum length of a String is < INT_MAX32. */
- /* Bounds check on count: If this is triggered, we will error. */
- if ((tmp_count > INT_MAX32) || args[1]->unsigned_flag)
- count= INT_MAX32;
-
if (args[0]->null_value || args[1]->null_value)
goto err; // string and/or delim are null
null_value= 0;
- if ((tmp_count <= 0) && !args[1]->unsigned_flag) // For nicer SQL code
+
+ if (count <= 0 && (count == 0 || !args[1]->unsigned_flag))
return &my_empty_string;
+
+ /* Assumes that the maximum length of a String is < INT_MAX32. */
+ /* Bounds check on count: If this is triggered, we will error. */
+ if ((ulonglong) count > INT_MAX32)
+ count= INT_MAX32;
if (count == 1) // To avoid reallocs
return res;
length=res->length();
// Safe length check
- if (length > current_thd->variables.max_allowed_packet/count)
+ if (length > current_thd->variables.max_allowed_packet / (uint) count)
{
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_ALLOWED_PACKET_OVERFLOWED,
@@ -2364,15 +2434,14 @@ String *Item_func_rpad::val_str(String *str)
String *res= args[0]->val_str(str);
String *rpad= args[2]->val_str(&rpad_str);
+ if (!res || args[1]->null_value || !rpad ||
+ ((count < 0) && !args[1]->unsigned_flag))
+ goto err;
+ null_value=0;
/* Assumes that the maximum length of a String is < INT_MAX32. */
/* Set here so that rest of code sees out-of-bound value as such. */
- if ((count > INT_MAX32) || args[1]->unsigned_flag)
+ if ((ulonglong) count > INT_MAX32)
count= INT_MAX32;
-
- if (!res || args[1]->null_value || !rpad || count < 0)
- goto err;
- null_value=0;
-
if (count <= (res_char_length= res->numchars()))
{ // String to pad is big enough
res->length(res->charpos((int) count)); // Shorten result if longer
@@ -2466,14 +2535,15 @@ String *Item_func_lpad::val_str(String *str)
String *res= args[0]->val_str(&tmp_value);
String *pad= args[2]->val_str(&lpad_str);
+ if (!res || args[1]->null_value || !pad ||
+ ((count < 0) && !args[1]->unsigned_flag))
+ goto err;
+ null_value=0;
/* Assumes that the maximum length of a String is < INT_MAX32. */
/* Set here so that rest of code sees out-of-bound value as such. */
- if ((count > INT_MAX32) || args[1]->unsigned_flag)
+ if ((ulonglong) count > INT_MAX32)
count= INT_MAX32;
- if (!res || args[1]->null_value || !pad || count < 0)
- goto err;
- null_value=0;
res_char_length= res->numchars();
if (count <= res_char_length)
@@ -2809,6 +2879,11 @@ String *Item_load_file::val_str(String *str)
(void) fn_format(path, file_name->c_ptr(), mysql_real_data_home, "",
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
+ /* Read only allowed from within dir specified by secure_file_priv */
+ if (opt_secure_file_priv &&
+ strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
+ goto err;
+
if (!my_stat(path, &stat_info, MYF(0)))
goto err;
@@ -2829,7 +2904,7 @@ String *Item_load_file::val_str(String *str)
goto err;
if ((file = my_open(file_name->c_ptr(), O_RDONLY, MYF(0))) < 0)
goto err;
- if (my_read(file, (byte*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
+ if (my_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
{
my_close(file, MYF(0));
goto err;
@@ -3270,15 +3345,17 @@ String *Item_func_uuid::val_str(String *str)
int i;
if (my_gethwaddr(mac))
{
+ /* purecov: begin inspected */
/*
generating random "hardware addr"
and because specs explicitly specify that it should NOT correlate
with a clock_seq value (initialized random below), we use a separate
randominit() here
*/
- randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)query_id);
+ randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)global_query_id);
for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
+ /* purecov: end */
}
s=clock_seq_and_node_str+sizeof(clock_seq_and_node_str)-1;
for (i=sizeof(mac)-1 ; i>=0 ; i--)
@@ -3286,7 +3363,7 @@ String *Item_func_uuid::val_str(String *str)
*--s=_dig_vec_lower[mac[i] & 15];
*--s=_dig_vec_lower[mac[i] >> 4];
}
- randominit(&uuid_rand, tmp + (ulong)start_time,
+ randominit(&uuid_rand, tmp + (ulong) server_start_time,
tmp + thd->status_var.bytes_sent);
set_clock_seq_str();
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 3b171b5d50f..c036ec490db 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -51,7 +50,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "md5"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -95,7 +94,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "concat"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_concat_ws :public Item_str_func
@@ -117,7 +116,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "reverse"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -149,13 +148,13 @@ class Item_str_conv :public Item_str_func
{
protected:
uint multiply;
- uint (*converter)(CHARSET_INFO *cs, char *src, uint srclen,
- char *dst, uint dstlen);
+ size_t (*converter)(CHARSET_INFO *cs, char *src, size_t srclen,
+ char *dst, size_t dstlen);
String tmp_value;
public:
Item_str_conv(Item *item) :Item_str_func(item) {}
String *val_str(String *);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -427,8 +426,8 @@ public:
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec()
{
- max_length= ((USERNAME_LENGTH + HOSTNAME_LENGTH + 1) *
- system_charset_info->mbmaxlen);
+ max_length= (USERNAME_LENGTH +
+ (HOSTNAME_LENGTH + 1) * SYSTEM_CHARSET_MBMAXLEN);
}
const char *func_name() const { return "user"; }
const char *fully_qualified_func_name() const { return "user()"; }
@@ -456,7 +455,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "soundex"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -492,12 +491,12 @@ public:
void update_used_tables();
const char *func_name() const { return "make_set"; }
- bool walk(Item_processor processor, bool walk_subquery, byte *arg)
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
return item->walk(processor, walk_subquery, arg) ||
Item_str_func::walk(processor, walk_subquery, arg);
}
- Item *transform(Item_transformer transformer, byte *arg);
+ Item *transform(Item_transformer transformer, uchar *arg);
void print(String *str);
};
@@ -550,7 +549,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "rpad"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -563,7 +562,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "lpad"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -578,7 +577,7 @@ public:
collation.set(default_charset());
max_length= 64;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -595,14 +594,18 @@ public:
decimals=0;
max_length=args[0]->max_length*2*collation.collation->mbmaxlen;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_unhex :public Item_str_func
{
String tmp_value;
public:
- Item_func_unhex(Item *a) :Item_str_func(a) {}
+ Item_func_unhex(Item *a) :Item_str_func(a)
+ {
+ /* there can be bad hex strings */
+ maybe_null= 1;
+ }
const char *func_name() const { return "unhex"; }
String *val_str(String *);
void fix_length_and_dec()
@@ -611,7 +614,7 @@ public:
decimals=0;
max_length=(1+args[0]->max_length)/2;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -635,7 +638,7 @@ public:
}
void print(String *str);
const char *func_name() const { return "cast_as_binary"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -675,7 +678,7 @@ public:
String* val_str(String* str);
const char *func_name() const { return "inet_ntoa"; }
void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_quote :public Item_str_func
@@ -690,7 +693,7 @@ public:
collation.set(args[0]->collation);
max_length= args[0]->max_length * 2 + 2;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_conv_charset :public Item_str_func
@@ -787,11 +790,11 @@ class Item_func_crc32 :public Item_int_func
{
String value;
public:
- Item_func_crc32(Item *a) :Item_int_func(a) {}
+ Item_func_crc32(Item *a) :Item_int_func(a) { unsigned_flag= 1; }
const char *func_name() const { return "crc32"; }
void fix_length_and_dec() { max_length=10; }
longlong val_int();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_uncompressed_length : public Item_int_func
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index da491b91143..000abb313a0 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -52,6 +51,10 @@ Item_subselect::Item_subselect():
void Item_subselect::init(st_select_lex *select_lex,
select_subselect *result)
{
+ /*
+ Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(),
+ which depends on alterations to the parse tree implemented here.
+ */
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex));
@@ -79,7 +82,7 @@ void Item_subselect::init(st_select_lex *select_lex,
parsing_place= (outer_select->in_sum_expr ?
NO_MATTER :
outer_select->parsing_place);
- if (select_lex->next_select())
+ if (unit->is_union())
engine= new subselect_union_engine(unit, result, this);
else
engine= new subselect_single_select_engine(select_lex, result, this);
@@ -92,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_subselect::get_select_lex()
+{
+ return unit->first_select();
+}
+
void Item_subselect::cleanup()
{
DBUG_ENTER("Item_subselect::cleanup");
@@ -140,7 +149,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
- if (check_stack_overrun(thd, STACK_MIN_SIZE, (gptr)&res))
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*)&res))
return TRUE;
res= engine->prepare();
@@ -197,7 +206,7 @@ err:
bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
- byte *argument)
+ uchar *argument)
{
if (walk_subquery)
@@ -235,16 +244,20 @@ bool Item_subselect::walk(Item_processor processor, bool walk_subquery,
}
-bool Item_subselect::exec(bool full_scan)
+bool Item_subselect::exec()
{
int res;
- res= engine->exec(full_scan);
+ if (thd->net.report_error)
+ /* Do not execute subselect in case of a fatal error */
+ return 1;
+
+ res= engine->exec();
if (engine_changed)
{
engine_changed= 0;
- return exec(full_scan);
+ return exec();
}
return (res);
}
@@ -272,11 +285,11 @@ bool Item_subselect::const_item() const
return const_item_cache;
}
-Item *Item_subselect::get_tmp_table_item(THD *thd)
+Item *Item_subselect::get_tmp_table_item(THD *thd_arg)
{
if (!with_sum_func && !const_item())
return new Item_field(result_field);
- return copy_or_same(thd);
+ return copy_or_same(thd_arg);
}
void Item_subselect::update_used_tables()
@@ -308,6 +321,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_singlerow_subselect::invalidate_and_restore_select_lex()
+{
+ DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex");
+ st_select_lex *result= get_select_lex();
+
+ DBUG_ASSERT(result);
+
+ /*
+ This code restore the parse tree in it's state before the execution of
+ Item_singlerow_subselect::Item_singlerow_subselect(),
+ and in particular decouples this object from the SELECT_LEX,
+ so that the SELECT_LEX can be used with a different flavor
+ or Item_subselect instead, as part of query rewriting.
+ */
+ unit->item= NULL;
+
+ DBUG_RETURN(result);
+}
+
Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
Item_subselect *parent,
st_select_lex *select_lex,
@@ -379,7 +412,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
SELECT_LEX *select_lex= join->select_lex;
Query_arena *arena= thd->stmt_arena;
- if (!select_lex->master_unit()->first_select()->next_select() &&
+ if (!select_lex->master_unit()->is_union() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
!select_lex->item_list.head()->with_sum_func &&
@@ -392,6 +425,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
*/
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
select_lex->item_list.head()->type() == REF_ITEM) &&
+ !join->conds && !join->having &&
/*
switch off this optimization for prepare statement,
because we do not rollback this changes
@@ -415,9 +449,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
'upper' select is not really dependent => we remove this dependence
*/
substitution->walk(&Item::remove_dependence_processor, 0,
- (byte *) select_lex->outer_select());
- /* SELECT without FROM clause can't have WHERE or HAVING clause */
- DBUG_ASSERT(join->conds == 0 && join->having == 0);
+ (uchar *) select_lex->outer_select());
return RES_REDUCE;
}
return RES_OK;
@@ -493,13 +525,13 @@ bool Item_singlerow_subselect::null_inside()
void Item_singlerow_subselect::bring_value()
{
- exec(FALSE);
+ exec();
}
double Item_singlerow_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_real();
@@ -514,7 +546,7 @@ double Item_singlerow_subselect::val_real()
longlong Item_singlerow_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_int();
@@ -528,7 +560,7 @@ longlong Item_singlerow_subselect::val_int()
String *Item_singlerow_subselect::val_str(String *str)
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_str(str);
@@ -543,7 +575,7 @@ String *Item_singlerow_subselect::val_str(String *str)
my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_decimal(decimal_value);
@@ -558,7 +590,7 @@ my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
bool Item_singlerow_subselect::val_bool()
{
- if (!exec(FALSE) && !value->null_value)
+ if (!exec() && !value->null_value)
{
null_value= 0;
return value->val_bool();
@@ -592,13 +624,13 @@ void Item_exists_subselect::print(String *str)
}
-bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
+bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit_arg)
{
- if (unit->fake_select_lex &&
- unit->fake_select_lex->test_limit())
+ if (unit_arg->fake_select_lex &&
+ unit_arg->fake_select_lex->test_limit())
return(1);
- SELECT_LEX *sl= unit->first_select();
+ SELECT_LEX *sl= unit_arg->first_select();
for (; sl; sl= sl->next_select())
{
if (sl->test_limit())
@@ -610,7 +642,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex):
Item_exists_subselect(), optimizer(0), transformed(0),
- enable_pushed_conds(TRUE), upper_item(0)
+ pushed_cond_guards(NULL), upper_item(0)
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp;
@@ -655,7 +687,7 @@ void Item_exists_subselect::fix_length_and_dec()
double Item_exists_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -666,7 +698,7 @@ double Item_exists_subselect::val_real()
longlong Item_exists_subselect::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -677,7 +709,7 @@ longlong Item_exists_subselect::val_int()
String *Item_exists_subselect::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -690,7 +722,7 @@ String *Item_exists_subselect::val_str(String *str)
my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -703,7 +735,7 @@ my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
bool Item_exists_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
- if (exec(FALSE))
+ if (exec())
{
reset();
return 0;
@@ -721,7 +753,7 @@ double Item_in_subselect::val_real()
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -742,7 +774,7 @@ longlong Item_in_subselect::val_int()
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -763,7 +795,7 @@ String *Item_in_subselect::val_str(String *str)
DBUG_ASSERT(0);
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -783,9 +815,14 @@ bool Item_in_subselect::val_bool()
{
DBUG_ASSERT(fixed == 1);
null_value= 0;
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
+ /*
+ Must mark the IN predicate as NULL so as to make sure an enclosing NOT
+ predicate will return FALSE. See the comments in
+ subselect_uniquesubquery_engine::copy_ref_key for further details.
+ */
null_value= 1;
return 0;
}
@@ -803,7 +840,7 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value)
DBUG_ASSERT(0);
null_value= 0;
DBUG_ASSERT(fixed == 1);
- if (exec(!enable_pushed_conds))
+ if (exec())
{
reset();
null_value= 1;
@@ -870,7 +907,6 @@ Item_subselect::trans_res
Item_in_subselect::single_value_transformer(JOIN *join,
Comp_creator *func)
{
- Item_subselect::trans_res result= RES_ERROR;
SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
@@ -967,8 +1003,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!substitution)
{
- //first call for this unit
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ /* We're invoked for the 1st (or the only) SELECT in the subquery UNION */
+ SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
SELECT_LEX *current= thd->lex->current_select, *up;
@@ -991,21 +1027,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
(char *)"<no matter>",
(char *)in_left_expr_name);
- unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ master_unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ }
+ if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
+ {
+ if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool))))
+ DBUG_RETURN(RES_ERROR);
+ pushed_cond_guards[0]= TRUE;
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
- /*
- Add the left part of a subselect to a WHERE or HAVING clause of
- the right part, e.g.
-
- SELECT 1 IN (SELECT a FROM t1) =>
-
- SELECT Item_in_optimizer(1, SELECT a FROM t1 WHERE a=1)
-
- HAVING is used only if the right part contains a SUM function, a GROUP
- BY or a HAVING clause.
- */
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.elements)
{
@@ -1017,13 +1048,13 @@ Item_in_subselect::single_value_transformer(JOIN *join,
ref_pointer_array,
(char *)"<ref>",
this->full_name()));
- if (!abort_on_null && ((Item*)select_lex->item_list.head())->maybe_null)
+ if (!abort_on_null && left_expr->maybe_null)
{
/*
We can encounter "NULL IN (SELECT ...)". Wrap the added condition
- within a trigger.
+ within a trig_cond.
*/
- item= new Item_func_trig_cond(item, &enable_pushed_conds);
+ item= new Item_func_trig_cond(item, get_cond_guard(0));
}
/*
@@ -1032,6 +1063,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->having= join->having= and_items(join->having, item);
+ if (join->having == item)
+ item->name= (char*)in_having_cond;
select_lex->having_fix_field= 1;
/*
we do not check join->having->fixed, because Item_and (from and_items)
@@ -1052,20 +1085,26 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Item *having= item, *orig_item= item;
select_lex->item_list.empty();
select_lex->item_list.push_back(new Item_int("Not_used",
- (longlong) 1, 21));
+ (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
item= func->create(expr, item);
if (!abort_on_null && orig_item->maybe_null)
{
- having=
- new Item_func_trig_cond(new Item_is_not_null_test(this, having),
- &enable_pushed_conds);
+ having= new Item_is_not_null_test(this, having);
+ if (left_expr->maybe_null)
+ {
+ if (!(having= new Item_func_trig_cond(having,
+ get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
/*
Item_is_not_null_test can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields()
*/
+ having->name= (char*)in_having_cond;
select_lex->having= join->having= having;
select_lex->having_fix_field= 1;
/*
@@ -1077,17 +1116,25 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->having_fix_field= 0;
if (tmp)
DBUG_RETURN(RES_ERROR);
- /*
- NOTE: It is important that we add this "IS NULL" here, even when
- orig_item can't be NULL. This is needed so that this predicate is
- only used by ref[_or_null] analyzer (and, e.g. is not used by const
- propagation).
- */
item= new Item_cond_or(item,
new Item_func_isnull(orig_item));
- item= new Item_func_trig_cond(item, &enable_pushed_conds);
}
+ /*
+ If we may encounter NULL IN (SELECT ...) and care whether subquery
+ result is NULL or FALSE, wrap condition in a trig_cond.
+ */
+ if (!abort_on_null && left_expr->maybe_null)
+ {
+ if (!(item= new Item_func_trig_cond(item, get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ /*
+ TODO: figure out why the following is done here in
+ single_value_transformer but there is no corresponding action in
+ row_value_transformer?
+ */
item->name= (char *)in_additional_cond;
+
/*
AND can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
@@ -1105,7 +1152,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
else
{
bool tmp;
- if (select_lex->master_unit()->first_select()->next_select())
+ if (select_lex->master_unit()->is_union())
{
/*
comparison functions can't be changed during fix_fields()
@@ -1118,10 +1165,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->ref_pointer_array,
(char *)"<no matter>",
(char *)"<result>"));
- new_having= new Item_func_trig_cond(new_having, &enable_pushed_conds);
+ if (!abort_on_null && left_expr->maybe_null)
+ {
+ if (!(new_having= new Item_func_trig_cond(new_having,
+ get_cond_guard(0))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ new_having->name= (char*)in_having_cond;
select_lex->having= join->having= new_having;
-
select_lex->having_fix_field= 1;
+
/*
we do not check join->having->fixed, because comparison function
(from func->create) can't be fixed after creation
@@ -1174,7 +1227,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (!substitution)
{
//first call for this unit
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
SELECT_LEX *current= thd->lex->current_select, *up;
@@ -1190,7 +1243,16 @@ Item_in_subselect::row_value_transformer(JOIN *join)
optimizer->keep_top_level_cache();
thd->lex->current_select= current;
- unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ master_unit->uncacheable|= UNCACHEABLE_DEPENDENT;
+
+ if (!abort_on_null && left_expr->maybe_null && !pushed_cond_guards)
+ {
+ if (!(pushed_cond_guards= (bool*)join->thd->alloc(sizeof(bool) *
+ left_expr->cols())))
+ DBUG_RETURN(RES_ERROR);
+ for (uint i= 0; i < cols_num; i++)
+ pushed_cond_guards[i]= TRUE;
+ }
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
@@ -1207,13 +1269,14 @@ Item_in_subselect::row_value_transformer(JOIN *join)
is_not_null_test(v3))
where is_not_null_test used to register nulls in case if we have
not found matching to return correct NULL value
+ TODO: say here explicitly if the order of AND parts matters or not.
*/
Item *item_having_part2= 0;
for (uint i= 0; i < cols_num; i++)
{
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
- check_cols(left_expr->el(i)->cols()))
+ check_cols(left_expr->element_index(i)->cols()))
DBUG_RETURN(RES_ERROR);
Item *item_eq=
new Item_func_eq(new
@@ -1235,21 +1298,28 @@ Item_in_subselect::row_value_transformer(JOIN *join)
(char *)"<no matter>",
(char *)"<list ref>")
);
- having_item=
- and_items(having_item,
- new Item_cond_or(item_eq, item_isnull));
- item_having_part2=
- and_items(item_having_part2,
- new
- Item_is_not_null_test(this,
- new
- Item_ref(&select_lex->context,
- select_lex->
- ref_pointer_array + i,
- (char *)"<no matter>",
- (char *)"<list ref>")
- )
- );
+ Item *col_item= new Item_cond_or(item_eq, item_isnull);
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ {
+ if (!(col_item= new Item_func_trig_cond(col_item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ having_item= and_items(having_item, col_item);
+
+ Item *item_nnull_test=
+ new Item_is_not_null_test(this,
+ new Item_ref(&select_lex->context,
+ select_lex->
+ ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>"));
+ if (!abort_on_null && left_expr->element_index(i)->maybe_null)
+ {
+ if (!(item_nnull_test=
+ new Item_func_trig_cond(item_nnull_test, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ item_having_part2= and_items(item_having_part2, item_nnull_test);
item_having_part2->top_level_item();
}
having_item= and_items(having_item, item_having_part2);
@@ -1280,7 +1350,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
Item *item, *item_isnull;
DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
if (select_lex->ref_pointer_array[i]->
- check_cols(left_expr->el(i)->cols()))
+ check_cols(left_expr->element_index(i)->cols()))
DBUG_RETURN(RES_ERROR);
item=
new Item_func_eq(new
@@ -1298,18 +1368,15 @@ Item_in_subselect::row_value_transformer(JOIN *join)
);
if (!abort_on_null)
{
- having_item=
- and_items(having_item,
- new
- Item_is_not_null_test(this,
- new
- Item_ref(&select_lex->context,
- select_lex->
- ref_pointer_array + i,
- (char *)"<no matter>",
- (char *)"<list ref>")
- )
- );
+ Item *having_col_item=
+ new Item_is_not_null_test(this,
+ new
+ Item_ref(&select_lex->context,
+ select_lex->ref_pointer_array + i,
+ (char *)"<no matter>",
+ (char *)"<list ref>"));
+
+
item_isnull= new
Item_func_isnull(new
Item_direct_ref(&select_lex->context,
@@ -1318,14 +1385,23 @@ Item_in_subselect::row_value_transformer(JOIN *join)
(char *)"<no matter>",
(char *)"<list ref>")
);
-
item= new Item_cond_or(item, item_isnull);
+ /*
+ TODO: why we create the above for cases where the right part
+ cant be NULL?
+ */
+ if (left_expr->element_index(i)->maybe_null)
+ {
+ if (!(item= new Item_func_trig_cond(item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ if (!(having_col_item=
+ new Item_func_trig_cond(having_col_item, get_cond_guard(i))))
+ DBUG_RETURN(RES_ERROR);
+ }
+ having_item= and_items(having_item, having_col_item);
}
-
where_item= and_items(where_item, item);
}
- if (where_item)
- where_item= new Item_func_trig_cond(where_item, &enable_pushed_conds);
/*
AND can't be changed during fix_fields()
we can assign select_lex->where here, and pass 0 as last
@@ -1339,9 +1415,9 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (having_item)
{
bool res;
- having_item= new Item_func_trig_cond(having_item, &enable_pushed_conds);
-
select_lex->having= join->having= and_items(join->having, having_item);
+ if (having_item == select_lex->having)
+ having_item->name= (char*)in_having_cond;
select_lex->having->top_level_item();
/*
AND can't be changed during fix_fields()
@@ -1476,14 +1552,14 @@ void Item_in_subselect::print(String *str)
}
-bool Item_in_subselect::fix_fields(THD *thd, Item **ref)
+bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
{
bool result = 0;
- if(thd->lex->view_prepare_mode && left_expr && !left_expr->fixed)
- result = left_expr->fix_fields(thd, &left_expr);
+ if (thd_arg->lex->view_prepare_mode && left_expr && !left_expr->fixed)
+ result = left_expr->fix_fields(thd_arg, &left_expr);
- return result || Item_subselect::fix_fields(thd, ref);
+ return result || Item_subselect::fix_fields(thd_arg, ref);
}
@@ -1522,13 +1598,13 @@ void subselect_engine::set_thd(THD *thd_arg)
subselect_single_select_engine::
subselect_single_select_engine(st_select_lex *select,
- select_subselect *result,
- Item_subselect *item)
- :subselect_engine(item, result),
+ select_subselect *result_arg,
+ Item_subselect *item_arg)
+ :subselect_engine(item_arg, result_arg),
prepared(0), optimized(0), executed(0),
select_lex(select), join(0)
{
- select_lex->master_unit()->item= item;
+ select_lex->master_unit()->item= item_arg;
}
@@ -1674,7 +1750,7 @@ void subselect_engine::set_row(List<Item> &item_list, Item_cache **row)
Item *sel_item;
List_iterator_fast<Item> li(item_list);
res_type= STRING_RESULT;
- res_field_type= FIELD_TYPE_VAR_STRING;
+ res_field_type= MYSQL_TYPE_VAR_STRING;
for (uint i= 0; (sel_item= li++); i++)
{
item->max_length= sel_item->max_length;
@@ -1727,7 +1803,7 @@ int init_read_record_seq(JOIN_TAB *tab);
int join_read_always_key_or_null(JOIN_TAB *tab);
int join_read_next_same_or_null(READ_RECORD *info);
-int subselect_single_select_engine::exec(bool full_scan)
+int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
char const *save_where= thd->where;
@@ -1746,6 +1822,21 @@ int subselect_single_select_engine::exec(bool full_scan)
thd->lex->current_select= save_select;
DBUG_RETURN(join->error ? join->error : 1);
}
+ if (!select_lex->uncacheable && thd->lex->describe &&
+ !(join->select_options & SELECT_DESCRIBE) &&
+ join->need_tmp && item->const_item())
+ {
+ /*
+ Force join->join_tmp creation, because this subquery will be replaced
+ by a simple select from the materialization temp table by optimize()
+ called by EXPLAIN and we need to preserve the initial query structure
+ so we can display it.
+ */
+ select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
+ select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
+ if (join->init_save_join_tab())
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
if (item->engine_changed)
{
DBUG_RETURN(1);
@@ -1765,9 +1856,12 @@ int subselect_single_select_engine::exec(bool full_scan)
if (!executed)
{
item->reset_value_registration();
- if (full_scan)
+ JOIN_TAB *changed_tabs[MAX_TABLES];
+ JOIN_TAB **last_changed_tab= changed_tabs;
+ if (item->have_guarded_conds())
{
/*
+ For at least one of the pushed predicates the following is true:
We should not apply optimizations based on the condition that was
pushed down into the subquery. Those optimizations are ref[_or_null]
acceses. Change them to be full table scans.
@@ -1775,32 +1869,38 @@ int subselect_single_select_engine::exec(bool full_scan)
for (uint i=join->const_tables ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
- if (tab->keyuse && tab->keyuse->outer_ref)
+ if (tab && tab->keyuse)
{
- tab->read_first_record= init_read_record_seq;
- tab->read_record.record= tab->table->record[0];
- tab->read_record.thd= join->thd;
- tab->read_record.ref_length= tab->table->file->ref_length;
+ for (uint i= 0; i < tab->ref.key_parts; i++)
+ {
+ bool *cond_guard= tab->ref.cond_guards[i];
+ if (cond_guard && !*cond_guard)
+ {
+ /* Change the access method to full table scan */
+ tab->save_read_first_record= tab->read_first_record;
+ tab->save_read_record= tab->read_record.read_record;
+ tab->read_first_record= init_read_record_seq;
+ tab->read_record.record= tab->table->record[0];
+ tab->read_record.thd= join->thd;
+ tab->read_record.ref_length= tab->table->file->ref_length;
+ *(last_changed_tab++)= tab;
+ break;
+ }
+ }
}
}
}
join->exec();
- if (full_scan)
+ /* Enable the optimizations back */
+ for (JOIN_TAB **ptab= changed_tabs; ptab != last_changed_tab; ptab++)
{
- /* Enable the optimizations back */
- for (uint i=join->const_tables ; i < join->tables ; i++)
- {
- JOIN_TAB *tab=join->join_tab+i;
- if (tab->keyuse && tab->keyuse->outer_ref)
- {
- tab->read_record.record= 0;
- tab->read_record.ref_length= 0;
- tab->read_first_record= join_read_always_key_or_null;
- tab->read_record.read_record= join_read_next_same_or_null;
- }
- }
+ JOIN_TAB *tab= *ptab;
+ tab->read_record.record= 0;
+ tab->read_record.ref_length= 0;
+ tab->read_first_record= tab->save_read_first_record;
+ tab->read_record.read_record= tab->save_read_record;
}
executed= 1;
thd->where= save_where;
@@ -1812,13 +1912,9 @@ int subselect_single_select_engine::exec(bool full_scan)
DBUG_RETURN(0);
}
-int subselect_union_engine::exec(bool full_scan)
+int subselect_union_engine::exec()
{
char const *save_where= thd->where;
- /*
- Ignore the full_scan parameter: the pushed down predicates are only used
- for filtering, and the caller has disabled them if necessary.
- */
int res= unit->exec();
thd->where= save_where;
return res;
@@ -1826,7 +1922,7 @@ int subselect_union_engine::exec(bool full_scan)
/*
- Search for at least on row satisfying select condition
+ Search for at least one row satisfying select condition
SYNOPSIS
subselect_uniquesubquery_engine::scan_table()
@@ -1835,8 +1931,8 @@ int subselect_union_engine::exec(bool full_scan)
Scan the table using sequential access until we find at least one row
satisfying select condition.
- The result of this function (info about whether a row was found) is
- stored in this->empty_result_set.
+ The caller must set this->empty_result_set=FALSE before calling this
+ function. This function will set it to TRUE if it finds a matching row.
RETURN
FALSE - OK
@@ -1848,7 +1944,6 @@ int subselect_uniquesubquery_engine::scan_table()
int error;
TABLE *table= tab->table;
DBUG_ENTER("subselect_uniquesubquery_engine::scan_table");
- empty_result_set= TRUE;
if (table->file->inited)
table->file->ha_index_end();
@@ -1889,10 +1984,38 @@ int subselect_uniquesubquery_engine::scan_table()
DESCRIPTION
Copy ref key and check for null parts in it.
+ Depending on the nullability and conversion problems this function
+ recognizes and processes the following states :
+ 1. Partial match on top level. This means IN has a value of FALSE
+ regardless of the data in the subquery table.
+ Detected by finding a NULL in the left IN operand of a top level
+ expression.
+ We may actually skip reading the subquery, so return TRUE to skip
+ the table scan in subselect_uniquesubquery_engine::exec and make
+ the value of the IN predicate a NULL (that is equal to FALSE on
+ top level).
+ 2. No exact match when IN is nested inside another predicate.
+ Detected by finding a NULL in the left IN operand when IN is not
+ a top level predicate.
+ We cannot have an exact match. But we must proceed further with a
+ table scan to find out if it's a partial match (and IN has a value
+ of NULL) or no match (and IN has a value of FALSE).
+ So we return FALSE to continue with the scan and see if there are
+ any record that would constitute a partial match (as we cannot
+ determine that from the index).
+ 3. Error converting the left IN operand to the column type of the
+ right IN operand. This counts as no match (and IN has the value of
+ FALSE). We mark the subquery table cursor as having no more rows
+ (to ensure that the processing that follows will not find a match)
+ and return FALSE, so IN is not treated as returning NULL.
+
RETURN
- FALSE - ok, index lookup key without keys copied.
- TRUE - an error occured while copying the key
+ FALSE - The value of the IN predicate is not known. Proceed to find the
+ value of the IN predicate using the determined values of
+ null_keypart and table->status.
+ TRUE - IN predicate has a value of NULL. Stop the processing right there
+ and return NULL to the outer predicates.
*/
bool subselect_uniquesubquery_engine::copy_ref_key()
@@ -1912,13 +2035,37 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
function.
*/
null_keypart= (*copy)->null_key;
- bool top_level= ((Item_in_subselect *) item)->is_top_level_item();
- if (null_keypart && !top_level)
- break;
- if ((tab->ref.key_err) & 1 || (null_keypart && top_level))
+ if (null_keypart)
+ {
+ bool top_level= ((Item_in_subselect *) item)->is_top_level_item();
+ if (top_level)
+ {
+ /* Partial match on top level */
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ /* No exact match when IN is nested inside another predicate */
+ break;
+ }
+ }
+
+ /*
+ Check if the error is equal to STORE_KEY_FATAL. This is not expressed
+ using the store_key::store_key_result enum because ref.key_err is a
+ boolean and we want to detect both TRUE and STORE_KEY_FATAL from the
+ space of the union of the values of [TRUE, FALSE] and
+ store_key::store_key_result.
+ TODO: fix the variable an return types.
+ */
+ if (tab->ref.key_err & 1)
{
+ /*
+ Error converting the left IN operand to the column type of the right
+ IN operand.
+ */
tab->table->status= STATUS_NOT_FOUND;
- DBUG_RETURN(1);
+ break;
}
}
DBUG_RETURN(0);
@@ -1941,10 +2088,13 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
- FALSE otherwise.
In some cases (IN subselect is a top level item, i.e. abort_on_null==TRUE)
- the caller doesn't distinguish between NULL and FALSE result and we just
+ the caller doesn't distinguish between NULL and FALSE result and we just
return FALSE.
- Otherwise we make a full table scan to see if there is at least one matching row.
-
+ Otherwise we make a full table scan to see if there is at least one
+ matching row.
+
+ The result of this function (info about whether a row was found) is
+ stored in this->empty_result_set.
NOTE
RETURN
@@ -1952,15 +2102,26 @@ bool subselect_uniquesubquery_engine::copy_ref_key()
TRUE - an error occured while scanning
*/
-int subselect_uniquesubquery_engine::exec(bool full_scan)
+int subselect_uniquesubquery_engine::exec()
{
DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error;
TABLE *table= tab->table;
+ empty_result_set= TRUE;
+ table->status= 0;
/* TODO: change to use of 'full_scan' here? */
if (copy_ref_key())
DBUG_RETURN(1);
+ if (table->status)
+ {
+ /*
+ We know that there will be no rows even if we scan.
+ Can be set in copy_ref_key.
+ */
+ ((Item_in_subselect *) item)->value= 0;
+ DBUG_RETURN(0);
+ }
if (null_keypart)
DBUG_RETURN(scan_table());
@@ -1969,7 +2130,8 @@ int subselect_uniquesubquery_engine::exec(bool full_scan)
table->file->ha_index_init(tab->ref.key, 0);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);
@@ -1977,9 +2139,13 @@ int subselect_uniquesubquery_engine::exec(bool full_scan)
{
error= 0;
table->null_row= 0;
- ((Item_in_subselect *) item)->value= (!table->status &&
- (!cond || cond->val_int()) ? 1 :
- 0);
+ if (!table->status && (!cond || cond->val_int()))
+ {
+ ((Item_in_subselect *) item)->value= 1;
+ empty_result_set= FALSE;
+ }
+ else
+ ((Item_in_subselect *) item)->value= 0;
}
DBUG_RETURN(error != 0);
@@ -2045,7 +2211,7 @@ subselect_uniquesubquery_engine::~subselect_uniquesubquery_engine()
1
*/
-int subselect_indexsubquery_engine::exec(bool full_scan)
+int subselect_indexsubquery_engine::exec()
{
DBUG_ENTER("subselect_indexsubquery_engine::exec");
int error;
@@ -2074,7 +2240,8 @@ int subselect_indexsubquery_engine::exec(bool full_scan)
table->file->ha_index_init(tab->ref.key, 1);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);
@@ -2086,8 +2253,9 @@ int subselect_indexsubquery_engine::exec(bool full_scan)
table->null_row= 0;
if (!table->status)
{
- if (!cond || cond->val_int())
+ if ((!cond || cond->val_int()) && (!having || having->val_int()))
{
+ empty_result_set= FALSE;
if (null_finding)
((Item_in_subselect *) item)->was_null= 1;
else
@@ -2230,11 +2398,16 @@ void subselect_indexsubquery_engine::print(String *str)
str->append(key_info->name);
if (check_null)
str->append(STRING_WITH_LEN(" checking NULL"));
- if (cond)
+ if (cond)
{
str->append(STRING_WITH_LEN(" where "));
cond->print(str);
}
+ if (having)
+ {
+ str->append(STRING_WITH_LEN(" having "));
+ having->print(str);
+ }
str->append(')');
}
@@ -2321,6 +2494,22 @@ bool subselect_single_select_engine::no_tables()
/*
+ Check statically whether the subquery can return NULL
+
+ SINOPSYS
+ subselect_single_select_engine::may_be_null()
+
+ RETURN
+ FALSE can guarantee that the subquery never return NULL
+ TRUE otherwise
+*/
+bool subselect_single_select_engine::may_be_null()
+{
+ return ((no_tables() && !join->conds && !join->having) ? maybe_null : 1);
+}
+
+
+/*
Report about presence of tables in subquery
SYNOPSIS
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index c274b5ca31b..51ab7b8ad42 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -95,7 +94,7 @@ public:
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
- virtual bool exec(bool full_scan);
+ virtual bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
table_map not_null_tables() const { return 0; }
@@ -105,6 +104,7 @@ public:
Item *get_tmp_table_item(THD *thd);
void update_used_tables();
void print(String *str);
+ virtual bool have_guarded_conds() { return FALSE; }
bool change_engine(subselect_engine *eng)
{
old_engine= engine;
@@ -125,7 +125,13 @@ public:
*/
virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
- bool walk(Item_processor processor, bool walk_subquery, byte *arg);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
+
+ /**
+ Get the SELECT_LEX structure associated with this Item.
+ @return the SELECT_LEX structure associated with this Item
+ */
+ st_select_lex* get_select_lex();
friend class select_subselect;
friend class Item_in_optimizer;
@@ -164,12 +170,26 @@ public:
void fix_length_and_dec();
uint cols();
- Item* el(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
+ Item* element_index(uint i) { return my_reinterpret_cast(Item*)(row[i]); }
Item** addr(uint i) { return (Item**)row + i; }
bool check_cols(uint c);
bool null_inside();
void bring_value();
+ /**
+ This method is used to implement a special case of semantic tree
+ rewriting, mandated by a SQL:2003 exception in the specification.
+ The only caller of this method is handle_sql2003_note184_exception(),
+ see the code there for more details.
+ Note that this method breaks the object internal integrity, by
+ removing it's association with the corresponding SELECT_LEX,
+ making this object orphan from the parse tree.
+ No other method, beside the destructor, should be called on this
+ object, as it is now invalid.
+ @return the SELECT_LEX structure that was given in the constructor.
+ */
+ st_select_lex* invalidate_and_restore_select_lex();
+
friend class select_singlerow_subselect;
};
@@ -251,13 +271,25 @@ protected:
bool transformed;
public:
/* Used to trigger on/off conditions that were pushed down to subselect */
- bool enable_pushed_conds;
+ bool *pushed_cond_guards;
+
+ bool *get_cond_guard(int i)
+ {
+ return pushed_cond_guards ? pushed_cond_guards + i : NULL;
+ }
+ void set_cond_guard_var(int i, bool v)
+ {
+ if ( pushed_cond_guards)
+ pushed_cond_guards[i]= v;
+ }
+ bool have_guarded_conds() { return test(pushed_cond_guards); }
+
Item_func_not_all *upper_item; // point on NOT/NOP before ALL/SOME subquery
Item_in_subselect(Item * left_expr, st_select_lex *select_lex);
Item_in_subselect()
:Item_exists_subselect(), optimizer(0), abort_on_null(0), transformed(0),
- enable_pushed_conds(TRUE), upper_item(0)
+ pushed_cond_guards(NULL), upper_item(0)
{}
subs_type substype() { return IN_SUBS; }
@@ -323,7 +355,7 @@ public:
result= res;
item= si;
res_type= STRING_RESULT;
- res_field_type= FIELD_TYPE_VAR_STRING;
+ res_field_type= MYSQL_TYPE_VAR_STRING;
maybe_null= 0;
}
virtual ~subselect_engine() {}; // to satisfy compiler
@@ -342,29 +374,28 @@ public:
SYNOPSIS
exec()
- full_scan TRUE - Pushed-down predicates are disabled, the engine
- must disable made based on those predicates.
- FALSE - Pushed-down predicates are in effect.
+
DESCRIPTION
Execute the engine. The result of execution is subquery value that is
either captured by previously set up select_result-based 'sink' or
stored somewhere by the exec() method itself.
- A required side effect: if full_scan==TRUE, subselect_engine->no_rows()
- should return correct result.
+ A required side effect: If at least one pushed-down predicate is
+ disabled, subselect_engine->no_rows() must return correct result after
+ the exec() call.
RETURN
0 - OK
- 1 - Either an execution error, or the engine was be "changed", and
+ 1 - Either an execution error, or the engine was "changed", and the
caller should call exec() again for the new engine.
*/
- virtual int exec(bool full_scan)= 0;
+ virtual int exec()= 0;
virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
enum_field_types field_type() { return res_field_type; }
virtual void exclude()= 0;
- bool may_be_null() { return maybe_null; };
+ virtual bool may_be_null() { return maybe_null; };
virtual table_map upper_select_const_tables()= 0;
static table_map calc_const_tables(TABLE_LIST *);
virtual void print(String *str)= 0;
@@ -393,7 +424,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols();
uint8 uncacheable();
void exclude();
@@ -401,6 +432,7 @@ public:
void print (String *str);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
+ bool may_be_null();
bool is_executed() const { return executed; }
bool no_rows();
};
@@ -416,7 +448,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols();
uint8 uncacheable();
void exclude();
@@ -430,11 +462,30 @@ public:
struct st_join_table;
+
+
+/*
+ A subquery execution engine that evaluates the subquery by doing one index
+ lookup in a unique index.
+
+ This engine is used to resolve subqueries in forms
+
+ outer_expr IN (SELECT tbl.unique_key FROM tbl WHERE subq_where)
+
+ or, tuple-based:
+
+ (oe1, .. oeN) IN (SELECT uniq_key_part1, ... uniq_key_partK
+ FROM tbl WHERE subqwhere)
+
+ i.e. the subquery is a single table SELECT without GROUP BY, aggregate
+ functions, etc.
+*/
+
class subselect_uniquesubquery_engine: public subselect_engine
{
protected:
st_join_table *tab;
- Item *cond;
+ Item *cond; /* The WHERE condition of subselect */
/*
TRUE<=> last execution produced empty set. Valid only when left
expression is NULL.
@@ -454,7 +505,7 @@ public:
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
- int exec(bool full_scan);
+ int exec();
uint cols() { return 1; }
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
void exclude();
@@ -472,16 +523,47 @@ class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{
/* FALSE for 'ref', TRUE for 'ref-or-null'. */
bool check_null;
+ /*
+ The "having" clause. This clause (further reffered to as "artificial
+ having") was inserted by subquery transformation code. It contains
+ Item(s) that have a side-effect: they record whether the subquery has
+ produced a row with NULL certain components. We need to use it for cases
+ like
+ (oe1, oe2) IN (SELECT t.key, t.no_key FROM t1)
+ where we do index lookup on t.key=oe1 but need also to check if there
+ was a row such that t.no_key IS NULL.
+
+ NOTE: This is currently here and not in the uniquesubquery_engine. Ideally
+ it should have been in uniquesubquery_engine in order to allow execution of
+ subqueries like
+
+ (oe1, oe2) IN (SELECT primary_key, non_key_maybe_null_field FROM tbl)
+
+ We could use uniquesubquery_engine for the first component and let
+ Item_is_not_null_test( non_key_maybe_null_field) to handle the second.
+
+ However, subqueries like the above are currently not handled by index
+ lookup-based subquery engines, the engine applicability check misses
+ them: it doesn't switch the engine for case of artificial having and
+ [eq_]ref access (only for artifical having + ref_or_null or no having).
+ The above example subquery is handled as a full-blown SELECT with eq_ref
+ access to one table.
+
+ Due to this limitation, the "artificial having" currently needs to be
+ checked by only in indexsubquery_engine.
+ */
+ Item *having;
public:
// constructor can assign THD because it will be called after JOIN::prepare
- subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
+ subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg,
Item_subselect *subs, Item *where,
- bool chk_null)
- :subselect_uniquesubquery_engine(thd, tab_arg, subs, where),
- check_null(chk_null)
+ Item *having_arg, bool chk_null)
+ :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where),
+ check_null(chk_null),
+ having(having_arg)
{}
- int exec(bool full_scan);
+ int exec();
void print (String *str);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 7ea13e61c23..08ce47573e7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -64,6 +63,7 @@ bool Item_sum::init_sum_func_check(THD *thd)
nest_level= thd->lex->current_select->nest_level;
ref_by= 0;
aggr_level= -1;
+ aggr_sel= NULL;
max_arg_level= -1;
max_sum_func_level= -1;
return FALSE;
@@ -149,9 +149,14 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
if (register_sum_func(thd, ref))
return TRUE;
invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level));
+ if (!invalid && thd->variables.sql_mode & MODE_ANSI)
+ invalid= aggr_level < 0 && max_arg_level < nest_level;
}
if (!invalid && aggr_level < 0)
+ {
aggr_level= nest_level;
+ aggr_sel= thd->lex->current_select;
+ }
/*
By this moment we either found a subquery where the set function is
to be aggregated and assigned a value that is >= 0 to aggr_level,
@@ -161,22 +166,36 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
Additionally we have to check whether possible nested set functions
are acceptable here: they are not, if the level of aggregation of
some of them is less than aggr_level.
- */
- invalid= aggr_level <= max_sum_func_level;
+ */
+ if (!invalid)
+ invalid= aggr_level <= max_sum_func_level;
if (invalid)
{
my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE),
MYF(0));
return TRUE;
}
- if (in_sum_func && in_sum_func->nest_level == nest_level)
+ if (in_sum_func)
{
/*
If the set function is nested adjust the value of
max_sum_func_level for the nesting set function.
+ We take into account only enclosed set functions that are to be
+ aggregated on the same level or above of the nest level of
+ the enclosing set function.
+ But we must always pass up the max_sum_func_level because it is
+ the maximum nested level of all directly and indirectly enclosed
+ set functions. We must do that even for set functions that are
+ aggregated inside of their enclosing set function's nest level
+ because the enclosing function may contain another enclosing
+ function that is to be aggregated outside or on the same level
+ as its parent's nest level.
*/
- set_if_bigger(in_sum_func->max_sum_func_level, aggr_level);
+ if (in_sum_func->nest_level >= aggr_level)
+ set_if_bigger(in_sum_func->max_sum_func_level, aggr_level);
+ set_if_bigger(in_sum_func->max_sum_func_level, max_sum_func_level);
}
+ update_used_tables();
thd->lex->in_sum_func= in_sum_func;
return FALSE;
}
@@ -211,7 +230,6 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
bool Item_sum::register_sum_func(THD *thd, Item **ref)
{
SELECT_LEX *sl;
- SELECT_LEX *aggr_sl= NULL;
nesting_map allow_sum_func= thd->lex->allow_sum_func;
for (sl= thd->lex->current_select->master_unit()->outer_select() ;
sl && sl->nest_level > max_arg_level;
@@ -221,7 +239,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
{
/* Found the most nested subquery where the function can be aggregated */
aggr_level= sl->nest_level;
- aggr_sl= sl;
+ aggr_sel= sl;
}
}
if (sl && (allow_sum_func & (1 << sl->nest_level)))
@@ -232,21 +250,22 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
The set function will be aggregated in this subquery.
*/
aggr_level= sl->nest_level;
- aggr_sl= sl;
+ aggr_sel= sl;
+
}
if (aggr_level >= 0)
{
ref_by= ref;
- /* Add the object to the list of registered objects assigned to aggr_sl */
- if (!aggr_sl->inner_sum_func_list)
+ /* Add the object to the list of registered objects assigned to aggr_sel */
+ if (!aggr_sel->inner_sum_func_list)
next= this;
else
{
- next= aggr_sl->inner_sum_func_list->next;
- aggr_sl->inner_sum_func_list->next= this;
+ next= aggr_sel->inner_sum_func_list->next;
+ aggr_sel->inner_sum_func_list->next= this;
}
- aggr_sl->inner_sum_func_list= this;
- aggr_sl->with_sum_func= 1;
+ aggr_sel->inner_sum_func_list= this;
+ aggr_sel->with_sum_func= 1;
/*
Mark Item_subselect(s) as containing aggregate function all the way up
@@ -264,16 +283,17 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
has aggregate functions directly referenced (i.e. not through a sub-select).
*/
for (sl= thd->lex->current_select;
- sl && sl != aggr_sl && sl->master_unit()->item;
+ sl && sl != aggr_sel && sl->master_unit()->item;
sl= sl->master_unit()->outer_select() )
sl->master_unit()->item->with_sum_func= 1;
}
+ thd->lex->current_select->mark_as_dependent(aggr_sel);
return FALSE;
}
-Item_sum::Item_sum(List<Item> &list)
- :arg_count(list.elements)
+Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
+ forced_const(FALSE)
{
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
{
@@ -297,7 +317,10 @@ Item_sum::Item_sum(List<Item> &list)
Item_sum::Item_sum(THD *thd, Item_sum *item):
Item_result_field(thd, item), arg_count(item->arg_count),
- quick_group(item->quick_group)
+ aggr_sel(item->aggr_sel),
+ nest_level(item->nest_level), aggr_level(item->aggr_level),
+ quick_group(item->quick_group), used_tables_cache(item->used_tables_cache),
+ forced_const(item->forced_const)
{
if (arg_count <= 2)
args=tmp_args;
@@ -380,7 +403,7 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
bool Item_sum::walk (Item_processor processor, bool walk_subquery,
- byte *argument)
+ uchar *argument)
{
if (arg_count)
{
@@ -401,14 +424,14 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
Field *field;
switch (result_type()) {
case REAL_RESULT:
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
break;
case INT_RESULT:
field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
break;
case STRING_RESULT:
if (max_length/collation.collation->mbmaxlen <= 255 ||
- max_length/collation.collation->mbmaxlen >=UINT_MAX16 ||
+ convert_blob_length > Field_varstring::MAX_SIZE ||
!convert_blob_length)
return make_string_field(table);
field= new Field_varstring(convert_blob_length, maybe_null,
@@ -430,6 +453,25 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
}
+void Item_sum::update_used_tables ()
+{
+ if (!forced_const)
+ {
+ used_tables_cache= 0;
+ for (uint i=0 ; i < arg_count ; i++)
+ {
+ args[i]->update_used_tables();
+ used_tables_cache|= args[i]->used_tables();
+ }
+
+ used_tables_cache&= PSEUDO_TABLE_BITS;
+
+ /* the aggregate function is aggregated into its local context */
+ used_tables_cache |= (1 << aggr_sel->join->tables) - 1;
+ }
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
@@ -489,7 +531,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
- used_table_cache(item->used_table_cache), was_values(item->was_values)
+ was_values(item->was_values)
{
/* copy results from old value */
switch (hybrid_type) {
@@ -1060,14 +1102,8 @@ void Item_sum_count::clear()
bool Item_sum_count::add()
{
- if (!args[0]->maybe_null)
+ if (!args[0]->maybe_null || !args[0]->is_null())
count++;
- else
- {
- args[0]->update_null_value();
- if (!args[0]->null_value)
- count++;
- }
return 0;
}
@@ -1083,7 +1119,6 @@ void Item_sum_count::cleanup()
DBUG_ENTER("Item_sum_count::cleanup");
count= 0;
Item_sum_int::cleanup();
- used_table_cache= ~(table_map) 0;
DBUG_VOID_RETURN;
}
@@ -1106,8 +1141,10 @@ void Item_sum_avg::fix_length_and_dec()
f_scale= args[0]->decimals;
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
}
- else
+ else {
decimals= min(args[0]->decimals + prec_increment, NOT_FIXED_DEC);
+ max_length= args[0]->max_length + prec_increment;
+ }
}
@@ -1125,7 +1162,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
{
/*
We must store both value and counter in the temporary table in one field.
- The easyest way is to do this is to store both value in a string
+ The easiest way is to do this is to store both value in a string
and unpack on access.
*/
field= new Field_string(((hybrid_type == DECIMAL_RESULT) ?
@@ -1136,7 +1173,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
field= new Field_new_decimal(max_length, maybe_null, name,
decimals, unsigned_flag);
else
- field= new Field_double(max_length, maybe_null, name, decimals);
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
if (field)
field->init(table);
return field;
@@ -1173,7 +1210,7 @@ double Item_sum_avg::val_real()
my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
{
- my_decimal sum, cnt;
+ my_decimal sum_buff, cnt;
const my_decimal *sum_dec;
DBUG_ASSERT(fixed == 1);
if (!count)
@@ -1181,7 +1218,7 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
null_value=1;
return NULL;
}
- sum_dec= Item_sum_sum::val_decimal(&sum);
+ sum_dec= Item_sum_sum::val_decimal(&sum_buff);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment);
return val;
@@ -1203,8 +1240,9 @@ String *Item_sum_avg::val_str(String *str)
double Item_sum_std::val_real()
{
DBUG_ASSERT(fixed == 1);
- double tmp= Item_sum_variance::val_real();
- return tmp <= 0.0 ? 0.0 : sqrt(tmp);
+ double nr= Item_sum_variance::val_real();
+ DBUG_ASSERT(nr >= 0.0);
+ return sqrt(nr);
}
Item *Item_sum_std::copy_or_same(THD* thd)
@@ -1218,40 +1256,77 @@ Item *Item_sum_std::copy_or_same(THD* thd)
*/
-Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
- Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
- cur_dec(item->cur_dec), count(item->count), sample(item->sample),
- prec_increment(item->prec_increment)
+/**
+ Variance implementation for floating-point implementations, without
+ catastrophic cancellation, from Knuth's _TAoCP_, 3rd ed, volume 2, pg232.
+ This alters the value at m, s, and increments count.
+*/
+
+/*
+ These two functions are used by the Item_sum_variance and the
+ Item_variance_field classes, which are unrelated, and each need to calculate
+ variance. The difference between the two classes is that the first is used
+ for a mundane SELECT, while the latter is used in a GROUPing SELECT.
+*/
+static void variance_fp_recurrence_next(double *m, double *s, ulonglong *count, double nr)
{
- if (hybrid_type == DECIMAL_RESULT)
+ *count += 1;
+
+ if (*count == 1)
{
- memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum));
- memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr));
- for (int i=0; i<2; i++)
- {
- dec_sum[i].fix_buffer_pointer();
- dec_sqr[i].fix_buffer_pointer();
- }
+ *m= nr;
+ *s= 0;
}
else
{
- sum= item->sum;
- sum_sqr= item->sum_sqr;
+ double m_kminusone= *m;
+ *m= m_kminusone + (nr - m_kminusone) / (double) *count;
+ *s= *s + (nr - m_kminusone) * (nr - *m);
}
}
+static double variance_fp_recurrence_result(double s, ulonglong count, bool is_sample_variance)
+{
+ if (count == 1)
+ return 0.0;
+
+ if (is_sample_variance)
+ return s / (count - 1);
+
+ /* else, is a population variance */
+ return s / count;
+}
+
+
+Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
+ Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ count(item->count), sample(item->sample),
+ prec_increment(item->prec_increment)
+{
+ recurrence_m= item->recurrence_m;
+ recurrence_s= item->recurrence_s;
+}
+
+
void Item_sum_variance::fix_length_and_dec()
{
DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
maybe_null= null_value= 1;
prec_increment= current_thd->variables.div_precincrement;
+
+ /*
+ According to the SQL2003 standard (Part 2, Foundations; sec 10.9,
+ aggregate function; paragraph 7h of Syntax Rules), "the declared
+ type of the result is an implementation-defined aproximate numeric
+ type.
+ */
+ hybrid_type= REAL_RESULT;
+
switch (args[0]->result_type()) {
case REAL_RESULT:
case STRING_RESULT:
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
- hybrid_type= REAL_RESULT;
- sum= 0.0;
break;
case INT_RESULT:
case DECIMAL_RESULT:
@@ -1260,37 +1335,14 @@ void Item_sum_variance::fix_length_and_dec()
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
- cur_dec= 0;
- hybrid_type= DECIMAL_RESULT;
- my_decimal_set_zero(dec_sum);
- my_decimal_set_zero(dec_sqr);
- /*
- The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2
- becasue we need to be able to calculate in dec_bin_size1
- column_value * column_value
- */
- f_scale0= args[0]->decimals;
- f_precision0= min(args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS,
- DECIMAL_MAX_PRECISION);
- f_scale1= min(args[0]->decimals * 2, DECIMAL_MAX_SCALE);
- f_precision1= min(args[0]->decimal_precision()*2 + DECIMAL_LONGLONG_DIGITS,
- DECIMAL_MAX_PRECISION);
- dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0);
- dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1);
break;
}
case ROW_RESULT:
default:
DBUG_ASSERT(0);
}
- DBUG_PRINT("info", ("Type: %s (%d, %d)",
- (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
- hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
- hybrid_type == INT_RESULT ? "INT_RESULT" :
- "--ILLEGAL!!!--"),
- max_length,
- (int)decimals));
+ DBUG_PRINT("info", ("Type: REAL_RESULT (%d, %d)", max_length, (int)decimals));
DBUG_VOID_RETURN;
}
@@ -1301,6 +1353,11 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
}
+/**
+ Create a new field to match the type of value we're expected to yield.
+ If we're grouping, then we need some space to serialize variables into, to
+ pass around.
+*/
Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
uint convert_blob_len)
{
@@ -1309,201 +1366,114 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
{
/*
We must store both value and counter in the temporary table in one field.
- The easyest way is to do this is to store both value in a string
+ The easiest way is to do this is to store both value in a string
and unpack on access.
*/
- field= new Field_string(((hybrid_type == DECIMAL_RESULT) ?
- dec_bin_size0 + dec_bin_size1 :
- sizeof(double)*2) + sizeof(longlong),
- 0, name, &my_charset_bin);
+ field= new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, &my_charset_bin);
}
else
- {
- field= new Field_double(max_length, maybe_null,name, decimals);
- }
- if (field)
+ field= new Field_double(max_length, maybe_null, name, decimals, TRUE);
+
+ if (field != NULL)
field->init(table);
+
return field;
}
void Item_sum_variance::clear()
{
- if (hybrid_type == DECIMAL_RESULT)
- {
- my_decimal_set_zero(dec_sum);
- my_decimal_set_zero(dec_sqr);
- cur_dec= 0;
- }
- else
- sum=sum_sqr=0.0;
- count=0;
+ count= 0;
}
bool Item_sum_variance::add()
{
- if (hybrid_type == DECIMAL_RESULT)
- {
- my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf);
- my_decimal sqr_buf;
- if (!args[0]->null_value)
- {
- count++;
- int next_dec= cur_dec ^ 1;
- my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
- my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec,
- dec_sqr+cur_dec, &sqr_buf);
- my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec,
- dec_sum+cur_dec, dec);
- cur_dec= next_dec;
- }
- }
- else
- {
- double nr= args[0]->val_real();
- if (!args[0]->null_value)
- {
- sum+=nr;
- sum_sqr+=nr*nr;
- count++;
- }
- }
+ /*
+ Why use a temporary variable? We don't know if it is null until we
+ evaluate it, which has the side-effect of setting null_value .
+ */
+ double nr= args[0]->val_real();
+
+ if (!args[0]->null_value)
+ variance_fp_recurrence_next(&recurrence_m, &recurrence_s, &count, nr);
return 0;
}
double Item_sum_variance::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (hybrid_type == DECIMAL_RESULT)
- return val_real_from_decimal();
+ /*
+ 'sample' is a 1/0 boolean value. If it is 1/true, id est this is a sample
+ variance call, then we should set nullness when the count of the items
+ is one or zero. If it's zero, i.e. a population variance, then we only
+ set nullness when the count is zero.
+
+ Another way to read it is that 'sample' is the numerical threshhold, at and
+ below which a 'count' number of items is called NULL.
+ */
+ DBUG_ASSERT((sample == 0) || (sample == 1));
if (count <= sample)
{
null_value=1;
return 0.0;
}
+
null_value=0;
- /* Avoid problems when the precision isn't good enough */
- double tmp=ulonglong2double(count);
- double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample);
- return tmp2 <= 0.0 ? 0.0 : tmp2;
+ return variance_fp_recurrence_result(recurrence_s, count, sample);
}
my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
{
- my_decimal count_buf, count1_buf, sum_sqr_buf;
- DBUG_ASSERT(fixed ==1 );
- if (hybrid_type == REAL_RESULT)
- return val_decimal_from_real(dec_buf);
-
- if (count <= sample)
- {
- null_value= 1;
- return 0;
- }
- null_value= 0;
- int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf);
- int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &count1_buf);
- my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
- dec_sum+cur_dec, dec_sum+cur_dec);
- my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
- &sum_sqr_buf, &count_buf, prec_increment);
- my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf);
- my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
- &sum_sqr_buf, &count1_buf, prec_increment);
- return dec_buf;
+ DBUG_ASSERT(fixed == 1);
+ return val_decimal_from_real(dec_buf);
}
void Item_sum_variance::reset_field()
{
double nr;
- char *res= result_field->ptr;
+ uchar *res= result_field->ptr;
- if (hybrid_type == DECIMAL_RESULT)
- {
- my_decimal value, *arg_dec, *arg2_dec;
- longlong tmp;
-
- arg_dec= args[0]->val_decimal(&value);
- if (args[0]->null_value)
- {
- arg_dec= arg2_dec= &decimal_zero;
- tmp= 0;
- }
- else
- {
- my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec);
- arg2_dec= dec_sum;
- tmp= 1;
- }
- my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
- res, f_precision0, f_scale0);
- my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec,
- res+dec_bin_size0, f_precision1, f_scale1);
- res+= dec_bin_size0 + dec_bin_size1;
- int8store(res,tmp);
- return;
- }
- nr= args[0]->val_real();
+ nr= args[0]->val_real(); /* sets null_value as side-effect */
if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong));
else
{
- longlong tmp;
- float8store(res,nr);
- nr*=nr;
- float8store(res+sizeof(double),nr);
- tmp= 1;
- int8store(res+sizeof(double)*2,tmp);
+ /* Serialize format is (double)m, (double)s, (longlong)count */
+ ulonglong tmp_count;
+ double tmp_s;
+ float8store(res, nr); /* recurrence variable m */
+ tmp_s= 0.0;
+ float8store(res + sizeof(double), tmp_s);
+ tmp_count= 1;
+ int8store(res + sizeof(double)*2, tmp_count);
}
}
void Item_sum_variance::update_field()
{
- longlong field_count;
- char *res=result_field->ptr;
- if (hybrid_type == DECIMAL_RESULT)
- {
- my_decimal value, *arg_val= args[0]->val_decimal(&value);
- if (!args[0]->null_value)
- {
- binary2my_decimal(E_DEC_FATAL_ERROR, res,
- dec_sum+1, f_precision0, f_scale0);
- binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0,
- dec_sqr+1, f_precision1, f_scale1);
- field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1));
- my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1);
- my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val);
- my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1);
- field_count++;
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
- res, f_precision0, f_scale0);
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr,
- res+dec_bin_size0, f_precision1, f_scale1);
- res+= dec_bin_size0 + dec_bin_size1;
- int8store(res, field_count);
- }
+ ulonglong field_count;
+ uchar *res=result_field->ptr;
+
+ double nr= args[0]->val_real(); /* sets null_value as side-effect */
+
+ if (args[0]->null_value)
return;
- }
- double nr,old_nr,old_sqr;
- float8get(old_nr, res);
- float8get(old_sqr, res+sizeof(double));
+ /* Serialize format is (double)m, (double)s, (longlong)count */
+ double field_recurrence_m, field_recurrence_s;
+ float8get(field_recurrence_m, res);
+ float8get(field_recurrence_s, res + sizeof(double));
field_count=sint8korr(res+sizeof(double)*2);
- nr= args[0]->val_real();
- if (!args[0]->null_value)
- {
- old_nr+=nr;
- old_sqr+=nr*nr;
- field_count++;
- }
- float8store(res,old_nr);
- float8store(res+sizeof(double),old_sqr);
+ variance_fp_recurrence_next(&field_recurrence_m, &field_recurrence_s, &field_count, nr);
+
+ float8store(res, field_recurrence_m);
+ float8store(res + sizeof(double), field_recurrence_s);
res+= sizeof(double)*2;
int8store(res,field_count);
}
@@ -1640,7 +1610,7 @@ void Item_sum_hybrid::cleanup()
{
DBUG_ENTER("Item_sum_hybrid::cleanup");
Item_sum::cleanup();
- used_table_cache= ~(table_map) 0;
+ forced_const= FALSE;
/*
by default it is TRUE to avoid TRUE reporting by
@@ -1695,7 +1665,7 @@ bool Item_sum_min::add()
break;
case DECIMAL_RESULT:
{
- my_decimal value, *val= args[0]->val_decimal(&value);
+ my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
{
@@ -1759,7 +1729,7 @@ bool Item_sum_max::add()
break;
case DECIMAL_RESULT:
{
- my_decimal value, *val= args[0]->val_decimal(&value);
+ my_decimal value_buff, *val= args[0]->val_decimal(&value_buff);
if (!args[0]->null_value &&
(null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
{
@@ -1851,7 +1821,7 @@ bool Item_sum_and::add()
void Item_sum_num::reset_field()
{
double nr= args[0]->val_real();
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
if (maybe_null)
{
@@ -1924,7 +1894,7 @@ void Item_sum_hybrid::reset_field()
}
case DECIMAL_RESULT:
{
- my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
if (maybe_null)
{
@@ -1973,24 +1943,18 @@ void Item_sum_sum::reset_field()
void Item_sum_count::reset_field()
{
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
longlong nr=0;
- if (!args[0]->maybe_null)
+ if (!args[0]->maybe_null || !args[0]->is_null())
nr=1;
- else
- {
- args[0]->update_null_value();
- if (!args[0]->null_value)
- nr=1;
- }
int8store(res,nr);
}
void Item_sum_avg::reset_field()
{
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
if (hybrid_type == DECIMAL_RESULT)
{
longlong tmp;
@@ -2031,7 +1995,7 @@ void Item_sum_bit::reset_field()
void Item_sum_bit::update_field()
{
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
bits= uint8korr(res);
add();
int8store(res, bits);
@@ -2066,7 +2030,7 @@ void Item_sum_sum::update_field()
else
{
double old_nr,nr;
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
float8get(old_nr,res);
nr= args[0]->val_real();
@@ -2083,17 +2047,11 @@ void Item_sum_sum::update_field()
void Item_sum_count::update_field()
{
longlong nr;
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
nr=sint8korr(res);
- if (!args[0]->maybe_null)
+ if (!args[0]->maybe_null || !args[0]->is_null())
nr++;
- else
- {
- args[0]->update_null_value();
- if (!args[0]->null_value)
- nr++;
- }
int8store(res,nr);
}
@@ -2101,7 +2059,7 @@ void Item_sum_count::update_field()
void Item_sum_avg::update_field()
{
longlong field_count;
- char *res=result_field->ptr;
+ uchar *res=result_field->ptr;
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal value, *arg_val= args[0]->val_decimal(&value);
@@ -2270,7 +2228,7 @@ double Item_avg_field::val_real()
// fix_fields() never calls for this Item
double nr;
longlong count;
- char *res;
+ uchar *res;
if (hybrid_type == DECIMAL_RESULT)
return val_real_from_decimal();
@@ -2330,25 +2288,9 @@ double Item_std_field::val_real()
{
double nr;
// fix_fields() never calls for this Item
- if (hybrid_type == REAL_RESULT)
- {
- /*
- We can't call Item_variance_field::val_real() on a DECIMAL_RESULT
- as this would call Item_std_field::val_decimal() and we would
- calculate sqrt() twice
- */
- nr= Item_variance_field::val_real();
- }
- else
- {
- my_decimal dec_buf,*dec;
- dec= Item_variance_field::val_decimal(&dec_buf);
- if (!dec)
- nr= 0.0; // NULL; Return 0.0
- else
- my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
- }
- return nr <= 0.0 ? 0.0 : sqrt(nr);
+ nr= Item_variance_field::val_real();
+ DBUG_ASSERT(nr >= 0.0);
+ return sqrt(nr);
}
@@ -2362,11 +2304,13 @@ my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf)
double nr;
if (hybrid_type == REAL_RESULT)
return val_decimal_from_real(dec_buf);
+
dec= Item_variance_field::val_decimal(dec_buf);
if (!dec)
return 0;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr);
- nr= nr <= 0.0 ? 0.0 : sqrt(nr);
+ DBUG_ASSERT(nr >= 0.0);
+ nr= sqrt(nr);
double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec);
my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf);
return dec_buf;
@@ -2401,52 +2345,15 @@ double Item_variance_field::val_real()
if (hybrid_type == DECIMAL_RESULT)
return val_real_from_decimal();
- double sum,sum_sqr;
- longlong count;
- float8get(sum,field->ptr);
- float8get(sum_sqr,(field->ptr+sizeof(double)));
+ double recurrence_s;
+ ulonglong count;
+ float8get(recurrence_s, (field->ptr + sizeof(double)));
count=sint8korr(field->ptr+sizeof(double)*2);
if ((null_value= (count <= sample)))
return 0.0;
- double tmp= (double) count;
- double tmp2= (sum_sqr - sum*sum/tmp)/(tmp - (double)sample);
- return tmp2 <= 0.0 ? 0.0 : tmp2;
-}
-
-
-String *Item_variance_field::val_str(String *str)
-{
- if (hybrid_type == DECIMAL_RESULT)
- return val_string_from_decimal(str);
- return val_string_from_real(str);
-}
-
-
-my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
-{
- // fix_fields() never calls for this Item
- if (hybrid_type == REAL_RESULT)
- return val_decimal_from_real(dec_buf);
-
- longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
- if ((null_value= (count <= sample)))
- return 0;
-
- my_decimal dec_count, dec1_count, dec_sum, dec_sqr, tmp;
- int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
- int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &dec1_count);
- binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr,
- &dec_sum, f_precision0, f_scale0);
- binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0,
- &dec_sqr, f_precision1, f_scale1);
- my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum);
- my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, prec_increment);
- my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf);
- my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
- &dec_sum, &dec1_count, prec_increment);
- return dec_buf;
+ return variance_fp_recurrence_result(recurrence_s, count, sample);
}
@@ -2454,10 +2361,10 @@ my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
** COUNT(DISTINCT ...)
****************************************************************************/
-int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
+int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2)
{
Field *f= (Field*) arg;
- return f->cmp((const char*)key1, (const char*)key2);
+ return f->cmp(key1, key2);
}
/*
@@ -2467,7 +2374,7 @@ int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
static
*/
-int composite_key_cmp(void* arg, byte* key1, byte* key2)
+int composite_key_cmp(void* arg, uchar* key1, uchar* key2)
{
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
Field **field = item->table->field;
@@ -2477,7 +2384,7 @@ int composite_key_cmp(void* arg, byte* key1, byte* key2)
{
Field* f = *field;
int len = *lengths++;
- int res = f->cmp((char *) key1, (char *) key2);
+ int res = f->cmp(key1, key2);
if (res)
return res;
key1 += len;
@@ -2568,12 +2475,8 @@ bool Item_sum_count_distinct::setup(THD *thd)
Item *item=args[i];
if (list.push_back(item))
return TRUE; // End of memory
- if (item->const_item())
- {
- item->update_null_value();
- if (item->null_value)
- always_null=1;
- }
+ if (item->const_item() && item->is_null())
+ always_null= 1;
}
if (always_null)
return FALSE;
@@ -2588,7 +2491,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
- if (table->s->db_type == heap_hton)
+ if (table->s->db_type() == heap_hton)
{
/*
No blobs, otherwise it would have been MyISAM: set up a compare
@@ -2603,11 +2506,11 @@ bool Item_sum_count_distinct::setup(THD *thd)
for (tree_key_length= 0; field < field_end; ++field)
{
Field *f= *field;
- enum enum_field_types type= f->type();
+ enum enum_field_types f_type= f->type();
tree_key_length+= f->pack_length();
- if ((type == MYSQL_TYPE_VARCHAR) ||
- !f->binary() && (type == MYSQL_TYPE_STRING ||
- type == MYSQL_TYPE_VAR_STRING))
+ if ((f_type == MYSQL_TYPE_VARCHAR) ||
+ !f->binary() && (f_type == MYSQL_TYPE_STRING ||
+ f_type == MYSQL_TYPE_VAR_STRING))
{
all_binary= FALSE;
break;
@@ -2936,8 +2839,8 @@ String *Item_sum_udf_str::val_str(String *str)
GROUP_CONCAT(DISTINCT expr,...)
*/
-int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
- byte* key2)
+int group_concat_key_cmp_with_distinct(void* arg, uchar* key1,
+ uchar* key2)
{
Item_func_group_concat* grp_item= (Item_func_group_concat*)arg;
TABLE *table= grp_item->table;
@@ -2962,7 +2865,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
int res;
uint offset= (field->offset(field->table->record[0]) -
table->s->null_bytes);
- if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset)))
+ if ((res= field->cmp(key1 + offset, key2 + offset)))
return res;
}
}
@@ -2975,7 +2878,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
GROUP_CONCAT(expr,... ORDER BY col,... )
*/
-int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
+int group_concat_key_cmp_with_order(void* arg, uchar* key1, uchar* key2)
{
Item_func_group_concat* grp_item= (Item_func_group_concat*) arg;
ORDER **order_item, **end;
@@ -3001,7 +2904,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
int res;
uint offset= (field->offset(field->table->record[0]) -
table->s->null_bytes);
- if ((res= field->cmp((char *) key1 + offset, (char *) key2 + offset)))
+ if ((res= field->cmp(key1 + offset, key2 + offset)))
return (*order_item)->asc ? res : -res;
}
}
@@ -3024,8 +2927,8 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
the duplicated values when inserting things sorted by ORDER BY
*/
-int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
- byte* key2)
+int group_concat_key_cmp_with_distinct_and_order(void* arg,uchar* key1,
+ uchar* key2)
{
if (!group_concat_key_cmp_with_distinct(arg,key1,key2))
return 0;
@@ -3037,7 +2940,7 @@ int group_concat_key_cmp_with_distinct_and_order(void* arg,byte* key1,
Append data from current leaf to item->result
*/
-int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
+int dump_leaf_key(uchar* key, element_count count __attribute__((unused)),
Item_func_group_concat *item)
{
TABLE *table= item->table;
@@ -3071,7 +2974,7 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)),
uint offset= (field->offset(field->table->record[0]) -
table->s->null_bytes);
DBUG_ASSERT(offset < table->s->reclength);
- res= field->val_str(&tmp, (char *) key + offset);
+ res= field->val_str(&tmp, key + offset);
}
else
res= (*arg)->val_str(&tmp);
@@ -3192,8 +3095,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd,
void Item_func_group_concat::cleanup()
{
- THD *thd= current_thd;
-
DBUG_ENTER("Item_func_group_concat::cleanup");
Item_sum::cleanup();
@@ -3202,7 +3103,7 @@ void Item_func_group_concat::cleanup()
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values);
- warning->set_msg(thd, warn_buff);
+ warning->set_msg(current_thd, warn_buff);
warning= 0;
}
@@ -3232,8 +3133,7 @@ void Item_func_group_concat::cleanup()
warning= 0;
}
}
- DBUG_ASSERT(tree == 0);
- DBUG_ASSERT(warning == 0);
+ DBUG_ASSERT(tree == 0 && warning == 0);
}
DBUG_VOID_RETURN;
}
@@ -3390,14 +3290,20 @@ bool Item_func_group_concat::setup(THD *thd)
tmp_table_param->force_copy_fields= force_copy_fields;
DBUG_ASSERT(table == 0);
/*
+ Currently we have to force conversion of BLOB values to VARCHAR's
+ if we are to store them in TREE objects used for ORDER BY and
+ DISTINCT. This leads to truncation if the BLOB's size exceeds
+ Field_varstring::MAX_SIZE.
+ */
+ if (arg_count_order > 0 || distinct)
+ set_if_smaller(tmp_table_param->convert_blob_length,
+ Field_varstring::MAX_SIZE);
+ /*
We have to create a temporary table to get descriptions of fields
(types, sizes and so on).
Note that in the table, we first have the ORDER BY fields, then the
field list.
-
- We need to set set_sum_field in true for storing value of blob in buffer
- of a record instead of a pointer of one.
*/
if (!(table= create_tmp_table(thd, tmp_table_param, all_fields,
(ORDER*) 0, 0, TRUE,
@@ -3460,6 +3366,10 @@ String* Item_func_group_concat::val_str(String* str)
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
+ if (!result.length() && tree)
+ /* Tree is used for sorting as in ORDER BY */
+ tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
+ left_root_right);
if (count_cut_values && !warning)
{
/*
@@ -3471,11 +3381,6 @@ String* Item_func_group_concat::val_str(String* str)
ER_CUT_VALUE_GROUP_CONCAT,
ER(ER_CUT_VALUE_GROUP_CONCAT));
}
- if (result.length())
- return &result;
- if (tree)
- tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this,
- left_root_right);
return &result;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index acd23d1ff4c..84b425755d1 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -216,14 +215,16 @@
TODO: to catch queries where the limit is exceeded to make the
code clean here.
-*/
+*/
+
+class st_select_lex;
class Item_sum :public Item_result_field
{
public:
enum Sumfunctype
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
- AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC,
+ AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC,
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
};
@@ -232,25 +233,32 @@ public:
Item_sum *next; /* next in the circular chain of registered objects */
uint arg_count;
Item_sum *in_sum_func; /* embedding set function if any */
+ st_select_lex * aggr_sel; /* select where the function is aggregated */
int8 nest_level; /* number of the nesting level of the set function */
int8 aggr_level; /* nesting level of the aggregating subquery */
int8 max_arg_level; /* max level of unbound column references */
int8 max_sum_func_level;/* max level of aggregation for embedded functions */
bool quick_group; /* If incremental update of fields */
+protected:
+ table_map used_tables_cache;
+ bool forced_const;
+
+public:
+
void mark_as_sum_func();
- Item_sum() :arg_count(0), quick_group(1)
+ Item_sum() :arg_count(0), quick_group(1), forced_const(FALSE)
{
mark_as_sum_func();
}
- Item_sum(Item *a)
- :args(tmp_args), arg_count(1), quick_group(1)
+ Item_sum(Item *a) :args(tmp_args), arg_count(1), quick_group(1),
+ forced_const(FALSE)
{
args[0]=a;
mark_as_sum_func();
}
- Item_sum( Item *a, Item *b )
- :args(tmp_args), arg_count(2), quick_group(1)
+ Item_sum( Item *a, Item *b ) :args(tmp_args), arg_count(2), quick_group(1),
+ forced_const(FALSE)
{
args[0]=a; args[1]=b;
mark_as_sum_func();
@@ -320,10 +328,20 @@ public:
virtual const char *func_name() const= 0;
virtual Item *result_item(Field *field)
{ return new Item_field(field); }
- table_map used_tables() const { return ~(table_map) 0; } /* Not used */
- bool const_item() const { return 0; }
+ table_map used_tables() const { return used_tables_cache; }
+ void update_used_tables ();
+ void cleanup()
+ {
+ Item::cleanup();
+ forced_const= FALSE;
+ }
bool is_null() { return null_value; }
- void update_used_tables() { }
+ void make_const ()
+ {
+ used_tables_cache= 0;
+ forced_const= TRUE;
+ }
+ virtual bool const_item() const { return forced_const; }
void make_field(Send_field *field);
void print(String *str);
void fix_num_length_and_dec();
@@ -343,10 +361,12 @@ public:
Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
- bool walk(Item_processor processor, bool walk_subquery, byte *argument);
+ bool walk(Item_processor processor, bool walk_subquery, uchar *argument);
bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref);
bool register_sum_func(THD *thd, Item **ref);
+ st_select_lex *depended_from()
+ { return (nest_level == aggr_level ? 0 : aggr_sel); }
};
@@ -510,23 +530,23 @@ public:
class Item_sum_count :public Item_sum_int
{
longlong count;
- table_map used_table_cache;
public:
Item_sum_count(Item *item_par)
- :Item_sum_int(item_par),count(0),used_table_cache(~(table_map) 0)
+ :Item_sum_int(item_par),count(0)
{}
Item_sum_count(THD *thd, Item_sum_count *item)
- :Item_sum_int(thd, item), count(item->count),
- used_table_cache(item->used_table_cache)
+ :Item_sum_int(thd, item), count(item->count)
{}
- table_map used_tables() const { return used_table_cache; }
- bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
void clear();
void no_rows_in_result() { count=0; }
bool add();
- void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
+ void make_const(longlong count_arg)
+ {
+ count=count_arg;
+ Item_sum::make_const();
+ }
longlong val_int();
void reset_field();
void cleanup();
@@ -567,8 +587,8 @@ class Item_sum_count_distinct :public Item_sum_int
bool always_null; // Set to 1 if the result is always NULL
- friend int composite_key_cmp(void* arg, byte* key1, byte* key2);
- friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2);
+ friend int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
+ friend int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2);
public:
Item_sum_count_distinct(List<Item> &list)
@@ -683,8 +703,10 @@ public:
double val_real();
longlong val_int()
{ /* can't be fix_fields()ed */ return (longlong) rint(val_real()); }
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *);
+ String *val_str(String *str)
+ { return val_string_from_real(str); }
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ { return val_decimal_from_real(dec_buf); }
bool is_null() { update_null_value(); return null_value; }
enum_field_types field_type() const
{
@@ -706,6 +728,14 @@ public:
= (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) =
= (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) =
= (sum(ai^2) - sum(a)^2/count(a))/count(a)
+
+But, this falls prey to catastrophic cancellation. Instead, use the recurrence formulas
+
+ M_{1} = x_{1}, ~ M_{k} = M_{k-1} + (x_{k} - M_{k-1}) / k newline
+ S_{1} = 0, ~ S_{k} = S_{k-1} + (x_{k} - M_{k-1}) times (x_{k} - M_{k}) newline
+ for 2 <= k <= n newline
+ ital variance = S_{n} / (n-1)
+
*/
class Item_sum_variance : public Item_sum_num
@@ -714,9 +744,8 @@ class Item_sum_variance : public Item_sum_num
public:
Item_result hybrid_type;
- double sum, sum_sqr;
- my_decimal dec_sum[2], dec_sqr[2];
int cur_dec;
+ double recurrence_m, recurrence_s; /* Used in recurrence relation. */
ulonglong count;
uint f_precision0, f_scale0;
uint f_precision1, f_scale1;
@@ -725,7 +754,7 @@ public:
uint prec_increment;
Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par),
- hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg)
+ hybrid_type(REAL_RESULT), count(0), sample(sample_arg)
{}
Item_sum_variance(THD *thd, Item_sum_variance *item);
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
@@ -745,7 +774,6 @@ public:
enum Item_result result_type () const { return REAL_RESULT; }
void cleanup()
{
- cur_dec= 0;
count= 0;
Item_sum_num::cleanup();
}
@@ -798,28 +826,22 @@ protected:
Item_result hybrid_type;
enum_field_types hybrid_field_type;
int cmp_sign;
- table_map used_table_cache;
bool was_values; // Set if we have found at least one row (for max/min only)
public:
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
- hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
- cmp_sign(sign), used_table_cache(~(table_map) 0),
- was_values(TRUE)
+ hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG),
+ cmp_sign(sign), was_values(TRUE)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
bool fix_fields(THD *, Item **);
- table_map used_tables() const { return used_table_cache; }
- bool const_item() const { return !used_table_cache; }
-
void clear();
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
void reset_field();
String *val_str(String *);
- void make_const() { used_table_cache=0; }
bool keep_field_type(void) const { return 1; }
enum Item_result result_type () const { return hybrid_type; }
enum enum_field_types field_type() const { return hybrid_field_type; }
@@ -1161,14 +1183,14 @@ class Item_func_group_concat : public Item_sum
*/
Item_func_group_concat *original;
- friend int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
- byte* key2);
- friend int group_concat_key_cmp_with_order(void* arg, byte* key1,
- byte* key2);
+ friend int group_concat_key_cmp_with_distinct(void* arg, uchar* key1,
+ uchar* key2);
+ friend int group_concat_key_cmp_with_order(void* arg, uchar* key1,
+ uchar* key2);
friend int group_concat_key_cmp_with_distinct_and_order(void* arg,
- byte* key1,
- byte* key2);
- friend int dump_leaf_key(byte* key,
+ uchar* key1,
+ uchar* key2);
+ friend int dump_leaf_key(uchar* key,
element_count count __attribute__((unused)),
Item_func_group_concat *group_concat_item);
@@ -1187,7 +1209,7 @@ public:
enum_field_types field_type() const
{
if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB )
- return FIELD_TYPE_BLOB;
+ return MYSQL_TYPE_BLOB;
else
return MYSQL_TYPE_VARCHAR;
}
@@ -1221,6 +1243,6 @@ public:
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
void print(String *str);
- virtual bool change_context_processor(byte *cntx)
+ virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index cb28fab8b0e..6f38a1acc67 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -47,7 +46,7 @@
the microseconds twice.
*/
-static bool make_datetime(date_time_format_types format, TIME *ltime,
+static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
String *str)
{
char *buff;
@@ -96,7 +95,7 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
/*
- Wrapper over make_datetime() with validation of the input TIME value
+ Wrapper over make_datetime() with validation of the input MYSQL_TIME value
NOTE
see make_datetime() for more information
@@ -106,7 +105,7 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
0 otherwise
*/
-static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime,
+static bool make_datetime_with_warn(date_time_format_types format, MYSQL_TIME *ltime,
String *str)
{
int warning= 0;
@@ -118,14 +117,15 @@ static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime,
if (!warning)
return 0;
- make_truncated_value_warning(current_thd, str->ptr(), str->length(),
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ str->ptr(), str->length(),
MYSQL_TIMESTAMP_TIME, NullS);
return make_datetime(format, ltime, str);
}
/*
- Wrapper over make_time() with validation of the input TIME value
+ Wrapper over make_time() with validation of the input MYSQL_TIME value
NOTE
see make_time() for more info
@@ -136,7 +136,7 @@ static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime,
*/
static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
- TIME *l_time, String *str)
+ MYSQL_TIME *l_time, String *str)
{
int warning= 0;
make_time(format, l_time, str);
@@ -144,7 +144,8 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
return 1;
if (warning)
{
- make_truncated_value_warning(current_thd, str->ptr(), str->length(),
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ str->ptr(), str->length(),
MYSQL_TIMESTAMP_TIME, NullS);
make_time(format, l_time, str);
}
@@ -154,16 +155,16 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
/*
- Convert seconds to TIME value with overflow checking
+ Convert seconds to MYSQL_TIME value with overflow checking
SYNOPSIS:
sec_to_time()
seconds number of seconds
unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise
- ltime output TIME value
+ ltime output MYSQL_TIME value
DESCRIPTION
- If the 'seconds' argument is inside TIME data range, convert it to a
+ If the 'seconds' argument is inside MYSQL_TIME data range, convert it to a
corresponding value.
Otherwise, truncate the resulting value to the nearest endpoint, and
produce a warning message.
@@ -173,7 +174,7 @@ static bool make_time_with_warn(const DATE_TIME_FORMAT *format,
0 otherwise
*/
-static bool sec_to_time(longlong seconds, bool unsigned_flag, TIME *ltime)
+static bool sec_to_time(longlong seconds, bool unsigned_flag, MYSQL_TIME *ltime)
{
uint sec;
@@ -206,7 +207,8 @@ overflow:
char buf[22];
int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10)
- buf);
- make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME,
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ buf, len, MYSQL_TIMESTAMP_TIME,
NullS);
return 1;
@@ -225,7 +227,7 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
{(char *)"%H:%i:%S", 8}};
/*
- Extract datetime value to TIME struct from string value
+ Extract datetime value to MYSQL_TIME struct from string value
according to format string.
SYNOPSIS
@@ -258,7 +260,7 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
*/
static bool extract_date_time(DATE_TIME_FORMAT *format,
- const char *val, uint length, TIME *l_time,
+ const char *val, uint length, MYSQL_TIME *l_time,
timestamp_type cached_timestamp_type,
const char **sub_pattern_end,
const char *date_time_type)
@@ -306,13 +308,15 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
case 'Y':
tmp= (char*) val + min(4, val_len);
l_time->year= (int) my_strtoll10(val, &tmp, &error);
+ if ((int) (tmp-val) <= 2)
+ l_time->year= year_2000_handling(l_time->year);
val= tmp;
break;
case 'y':
tmp= (char*) val + min(2, val_len);
l_time->year= (int) my_strtoll10(val, &tmp, &error);
val= tmp;
- l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
+ l_time->year= year_2000_handling(l_time->year);
break;
/* Month */
@@ -515,7 +519,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
if (yearday > 0)
{
- uint days= calc_daynr(l_time->year,1,1) + yearday - 1;
+ uint days;
+ days= calc_daynr(l_time->year,1,1) + yearday - 1;
if (days <= 0 || days > MAX_DAY_NUMBER)
goto err;
get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
@@ -577,7 +582,8 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
{
if (!my_isspace(&my_charset_latin1,*val))
{
- make_truncated_value_warning(current_thd, val_begin, length,
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ val_begin, length,
cached_timestamp_type, NullS);
break;
}
@@ -601,7 +607,7 @@ err:
Create a formated date/time value in a string
*/
-bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
+bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
timestamp_type type, String *str)
{
char intbuff[15];
@@ -880,9 +886,9 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
{
i++;
/* Change values[0...i-1] -> values[0...count-1] */
- bmove_upp((char*) (values+count), (char*) (values+i),
+ bmove_upp((uchar*) (values+count), (uchar*) (values+i),
sizeof(*values)*i);
- bzero((char*) values, sizeof(*values)*(count-i));
+ bzero((uchar*) values, sizeof(*values)*(count-i));
break;
}
}
@@ -922,7 +928,7 @@ longlong Item_func_period_diff::val_int()
longlong Item_func_to_days::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
@@ -959,7 +965,7 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime,TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
@@ -969,7 +975,7 @@ longlong Item_func_dayofyear::val_int()
longlong Item_func_dayofmonth::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.day;
}
@@ -977,7 +983,7 @@ longlong Item_func_dayofmonth::val_int()
longlong Item_func_month::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.month;
}
@@ -1007,15 +1013,16 @@ String* Item_func_monthname::val_str(String* str)
longlong Item_func_quarter::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
- (void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
+ MYSQL_TIME ltime;
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
return (longlong) ((ltime.month+2)/3);
}
longlong Item_func_hour::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_time(&ltime);
return ltime.hour;
}
@@ -1023,7 +1030,7 @@ longlong Item_func_hour::val_int()
longlong Item_func_minute::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_time(&ltime);
return ltime.minute;
}
@@ -1032,7 +1039,7 @@ longlong Item_func_minute::val_int()
longlong Item_func_second::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_time(&ltime);
return ltime.second;
}
@@ -1079,7 +1086,7 @@ longlong Item_func_week::val_int()
{
DBUG_ASSERT(fixed == 1);
uint year;
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_week(&ltime,
@@ -1092,7 +1099,7 @@ longlong Item_func_yearweek::val_int()
{
DBUG_ASSERT(fixed == 1);
uint year,week;
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
week= calc_week(&ltime,
@@ -1105,7 +1112,7 @@ longlong Item_func_yearweek::val_int()
longlong Item_func_weekday::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
@@ -1120,14 +1127,14 @@ String* Item_func_dayname::val_str(String* str)
{
DBUG_ASSERT(fixed == 1);
uint weekday=(uint) val_int(); // Always Item_func_daynr()
- const char *name;
+ const char *day_name;
THD *thd= current_thd;
if (null_value)
return (String*) 0;
- name= thd->variables.lc_time_names->day_names->type_names[weekday];
- str->set(name, strlen(name), system_charset_info);
+ day_name= thd->variables.lc_time_names->day_names->type_names[weekday];
+ str->set(day_name, strlen(day_name), system_charset_info);
return str;
}
@@ -1135,7 +1142,7 @@ String* Item_func_dayname::val_str(String* str)
longlong Item_func_year::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
(void) get_arg0_date(&ltime, TIME_FUZZY_DATE);
return (longlong) ltime.year;
}
@@ -1166,7 +1173,7 @@ enum_monotonicity_info Item_func_year::get_monotonicity_info() const
longlong Item_func_unix_timestamp::val_int()
{
- TIME ltime;
+ MYSQL_TIME ltime;
my_bool not_used;
DBUG_ASSERT(fixed == 1);
@@ -1175,7 +1182,7 @@ longlong Item_func_unix_timestamp::val_int()
if (args[0]->type() == FIELD_ITEM)
{ // Optimize timestamp field
Field *field=((Item_field*) args[0])->field;
- if (field->type() == FIELD_TYPE_TIMESTAMP)
+ if (field->type() == MYSQL_TYPE_TIMESTAMP)
return ((Field_timestamp*) field)->get_timestamp(&null_value);
}
@@ -1197,7 +1204,7 @@ longlong Item_func_unix_timestamp::val_int()
longlong Item_func_time_to_sec::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
longlong seconds;
(void) get_arg0_time(&ltime);
seconds=ltime.hour*3600L+ltime.minute*60+ltime.second;
@@ -1216,7 +1223,7 @@ bool get_interval_value(Item *args,interval_type int_type,
ulonglong array[5];
longlong value;
const char *str;
- uint32 length;
+ size_t length;
CHARSET_INFO *cs=str_value->charset();
LINT_INIT(value);
@@ -1251,7 +1258,7 @@ bool get_interval_value(Item *args,interval_type int_type,
interval->neg=1;
str++;
}
- length=(uint32) (end-str); // Set up pointers to new str
+ length= (size_t) (end-str); // Set up pointers to new str
}
switch (int_type) {
@@ -1369,7 +1376,7 @@ bool get_interval_value(Item *args,interval_type int_type,
String *Item_date::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return (String *) 0;
if (str->alloc(11))
@@ -1385,19 +1392,19 @@ String *Item_date::val_str(String *str)
longlong Item_date::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return 0;
return (longlong) (ltime.year*10000L+ltime.month*100+ltime.day);
}
-bool Item_func_from_days::get_date(TIME *ltime, uint fuzzy_date)
+bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
longlong value=args[0]->val_int();
if ((null_value=args[0]->null_value))
return 1;
- bzero(ltime, sizeof(TIME));
+ bzero(ltime, sizeof(MYSQL_TIME));
get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
ltime->time_type= MYSQL_TIMESTAMP_DATE;
return 0;
@@ -1431,10 +1438,10 @@ String *Item_func_curdate::val_str(String *str)
}
/*
- Converts current time in my_time_t to TIME represenatation for local
+ Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole CURDATE function.
*/
-void Item_func_curdate_local::store_now_in_TIME(TIME *now_time)
+void Item_func_curdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
thd->variables.time_zone->gmt_sec_to_TIME(now_time,
@@ -1444,10 +1451,10 @@ void Item_func_curdate_local::store_now_in_TIME(TIME *now_time)
/*
- Converts current time in my_time_t to TIME represenatation for UTC
+ Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
time zone. Defines time zone (UTC) used for whole UTC_DATE function.
*/
-void Item_func_curdate_utc::store_now_in_TIME(TIME *now_time)
+void Item_func_curdate_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
my_tz_UTC->gmt_sec_to_TIME(now_time,
(my_time_t)(current_thd->query_start()));
@@ -1458,7 +1465,7 @@ void Item_func_curdate_utc::store_now_in_TIME(TIME *now_time)
}
-bool Item_func_curdate::get_date(TIME *res,
+bool Item_func_curdate::get_date(MYSQL_TIME *res,
uint fuzzy_date __attribute__((unused)))
{
*res=ltime;
@@ -1476,7 +1483,7 @@ String *Item_func_curtime::val_str(String *str)
void Item_func_curtime::fix_length_and_dec()
{
- TIME ltime;
+ MYSQL_TIME ltime;
decimals= DATETIME_DEC;
collation.set(&my_charset_bin);
@@ -1488,10 +1495,10 @@ void Item_func_curtime::fix_length_and_dec()
/*
- Converts current time in my_time_t to TIME represenatation for local
+ Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole CURTIME function.
*/
-void Item_func_curtime_local::store_now_in_TIME(TIME *now_time)
+void Item_func_curtime_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
thd->variables.time_zone->gmt_sec_to_TIME(now_time,
@@ -1501,10 +1508,10 @@ void Item_func_curtime_local::store_now_in_TIME(TIME *now_time)
/*
- Converts current time in my_time_t to TIME represenatation for UTC
+ Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
time zone. Defines time zone (UTC) used for whole UTC_TIME function.
*/
-void Item_func_curtime_utc::store_now_in_TIME(TIME *now_time)
+void Item_func_curtime_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
my_tz_UTC->gmt_sec_to_TIME(now_time,
(my_time_t)(current_thd->query_start()));
@@ -1537,10 +1544,10 @@ void Item_func_now::fix_length_and_dec()
/*
- Converts current time in my_time_t to TIME represenatation for local
+ Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole NOW function.
*/
-void Item_func_now_local::store_now_in_TIME(TIME *now_time)
+void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
thd->variables.time_zone->gmt_sec_to_TIME(now_time,
@@ -1550,10 +1557,10 @@ void Item_func_now_local::store_now_in_TIME(TIME *now_time)
/*
- Converts current time in my_time_t to TIME represenatation for UTC
+ Converts current time in my_time_t to MYSQL_TIME represenatation for UTC
time zone. Defines time zone (UTC) used for whole UTC_TIMESTAMP function.
*/
-void Item_func_now_utc::store_now_in_TIME(TIME *now_time)
+void Item_func_now_utc::store_now_in_TIME(MYSQL_TIME *now_time)
{
my_tz_UTC->gmt_sec_to_TIME(now_time,
(my_time_t)(current_thd->query_start()));
@@ -1564,7 +1571,7 @@ void Item_func_now_utc::store_now_in_TIME(TIME *now_time)
}
-bool Item_func_now::get_date(TIME *res,
+bool Item_func_now::get_date(MYSQL_TIME *res,
uint fuzzy_date __attribute__((unused)))
{
*res= ltime;
@@ -1581,13 +1588,13 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
/*
- Converts current time in my_time_t to TIME represenatation for local
+ Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole SYSDATE function.
*/
-void Item_func_sysdate_local::store_now_in_TIME(TIME *now_time)
+void Item_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time)
{
THD *thd= current_thd;
- thd->variables.time_zone->gmt_sec_to_TIME(now_time, time(NULL));
+ thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) time(NULL));
thd->time_zone_used= 1;
}
@@ -1626,7 +1633,7 @@ void Item_func_sysdate_local::fix_length_and_dec()
}
-bool Item_func_sysdate_local::get_date(TIME *res,
+bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
uint fuzzy_date __attribute__((unused)))
{
store_now_in_TIME(&ltime);
@@ -1647,7 +1654,8 @@ int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions)
String *Item_func_sec_to_time::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
+ longlong arg_val= args[0]->val_int();
if ((null_value=args[0]->null_value) || str->alloc(19))
{
@@ -1655,7 +1663,7 @@ String *Item_func_sec_to_time::val_str(String *str)
return (String*) 0;
}
- sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
@@ -1665,12 +1673,13 @@ String *Item_func_sec_to_time::val_str(String *str)
longlong Item_func_sec_to_time::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
+ longlong arg_val= args[0]->val_int();
if ((null_value=args[0]->null_value))
return 0;
- sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
return (ltime.neg ? -1 : 1) *
((ltime.hour)*10000 + ltime.minute*100 + ltime.second);
@@ -1806,7 +1815,7 @@ uint Item_func_date_format::format_length(const String *format)
String *Item_func_date_format::val_str(String *str)
{
String *format;
- TIME l_time;
+ MYSQL_TIME l_time;
uint size;
DBUG_ASSERT(fixed == 1);
@@ -1869,7 +1878,7 @@ void Item_func_from_unixtime::fix_length_and_dec()
String *Item_func_from_unixtime::val_str(String *str)
{
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
DBUG_ASSERT(fixed == 1);
@@ -1889,7 +1898,7 @@ String *Item_func_from_unixtime::val_str(String *str)
longlong Item_func_from_unixtime::val_int()
{
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
DBUG_ASSERT(fixed == 1);
@@ -1899,7 +1908,7 @@ longlong Item_func_from_unixtime::val_int()
return (longlong) TIME_to_ulonglong_datetime(&time_tmp);
}
-bool Item_func_from_unixtime::get_date(TIME *ltime,
+bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
ulonglong tmp= (ulonglong)(args[0]->val_int());
@@ -1925,22 +1934,9 @@ void Item_func_convert_tz::fix_length_and_dec()
}
-bool
-Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref)
-{
- String str;
- if (Item_date_func::fix_fields(thd_arg, ref))
- return TRUE;
-
- tz_tables= thd_arg->lex->time_zone_tables_used;
-
- return FALSE;
-}
-
-
String *Item_func_convert_tz::val_str(String *str)
{
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
if (get_date(&time_tmp, 0))
return 0;
@@ -1958,7 +1954,7 @@ String *Item_func_convert_tz::val_str(String *str)
longlong Item_func_convert_tz::val_int()
{
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
if (get_date(&time_tmp, 0))
return 0;
@@ -1967,21 +1963,22 @@ longlong Item_func_convert_tz::val_int()
}
-bool Item_func_convert_tz::get_date(TIME *ltime,
+bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
my_time_t my_time_tmp;
String str;
+ THD *thd= current_thd;
if (!from_tz_cached)
{
- from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
+ from_tz= my_tz_find(thd, args[1]->val_str(&str));
from_tz_cached= args[1]->const_item();
}
if (!to_tz_cached)
{
- to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
+ to_tz= my_tz_find(thd, args[2]->val_str(&str));
to_tz_cached= args[2]->const_item();
}
@@ -2028,7 +2025,7 @@ void Item_date_add_interval::fix_length_and_dec()
- If first arg is a MYSQL_TYPE_DATE and the interval type uses hours,
minutes or seconds then type is MYSQL_TYPE_DATETIME.
- Otherwise the result is MYSQL_TYPE_STRING
- (This is because you can't know if the string contains a DATE, TIME or
+ (This is because you can't know if the string contains a DATE, MYSQL_TIME or
DATETIME argument)
*/
cached_field_type= MYSQL_TYPE_STRING;
@@ -2048,7 +2045,7 @@ void Item_date_add_interval::fix_length_and_dec()
/* Here arg[1] is a Item_interval object */
-bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
+bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
INTERVAL interval;
@@ -2058,17 +2055,17 @@ bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
if (date_sub_interval)
interval.neg = !interval.neg;
- if (ltime->year < YY_MAGIC_BELOW)
- return (null_value=1);
- return (null_value= date_add_interval(ltime, int_type, interval));
+ if ((null_value= date_add_interval(ltime, int_type, interval)))
+ return 1;
+ return 0;
}
String *Item_date_add_interval::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
enum date_time_format_types format;
if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
@@ -2092,7 +2089,7 @@ String *Item_date_add_interval::val_str(String *str)
longlong Item_date_add_interval::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
longlong date;
if (Item_date_add_interval::get_date(&ltime, TIME_NO_ZERO_DATE))
return (longlong) 0;
@@ -2182,7 +2179,7 @@ void Item_extract::fix_length_and_dec()
longlong Item_extract::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
uint year;
ulong week_format;
long neg;
@@ -2435,7 +2432,7 @@ void Item_char_typecast::fix_length_and_dec()
String *Item_datetime_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
&ltime, str))
@@ -2449,7 +2446,7 @@ String *Item_datetime_typecast::val_str(String *str)
longlong Item_datetime_typecast::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_arg0_date(&ltime,1))
{
null_value= 1;
@@ -2460,7 +2457,7 @@ longlong Item_datetime_typecast::val_int()
}
-bool Item_time_typecast::get_time(TIME *ltime)
+bool Item_time_typecast::get_time(MYSQL_TIME *ltime)
{
bool res= get_arg0_time(ltime);
/*
@@ -2476,7 +2473,7 @@ bool Item_time_typecast::get_time(TIME *ltime)
longlong Item_time_typecast::val_int()
{
- TIME ltime;
+ MYSQL_TIME ltime;
if (get_time(&ltime))
{
null_value= 1;
@@ -2488,7 +2485,7 @@ longlong Item_time_typecast::val_int()
String *Item_time_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (!get_arg0_time(&ltime) &&
!make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
@@ -2500,7 +2497,7 @@ String *Item_time_typecast::val_str(String *str)
}
-bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date)
+bool Item_date_typecast::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
bool res= get_arg0_date(ltime, TIME_FUZZY_DATE);
ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
@@ -2512,7 +2509,7 @@ bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date)
String *Item_date_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) && !str->alloc(11))
{
@@ -2527,30 +2524,41 @@ String *Item_date_typecast::val_str(String *str)
longlong Item_date_typecast::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (args[0]->get_date(&ltime, TIME_FUZZY_DATE))
+ {
+ null_value= 1;
return 0;
+ }
return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
}
/*
MAKEDATE(a,b) is a date function that creates a date value
from a year and day value.
+
+ NOTES:
+ As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
+ In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
+ for dates between 0000-01-01 and 0099-12-31
*/
String *Item_func_makedate::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME l_time;
+ MYSQL_TIME l_time;
long daynr= (long) args[1]->val_int();
- long yearnr= (long) args[0]->val_int();
+ long year= (long) args[0]->val_int();
long days;
if (args[0]->null_value || args[1]->null_value ||
- yearnr < 0 || daynr <= 0)
+ year < 0 || daynr <= 0)
goto err;
- days= calc_daynr(yearnr,1,1) + daynr - 1;
+ if (year < 100)
+ year= year_2000_handling(year);
+
+ days= calc_daynr(year,1,1) + daynr - 1;
/* Day number from year 0 to 9999-12-31 */
if (days >= 0 && days <= MAX_DAY_NUMBER)
{
@@ -2568,19 +2576,32 @@ err:
}
+/*
+ MAKEDATE(a,b) is a date function that creates a date value
+ from a year and day value.
+
+ NOTES:
+ As arguments are integers, we can't know if the year is a 2 digit or 4 digit year.
+ In this case we treat all years < 100 as 2 digit years. Ie, this is not safe
+ for dates between 0000-01-01 and 0099-12-31
+*/
+
longlong Item_func_makedate::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME l_time;
+ MYSQL_TIME l_time;
long daynr= (long) args[1]->val_int();
- long yearnr= (long) args[0]->val_int();
+ long year= (long) args[0]->val_int();
long days;
if (args[0]->null_value || args[1]->null_value ||
- yearnr < 0 || daynr <= 0)
+ year < 0 || daynr <= 0)
goto err;
- days= calc_daynr(yearnr,1,1) + daynr - 1;
+ if (year < 100)
+ year= year_2000_handling(year);
+
+ days= calc_daynr(year,1,1) + daynr - 1;
/* Day number from year 0 to 9999-12-31 */
if (days >= 0 && days < MAX_DAY_NUMBER)
{
@@ -2635,7 +2656,7 @@ void Item_func_add_time::fix_length_and_dec()
String *Item_func_add_time::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME l_time1, l_time2, l_time3;
+ MYSQL_TIME l_time1, l_time2, l_time3;
bool is_time= 0;
long days, microseconds;
longlong seconds;
@@ -2737,7 +2758,7 @@ String *Item_func_timediff::val_str(String *str)
longlong seconds;
long microseconds;
int l_sign= 1;
- TIME l_time1 ,l_time2, l_time3;
+ MYSQL_TIME l_time1 ,l_time2, l_time3;
null_value= 0;
if (args[0]->get_time(&l_time1) ||
@@ -2782,7 +2803,7 @@ null_date:
String *Item_func_maketime::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
bool overflow= 0;
longlong hour= args[0]->val_int();
@@ -2826,7 +2847,8 @@ String *Item_func_maketime::val_str(String *str)
char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
int len = (int)(ptr - buf) +
my_sprintf(ptr, (ptr, ":%02u:%02u", (uint)minute, (uint)second));
- make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME,
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ buf, len, MYSQL_TIMESTAMP_TIME,
NullS);
}
@@ -2850,7 +2872,7 @@ String *Item_func_maketime::val_str(String *str)
longlong Item_func_microsecond::val_int()
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (!get_arg0_time(&ltime))
return ltime.second_part;
return 0;
@@ -2859,7 +2881,7 @@ longlong Item_func_microsecond::val_int()
longlong Item_func_timestamp_diff::val_int()
{
- TIME ltime1, ltime2;
+ MYSQL_TIME ltime1, ltime2;
longlong seconds;
long microseconds;
long months= 0;
@@ -3165,14 +3187,14 @@ void Item_func_str_to_date::fix_length_and_dec()
}
}
-bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
+bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
DATE_TIME_FORMAT date_time_format;
char val_buff[64], format_buff[64];
- String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val;
+ String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
- val= args[0]->val_str(&val_str);
+ val= args[0]->val_str(&val_string);
format= args[1]->val_str(&format_str);
if (args[0]->null_value || args[1]->null_value)
goto null_date;
@@ -3206,7 +3228,7 @@ null_date:
String *Item_func_str_to_date::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- TIME ltime;
+ MYSQL_TIME ltime;
if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
return 0;
@@ -3219,7 +3241,7 @@ String *Item_func_str_to_date::val_str(String *str)
}
-bool Item_func_last_day::get_date(TIME *ltime, uint fuzzy_date)
+bool Item_func_last_day::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
{
if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) ||
(ltime->month == 0))
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 360307a677f..bd0954e6bdb 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -39,7 +38,7 @@ public:
{
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -54,7 +53,7 @@ public:
decimals=0;
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -71,7 +70,7 @@ public:
maybe_null=1;
}
enum_monotonicity_info get_monotonicity_info() const;
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -87,7 +86,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -112,7 +111,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -145,7 +144,7 @@ public:
max_length=3*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -161,7 +160,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -177,7 +176,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -193,7 +192,7 @@ public:
max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -209,7 +208,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -225,7 +224,7 @@ public:
max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_yearweek :public Item_int_func
@@ -240,7 +239,7 @@ public:
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -257,7 +256,7 @@ public:
max_length=4*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -287,7 +286,7 @@ public:
max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_dayname :public Item_func_weekday
@@ -320,7 +319,7 @@ public:
decimals=0;
max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -335,7 +334,7 @@ public:
decimals=0;
max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -352,7 +351,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
String *val_str(String *str);
longlong val_int();
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
+ double val_real() { return val_real_from_decimal(); }
const char *func_name() const { return "date"; }
void fix_length_and_dec()
{
@@ -390,6 +389,7 @@ public:
return tmp_table_field_from_field_type(table, 0);
}
bool result_as_longlong() { return TRUE; }
+ double val_real() { return (double) val_int(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -412,13 +412,14 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
void fix_length_and_dec()
{
- decimals=0;
+ decimals= DATETIME_DEC;
max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *table)
{
return tmp_table_field_from_field_type(table, 0);
}
+ double val_real() { return val_real_from_decimal(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -448,9 +449,9 @@ public:
/*
Abstract method that defines which time zone is used for conversion.
Converts time current time in my_time_t representation to broken-down
- TIME representation using UTC-SYSTEM or per-thread time zone.
+ MYSQL_TIME representation using UTC-SYSTEM or per-thread time zone.
*/
- virtual void store_now_in_TIME(TIME *now_time)=0;
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
bool result_as_longlong() { return TRUE; }
};
@@ -461,7 +462,7 @@ public:
Item_func_curtime_local() :Item_func_curtime() {}
Item_func_curtime_local(Item *a) :Item_func_curtime(a) {}
const char *func_name() const { return "curtime"; }
- virtual void store_now_in_TIME(TIME *now_time);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -471,7 +472,7 @@ public:
Item_func_curtime_utc() :Item_func_curtime() {}
Item_func_curtime_utc(Item *a) :Item_func_curtime(a) {}
const char *func_name() const { return "utc_time"; }
- virtual void store_now_in_TIME(TIME *now_time);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -480,14 +481,14 @@ public:
class Item_func_curdate :public Item_date
{
longlong value;
- TIME ltime;
+ MYSQL_TIME ltime;
public:
Item_func_curdate() :Item_date() {}
longlong val_int() { DBUG_ASSERT(fixed == 1); return (value) ; }
String *val_str(String *str);
void fix_length_and_dec();
- bool get_date(TIME *res, uint fuzzy_date);
- virtual void store_now_in_TIME(TIME *now_time)=0;
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
};
@@ -496,7 +497,7 @@ class Item_func_curdate_local :public Item_func_curdate
public:
Item_func_curdate_local() :Item_func_curdate() {}
const char *func_name() const { return "curdate"; }
- void store_now_in_TIME(TIME *now_time);
+ void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -505,7 +506,7 @@ class Item_func_curdate_utc :public Item_func_curdate
public:
Item_func_curdate_utc() :Item_func_curdate() {}
const char *func_name() const { return "utc_date"; }
- void store_now_in_TIME(TIME *now_time);
+ void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -517,18 +518,17 @@ protected:
longlong value;
char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy
uint buff_length;
- TIME ltime;
+ MYSQL_TIME ltime;
public:
Item_func_now() :Item_date_func() {}
Item_func_now(Item *a) :Item_date_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
int save_in_field(Field *to, bool no_conversions);
String *val_str(String *str);
void fix_length_and_dec();
- bool get_date(TIME *res, uint fuzzy_date);
- virtual void store_now_in_TIME(TIME *now_time)=0;
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time)=0;
};
@@ -538,7 +538,7 @@ public:
Item_func_now_local() :Item_func_now() {}
Item_func_now_local(Item *a) :Item_func_now(a) {}
const char *func_name() const { return "now"; }
- virtual void store_now_in_TIME(TIME *now_time);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time);
virtual enum Functype functype() const { return NOW_FUNC; }
};
@@ -549,7 +549,7 @@ public:
Item_func_now_utc() :Item_func_now() {}
Item_func_now_utc(Item *a) :Item_func_now(a) {}
const char *func_name() const { return "utc_timestamp"; }
- virtual void store_now_in_TIME(TIME *now_time);
+ virtual void store_now_in_TIME(MYSQL_TIME *now_time);
};
@@ -564,13 +564,13 @@ public:
Item_func_sysdate_local(Item *a) :Item_func_now(a) {}
bool const_item() const { return 0; }
const char *func_name() const { return "sysdate"; }
- void store_now_in_TIME(TIME *now_time);
+ void store_now_in_TIME(MYSQL_TIME *now_time);
double val_real();
longlong val_int();
int save_in_field(Field *to, bool no_conversions);
String *val_str(String *str);
void fix_length_and_dec();
- bool get_date(TIME *res, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
void update_used_tables()
{
Item_func_now::update_used_tables();
@@ -584,8 +584,8 @@ class Item_func_from_days :public Item_date
public:
Item_func_from_days(Item *a) :Item_date(a) {}
const char *func_name() const { return "from_days"; }
- bool get_date(TIME *res, uint fuzzy_date);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -603,7 +603,7 @@ public:
void fix_length_and_dec();
uint format_length(const String *format);
bool eq(const Item *item, bool binary_cmp) const;
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -612,17 +612,12 @@ class Item_func_from_unixtime :public Item_date_func
THD *thd;
public:
Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
- double val_real()
- {
- DBUG_ASSERT(fixed == 1);
- return (double) Item_func_from_unixtime::val_int();
- }
longlong val_int();
String *val_str(String *str);
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec();
- bool get_date(TIME *res, uint fuzzy_date);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -642,8 +637,6 @@ class Time_zone;
*/
class Item_func_convert_tz :public Item_date_func
{
- /* Cached pointer to list of pre-opened time zone tables. */
- TABLE_LIST *tz_tables;
/*
If time zone parameters are constants we are caching objects that
represent them (we use separate from_tz_cached/to_tz_cached members
@@ -656,12 +649,10 @@ class Item_func_convert_tz :public Item_date_func
Item_func_convert_tz(Item *a, Item *b, Item *c):
Item_date_func(a, b, c), from_tz_cached(0), to_tz_cached(0) {}
longlong val_int();
- double val_real() { return (double) val_int(); }
String *val_str(String *str);
const char *func_name() const { return "convert_tz"; }
- bool fix_fields(THD *, Item **);
void fix_length_and_dec();
- bool get_date(TIME *res, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
void cleanup();
};
@@ -682,11 +673,10 @@ public:
Item_str_timefunc::fix_length_and_dec();
collation.set(&my_charset_bin);
maybe_null=1;
- decimals= DATETIME_DEC;
}
const char *func_name() const { return "sec_to_time"; }
bool result_as_longlong() { return TRUE; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -704,12 +694,11 @@ public:
const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec();
enum_field_types field_type() const { return cached_field_type; }
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
longlong val_int();
- bool get_date(TIME *res, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -727,7 +716,7 @@ class Item_extract :public Item_int_func
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -764,7 +753,7 @@ public:
max_length=args[0]->max_length;
maybe_null= 1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -784,7 +773,7 @@ public:
String *val_str(String *a);
void fix_length_and_dec();
void print(String *str);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -794,7 +783,7 @@ public:
Item_date_typecast(Item *a) :Item_typecast_maybe_null(a) {}
const char *func_name() const { return "cast_as_date"; }
String *val_str(String *str);
- bool get_date(TIME *ltime, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
const char *cast_type() const { return "date"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
Field *tmp_table_field(TABLE *table)
@@ -809,6 +798,7 @@ public:
}
bool result_as_longlong() { return TRUE; }
longlong val_int();
+ double val_real() { return (double) val_int(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -827,7 +817,7 @@ public:
Item_time_typecast(Item *a) :Item_typecast_maybe_null(a) {}
const char *func_name() const { return "cast_as_time"; }
String *val_str(String *str);
- bool get_time(TIME *ltime);
+ bool get_time(MYSQL_TIME *ltime);
const char *cast_type() const { return "time"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
Field *tmp_table_field(TABLE *table)
@@ -836,6 +826,7 @@ public:
}
bool result_as_longlong() { return TRUE; }
longlong val_int();
+ double val_real() { return val_real_from_decimal(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -860,8 +851,15 @@ public:
{
return tmp_table_field_from_field_type(table, 0);
}
+ void fix_length_and_dec()
+ {
+ Item_typecast_maybe_null::fix_length_and_dec();
+ decimals= DATETIME_DEC;
+ }
bool result_as_longlong() { return TRUE; }
longlong val_int();
+ double val_real() { return val_real_from_decimal(); }
+ double val() { return (double) val_int(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -886,7 +884,7 @@ public:
max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
longlong val_int();
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -909,7 +907,8 @@ public:
}
void print(String *str);
const char *func_name() const { return "add_time"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ double val_real() { return val_real_from_decimal(); }
my_decimal *val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
@@ -950,7 +949,7 @@ public:
:Item_str_timefunc(a, b ,c) {}
String *val_str(String *str);
const char *func_name() const { return "maketime"; }
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
class Item_func_microsecond :public Item_int_func
@@ -964,7 +963,7 @@ public:
decimals=0;
maybe_null=1;
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -982,7 +981,7 @@ public:
maybe_null=1;
}
void print(String *str);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1021,7 +1020,7 @@ public:
:Item_str_func(a, b)
{}
String *val_str(String *str);
- bool get_date(TIME *ltime, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *ltime, uint fuzzy_date);
const char *func_name() const { return "str_to_date"; }
enum_field_types field_type() const { return cached_field_type; }
void fix_length_and_dec();
@@ -1029,7 +1028,7 @@ public:
{
return tmp_table_field_from_field_type(table, 1);
}
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1038,5 +1037,5 @@ class Item_func_last_day :public Item_date
public:
Item_func_last_day(Item *a) :Item_date(a) {}
const char *func_name() const { return "last_day"; }
- bool get_date(TIME *res, uint fuzzy_date);
+ bool get_date(MYSQL_TIME *res, uint fuzzy_date);
};
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
deleted file mode 100644
index 9db8228b345..00000000000
--- a/sql/item_uniq.cc
+++ /dev/null
@@ -1,32 +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 */
-
-/* Compability file */
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-
-Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table,
- uint convert_blob_length)
-{
- Field *field= new Field_long(9, maybe_null, name, 1);
- if (field)
- field->init(table);
- return field;
-}
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
deleted file mode 100644
index a0aa0b96cc6..00000000000
--- a/sql/item_uniq.h
+++ /dev/null
@@ -1,63 +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 */
-
-/* Compability file ; This file only contains dummy functions */
-
-#ifdef USE_PRAGMA_INTERFACE
-#pragma interface
-#endif
-
-#include <queues.h>
-
-class Item_func_unique_users :public Item_real_func
-{
-public:
- Item_func_unique_users(Item *name_arg,int start,int end,List<Item> &list)
- :Item_real_func(list) {}
- double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
- void fix_length_and_dec() { decimals=0; max_length=6; }
- void print(String *str) { str->append(STRING_WITH_LEN("0.0")); }
- const char *func_name() const { return "unique_users"; }
-};
-
-
-class Item_sum_unique_users :public Item_sum_num
-{
-public:
- Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg)
- :Item_sum_num(item_arg) {}
- Item_sum_unique_users(THD *thd, Item_sum_unique_users *item)
- :Item_sum_num(thd, item) {}
- double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
- enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
- void clear() {}
- bool add() { return 0; }
- void reset_field() {}
- void update_field() {}
- bool fix_fields(THD *thd, Item **ref)
- {
- DBUG_ASSERT(fixed == 0);
- fixed= 1;
- return FALSE;
- }
- Item *copy_or_same(THD* thd)
- {
- return new Item_sum_unique_users(thd, this);
- }
- void print(String *str) { str->append(STRING_WITH_LEN("0.0")); }
- Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
- const char *func_name() const { return "sum_unique_users"; }
-};
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 966bae43984..f8457a1ae50 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,8 +11,7 @@
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 */
-
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef __GNUC__
#pragma implementation
@@ -21,7 +19,7 @@
#include "mysql_priv.h"
#include "my_xml.h"
-
+#include "sp_pcontext.h"
/*
TODO: future development directions:
@@ -579,7 +577,6 @@ String * Item_nodeset_func_union::val_nodeset(String *nodeset)
both_str.alloc(numnodes);
char *both= (char*) both_str.ptr();
bzero((void*)both, numnodes);
- uint pos= 0;
MY_XPATH_FLT *flt;
fltbeg= (MY_XPATH_FLT*) s0->ptr();
@@ -926,8 +923,8 @@ static Item *create_comparator(MY_XPATH *xpath,
else if (a->type() == Item::XPATH_NODESET &&
b->type() == Item::XPATH_NODESET)
{
- uint len= context->end - context->beg;
- set_if_bigger(len, 32);
+ uint len= xpath->query.end - context->beg;
+ set_if_smaller(len, 32);
my_printf_error(ER_UNKNOWN_ERROR,
"XPATH error: "
"comparison of two nodesets is not supported: '%.*s'",
@@ -1047,12 +1044,12 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_OR , "or" , 2, 0 },
{MY_XPATH_LEX_DIV , "div" , 3, 0 },
{MY_XPATH_LEX_MOD , "mod" , 3, 0 },
-
- {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
- {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
- {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
- {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
-
+ {0,NULL,0,0}
+};
+
+
+static struct my_xpath_keyword_names_st my_axis_names[]=
+{
{MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
{MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
{MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
@@ -1066,7 +1063,16 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
{MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
{MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
{MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
+ {0,NULL,0,0}
+};
+
+static struct my_xpath_keyword_names_st my_nodetype_names[]=
+{
+ {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
+ {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
+ {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
+ {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
{0,NULL,0,0}
};
@@ -1081,11 +1087,14 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
- Token type, on lookup success.
- MY_XPATH_LEX_IDENT, on lookup failure.
*/
-static int my_xpath_keyword(MY_XPATH *x, const char *beg, const char *end)
+static int
+my_xpath_keyword(MY_XPATH *x,
+ struct my_xpath_keyword_names_st *keyword_names,
+ const char *beg, const char *end)
{
struct my_xpath_keyword_names_st *k;
size_t length= end-beg;
- for (k= my_keyword_names; k->name; k++)
+ for (k= keyword_names; k->name; k++)
{
if (length == k->length && !strncasecmp(beg, k->name, length))
{
@@ -1371,15 +1380,32 @@ my_xpath_lex_scan(MY_XPATH *xpath,
beg+= length) /* no op */;
lex->end= beg;
- // check if a function call
- if (*beg == '(' && (xpath->func= my_xpath_function(lex->beg, beg)))
+ if (beg < end)
{
- lex->term= MY_XPATH_LEX_FUNC;
- return;
+ if (*beg == '(')
+ {
+ /*
+ check if a function call, e.g.: count(/a/b)
+ or a nodetype test, e.g.: /a/b/text()
+ */
+ if ((xpath->func= my_xpath_function(lex->beg, beg)))
+ lex->term= MY_XPATH_LEX_FUNC;
+ else
+ lex->term= my_xpath_keyword(xpath, my_nodetype_names,
+ lex->beg, beg);
+ return;
+ }
+ // check if an axis specifier, e.g.: /a/b/child::*
+ else if (*beg == ':' && beg + 1 < end && beg[1] == ':')
+ {
+ lex->term= my_xpath_keyword(xpath, my_axis_names,
+ lex->beg, beg);
+ return;
+ }
}
-
// check if a keyword
- lex->term= my_xpath_keyword(xpath, lex->beg, beg);
+ lex->term= my_xpath_keyword(xpath, my_keyword_names,
+ lex->beg, beg);
return;
}
@@ -1486,7 +1512,6 @@ static int my_xpath_parse_AxisName(MY_XPATH *xpath)
static int my_xpath_parse_LocationPath(MY_XPATH *xpath);
static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath);
static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath);
-static int my_xpath_parse_AbbreviatedAbsoluteLocationPath(MY_XPATH *xpath);
static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath);
static int my_xpath_parse_Step(MY_XPATH *xpath);
static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath);
@@ -1505,7 +1530,6 @@ static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath);
static int my_xpath_parse_AndExpr(MY_XPATH *xpath);
static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath);
static int my_xpath_parse_VariableReference(MY_XPATH *xpath);
-static int my_xpath_parse_slash_opt_slash(MY_XPATH *xpath);
/*
@@ -2334,6 +2358,36 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
/*
+ Scan NCName.
+
+ SYNOPSYS
+
+ The keywords AND, OR, MOD, DIV are valid identitiers
+ when they are in identifier context:
+
+ SELECT
+ ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
+ '/and/or/mod/div')
+ -> VALUE
+
+ RETURN
+ 1 - success
+ 0 - failure
+*/
+
+static int
+my_xpath_parse_NCName(MY_XPATH *xpath)
+{
+ return
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_AND) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_OR) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD) ||
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ? 1 : 0;
+}
+
+
+/*
QName grammar can be found in a separate document
http://www.w3.org/TR/REC-xml-names/#NT-QName
@@ -2341,37 +2395,95 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
[7] Prefix ::= NCName
[8] LocalPart ::= NCName
*/
+
static int
my_xpath_parse_QName(MY_XPATH *xpath)
{
const char *beg;
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
beg= xpath->prevtok.beg;
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
return 1; /* Non qualified name */
- if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
+ if (!my_xpath_parse_NCName(xpath))
return 0;
xpath->prevtok.beg= beg;
return 1;
}
-/*
+/**
Scan Variable reference
- SYNOPSYS
+ @details Implements parsing of two syntax structures:
- [36] VariableReference ::= '$' QName
- RETURN
- 1 - success
- 0 - failure
+ 1. Standard XPath syntax [36], for SP variables:
+
+ VariableReference ::= '$' QName
+
+ Finds a SP variable with the given name.
+ If outside of a SP context, or variable with
+ the given name doesn't exists, then error is returned.
+
+ 2. Non-standard syntax - MySQL extension for user variables:
+
+ VariableReference ::= '$' '@' QName
+
+ Item, corresponding to the variable, is returned
+ in xpath->item in both cases.
+
+ @param xpath pointer to XPath structure
+
+ @return Operation status
+ @retval 1 Success
+ @retval 0 Failure
*/
+
static int
my_xpath_parse_VariableReference(MY_XPATH *xpath)
{
- return my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) &&
- my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT);
+ LEX_STRING name;
+ int user_var;
+ const char *dollar_pos;
+ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) ||
+ (!(dollar_pos= xpath->prevtok.beg)) ||
+ (!((user_var= my_xpath_parse_term(xpath, MY_XPATH_LEX_AT) &&
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))) &&
+ !my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT)))
+ return 0;
+
+ name.length= xpath->prevtok.end - xpath->prevtok.beg;
+ name.str= (char*) xpath->prevtok.beg;
+
+ if (user_var)
+ xpath->item= new Item_func_get_user_var(name);
+ else
+ {
+ sp_variable_t *spv;
+ sp_pcontext *spc;
+ LEX *lex;
+ if ((lex= current_thd->lex) &&
+ (spc= lex->spcont) &&
+ (spv= spc->find_variable(&name)))
+ {
+ Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0);
+#ifndef DBUG_OFF
+ if (splocal)
+ splocal->m_sp= lex->sphead;
+#endif
+ xpath->item= (Item*) splocal;
+ }
+ else
+ {
+ xpath->item= NULL;
+ DBUG_ASSERT(xpath->query.end > dollar_pos);
+ uint len= xpath->query.end - dollar_pos;
+ set_if_smaller(len, 32);
+ my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
+ MYF(0), len, dollar_pos);
+ }
+ }
+ return xpath->item ? 1 : 0;
}
@@ -2479,12 +2591,10 @@ void Item_xml_str_func::fix_length_and_dec()
if (!rc)
{
- char context[32];
uint clen= xpath.query.end - xpath.lasttok.beg;
- set_if_bigger(clen, sizeof(context) - 1);
- strmake(context, xpath.lasttok.beg, clen);
- my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%s'",
- MYF(0), context);
+ set_if_smaller(clen, 32);
+ my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'",
+ MYF(0), clen, xpath.lasttok.beg);
return;
}
@@ -2546,7 +2656,7 @@ static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level)
RETURN
Currently only MY_XML_OK
*/
-static int xml_enter(MY_XML_PARSER *st,const char *attr, uint len)
+static int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len)
{
MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
@@ -2577,7 +2687,7 @@ static int xml_enter(MY_XML_PARSER *st,const char *attr, uint len)
RETURN
Currently only MY_XML_OK
*/
-static int xml_value(MY_XML_PARSER *st,const char *attr, uint len)
+static int xml_value(MY_XML_PARSER *st,const char *attr, size_t len)
{
MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
@@ -2607,7 +2717,7 @@ static int xml_value(MY_XML_PARSER *st,const char *attr, uint len)
RETURN
Currently only MY_XML_OK
*/
-static int xml_leave(MY_XML_PARSER *st,const char *attr, uint len)
+static int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len)
{
MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
DBUG_ASSERT(data->level > 0);
@@ -2657,7 +2767,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf)
if ((rc= my_xml_parse(&p, raw_xml->ptr(), raw_xml->length())) != MY_XML_OK)
{
char buf[128];
- my_snprintf(buf, sizeof(buf)-1, "parse error at line %d pos %d: %s",
+ my_snprintf(buf, sizeof(buf)-1, "parse error at line %d pos %lu: %s",
my_xml_error_lineno(&p) + 1,
my_xml_error_pos(&p) + 1,
my_xml_error_string(&p));
@@ -2701,7 +2811,6 @@ String *Item_func_xml_update::val_str(String *str)
}
MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr();
- MY_XML_NODE *nodeend= (MY_XML_NODE*) pxml.ptr() + pxml.length();
MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
@@ -2714,6 +2823,16 @@ String *Item_func_xml_update::val_str(String *str)
nodebeg+= fltbeg->num;
+ if (!nodebeg->level)
+ {
+ /*
+ Root element, without NameTest:
+ UpdateXML(xml, '/', 'replacement');
+ Just return the replacement string.
+ */
+ return rep;
+ }
+
tmp_value.length(0);
tmp_value.set_charset(collation.collation);
uint offs= nodebeg->type == MY_XML_NODE_TAG ? 1 : 0;
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index 6fa33081373..650893fa7bd 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -42,7 +41,7 @@ public:
Item_func_xml_extractvalue(Item *a,Item *b) :Item_xml_str_func(a,b) {}
const char *func_name() const { return "extractvalue"; }
String *val_str(String *);
- bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
diff --git a/sql/key.cc b/sql/key.cc
index dceeab1c011..fee06ec058f 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -30,6 +29,7 @@
field Field to search after
key_length On partial match, contains length of fields before
field
+ keypart key part # of a field
NOTES
Used when calculating key for NEXT_NUMBER
@@ -45,8 +45,8 @@
key_length is set to length of key before (not including) field
*/
-int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
- uint *key_length)
+int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
+ uint *key_length, uint *keypart)
{
reg2 int i;
reg3 KEY *key_info;
@@ -61,8 +61,8 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
{
if (key_info->key_part[0].offset == fieldpos)
{ /* Found key. Calc keylength */
- *key_length=0;
- return(i); /* Use this key */
+ *key_length= *keypart= 0;
+ return i; /* Use this key */
}
}
@@ -79,8 +79,11 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
j++, key_part++)
{
if (key_part->offset == fieldpos)
- return(i); /* Use this key */
- *key_length+=key_part->store_length;
+ {
+ *keypart= j;
+ return i; /* Use this key */
+ }
+ *key_length+= key_part->store_length;
}
}
return(-1); /* No key is ok */
@@ -108,7 +111,8 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
None
*/
-void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
+void key_copy(uchar *to_key, uchar *from_record, KEY *key_info,
+ uint key_length)
{
uint length;
KEY_PART_INFO *key_part;
@@ -128,7 +132,7 @@ void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
Field_bit *field= (Field_bit *) (key_part->field);
if (field->bit_len)
{
- uchar bits= get_rec_bits((uchar*) from_record +
+ uchar bits= get_rec_bits(from_record +
key_part->null_offset +
(key_part->null_bit == 128),
field->bit_ofs, field->bit_len);
@@ -136,29 +140,22 @@ void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
key_length--;
}
}
- if (key_part->key_part_flag & HA_BLOB_PART)
- {
- char *pos;
- ulong blob_length= ((Field_blob*) key_part->field)->get_length();
- key_length-= HA_KEY_BLOB_LENGTH;
- ((Field_blob*) key_part->field)->get_ptr(&pos);
- length=min(key_length, key_part->length);
- set_if_smaller(blob_length, length);
- int2store(to_key, (uint) blob_length);
- to_key+= HA_KEY_BLOB_LENGTH; // Skip length info
- memcpy(to_key, pos, blob_length);
- }
- else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
+ if (key_part->key_part_flag & HA_BLOB_PART ||
+ key_part->key_part_flag & HA_VAR_LENGTH_PART)
{
key_length-= HA_KEY_BLOB_LENGTH;
length= min(key_length, key_part->length);
- key_part->field->get_key_image((char *) to_key, length, Field::itRAW);
+ key_part->field->get_key_image(to_key, length, Field::itRAW);
to_key+= HA_KEY_BLOB_LENGTH;
}
else
{
length= min(key_length, key_part->length);
- memcpy(to_key, from_record + key_part->offset, (size_t) length);
+ Field *field= key_part->field;
+ CHARSET_INFO *cs= field->charset();
+ uint bytes= field->get_key_image(to_key, length, Field::itRAW);
+ if (bytes < length)
+ cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
}
to_key+= length;
key_length-= length;
@@ -184,7 +181,7 @@ void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length)
None
*/
-void key_restore(byte *to_record, byte *from_key, KEY *key_info,
+void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
uint key_length)
{
uint length;
@@ -218,23 +215,34 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
}
if (key_part->key_part_flag & HA_BLOB_PART)
{
+ /*
+ This in fact never happens, as we have only partial BLOB
+ keys yet anyway, so it's difficult to find any sence to
+ restore the part of a record.
+ Maybe this branch is to be removed, but now we
+ have to ignore GCov compaining.
+ */
uint blob_length= uint2korr(from_key);
+ Field_blob *field= (Field_blob*) key_part->field;
from_key+= HA_KEY_BLOB_LENGTH;
key_length-= HA_KEY_BLOB_LENGTH;
- ((Field_blob*) key_part->field)->set_ptr((ulong) blob_length,
- (char*) from_key);
+ field->set_ptr_offset(to_record - field->table->record[0],
+ (ulong) blob_length, from_key);
length= key_part->length;
}
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
{
+ Field *field= key_part->field;
my_bitmap_map *old_map;
+ my_ptrdiff_t ptrdiff= to_record - field->table->record[0];
+ field->move_field_offset(ptrdiff);
key_length-= HA_KEY_BLOB_LENGTH;
length= min(key_length, key_part->length);
- old_map= dbug_tmp_use_all_columns(key_part->field->table,
- key_part->field->table->write_set);
- key_part->field->set_key_image((char *) from_key, length);
- dbug_tmp_restore_column_map(key_part->field->table->write_set, old_map);
+ old_map= dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ field->set_key_image(from_key, length);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
from_key+= HA_KEY_BLOB_LENGTH;
+ field->move_field_offset(-ptrdiff);
}
else
{
@@ -268,11 +276,11 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
1 Key has changed
*/
-bool key_cmp_if_same(TABLE *table,const byte *key,uint idx,uint key_length)
+bool key_cmp_if_same(TABLE *table,const uchar *key,uint idx,uint key_length)
{
uint store_length;
KEY_PART_INFO *key_part;
- const byte *key_end= key + key_length;;
+ const uchar *key_end= key + key_length;;
for (key_part=table->key_info[idx].key_part;
key < key_end ;
@@ -304,7 +312,7 @@ bool key_cmp_if_same(TABLE *table,const byte *key,uint idx,uint key_length)
{
CHARSET_INFO *cs= key_part->field->charset();
uint char_length= key_part->length / cs->mbmaxlen;
- const byte *pos= table->record[0] + key_part->offset;
+ const uchar *pos= table->record[0] + key_part->offset;
if (length > char_length)
{
char_length= my_charpos(cs, pos, pos + length, char_length);
@@ -428,11 +436,11 @@ bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields)
1 Key is larger than range
*/
-int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length)
+int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length)
{
uint store_length;
- for (const byte *end=key + key_length;
+ for (const uchar *end=key + key_length;
key < end;
key+= store_length, key_part++)
{
@@ -455,7 +463,7 @@ int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length)
key++; // Skip null byte
store_length--;
}
- if ((cmp=key_part->field->key_cmp((byte*) key, key_part->length)) < 0)
+ if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
return -1;
if (cmp > 0)
return 1;
@@ -488,13 +496,13 @@ int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length)
and return the result of the comparison.
*/
-int key_rec_cmp(void *key, byte *first_rec, byte *second_rec)
+int key_rec_cmp(void *key, uchar *first_rec, uchar *second_rec)
{
KEY *key_info= (KEY*)key;
uint key_parts= key_info->key_parts, i= 0;
KEY_PART_INFO *key_part= key_info->key_part;
- char *rec0= key_part->field->ptr - key_part->offset;
- my_ptrdiff_t first_diff= first_rec - (byte*)rec0, sec_diff= second_rec - (byte*)rec0;
+ uchar *rec0= key_part->field->ptr - key_part->offset;
+ my_ptrdiff_t first_diff= first_rec - rec0, sec_diff= second_rec - rec0;
int result= 0;
DBUG_ENTER("key_rec_cmp");
diff --git a/sql/lex.h b/sql/lex.h
index 254d7f10fb7..e311379120d 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -223,12 +222,13 @@ static SYMBOL symbols[] = {
{ "GLOBAL", SYM(GLOBAL_SYM)},
{ "GRANT", SYM(GRANT)},
{ "GRANTS", SYM(GRANTS)},
- { "GROUP", SYM(GROUP)},
+ { "GROUP", SYM(GROUP_SYM)},
{ "HANDLER", SYM(HANDLER_SYM)},
{ "HASH", SYM(HASH_SYM)},
{ "HAVING", SYM(HAVING)},
{ "HELP", SYM(HELP_SYM)},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY)},
+ { "HOST", SYM(HOST_SYM)},
{ "HOSTS", SYM(HOSTS_SYM)},
{ "HOUR", SYM(HOUR_SYM)},
{ "HOUR_MICROSECOND", SYM(HOUR_MICROSECOND_SYM)},
@@ -312,6 +312,7 @@ static SYMBOL symbols[] = {
{ "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM)},
{ "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM)},
{ "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM)},
+ { "MASTER_SSL_VERIFY_SERVER_CERT", SYM(MASTER_SSL_VERIFY_SERVER_CERT_SYM)},
{ "MASTER_USER", SYM(MASTER_USER_SYM)},
{ "MATCH", SYM(MATCH)},
{ "MAX_CONNECTIONS_PER_HOUR", SYM(MAX_CONNECTIONS_PER_HOUR)},
@@ -368,6 +369,7 @@ static SYMBOL symbols[] = {
{ "ONE_SHOT", SYM(ONE_SHOT_SYM)},
{ "OPEN", SYM(OPEN_SYM)},
{ "OPTIMIZE", SYM(OPTIMIZE)},
+ { "OPTIONS", SYM(OPTIONS_SYM)},
{ "OPTION", SYM(OPTION)},
{ "OPTIONALLY", SYM(OPTIONALLY)},
{ "OR", SYM(OR_SYM)},
@@ -375,6 +377,7 @@ static SYMBOL symbols[] = {
{ "OUT", SYM(OUT_SYM)},
{ "OUTER", SYM(OUTER)},
{ "OUTFILE", SYM(OUTFILE)},
+ { "OWNER", SYM(OWNER_SYM)},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)},
{ "PARSER", SYM(PARSER_SYM)},
{ "PARTIAL", SYM(PARTIAL)},
@@ -387,6 +390,7 @@ static SYMBOL symbols[] = {
{ "PLUGINS", SYM(PLUGINS_SYM)},
{ "POINT", SYM(POINT_SYM)},
{ "POLYGON", SYM(POLYGON)},
+ { "PORT", SYM(PORT_SYM)},
{ "PRECISION", SYM(PRECISION)},
{ "PREPARE", SYM(PREPARE_SYM)},
{ "PRESERVE", SYM(PRESERVE_SYM)},
@@ -456,6 +460,7 @@ static SYMBOL symbols[] = {
{ "SERIAL", SYM(SERIAL_SYM)},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM)},
{ "SESSION", SYM(SESSION_SYM)},
+ { "SERVER", SYM(SERVER_SYM)},
{ "SET", SYM(SET)},
{ "SHARE", SYM(SHARE_SYM)},
{ "SHOW", SYM(SHOW)},
@@ -465,6 +470,7 @@ static SYMBOL symbols[] = {
{ "SLAVE", SYM(SLAVE)},
{ "SNAPSHOT", SYM(SNAPSHOT_SYM)},
{ "SMALLINT", SYM(SMALLINT)},
+ { "SOCKET", SYM(SOCKET_SYM)},
{ "SOME", SYM(ANY_SYM)},
{ "SONAME", SYM(SONAME_SYM)},
{ "SOUNDS", SYM(SOUNDS_SYM)},
@@ -569,6 +575,7 @@ static SYMBOL symbols[] = {
{ "VIEW", SYM(VIEW_SYM)},
{ "WITH", SYM(WITH)},
{ "WORK", SYM(WORK_SYM)},
+ { "WRAPPER", SYM(WRAPPER_SYM)},
{ "WRITE", SYM(WRITE_SYM)},
{ "X509", SYM(X509_SYM)},
{ "XOR", SYM(XOR)},
@@ -593,7 +600,6 @@ static SYMBOL sql_functions[] = {
{ "DATE_SUB", SYM(DATE_SUB_INTERVAL)},
{ "EXTRACT", SYM(EXTRACT_SYM)},
{ "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)},
- { "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS)},
{ "MAX", SYM(MAX_SYM)},
{ "MID", SYM(SUBSTRING)}, /* unireg function */
{ "MIN", SYM(MIN_SYM)},
@@ -611,7 +617,6 @@ static SYMBOL sql_functions[] = {
{ "SYSDATE", SYM(SYSDATE)},
{ "SYSTEM_USER", SYM(USER)},
{ "TRIM", SYM(TRIM)},
- { "UNIQUE_USERS", SYM(UNIQUE_USERS)},
{ "VARIANCE", SYM(VARIANCE_SYM)},
{ "VAR_POP", SYM(VARIANCE_SYM)},
{ "VAR_SAMP", SYM(VAR_SAMP_SYM)},
diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h
index 5ba785d16f3..000c0709071 100644
--- a/sql/lex_symbol.h
+++ b/sql/lex_symbol.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/lock.cc b/sql/lock.cc
index f36ecf58620..6f1dd0669ee 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -138,7 +137,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
sql_lock=0;
break;
}
@@ -146,18 +145,35 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
goto retry;
}
}
+ if ( write_lock_used
+ && opt_readonly
+ && ! (thd->security_ctx->master_access & SUPER_ACL)
+ && ! thd->slave_thread
+ )
+ {
+ /*
+ Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
+ We do not wait for READ_ONLY=0, and fail.
+ */
+ reset_lock_data(sql_lock);
+ my_free((uchar*) sql_lock, MYF(0));
+ sql_lock=0;
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ break;
+ }
+
thd->proc_info="System lock";
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
if (lock_external(thd, tables, count))
{
/* Clear the lock type of all lock data to avoid reusage. */
reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
sql_lock=0;
break;
}
@@ -175,7 +191,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
if (rc > 1) /* a timeout or a deadlock */
{
my_error(rc, MYF(0));
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
sql_lock= 0;
break;
}
@@ -269,7 +285,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
if (sql_lock->table_count)
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
DBUG_VOID_RETURN;
}
@@ -419,7 +435,7 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table,
{
for (uint i=0; i < locked->lock_count; i++)
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
- my_free((gptr) locked,MYF(0));
+ my_free((uchar*) locked,MYF(0));
}
}
@@ -437,7 +453,7 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
{
for (uint i=0; i < locked->lock_count; i++)
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
- my_free((gptr) locked,MYF(0));
+ my_free((uchar*) locked,MYF(0));
}
DBUG_VOID_RETURN;
}
@@ -469,10 +485,10 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
for (uint i=0; i < locked->lock_count; i++)
{
if (thr_abort_locks_for_thread(locked->locks[i]->lock,
- table->in_use->real_id))
+ table->in_use->thread_id))
result= TRUE;
}
- my_free((gptr) locked,MYF(0));
+ my_free((uchar*) locked,MYF(0));
}
DBUG_RETURN(result);
}
@@ -514,8 +530,8 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
}
/* Delete old, not needed locks */
- my_free((gptr) a,MYF(0));
- my_free((gptr) b,MYF(0));
+ my_free((uchar*) a,MYF(0));
+ my_free((uchar*) b,MYF(0));
DBUG_RETURN(sql_lock);
}
@@ -566,7 +582,7 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
goto end;
/* A temporary table does not have locks. */
- if (table->s->tmp_table == TMP_TABLE)
+ if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
goto end;
/* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
@@ -588,10 +604,10 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
for (; haystack; haystack= haystack->next_global)
{
- if (haystack->placeholder() || haystack->schema_table)
+ if (haystack->placeholder())
continue;
table2= haystack->table;
- if (table2->s->tmp_table == TMP_TABLE)
+ if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
continue;
/* All tables in list must be in lock. */
@@ -676,9 +692,10 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
DBUG_PRINT("info", ("count %d", count));
*write_lock_used=0;
+ uint system_count= 0;
for (i=tables=lock_count=0 ; i < count ; i++)
{
- if (table_ptr[i]->s->tmp_table != TMP_TABLE)
+ if (table_ptr[i]->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
{
tables+=table_ptr[i]->file->lock_count();
lock_count++;
@@ -689,7 +706,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
*/
if (!table_ptr[i]-> file->
check_if_locking_is_allowed(thd->lex->sql_command, thd->lex->type,
- table_ptr[i], count,
+ table_ptr[i], count, i, &system_count,
(thd == logger.get_general_log_thd()) ||
(thd == logger.get_slow_log_thd()) ||
(thd == logger.get_privileged_thread())))
@@ -720,7 +737,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
TABLE *table;
enum thr_lock_type lock_type;
- if ((table=table_ptr[i])->s->tmp_table == TMP_TABLE)
+ if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
continue;
lock_type= table->reginfo.lock_type;
if (lock_type >= TL_WRITE_ALLOW_WRITE)
@@ -732,7 +749,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
/* Clear the lock type of the lock data that are stored already. */
sql_lock->lock_count= locks - sql_lock->locks;
reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
+ my_free((uchar*) sql_lock,MYF(0));
DBUG_RETURN(0);
}
}
@@ -875,8 +892,6 @@ end:
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
{
TABLE *table;
- TABLE_SHARE *share;
- char *key_buff;
char key[MAX_DBKEY_LENGTH];
char *db= table_list->db;
uint key_length;
@@ -889,10 +904,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
if (check_in_use)
{
/* Only insert the table if we haven't insert it already */
- for (table=(TABLE*) hash_first(&open_cache, (byte*)key,
+ for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
key_length, &state);
table ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,
+ table = (TABLE*) hash_next(&open_cache,(uchar*) key,
key_length, &state))
{
if (table->in_use == thd)
@@ -904,29 +919,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
}
}
}
- /*
- Create a table entry with the right key and with an old refresh version
- Note that we must use my_multi_malloc() here as this is freed by the
- table cache
- */
- if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &table, sizeof(*table),
- &share, sizeof(*share),
- &key_buff, key_length,
- NULL))
- DBUG_RETURN(-1);
- table->s= share;
- share->set_table_cache_key(key_buff, key, key_length);
- share->tmp_table= INTERNAL_TMP_TABLE; // for intern_close_table
- table->in_use= thd;
- table->locked_by_name=1;
- table_list->table=table;
- if (my_hash_insert(&open_cache, (byte*) table))
- {
- my_free((gptr) table,MYF(0));
+ if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
DBUG_RETURN(-1);
- }
+
+ table_list->table=table;
/* Return 1 if table is in use */
DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name,
@@ -938,7 +935,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list)
{
if (table_list->table)
{
- hash_delete(&open_cache, (byte*) table_list->table);
+ hash_delete(&open_cache, (uchar*) table_list->table);
broadcast_refresh();
}
}
diff --git a/sql/log.cc b/sql/log.cc
index 41e413e9ff7..6ef1c1ea912 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,6 +20,7 @@
#include "mysql_priv.h"
#include "sql_repl.h"
#include "rpl_filter.h"
+#include "rpl_rli.h"
#include <my_dir.h>
#include <stdarg.h>
@@ -32,15 +32,6 @@
#include <mysql/plugin.h>
-/*
- Define placement versions of operator new and operator delete since
- we cannot be sure that the <new> include exists.
- */
-inline void *operator new(size_t, void *ptr) { return ptr; }
-inline void *operator new[](size_t, void *ptr) { return ptr; }
-inline void operator delete(void*, void*) { /* Do nothing */ }
-inline void operator delete[](void*, void*) { /* Do nothing */ }
-
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
#define MAX_USER_HOST_SIZE 512
@@ -76,12 +67,47 @@ sql_print_message_func sql_print_message_handlers[3] =
char *make_default_log_name(char *buff,const char* log_ext)
{
- strmake(buff, glob_hostname, FN_REFLEN-5);
+ strmake(buff, pidfile_name, FN_REFLEN-5);
return fn_format(buff, buff, mysql_data_home, log_ext,
- MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT));
+ MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
}
/*
+ Helper class to hold a mutex for the duration of the
+ block.
+
+ Eliminates the need for explicit unlocking of mutexes on, e.g.,
+ error returns. On passing a null pointer, the sentry will not do
+ anything.
+ */
+class Mutex_sentry
+{
+public:
+ Mutex_sentry(pthread_mutex_t *mutex)
+ : m_mutex(mutex)
+ {
+ if (m_mutex)
+ pthread_mutex_lock(mutex);
+ }
+
+ ~Mutex_sentry()
+ {
+ if (m_mutex)
+ pthread_mutex_unlock(m_mutex);
+#ifndef DBUG_OFF
+ m_mutex= 0;
+#endif
+ }
+
+private:
+ pthread_mutex_t *m_mutex;
+
+ // It's not allowed to copy this object in any way
+ Mutex_sentry(Mutex_sentry const&);
+ void operator=(Mutex_sentry const&);
+};
+
+/*
Helper class to store binary log transaction data.
*/
class binlog_trx_data {
@@ -113,9 +139,13 @@ public:
*/
void truncate(my_off_t pos)
{
+ DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
+ DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos));
delete pending();
set_pending(0);
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
+ if (pos < before_stmt_pos)
+ before_stmt_pos= MY_OFF_T_UNDEF;
}
/*
@@ -230,7 +260,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
table->table_name_length= 8;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
/*
@@ -274,6 +304,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
{
table->table->use_all_columns();
table->table->locked_by_logger= TRUE;
+ table->table->no_replicate= TRUE;
}
/* restore thread settings */
if (curr)
@@ -539,11 +570,21 @@ bool Log_to_csv_event_handler::
if (query_start_arg)
{
+ /*
+ A TIME field can not hold the full longlong range; query_time or
+ lock_time may be truncated without warning here, if greater than
+ 839 hours (~35 days)
+ */
+ MYSQL_TIME t;
+ t.neg= 0;
+
/* fill in query_time field */
- if (table->field[2]->store(query_time, TRUE))
+ calc_time_from_sec(&t, (long) min(query_time, (longlong) TIME_MAX_VALUE_SECONDS), 0);
+ if (table->field[2]->store_time(&t, MYSQL_TIMESTAMP_TIME))
goto err;
/* lock_time */
- if (table->field[3]->store(lock_time, TRUE))
+ calc_time_from_sec(&t, (long) min(lock_time, (longlong) TIME_MAX_VALUE_SECONDS), 0);
+ if (table->field[3]->store_time(&t, MYSQL_TIMESTAMP_TIME))
goto err;
/* rows_sent */
if (table->field[4]->store((longlong) thd->sent_row_count, TRUE))
@@ -869,9 +910,9 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
bool is_command= FALSE;
char user_host_buff[MAX_USER_HOST_SIZE];
- my_time_t current_time;
+ time_t current_time;
Security_context *sctx= thd->security_ctx;
- uint message_buff_len= 0, user_host_len= 0;
+ uint user_host_len= 0;
longlong query_time= 0, lock_time= 0;
/*
@@ -1124,7 +1165,7 @@ void LOGGER::deactivate_log_handler(THD *thd, uint log_type)
log_thd= table_log_handler->general_log_thd;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
if (!(*tmp_opt))
@@ -1273,7 +1314,7 @@ void Log_to_csv_event_handler::
table= &slow_log;
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
/*
@@ -1394,7 +1435,7 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
DBUG_ASSERT(mysql_bin_log.is_open() && trx_data->empty());
thd->ha_data[binlog_hton->slot]= 0;
trx_data->~binlog_trx_data();
- my_free((gptr)trx_data, MYF(0));
+ my_free((uchar*)trx_data, MYF(0));
return 0;
}
@@ -1483,12 +1524,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
If rolling back a statement in a transaction, we truncate the
transaction cache to remove the statement.
-
*/
if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
trx_data->reset();
- else
- trx_data->truncate(trx_data->before_stmt_pos); // ...statement
+ else // ...statement
+ trx_data->truncate(trx_data->before_stmt_pos);
/*
We need to step the table map version on a rollback to ensure
@@ -1507,23 +1547,21 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all)
do nothing.
just pretend we can do 2pc, so that MySQL won't
switch to 1pc.
- real work will be done in MYSQL_BIN_LOG::log()
+ real work will be done in MYSQL_BIN_LOG::log_xid()
*/
return 0;
}
static int binlog_commit(handlerton *hton, THD *thd, bool all)
{
- int error= 0;
DBUG_ENTER("binlog_commit");
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
- if (all && trx_data->empty())
+ if (trx_data->empty())
{
- // we're here because trans_log was flushed in MYSQL_BIN_LOG::log()
+ // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
trx_data->reset();
DBUG_RETURN(0);
}
@@ -1547,7 +1585,6 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
int error=0;
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
if (trx_data->empty()) {
@@ -1561,8 +1598,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
table. Such cases should be rare (updating a
non-transactional table inside a transaction...)
*/
- if (unlikely(thd->options & (OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG)))
+ if (unlikely(thd->no_trans_update.all || (thd->options & OPTION_KEEP_LOG)))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
@@ -1610,9 +1646,6 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_rollback");
- binlog_trx_data *const trx_data=
- (binlog_trx_data*) thd->ha_data[binlog_hton->slot];
- IO_CACHE *trans_log= &trx_data->trans_log;
DBUG_ASSERT(mysql_bin_log.is_open());
/*
@@ -1620,10 +1653,9 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
- if (unlikely(thd->options &
- (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)))
+ if (unlikely(thd->no_trans_update.all || (thd->options & OPTION_KEEP_LOG)))
{
- int const error=
+ int error=
thd->binlog_query(THD::STMT_QUERY_TYPE,
thd->query, thd->query_length, TRUE, FALSE);
DBUG_RETURN(error);
@@ -1632,12 +1664,13 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
DBUG_RETURN(0);
}
+
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
{
char magic[4];
DBUG_ASSERT(my_b_tell(log) == 0);
- if (my_b_read(log, (byte*) magic, sizeof(magic)))
+ if (my_b_read(log, (uchar*) magic, sizeof(magic)))
{
*errmsg = "I/O error reading the header from the binary log";
sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
@@ -1652,6 +1685,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg)
return 0;
}
+
File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
{
File file;
@@ -1689,7 +1723,7 @@ err:
#ifdef __NT__
static int eventSource = 0;
-void setup_windows_event_source()
+static void setup_windows_event_source()
{
HKEY hRegKey= NULL;
DWORD dwError= 0;
@@ -1710,7 +1744,7 @@ void setup_windows_event_source()
/* Register EventMessageFile */
dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
- (PBYTE) szPath, strlen(szPath)+1);
+ (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
/* Register supported event types */
dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
@@ -1738,15 +1772,16 @@ static int find_uniq_filename(char *name)
struct st_my_dir *dir_info;
reg1 struct fileinfo *file_info;
ulong max_found=0;
-
+ size_t buf_length, length;
+ char *start, *end;
DBUG_ENTER("find_uniq_filename");
- uint length = dirname_part(buff,name);
- char *start = name + length;
- char *end = strend(start);
+ length= dirname_part(buff, name, &buf_length);
+ start= name + length;
+ end= strend(start);
*end='.';
- length= (uint) (end-start+1);
+ length= (size_t) (end-start+1);
if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
{ // This shouldn't happen
@@ -1756,7 +1791,7 @@ static int find_uniq_filename(char *name)
file_info= dir_info->dir_entry;
for (i=dir_info->number_off_files ; i-- ; file_info++)
{
- if (bcmp(file_info->name,start,length) == 0 &&
+ if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
test_if_number(file_info->name+length, &number,0))
{
set_if_bigger(max_found,(ulong) number);
@@ -1860,7 +1895,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
);
end= strnmov(buff + len, "Time Id Command Argument\n",
sizeof(buff) - len);
- if (my_b_write(&log_file, (byte*) buff, (uint) (end-buff)) ||
+ if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
flush_io_cache(&log_file))
goto err;
}
@@ -1882,8 +1917,8 @@ shutdown the MySQL server and restart it.", name, errno);
}
MYSQL_LOG::MYSQL_LOG()
- : name(0), log_type(LOG_UNKNOWN), log_state(LOG_CLOSED), write_error(FALSE),
- inited(FALSE)
+ : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
+ log_state(LOG_CLOSED)
{
/*
We don't want to initialize LOCK_Log here as such initialization depends on
@@ -2068,30 +2103,30 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
start.tm_mday, start.tm_hour,
start.tm_min, start.tm_sec);
- if (my_b_write(&log_file, (byte*) &time_buff, time_buff_len))
+ if (my_b_write(&log_file, (uchar*) &time_buff, time_buff_len))
goto err;
}
else
- if (my_b_write(&log_file, (byte*) "\t\t" ,2) < 0)
+ if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
goto err;
- /* command_type, thread_id */
+ /* command_type, thread_id */
length= my_snprintf(buff, 32, "%5ld ", (long) thread_id);
- if (my_b_write(&log_file, (byte*) buff, length))
+ if (my_b_write(&log_file, (uchar*) buff, length))
goto err;
- if (my_b_write(&log_file, (byte*) command_type, command_type_len))
+ if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
goto err;
- if (my_b_write(&log_file, (byte*) "\t", 1))
+ if (my_b_write(&log_file, (uchar*) "\t", 1))
goto err;
/* sql_text */
- if (my_b_write(&log_file, (byte*) sql_text, sql_text_len))
+ if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
goto err;
- if (my_b_write(&log_file, (byte*) "\n", 1) ||
+ if (my_b_write(&log_file, (uchar*) "\n", 1) ||
flush_io_cache(&log_file))
goto err;
}
@@ -2158,7 +2193,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
{
- Security_context *sctx= thd->security_ctx;
if (current_time != last_time)
{
last_time= current_time;
@@ -2172,7 +2206,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
start.tm_min, start.tm_sec);
/* Note that my_b_write() assumes it knows the length for this */
- if (my_b_write(&log_file, (byte*) buff, buff_len))
+ if (my_b_write(&log_file, (uchar*) buff, buff_len))
tmp_errno= errno;
}
if (my_b_printf(&log_file, "# User@Host: ", sizeof("# User@Host: ") - 1)
@@ -2180,7 +2214,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
tmp_errno= errno;
if (my_b_printf(&log_file, user_host, user_host_len) != user_host_len)
tmp_errno= errno;
- if (my_b_write(&log_file, (byte*) "\n", 1))
+ if (my_b_write(&log_file, (uchar*) "\n", 1))
tmp_errno= errno;
}
/* For slow query log */
@@ -2228,18 +2262,18 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
{
*end++=';';
*end='\n';
- if (my_b_write(&log_file, (byte*) "SET ", 4) ||
- my_b_write(&log_file, (byte*) buff + 1, (uint) (end-buff)))
+ if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
+ my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
tmp_errno= errno;
}
if (is_command)
{
end= strxmov(buff, "# administrator command: ", NullS);
buff_len= (ulong) (end - buff);
- my_b_write(&log_file, (byte*) buff, buff_len);
+ my_b_write(&log_file, (uchar*) buff, buff_len);
}
- if (my_b_write(&log_file, (byte*) sql_text, sql_text_len) ||
- my_b_write(&log_file, (byte*) ";\n",2) ||
+ if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
+ my_b_write(&log_file, (uchar*) ";\n",2) ||
flush_io_cache(&log_file))
tmp_errno= errno;
if (tmp_errno)
@@ -2266,7 +2300,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
TODO: The following should be using fn_format(); We just need to
first change fn_format() to cut the file name if it's too long.
*/
- strmake(buff, glob_hostname, FN_REFLEN - 5);
+ strmake(buff, pidfile_name, FN_REFLEN - 5);
strmov(fn_ext(buff), suffix);
return (const char *)buff;
}
@@ -2397,7 +2431,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
bool null_created_arg)
{
File file= -1;
- int open_flags = O_CREAT | O_BINARY;
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
@@ -2424,7 +2457,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
an extension for the binary log files.
In this case we write a standard header to it.
*/
- if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC,
+ if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC,
BIN_LOG_HEADER_SIZE))
goto err;
bytes_written+= BIN_LOG_HEADER_SIZE;
@@ -2476,7 +2509,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
/*
Set 'created' to 0, so that in next relay logs this event does not
trigger cleaning actions on the slave in
- Format_description_log_event::exec_event().
+ Format_description_log_event::apply_event_impl().
*/
description_event_for_queue->created= 0;
/* Don't set log_pos in event header */
@@ -2496,9 +2529,9 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
As this is a new log file, we write the file name to the index
file. As every time we write to the index file, we sync it.
*/
- if (my_b_write(&index_file, (byte*) log_file_name,
+ if (my_b_write(&index_file, (uchar*) log_file_name,
strlen(log_file_name)) ||
- my_b_write(&index_file, (byte*) "\n", 1) ||
+ my_b_write(&index_file, (uchar*) "\n", 1) ||
flush_io_cache(&index_file) ||
my_sync(index_file.file, MYF(MY_WME)))
goto err;
@@ -2559,12 +2592,14 @@ int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
0 ok
*/
+#ifdef HAVE_REPLICATION
+
static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
{
int bytes_read;
my_off_t init_offset= offset;
File file= index_file->file;
- byte io_buf[IO_SIZE*2];
+ uchar io_buf[IO_SIZE*2];
DBUG_ENTER("copy_up_file_and_fill");
for (;; offset+= bytes_read)
@@ -2576,7 +2611,7 @@ static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
if (!bytes_read)
break; // end of file
(void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
- if (my_write(file, (byte*) io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
+ if (my_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
goto err;
}
/* The following will either truncate the file or fill the end with \n' */
@@ -2592,6 +2627,7 @@ err:
DBUG_RETURN(1);
}
+#endif /* HAVE_REPLICATION */
/*
Find the position in the log-index-file for the given log name
@@ -2787,7 +2823,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
need_start_event=1;
if (!open_index_file(index_file_name, 0))
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
- my_free((gptr) save_name, MYF(0));
+ my_free((uchar*) save_name, MYF(0));
err:
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -3084,8 +3120,6 @@ err:
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
-
-
#endif /* HAVE_REPLICATION */
@@ -3182,8 +3216,10 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
{
tc_log_page_waits++;
pthread_mutex_lock(&LOCK_prep_xids);
- while (prepared_xids)
+ while (prepared_xids) {
+ DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
+ }
pthread_mutex_unlock(&LOCK_prep_xids);
}
@@ -3207,7 +3243,6 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
We log the whole file name for log file as the user may decide
to change base names at some point.
*/
- THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
Rotate_log_event r(new_name+dirname_length(new_name),
0, LOG_EVENT_OFFSET, 0);
r.write(&log_file);
@@ -3290,7 +3325,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
safe_mutex_assert_owner(&LOCK_log);
do
{
- if (my_b_append(&log_file,(byte*) buf,len))
+ if (my_b_append(&log_file,(uchar*) buf,len))
{
error= 1;
goto err;
@@ -3322,13 +3357,13 @@ bool MYSQL_BIN_LOG::flush_and_sync()
return err;
}
-void MYSQL_BIN_LOG::start_union_events(THD *thd)
+void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
{
DBUG_ASSERT(!thd->binlog_evt_union.do_union);
thd->binlog_evt_union.do_union= TRUE;
thd->binlog_evt_union.unioned_events= FALSE;
thd->binlog_evt_union.unioned_events_trans= FALSE;
- thd->binlog_evt_union.first_query_id= thd->query_id;
+ thd->binlog_evt_union.first_query_id= query_id_param;
}
void MYSQL_BIN_LOG::stop_union_events(THD *thd)
@@ -3364,7 +3399,7 @@ int THD::binlog_setup_trx_data()
open_cached_file(&trx_data->trans_log, mysql_tmpdir,
LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
{
- my_free((gptr)trx_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR));
ha_data[binlog_hton->slot]= 0;
DBUG_RETURN(1); // Didn't manage to set it up
}
@@ -3415,18 +3450,7 @@ THD::binlog_start_trans_and_stmt()
if (trx_data == NULL ||
trx_data->before_stmt_pos == MY_OFF_T_UNDEF)
{
- /*
- The call to binlog_trans_log_savepos() might create the trx_data
- structure, if it didn't exist before, so we save the position
- into an auto variable and then write it into the transaction
- data for the binary log (i.e., trx_data).
- */
- my_off_t pos= 0;
- binlog_trans_log_savepos(this, &pos);
- trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot];
-
- trx_data->before_stmt_pos= pos;
-
+ this->binlog_set_stmt_begin();
if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
trans_register_ha(this, TRUE, binlog_hton);
trans_register_ha(this, FALSE, binlog_hton);
@@ -3434,6 +3458,51 @@ THD::binlog_start_trans_and_stmt()
DBUG_VOID_RETURN;
}
+void THD::binlog_set_stmt_begin() {
+ binlog_trx_data *trx_data=
+ (binlog_trx_data*) ha_data[binlog_hton->slot];
+
+ /*
+ The call to binlog_trans_log_savepos() might create the trx_data
+ structure, if it didn't exist before, so we save the position
+ into an auto variable and then write it into the transaction
+ data for the binary log (i.e., trx_data).
+ */
+ my_off_t pos= 0;
+ binlog_trans_log_savepos(this, &pos);
+ trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot];
+ trx_data->before_stmt_pos= pos;
+}
+
+int THD::binlog_flush_transaction_cache()
+{
+ DBUG_ENTER("binlog_flush_transaction_cache");
+ binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot];
+ DBUG_PRINT("enter", ("trx_data=0x%lu", (ulong) trx_data));
+ if (trx_data)
+ DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%lu",
+ (ulong) trx_data->before_stmt_pos));
+
+ /*
+ Write the transaction cache to the binary log. We don't flush and
+ sync the log file since we don't know if more will be written to
+ it. If the caller want the log file sync:ed, the caller has to do
+ it.
+
+ The transaction data is only reset upon a successful write of the
+ cache to the binary log.
+ */
+
+ if (trx_data && likely(mysql_bin_log.is_open())) {
+ if (int error= mysql_bin_log.write_cache(&trx_data->trans_log, true, true))
+ DBUG_RETURN(error);
+ trx_data->reset();
+ }
+
+ DBUG_RETURN(0);
+}
+
+
/*
Write a table map to the binary log.
*/
@@ -3627,14 +3696,14 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
*/
if (likely(is_open()))
{
- const char *local_db= event_info->get_db();
IO_CACHE *file= &log_file;
#ifdef HAVE_REPLICATION
/*
- In the future we need to add to the following if tests like
- "do the involved tables match (to be implemented)
- binlog_[wild_]{do|ignore}_table?" (WL#1049)"
+ In the future we need to add to the following if tests like
+ "do the involved tables match (to be implemented)
+ binlog_[wild_]{do|ignore}_table?" (WL#1049)"
*/
+ const char *local_db= event_info->get_db();
if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
(!binlog_filter->db_ok(local_db)))
{
@@ -3716,7 +3785,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
nb_elements()));
/*
If the auto_increment was second in a table's index (possible with
- MyISAM or BDB) (table->next_number_key_offset != 0), such event is
+ MyISAM or BDB) (table->next_number_keypart != 0), such event is
in fact not necessary. We could avoid logging it.
*/
Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
@@ -3736,7 +3805,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
for (uint i= 0; i < thd->user_var_events.elements; i++)
{
BINLOG_USER_VAR_EVENT *user_var_event;
- get_dynamic(&thd->user_var_events,(gptr) &user_var_event, i);
+ get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
User_var_log_event e(thd, user_var_event->user_var_event->name.str,
user_var_event->user_var_event->name.length,
user_var_event->value,
@@ -3823,7 +3892,7 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
#ifdef HAVE_REPLICATION
if (expire_logs_days)
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
+ time_t purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
purge_logs_before_date(purge_time);
}
@@ -3844,12 +3913,48 @@ uint MYSQL_BIN_LOG::next_file_id()
/*
+ Write the contents of a cache to the binary log.
+
+ SYNOPSIS
+ write_cache()
+ cache Cache to write to the binary log
+ lock_log True if the LOCK_log mutex should be aquired, false otherwise
+ sync_log True if the log should be flushed and sync:ed
+
+ DESCRIPTION
+ Write the contents of the cache to the binary log. The cache will
+ be reset as a READ_CACHE to be able to read the contents from it.
+ */
+
+int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
+{
+ Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
+
+ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
+ return ER_ERROR_ON_WRITE;
+ uint bytes= my_b_bytes_in_cache(cache);
+ do
+ {
+ if (my_b_write(&log_file, cache->read_pos, bytes))
+ return ER_ERROR_ON_WRITE;
+ cache->read_pos= cache->read_end;
+ } while ((bytes= my_b_fill(cache)));
+
+ if (sync_log)
+ flush_and_sync();
+
+ return 0; // All OK
+}
+
+/*
Write a cached log entry to the binary log
SYNOPSIS
write()
thd
cache The cache to copy to the binlog
+ commit_event The commit event to print after writing the
+ contents of the cache.
NOTE
- We only come here if there is something in the cache.
@@ -3874,8 +3979,6 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (likely(is_open())) // Should always be true
{
- uint length;
-
/*
We only bother to write to the binary log if there is anything
to write.
@@ -3909,25 +4012,12 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (qinfo.write(&log_file))
goto err;
}
- /* Read from the file used to cache the queries .*/
- if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
- goto err;
- length=my_b_bytes_in_cache(cache);
- DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;);
- do
- {
- /* Write data to the binary log file */
- if (my_b_write(&log_file, cache->read_pos, length))
- goto err;
- cache->read_pos=cache->read_end; // Mark buffer used up
- DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;);
- } while ((length=my_b_fill(cache)));
+ if ((write_error= write_cache(cache, false, false)))
+ goto err;
+
if (commit_event && commit_event->write(&log_file))
goto err;
-#ifndef DBUG_OFF
- DBUG_skip_commit:
-#endif
if (flush_and_sync())
goto err;
DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
@@ -4042,8 +4132,16 @@ void MYSQL_BIN_LOG::close(uint exiting)
if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
{
my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
- byte flags=0; // clearing LOG_EVENT_BINLOG_IN_USE_F
+ my_off_t org_position= my_tell(log_file.file, MYF(0));
+ uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+ /*
+ Restore position so that anything we have in the IO_cache is written
+ to the correct position.
+ We need the seek here, as my_pwrite() is not guaranteed to keep the
+ original position on system that doesn't support pwrite().
+ */
+ my_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
}
/* this will cleanup IO_CACHE, sync and close the file */
@@ -4138,38 +4236,6 @@ static bool test_if_number(register const char *str,
} /* test_if_number */
-void print_buffer_to_file(enum loglevel level, const char *buffer)
-{
- time_t skr;
- struct tm tm_tmp;
- struct tm *start;
- DBUG_ENTER("print_buffer_to_file");
- DBUG_PRINT("enter",("buffer: %s", buffer));
-
- VOID(pthread_mutex_lock(&LOCK_error_log));
-
- skr=time(NULL);
- localtime_r(&skr, &tm_tmp);
- start=&tm_tmp;
-
- fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
- start->tm_year % 100,
- start->tm_mon+1,
- start->tm_mday,
- start->tm_hour,
- start->tm_min,
- start->tm_sec,
- (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
- "Warning" : "Note"),
- buffer);
-
- fflush(stderr);
-
- VOID(pthread_mutex_unlock(&LOCK_error_log));
- DBUG_VOID_RETURN;
-}
-
-
void sql_perror(const char *message)
{
#ifdef HAVE_STRERROR
@@ -4199,17 +4265,21 @@ bool flush_error_log()
(void) my_delete(err_temp, MYF(0));
if (freopen(err_temp,"a+",stdout))
{
+ int fd;
+ size_t bytes;
+ uchar buf[IO_SIZE];
+
freopen(err_temp,"a+",stderr);
(void) my_delete(err_renamed, MYF(0));
my_rename(log_error_file,err_renamed,MYF(0));
if (freopen(log_error_file,"a+",stdout))
freopen(log_error_file,"a+",stderr);
- int fd, bytes;
- char buf[IO_SIZE];
+
if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
{
- while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, MYF(0))) > 0)
- my_fwrite(stderr, (byte*) buf, bytes, MYF(0));
+ while ((bytes= my_read(fd, buf, IO_SIZE, MYF(0))) &&
+ bytes != MY_FILE_ERROR)
+ my_fwrite(stderr, buf, bytes, MYF(0));
my_close(fd, MYF(0));
}
(void) my_delete(err_temp, MYF(0));
@@ -4236,23 +4306,15 @@ void MYSQL_BIN_LOG::signal_update()
}
#ifdef __NT__
-void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
- uint length, int buffLen)
+static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
+ size_t length, size_t buffLen)
{
HANDLE event;
- char *buffptr;
- LPCSTR *buffmsgptr;
+ char *buffptr= buff;
DBUG_ENTER("print_buffer_to_nt_eventlog");
- buffptr= buff;
- if (length > (uint)(buffLen-5))
- {
- char *newBuff= new char[length + 5];
- strcpy(newBuff, buff);
- buffptr= newBuff;
- }
- strmov(buffptr+length, "\r\n\r\n");
- buffmsgptr= (LPCSTR*) &buffptr; // Keep windows happy
+ /* Add ending CR/LF's to string, overwrite last chars if necessary */
+ strmov(buffptr+min(length, buffLen-5), "\r\n\r\n");
setup_windows_event_source();
if ((event= RegisterEventSource(NULL,"MySQL")))
@@ -4260,24 +4322,20 @@ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
switch (level) {
case ERROR_LEVEL:
ReportEvent(event, EVENTLOG_ERROR_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
- buffmsgptr, NULL);
+ (LPCSTR*)&buffptr, NULL);
break;
case WARNING_LEVEL:
ReportEvent(event, EVENTLOG_WARNING_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
- buffmsgptr, NULL);
+ (LPCSTR*) &buffptr, NULL);
break;
case INFORMATION_LEVEL:
ReportEvent(event, EVENTLOG_INFORMATION_TYPE, 0, MSG_DEFAULT, NULL, 1,
- 0, buffmsgptr, NULL);
+ 0, (LPCSTR*) &buffptr, NULL);
break;
}
DeregisterEventSource(event);
}
- /* if we created a string buffer, then delete it */
- if (buffptr != buff)
- delete[] buffptr;
-
DBUG_VOID_RETURN;
}
#endif /* __NT__ */
@@ -4314,14 +4372,45 @@ int vprint_msg_to_log(enum loglevel level __attribute__((unused)),
DBUG_RETURN(0);
}
#else /*!EMBEDDED_LIBRARY*/
+static void print_buffer_to_file(enum loglevel level, const char *buffer)
+{
+ time_t skr;
+ struct tm tm_tmp;
+ struct tm *start;
+ DBUG_ENTER("print_buffer_to_file");
+ DBUG_PRINT("enter",("buffer: %s", buffer));
+
+ VOID(pthread_mutex_lock(&LOCK_error_log));
+
+ skr=time(NULL);
+ localtime_r(&skr, &tm_tmp);
+ start=&tm_tmp;
+
+ fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec,
+ (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
+ "Warning" : "Note"),
+ buffer);
+
+ fflush(stderr);
+
+ VOID(pthread_mutex_unlock(&LOCK_error_log));
+ DBUG_VOID_RETURN;
+}
+
+
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
{
char buff[1024];
- uint length;
+ size_t length;
DBUG_ENTER("vprint_msg_to_log");
- /* "- 5" is because of print_buffer_to_nt_eventlog() */
- length= my_vsnprintf(buff, sizeof(buff) - 5, format, args);
+ length= my_vsnprintf(buff, sizeof(buff), format, args);
print_buffer_to_file(level, buff);
#ifdef __NT__
@@ -4440,7 +4529,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
goto err;
if (using_heuristic_recover())
return 1;
- if ((fd= my_create(logname, O_RDWR, 0, MYF(MY_WME))) < 0)
+ if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
@@ -4587,21 +4676,34 @@ int TC_LOG_MMAP::overflow()
}
/*
- all access to active page is serialized but it's not a problem, as
- we're assuming that fsync() will be a main bottleneck.
- That is, parallelizing writes to log pages we'll decrease number of
- threads waiting for a page, but then all these threads will be waiting
- for a fsync() anyway
+ Record that transaction XID is committed on the persistent storage
+
+ NOTES
+ This function is called in the middle of two-phase commit:
+ First all resources prepare the transaction, then tc_log->log() is called,
+ then all resources commit the transaction, then tc_log->unlog() is called.
+
+ All access to active page is serialized but it's not a problem, as
+ we're assuming that fsync() will be a main bottleneck.
+ That is, parallelizing writes to log pages we'll decrease number of
+ threads waiting for a page, but then all these threads will be waiting
+ for a fsync() anyway
+
+ IMPLEMENTATION
+ If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and
+ records XID in a special Xid_log_event.
+ If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped
+ log.
RETURN
- 0 - error
- otherwise - "cookie", a number that will be passed as an argument
- to unlog() call. tc_log can define it any way it wants,
- and use for whatever purposes. TC_LOG_MMAP sets it
- to the position in memory where xid was logged to.
+ 0 Error
+ # "cookie", a number that will be passed as an argument
+ to unlog() call. tc_log can define it any way it wants,
+ and use for whatever purposes. TC_LOG_MMAP sets it
+ to the position in memory where xid was logged to.
*/
-int TC_LOG_MMAP::log(THD *thd, my_xid xid)
+int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
{
int err;
PAGE *p;
@@ -4710,6 +4812,7 @@ int TC_LOG_MMAP::sync()
erase xid from the page, update page free space counters/pointers.
cookie points directly to the memory where xid was logged
*/
+
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{
PAGE *p=pages+(cookie/tc_log_page_size);
@@ -4750,9 +4853,9 @@ void TC_LOG_MMAP::close()
pthread_cond_destroy(&pages[i].cond);
}
case 3:
- my_free((gptr)pages, MYF(0));
+ my_free((uchar*)pages, MYF(0));
case 2:
- my_munmap((byte*)data, (size_t)file_length);
+ my_munmap((char*)data, (size_t)file_length);
case 1:
my_close(fd, MYF(0));
}
@@ -4786,13 +4889,13 @@ int TC_LOG_MMAP::recover()
}
if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
for ( ; p < end_p ; p++)
{
for (my_xid *x=p->start; x < p->end; x++)
- if (*x && my_hash_insert(&xids, (byte *)x))
+ if (*x && my_hash_insert(&xids, (uchar *)x))
goto err2; // OOM
}
@@ -4952,7 +5055,7 @@ void TC_LOG_BINLOG::close()
0 - error
1 - success
*/
-int TC_LOG_BINLOG::log(THD *thd, my_xid xid)
+int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::log");
Xid_log_event xle(thd, xid);
@@ -4969,8 +5072,10 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
pthread_mutex_lock(&LOCK_prep_xids);
DBUG_ASSERT(prepared_xids > 0);
- if (--prepared_xids == 0)
+ if (--prepared_xids == 0) {
+ DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
pthread_cond_signal(&COND_prep_xids);
+ }
pthread_mutex_unlock(&LOCK_prep_xids);
rotate_and_purge(0); // as ::write() did not rotate
}
@@ -4983,7 +5088,7 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
if (! fdle->is_valid() ||
hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ sizeof(my_xid), 0, 0, MYF(0)))
goto err1;
init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
@@ -4995,8 +5100,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
if (ev->get_type_code() == XID_EVENT)
{
Xid_log_event *xev=(Xid_log_event *)ev;
- byte *x=(byte *)memdup_root(&mem_root, (char *)& xev->xid,
- sizeof(xev->xid));
+ uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
+ sizeof(xev->xid));
if (! x)
goto err2;
my_hash_insert(&xids, x);
diff --git a/sql/log.h b/sql/log.h
index 2316c96f266..25bcbd6c62d 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -34,7 +33,7 @@ class TC_LOG
virtual int open(const char *opt_name)=0;
virtual void close()=0;
- virtual int log(THD *thd, my_xid xid)=0;
+ virtual int log_xid(THD *thd, my_xid xid)=0;
virtual void unlog(ulong cookie, my_xid xid)=0;
};
@@ -44,7 +43,7 @@ public:
TC_LOG_DUMMY() {}
int open(const char *opt_name) { return 0; }
void close() { }
- int log(THD *thd, my_xid xid) { return 1; }
+ int log_xid(THD *thd, my_xid xid) { return 1; }
void unlog(ulong cookie, my_xid xid) { }
};
@@ -89,7 +88,7 @@ class TC_LOG_MMAP: public TC_LOG
TC_LOG_MMAP(): inited(0) {}
int open(const char *opt_name);
void close();
- int log(THD *thd, my_xid xid);
+ int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid);
int recover();
@@ -239,7 +238,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
fix_max_relay_log_size).
*/
ulong max_size;
- ulong prepared_xids; /* for tc log - number of xids to remember */
+ long prepared_xids; /* for tc log - number of xids to remember */
// current file sequence number for load data infile binary logging
uint file_id;
uint open_count; // For replication
@@ -288,7 +287,7 @@ public:
int open(const char *opt_name);
void close();
- int log(THD *thd, my_xid xid);
+ int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid);
int recover(IO_CACHE *log, Format_description_log_event *fdle);
#if !defined(MYSQL_CLIENT)
@@ -340,7 +339,9 @@ public:
bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
- void start_union_events(THD *thd);
+ int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
+
+ void start_union_events(THD *thd, query_id_t query_id_param);
void stop_union_events(THD *thd);
bool is_query_in_union(THD *thd, query_id_t query_id_param);
@@ -602,13 +603,13 @@ public:
};
enum enum_binlog_format {
- BINLOG_FORMAT_STMT= 0, // statement-based
- BINLOG_FORMAT_ROW= 1, // row_based
/*
statement-based except for cases where only row-based can work (UUID()
etc):
*/
- BINLOG_FORMAT_MIXED= 2,
+ BINLOG_FORMAT_MIXED= 0,
+ BINLOG_FORMAT_STMT= 1, // statement-based
+ BINLOG_FORMAT_ROW= 2, // row_based
/*
This value is last, after the end of binlog_format_typelib: it has no
corresponding cell in this typelib. We use this value to be able to know if
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 859f4c86776..eae87b75724 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,8 +22,11 @@
#include "mysql_priv.h"
#include "slave.h"
+#include "rpl_rli.h"
+#include "rpl_mi.h"
#include "rpl_filter.h"
#include "rpl_utility.h"
+#include "rpl_record.h"
#include <my_dir.h>
#endif /* MYSQL_CLIENT */
#include <base64.h>
@@ -32,6 +34,8 @@
#define log_cs &my_charset_latin1
+#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
+
/*
Cache that will automatically be written to a dedicated file on
destruction.
@@ -76,8 +80,7 @@ public:
~Write_on_release_cache()
{
- if (!my_b_copy_to_file(m_cache, m_file))
- reinit_io_cache(m_cache, WRITE_CACHE, 0L, FALSE, TRUE);
+ copy_event_cache_to_file_and_reinit(m_cache, m_file);
if (m_flags | FLUSH_F)
fflush(m_file);
}
@@ -89,9 +92,10 @@ public:
operator&()
DESCRIPTION
- Function to return a pointer to the internal, so that the object
- can be treated as a IO_CACHE and used with the my_b_* IO_CACHE
- functions
+
+ Function to return a pointer to the internal cache, so that the
+ object can be treated as a IO_CACHE and used with the my_b_*
+ IO_CACHE functions
RETURN VALUE
A pointer to the internal IO_CACHE.
@@ -140,22 +144,6 @@ static void pretty_print_str(IO_CACHE* cache, char* str, int len)
}
#endif /* MYSQL_CLIENT */
-#ifdef HAVE_purify
-static void
-valgrind_check_mem(void *ptr, size_t len)
-{
- static volatile uchar dummy;
- for (volatile uchar *p= (uchar*) ptr ; p != (uchar*) ptr + len ; ++p)
- {
- int const c = *p;
- if (c < 128)
- dummy= c + 1;
- else
- dummy = c - 1;
- }
-}
-#endif
-
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
static void clear_all_errors(THD *thd, RELAY_LOG_INFO *rli)
@@ -310,10 +298,10 @@ static void cleanup_load_tmpdir()
static bool write_str(IO_CACHE *file, char *str, uint length)
{
- byte tmp[1];
- tmp[0]= (byte) length;
+ uchar tmp[1];
+ tmp[0]= (uchar) length;
return (my_b_safe_write(file, tmp, sizeof(tmp)) ||
- my_b_safe_write(file, (byte*) str, length));
+ my_b_safe_write(file, (uchar*) str, length));
}
@@ -321,8 +309,8 @@ static bool write_str(IO_CACHE *file, char *str, uint length)
read_str()
*/
-static inline int read_str(char **buf, char *buf_end, char **str,
- uint8 *len)
+static inline int read_str(const char **buf, const char *buf_end,
+ const char **str, uint8 *len)
{
if (*buf + ((uint) (uchar) **buf) >= buf_end)
return 1;
@@ -381,12 +369,14 @@ append_query_string(CHARSET_INFO *csinfo,
}
#endif
+
/*
Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
commands just before it prints a query.
*/
#ifdef MYSQL_CLIENT
+
static void print_set_option(IO_CACHE* file, uint32 bits_changed,
uint32 option, uint32 flags, const char* name,
bool* need_comma)
@@ -434,6 +424,7 @@ const char* Log_event::get_type_str()
case DELETE_ROWS_EVENT: return "Delete_rows";
case BEGIN_LOAD_QUERY_EVENT: return "Begin_load_query";
case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query";
+ case INCIDENT_EVENT: return "Incident";
default: return "Unknown"; /* impossible */
}
}
@@ -545,71 +536,42 @@ Log_event::Log_event(const char* buf,
#ifndef MYSQL_CLIENT
#ifdef HAVE_REPLICATION
-/*
- Log_event::exec_event()
-*/
-
-int Log_event::exec_event(struct st_relay_log_info* rli)
+int Log_event::do_update_pos(RELAY_LOG_INFO *rli)
{
- DBUG_ENTER("Log_event::exec_event");
-
/*
- rli is null when (as far as I (Guilhem) know)
- the caller is
- Load_log_event::exec_event *and* that one is called from
- Execute_load_log_event::exec_event.
- In this case, we don't do anything here ;
- Execute_load_log_event::exec_event will call Log_event::exec_event
- again later with the proper rli.
- Strictly speaking, if we were sure that rli is null
- only in the case discussed above, 'if (rli)' is useless here.
- But as we are not 100% sure, keep it for now.
+ rli is null when (as far as I (Guilhem) know) the caller is
+ Load_log_event::do_apply_event *and* that one is called from
+ Execute_load_log_event::do_apply_event. In this case, we don't
+ do anything here ; Execute_load_log_event::do_apply_event will
+ call Log_event::do_apply_event again later with the proper rli.
+ Strictly speaking, if we were sure that rli is null only in the
+ case discussed above, 'if (rli)' is useless here. But as we are
+ not 100% sure, keep it for now.
+
+ Matz: I don't think we will need this check with this refactoring.
*/
if (rli)
- {
- /*
- If in a transaction, and if the slave supports transactions, just
- inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
- (not OPTION_NOT_AUTOCOMMIT) as transactions are logged with
- BEGIN/COMMIT, not with SET AUTOCOMMIT= .
-
- CAUTION: opt_using_transactions means
- innodb || bdb ; suppose the master supports InnoDB and BDB,
- but the slave supports only BDB, problems
- will arise:
- - suppose an InnoDB table is created on the master,
- - 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 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.
- */
- if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
- rli->inc_event_relay_log_pos();
- else
- {
- rli->inc_group_relay_log_pos(log_pos);
- flush_relay_log_info(rli);
- /*
- Note that Rotate_log_event::exec_event() does not call this
- function, so there is no chance that a fake rotate event resets
- last_master_timestamp.
- Note that we update without mutex (probably ok - except in some very
- rare cases, only consequence is that value may take some time to
- display in Seconds_Behind_Master - not critical).
- */
- rli->last_master_timestamp= when;
- }
- }
- DBUG_RETURN(0);
+ rli->stmt_done(log_pos, when);
+
+ return 0; // Cannot fail currently
+}
+
+
+Log_event::enum_skip_reason
+Log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ DBUG_PRINT("info", ("ev->server_id=%lu, ::server_id=%lu,"
+ " rli->replicate_same_server_id=%d,"
+ " rli->slave_skip_counter=%d",
+ (ulong) server_id, (ulong) ::server_id,
+ rli->replicate_same_server_id,
+ rli->slave_skip_counter));
+ if (server_id == ::server_id && !rli->replicate_same_server_id)
+ return EVENT_SKIP_IGNORE;
+ else if (rli->slave_skip_counter > 0)
+ return EVENT_SKIP_COUNT;
+ else
+ return EVENT_SKIP_NOT;
}
@@ -656,12 +618,13 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
void Log_event::init_show_field_list(List<Item>* field_list)
{
field_list->push_back(new Item_empty_string("Log_name", 20));
- field_list->push_back(new Item_return_int("Pos", 11,
+ field_list->push_back(new Item_return_int("Pos", MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Event_type", 20));
field_list->push_back(new Item_return_int("Server_id", 10,
MYSQL_TYPE_LONG));
- field_list->push_back(new Item_return_int("End_log_pos", 11,
+ field_list->push_back(new Item_return_int("End_log_pos",
+ MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Info", 20));
}
@@ -673,7 +636,7 @@ void Log_event::init_show_field_list(List<Item>* field_list)
bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
{
- byte header[LOG_EVENT_HEADER_LEN];
+ uchar header[LOG_EVENT_HEADER_LEN];
DBUG_ENTER("Log_event::write_header");
/* Store number of bytes that will be written by this event */
@@ -756,11 +719,11 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
ulong data_len;
int result=0;
char buf[LOG_EVENT_MINIMAL_HEADER_LEN];
- DBUG_ENTER("read_log_event");
+ DBUG_ENTER("Log_event::read_log_event");
if (log_lock)
pthread_mutex_lock(log_lock);
- if (my_b_read(file, (byte*) buf, sizeof(buf)))
+ if (my_b_read(file, (uchar*) buf, sizeof(buf)))
{
/*
If the read hits eof, we must report it as eof so the caller
@@ -783,19 +746,34 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
LOG_READ_TOO_LARGE);
goto end;
}
- packet->append(buf, sizeof(buf));
+
+ /* Append the log event header to packet */
+ if (packet->append(buf, sizeof(buf)))
+ {
+ /* Failed to allocate packet */
+ result= LOG_READ_MEM;
+ goto end;
+ }
data_len-= LOG_EVENT_MINIMAL_HEADER_LEN;
if (data_len)
{
+ /* Append rest of event, read directly from file into packet */
if (packet->append(file, data_len))
{
/*
- Here if we hit EOF it's really an error: as data_len is >=0
- there's supposed to be more bytes available.
- EOF means we are reading the event partially, which should
- never happen: either we read badly or the binlog is truncated.
+ Fatal error occured when appending rest of the event
+ to packet, possible failures:
+ 1. EOF occured when reading from file, it's really an error
+ as data_len is >=0 there's supposed to be more bytes available.
+ file->error will have been set to number of bytes left to read
+ 2. Read was interrupted, file->error would normally be set to -1
+ 3. Failed to allocate memory for packet, my_errno
+ will be ENOMEM(file->error shuold be 0, but since the
+ memory allocation occurs before the call to read it might
+ be uninitialized)
*/
- result= file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO;
+ result= (my_errno == ENOMEM ? LOG_READ_MEM :
+ (file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO));
/* Implicit goto end; */
}
}
@@ -831,7 +809,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file,
const Format_description_log_event *description_event)
#endif
{
- DBUG_ENTER("Log_event::read_log_event(IO_CACHE *, Format_description_log_event *");
+ DBUG_ENTER("Log_event::read_log_event");
DBUG_ASSERT(description_event != 0);
char head[LOG_EVENT_MINIMAL_HEADER_LEN];
/*
@@ -846,7 +824,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file,
LOCK_MUTEX;
DBUG_PRINT("info", ("my_b_tell: %lu", (ulong) my_b_tell(file)));
- if (my_b_read(file, (byte *) head, header_size))
+ if (my_b_read(file, (uchar *) head, header_size))
{
DBUG_PRINT("info", ("Log_event::read_log_event(IO_CACHE*,Format_desc*) \
failed my_b_read"));
@@ -880,14 +858,14 @@ failed my_b_read"));
}
// some events use the extra byte to null-terminate strings
- if (!(buf = my_malloc(data_len+1, MYF(MY_WME))))
+ if (!(buf = (char*) my_malloc(data_len+1, MYF(MY_WME))))
{
error = "Out of memory";
goto err;
}
buf[data_len] = 0;
memcpy(buf, head, header_size);
- if (my_b_read(file, (byte*) buf + header_size, data_len - header_size))
+ if (my_b_read(file, (uchar*) buf + header_size, data_len - header_size))
{
error = "read error";
goto err;
@@ -994,6 +972,15 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Format_description_log_event(buf, event_len, description_event);
break;
#if defined(HAVE_REPLICATION)
+ case PRE_GA_WRITE_ROWS_EVENT:
+ ev = new Write_rows_log_event_old(buf, event_len, description_event);
+ break;
+ case PRE_GA_UPDATE_ROWS_EVENT:
+ ev = new Update_rows_log_event_old(buf, event_len, description_event);
+ break;
+ case PRE_GA_DELETE_ROWS_EVENT:
+ ev = new Delete_rows_log_event_old(buf, event_len, description_event);
+ break;
case WRITE_ROWS_EVENT:
ev = new Write_rows_log_event(buf, event_len, description_event);
break;
@@ -1011,14 +998,22 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Begin_load_query_log_event(buf, event_len, description_event);
break;
case EXECUTE_LOAD_QUERY_EVENT:
- ev = new Execute_load_query_log_event(buf, event_len, description_event);
+ ev= new Execute_load_query_log_event(buf, event_len, description_event);
+ break;
+ case INCIDENT_EVENT:
+ ev = new Incident_log_event(buf, event_len, description_event);
break;
default:
- DBUG_PRINT("error",("Unknown evernt code: %d",(int) buf[EVENT_TYPE_OFFSET]));
+ DBUG_PRINT("error",("Unknown event code: %d",
+ (int) buf[EVENT_TYPE_OFFSET]));
ev= NULL;
break;
}
+ DBUG_PRINT("read_event", ("%s(type_code: %d; event_len: %d)",
+ ev ? ev->get_type_str() : "<unknown>",
+ buf[EVENT_TYPE_OFFSET],
+ event_len));
/*
is_valid() are small event-specific sanity tests which are
important; for example there are some my_malloc() in constructors
@@ -1096,8 +1091,8 @@ void Log_event::print_header(IO_CACHE* file,
ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13],
ptr[14], ptr[15], ptr[16], ptr[17], ptr[18]);
DBUG_ASSERT(bytes_written >= 0);
- DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
- my_b_write(file, (byte*) emit_buf, bytes_written);
+ DBUG_ASSERT(static_cast<size_t>(bytes_written) < sizeof(emit_buf));
+ my_b_write(file, (uchar*) emit_buf, bytes_written);
ptr += LOG_EVENT_MINIMAL_HEADER_LEN;
hexdump_from += LOG_EVENT_MINIMAL_HEADER_LEN;
}
@@ -1127,8 +1122,8 @@ void Log_event::print_header(IO_CACHE* file,
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
- DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
- my_b_write(file, (byte*) emit_buf, bytes_written);
+ DBUG_ASSERT(static_cast<size_t>(bytes_written) < sizeof(emit_buf));
+ my_b_write(file, (uchar*) emit_buf, bytes_written);
hex_string[0]= 0;
char_string[0]= 0;
c= char_string;
@@ -1144,13 +1139,18 @@ void Log_event::print_header(IO_CACHE* file,
char emit_buf[256];
int const bytes_written=
my_snprintf(emit_buf, sizeof(emit_buf),
- "# %8.8lx %-48.48s |%s|\n# ",
+ "# %8.8lx %-48.48s |%s|\n",
(unsigned long) (hexdump_from + (i & 0xfffffff0)),
hex_string, char_string);
DBUG_ASSERT(bytes_written >= 0);
- DBUG_ASSERT(static_cast<my_size_t>(bytes_written) < sizeof(emit_buf));
- my_b_write(file, (byte*) emit_buf, bytes_written);
+ DBUG_ASSERT(static_cast<size_t>(bytes_written) < sizeof(emit_buf));
+ my_b_write(file, (uchar*) emit_buf, bytes_written);
}
+ /*
+ need a # to prefix the rest of printouts for example those of
+ Rows_log_event::print_helper().
+ */
+ my_b_write(file, reinterpret_cast<const uchar*>("# "), 2);
}
DBUG_VOID_RETURN;
}
@@ -1162,7 +1162,6 @@ void Log_event::print_base64(IO_CACHE* file,
{
const uchar *ptr= (const uchar *)temp_buf;
uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
-
DBUG_ENTER("Log_event::print_base64");
size_t const tmp_str_sz= base64_needed_encoded_length((int) size);
@@ -1173,8 +1172,10 @@ void Log_event::print_base64(IO_CACHE* file,
DBUG_VOID_RETURN;
}
- int const res= base64_encode(ptr, (size_t) size, tmp_str);
- DBUG_ASSERT(res == 0);
+ if (base64_encode(ptr, (size_t) size, tmp_str))
+ {
+ DBUG_ASSERT(0);
+ }
if (my_b_tell(file) == 0)
my_b_printf(file, "\nBINLOG '\n");
@@ -1237,7 +1238,7 @@ void Query_log_event::pack_info(Protocol *protocol)
{
// TODO: show the catalog ??
char *buf, *pos;
- if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME))))
+ if (!(buf= (char*) my_malloc(9 + db_len + q_len, MYF(MY_WME))))
return;
pos= buf;
if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
@@ -1288,7 +1289,9 @@ bool Query_log_event::write(IO_CACHE* file)
1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
1+4+ // code of autoinc and the 2 autoinc variables
1+6+ // code of charset and charset
- 1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name
+ 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name
+ 1+2+ // code of lc_time_names and lc_time_names_number
+ 1+2 // code of charset_database and charset_database_number
], *start, *start_of_status;
ulong event_length;
@@ -1400,6 +1403,20 @@ bool Query_log_event::write(IO_CACHE* file)
memcpy(start, time_zone_str, time_zone_len);
start+= time_zone_len;
}
+ if (lc_time_names_number)
+ {
+ DBUG_ASSERT(lc_time_names_number <= 0xFFFF);
+ *start++= Q_LC_TIME_NAMES_CODE;
+ int2store(start, lc_time_names_number);
+ start+= 2;
+ }
+ if (charset_database_number)
+ {
+ DBUG_ASSERT(charset_database_number <= 0xFFFF);
+ *start++= Q_CHARSET_DATABASE_CODE;
+ int2store(start, charset_database_number);
+ start+= 2;
+ }
/*
Here there could be code like
if (command-line-option-which-says-"log_this_variable" && inited)
@@ -1422,12 +1439,12 @@ bool Query_log_event::write(IO_CACHE* file)
event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
return (write_header(file, event_length) ||
- my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
+ my_b_safe_write(file, (uchar*) buf, QUERY_HEADER_LEN) ||
write_post_header_for_derived(file) ||
- my_b_safe_write(file, (byte*) start_of_status,
+ my_b_safe_write(file, (uchar*) start_of_status,
(uint) (start-start_of_status)) ||
- my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
- my_b_safe_write(file, (byte*) query, q_len)) ? 1 : 0;
+ my_b_safe_write(file, (db) ? (uchar*) db : (uchar*)"", db_len + 1) ||
+ my_b_safe_write(file, (uchar*) query, q_len)) ? 1 : 0;
}
/*
@@ -1444,34 +1461,58 @@ Query_log_event::Query_log_event()
/*
- Query_log_event::Query_log_event()
+ SYNOPSIS
+ Query_log_event::Query_log_event()
+ thd - thread handle
+ query_arg - array of char representing the query
+ query_length - size of the `query_arg' array
+ using_trans - there is a modified transactional table
+ suppress_use - suppress the generation of 'USE' statements
+ killed_status_arg - an optional with default to THD::KILLED_NO_VALUE
+ if the value is different from the default, the arg
+ is set to the current thd->killed value.
+ A caller might need to masquerade thd->killed with
+ THD::NOT_KILLED.
+ DESCRIPTION
+ Creates an event for binlogging
+ The value for local `killed_status' can be supplied by caller.
*/
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans,
- bool suppress_use)
+ bool suppress_use, THD::killed_state killed_status_arg)
:Log_event(thd_arg,
((thd_arg->tmp_table_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0)
| (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0)),
using_trans),
data_buf(0), query(query_arg), catalog(thd_arg->catalog),
db(thd_arg->db), q_len((uint32) query_length),
- error_code((thd_arg->killed != THD::NOT_KILLED) ?
- ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ?
- 0 : thd->killed_errno()) : thd_arg->net.last_errno),
thread_id(thd_arg->thread_id),
/* save the original thread id; we already know the server id */
slave_proxy_id(thd_arg->variables.pseudo_thread_id),
flags2_inited(1), sql_mode_inited(1), charset_inited(1),
sql_mode(thd_arg->variables.sql_mode),
auto_increment_increment(thd_arg->variables.auto_increment_increment),
- auto_increment_offset(thd_arg->variables.auto_increment_offset)
+ auto_increment_offset(thd_arg->variables.auto_increment_offset),
+ lc_time_names_number(thd_arg->variables.lc_time_names->number),
+ charset_database_number(0)
{
time_t end_time;
+
+ if (killed_status_arg == THD::KILLED_NO_VALUE)
+ killed_status_arg= thd_arg->killed;
+ error_code=
+ (killed_status_arg == THD::NOT_KILLED) ? thd_arg->net.last_errno :
+ ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 :
+ thd->killed_errno());
+
time(&end_time);
exec_time = (ulong) (end_time - thd->start_time);
catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
/* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
+ if (thd_arg->variables.collation_database != thd_arg->db_charset)
+ charset_database_number= thd_arg->variables.collation_database->number;
+
/*
If we don't use flags2 for anything else than options contained in
thd->options, it would be more efficient to flags2=thd_arg->options
@@ -1506,42 +1547,50 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
/* 2 utility functions for the next method */
-static void get_str_len_and_pointer(const char **dst, const char **src, uint *len)
+/*
+ Get the pointer for a string (src) that contains the length in
+ the first byte. Set the output string (dst) to the string value
+ and place the length of the string in the byte after the string.
+*/
+static void get_str_len_and_pointer(const Log_event::Byte **src,
+ const char **dst,
+ uint *len)
{
if ((*len= **src))
- *dst= *src + 1; // Will be copied later
- (*src)+= *len+1;
+ *dst= (char *)*src + 1; // Will be copied later
+ (*src)+= *len + 1;
}
-
-static void copy_str_and_move(char **dst, const char **src, uint len)
+static void copy_str_and_move(const char **src,
+ Log_event::Byte **dst,
+ uint len)
{
memcpy(*dst, *src, len);
- *src= *dst;
+ *src= (const char *)*dst;
(*dst)+= len;
*(*dst)++= 0;
}
-
/*
Query_log_event::Query_log_event()
This is used by the SQL slave thread to prepare the event before execution.
*/
Query_log_event::Query_log_event(const char* buf, uint event_len,
- const Format_description_log_event *description_event,
+ const Format_description_log_event
+ *description_event,
Log_event_type event_type)
:Log_event(buf, description_event), data_buf(0), query(NullS),
db(NullS), catalog_len(0), status_vars_len(0),
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
auto_increment_increment(1), auto_increment_offset(1),
- time_zone_len(0)
+ time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
{
ulong data_len;
uint32 tmp;
uint8 common_header_len, post_header_len;
- char *start;
- const char *end;
+ Log_event::Byte *start;
+ const Log_event::Byte *end;
bool catalog_nz= 1;
DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
@@ -1587,9 +1636,9 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
/* variable-part: the status vars; only in MySQL 5.0 */
- start= (char*) (buf+post_header_len);
- end= (const char*) (start+status_vars_len);
- for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;)
+ start= (Log_event::Byte*) (buf+post_header_len);
+ end= (const Log_event::Byte*) (start+status_vars_len);
+ for (const Log_event::Byte* pos= start; pos < end;)
{
switch (*pos++) {
case Q_FLAGS2_CODE:
@@ -1611,7 +1660,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
break;
}
case Q_CATALOG_NZ_CODE:
- get_str_len_and_pointer(&catalog, (const char **)(&pos), &catalog_len);
+ get_str_len_and_pointer(&pos, &catalog, &catalog_len);
break;
case Q_AUTO_INCREMENT:
auto_increment_increment= uint2korr(pos);
@@ -1627,7 +1676,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
}
case Q_TIME_ZONE_CODE:
{
- get_str_len_and_pointer(&time_zone_str, (const char **)(&pos), &time_zone_len);
+ get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len);
break;
}
case Q_CATALOG_CODE: /* for 5.0.x where 0<=x<=3 masters */
@@ -1636,6 +1685,14 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
pos+= catalog_len+2; // leap over end 0
catalog_nz= 0; // catalog has end 0 in event
break;
+ case Q_LC_TIME_NAMES_CODE:
+ lc_time_names_number= uint2korr(pos);
+ pos+= 2;
+ break;
+ case Q_CHARSET_DATABASE_CODE:
+ charset_database_number= uint2korr(pos);
+ pos+= 2;
+ break;
default:
/* That's why you must write status vars in growing order of code */
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
@@ -1645,38 +1702,38 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
}
#if !defined(MYSQL_CLIENT) && defined(HAVE_QUERY_CACHE)
- if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
- time_zone_len + 1 +
- data_len + 1 +
- QUERY_CACHE_FLAGS_SIZE +
- db_len + 1,
- MYF(MY_WME))))
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 +
+ time_zone_len + 1 +
+ data_len + 1 +
+ QUERY_CACHE_FLAGS_SIZE +
+ db_len + 1,
+ MYF(MY_WME))))
#else
- if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
- time_zone_len + 1 +
- data_len + 1,
- MYF(MY_WME))))
+ if (!(start= data_buf = (Log_event::Byte*) my_malloc(catalog_len + 1 +
+ time_zone_len + 1 +
+ data_len + 1,
+ MYF(MY_WME))))
#endif
DBUG_VOID_RETURN;
if (catalog_len) // If catalog is given
{
if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3.
- copy_str_and_move(&start, &catalog, catalog_len);
+ copy_str_and_move(&catalog, &start, catalog_len);
else
{
memcpy(start, catalog, catalog_len+1); // copy end 0
- catalog= start;
+ catalog= (const char *)start;
start+= catalog_len+1;
}
}
if (time_zone_len)
- copy_str_and_move(&start, &time_zone_str, time_zone_len);
+ copy_str_and_move(&time_zone_str, &start, time_zone_len);
/* A 2nd variable part; this is common to all versions */
memcpy((char*) start, end, data_len); // Copy db and query
start[data_len]= '\0'; // End query with \0 (For safetly)
- db= start;
- query= start + db_len + 1;
+ db= (char *)start;
+ query= (char *)(start + db_len + 1);
q_len= data_len - db_len -1;
DBUG_VOID_RETURN;
}
@@ -1714,7 +1771,7 @@ void Query_log_event::print_query_header(IO_CACHE* file,
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
end= strmov(end, print_event_info->delimiter);
*end++='\n';
- my_b_write(file, (byte*) buff, (uint) (end-buff));
+ my_b_write(file, (uchar*) buff, (uint) (end-buff));
if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
(ulong)thread_id, print_event_info->delimiter);
@@ -1798,7 +1855,7 @@ void Query_log_event::print_query_header(IO_CACHE* file,
print_event_info->charset_inited= 1;
print_event_info->charset[0]= ~charset[0]; // force a difference to force write
}
- if (unlikely(bcmp(print_event_info->charset, charset, 6)))
+ if (unlikely(bcmp((uchar*) print_event_info->charset, (uchar*) charset, 6)))
{
CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
if (cs_info)
@@ -1821,13 +1878,30 @@ void Query_log_event::print_query_header(IO_CACHE* file,
}
if (time_zone_len)
{
- if (bcmp(print_event_info->time_zone_str, time_zone_str, time_zone_len+1))
+ if (bcmp((uchar*) print_event_info->time_zone_str,
+ (uchar*) time_zone_str, time_zone_len+1))
{
my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
time_zone_str, print_event_info->delimiter);
memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
}
}
+ if (lc_time_names_number != print_event_info->lc_time_names_number)
+ {
+ my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
+ lc_time_names_number, print_event_info->delimiter);
+ print_event_info->lc_time_names_number= lc_time_names_number;
+ }
+ if (charset_database_number != print_event_info->charset_database_number)
+ {
+ if (charset_database_number)
+ my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+ charset_database_number, print_event_info->delimiter);
+ else
+ my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+ print_event_info->delimiter);
+ print_event_info->charset_database_number= charset_database_number;
+ }
}
@@ -1836,34 +1910,35 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
Write_on_release_cache cache(&print_event_info->head_cache, file);
print_query_header(&cache, print_event_info);
- my_b_write(&cache, (byte*) query, q_len);
+ my_b_write(&cache, (uchar*) query, q_len);
my_b_printf(&cache, "%s\n", print_event_info->delimiter);
}
#endif /* MYSQL_CLIENT */
/*
- Query_log_event::exec_event()
+ Query_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Query_log_event::exec_event(struct st_relay_log_info* rli)
+int Query_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
- return exec_event(rli, query, q_len);
+ return do_apply_event(rli, query, q_len);
}
-int Query_log_event::exec_event(struct st_relay_log_info* rli,
- const char *query_arg, uint32 q_len_arg)
+int Query_log_event::do_apply_event(RELAY_LOG_INFO const *rli,
+ const char *query_arg, uint32 q_len_arg)
{
LEX_STRING new_db;
int expected_error,actual_error= 0;
/*
- Colleagues: please never free(thd->catalog) in MySQL. This would lead to
- bugs as here thd->catalog is a part of an alloced block, not an entire
- alloced block (see Query_log_event::exec_event()). Same for thd->db.
- Thank you.
+ Colleagues: please never free(thd->catalog) in MySQL. This would
+ lead to bugs as here thd->catalog is a part of an alloced block,
+ not an entire alloced block (see
+ Query_log_event::do_apply_event()). Same for thd->db. Thank
+ you.
*/
thd->catalog= catalog_len ? (char *) catalog : (char *)"";
new_db.length= db_len;
@@ -1882,11 +1957,11 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
END of the current log event (COMMIT). We save it in rli so that InnoDB can
access it.
*/
- rli->future_group_master_log_pos= log_pos;
+ const_cast<RELAY_LOG_INFO*>(rli)->future_group_master_log_pos= log_pos;
DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
- clear_all_errors(thd, rli);
- rli->clear_tables_to_lock();
+ clear_all_errors(thd, const_cast<RELAY_LOG_INFO*>(rli));
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
/*
Note: We do not need to execute reset_one_shot_variables() if this
@@ -1895,8 +1970,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
its companion query. If the SET is ignored because of
db_ok(), the companion query will also be ignored, and if
the companion query is ignored in the db_ok() test of
- ::exec_event(), then the companion SET also have so we
- don't need to reset_one_shot_variables().
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
*/
if (rpl_filter->db_ok(thd->db))
{
@@ -1962,17 +2037,44 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
if (time_zone_len)
{
String tmp(time_zone_str, time_zone_len, &my_charset_bin);
- if (!(thd->variables.time_zone=
- my_tz_find_with_opening_tz_tables(thd, &tmp)))
+ if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
{
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
thd->variables.time_zone= global_system_variables.time_zone;
goto compare_errors;
}
}
-
+ if (lc_time_names_number)
+ {
+ if (!(thd->variables.lc_time_names=
+ my_locale_by_number(lc_time_names_number)))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unknown locale: '%d'", MYF(0), lc_time_names_number);
+ thd->variables.lc_time_names= &my_locale_en_US;
+ goto compare_errors;
+ }
+ }
+ else
+ thd->variables.lc_time_names= &my_locale_en_US;
+ if (charset_database_number)
+ {
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_database_number, MYF(0))))
+ {
+ char buf[20];
+ int10_to_str((int) charset_database_number, buf, -10);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+ goto compare_errors;
+ }
+ thd->variables.collation_database= cs;
+ }
+ else
+ thd->variables.collation_database= thd->db_charset;
+
/* Execute the query (note that we bypass dispatch_command()) */
- mysql_parse(thd, thd->query, thd->query_length);
+ const char* found_semicolon= NULL;
+ mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
}
else
@@ -1985,7 +2087,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli,
to check/fix it.
*/
if (mysql_test_parse_for_slave(thd, thd->query, thd->query_length))
- clear_all_errors(thd, rli); /* Can ignore query */
+ clear_all_errors(thd, const_cast<RELAY_LOG_INFO*>(rli)); /* Can ignore query */
else
{
rli->report(ERROR_LEVEL, expected_error,
@@ -2036,7 +2138,7 @@ Default database: '%s'. Query: '%s'",
ignored_error_code(actual_error))
{
DBUG_PRINT("info",("error ignored"));
- clear_all_errors(thd, rli);
+ clear_all_errors(thd, const_cast<RELAY_LOG_INFO*>(rli));
}
/*
Other cases: mostly we expected no error and get one.
@@ -2103,16 +2205,26 @@ end:
thd->first_successful_insert_id_in_prev_stmt= 0;
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ return thd->query_error;
+}
+
+int Query_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
/*
- If there was an error we stop. Otherwise we increment positions. Note that
- we will not increment group* positions if we are just after a SET
- ONE_SHOT, because SET ONE_SHOT should not be separated from its following
- updating query.
+ Note that we will not increment group* positions if we are just
+ after a SET ONE_SHOT, because SET ONE_SHOT should not be separated
+ from its following updating query.
*/
- return (thd->query_error ? thd->query_error :
- (thd->one_shot_set ? (rli->inc_event_relay_log_pos(),0) :
- Log_event::exec_event(rli)));
+ if (thd->one_shot_set)
+ {
+ rli->inc_event_relay_log_pos();
+ return 0;
+ }
+ else
+ return Log_event::do_update_pos(rli);
}
+
+
#endif
@@ -2215,6 +2327,8 @@ Start_log_event_v3::Start_log_event_v3(const char* buf,
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
ST_SERVER_VER_LEN);
+ // prevent overrun if log is corrupted on disk
+ server_version[ST_SERVER_VER_LEN-1]= 0;
created= uint4korr(buf+ST_CREATED_OFFSET);
/* We use log_pos to mark if this was an artificial event or not */
artificial_event= (log_pos == 0);
@@ -2233,13 +2347,13 @@ bool Start_log_event_v3::write(IO_CACHE* file)
memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
int4store(buff + ST_CREATED_OFFSET,created);
return (write_header(file, sizeof(buff)) ||
- my_b_safe_write(file, (byte*) buff, sizeof(buff)));
+ my_b_safe_write(file, (uchar*) buff, sizeof(buff)));
}
#endif
/*
- Start_log_event_v3::exec_event()
+ Start_log_event_v3::do_apply_event()
The master started
@@ -2258,9 +2372,9 @@ bool Start_log_event_v3::write(IO_CACHE* file)
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Start_log_event_v3::exec_event(struct st_relay_log_info* rli)
+int Start_log_event_v3::do_apply_event(RELAY_LOG_INFO const *rli)
{
- DBUG_ENTER("Start_log_event_v3::exec_event");
+ DBUG_ENTER("Start_log_event_v3::do_apply_event");
switch (binlog_version)
{
case 3:
@@ -2302,7 +2416,7 @@ int Start_log_event_v3::exec_event(struct st_relay_log_info* rli)
/* this case is impossible */
DBUG_RETURN(1);
}
- DBUG_RETURN(Log_event::exec_event(rli));
+ DBUG_RETURN(0);
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -2338,6 +2452,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
switch (binlog_ver) {
case 4: /* MySQL 5.0 */
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+ DBUG_EXECUTE_IF("pretend_version_50034_in_binlog",
+ strmov(server_version, "5.0.34"););
common_header_len= LOG_EVENT_HEADER_LEN;
number_of_event_types= LOG_EVENT_TYPES;
/* we'll catch my_malloc() error in is_valid() */
@@ -2381,6 +2497,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[DELETE_ROWS_EVENT-1]= 6;);
post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= post_header_len[APPEND_BLOCK_EVENT-1];
post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
+ post_header_len[INCIDENT_EVENT-1]= INCIDENT_HEADER_LEN;
}
break;
@@ -2428,6 +2545,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len= 0; /* will make is_valid() fail */
break;
}
+ calc_server_version_split();
}
@@ -2464,9 +2582,10 @@ Format_description_log_event(const char* buf,
DBUG_PRINT("info", ("common_header_len=%d number_of_event_types=%d",
common_header_len, number_of_event_types));
/* If alloc fails, we'll detect it in is_valid() */
- post_header_len= (uint8*) my_memdup((byte*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
+ post_header_len= (uint8*) my_memdup((uchar*)buf+ST_COMMON_HEADER_LEN_OFFSET+1,
number_of_event_types*
sizeof(*post_header_len), MYF(0));
+ calc_server_version_split();
DBUG_VOID_RETURN;
}
@@ -2477,36 +2596,22 @@ bool Format_description_log_event::write(IO_CACHE* file)
We don't call Start_log_event_v3::write() because this would make 2
my_b_safe_write().
*/
- byte buff[FORMAT_DESCRIPTION_HEADER_LEN];
+ uchar buff[FORMAT_DESCRIPTION_HEADER_LEN];
int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
int4store(buff + ST_CREATED_OFFSET,created);
buff[ST_COMMON_HEADER_LEN_OFFSET]= LOG_EVENT_HEADER_LEN;
- memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET+1, (byte*) post_header_len,
+ memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET+1, (uchar*) post_header_len,
LOG_EVENT_TYPES);
return (write_header(file, sizeof(buff)) ||
my_b_safe_write(file, buff, sizeof(buff)));
}
#endif
-/*
- SYNOPSIS
- Format_description_log_event::exec_event()
-
- IMPLEMENTATION
- Save the information which describes the binlog's format, to be able to
- read all coming events.
- Call Start_log_event_v3::exec_event().
-*/
-
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
+int Format_description_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
- DBUG_ENTER("Format_description_log_event::exec_event");
-
- /* save the information describing this binlog */
- delete rli->relay_log.description_event_for_exec;
- rli->relay_log.description_event_for_exec= this;
+ DBUG_ENTER("Format_description_log_event::do_apply_event");
#ifdef USING_TRANSACTIONS
/*
@@ -2528,14 +2633,36 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
"or ROLLBACK in relay log). A probable cause is that "
"the master died while writing the transaction to "
"its binary log, thus rolled back too.");
- rli->cleanup_context(thd, 1);
+ const_cast<RELAY_LOG_INFO*>(rli)->cleanup_context(thd, 1);
}
#endif
/*
- If this event comes from ourselves, there is no cleaning task to perform,
- we don't call Start_log_event_v3::exec_event() (this was just to update the
- log's description event).
+ If this event comes from ourselves, there is no cleaning task to
+ perform, we don't call Start_log_event_v3::do_apply_event()
+ (this was just to update the log's description event).
*/
+ if (server_id != (uint32) ::server_id)
+ {
+ /*
+ If the event was not requested by the slave i.e. the master sent
+ it while the slave asked for a position >4, the event will make
+ rli->group_master_log_pos advance. Say that the slave asked for
+ position 1000, and the Format_desc event's end is 96. Then in
+ the beginning of replication rli->group_master_log_pos will be
+ 0, then 96, then jump to first really asked event (which is
+ >96). So this is ok.
+ */
+ DBUG_RETURN(Start_log_event_v3::do_apply_event(rli));
+ }
+ DBUG_RETURN(0);
+}
+
+int Format_description_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
+ /* save the information describing this binlog */
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= this;
+
if (server_id == (uint32) ::server_id)
{
/*
@@ -2552,21 +2679,53 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli)
the Intvar_log_event respectively.
*/
rli->inc_event_relay_log_pos();
- DBUG_RETURN(0);
+ return 0;
}
+ else
+ {
+ return Log_event::do_update_pos(rli);
+ }
+}
- /*
- If the event was not requested by the slave i.e. the master sent it while
- the slave asked for a position >4, the event will make
- rli->group_master_log_pos advance. Say that the slave asked for position
- 1000, and the Format_desc event's end is 96. Then in the beginning of
- replication rli->group_master_log_pos will be 0, then 96, then jump to
- first really asked event (which is >96). So this is ok.
- */
- DBUG_RETURN(Start_log_event_v3::exec_event(rli));
+Log_event::enum_skip_reason
+Format_description_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ return Log_event::EVENT_SKIP_NOT;
}
+
#endif
+
+/**
+ Splits the event's 'server_version' string into three numeric pieces stored
+ into 'server_version_split':
+ X.Y.Zabc (X,Y,Z numbers, a not a digit) -> {X,Y,Z}
+ X.Yabc -> {X,Y,0}
+ Xabc -> {X,0,0}
+ 'server_version_split' is then used for lookups to find if the server which
+ created this event has some known bug.
+*/
+void Format_description_log_event::calc_server_version_split()
+{
+ char *p= server_version, *r;
+ ulong number;
+ for (uint i= 0; i<=2; i++)
+ {
+ number= strtoul(p, &r, 10);
+ server_version_split[i]= (uchar)number;
+ DBUG_ASSERT(number < 256); // fit in uchar
+ p= r;
+ DBUG_ASSERT(!((i == 0) && (*r != '.'))); // should be true in practice
+ if (*r == '.')
+ p++; // skip the dot
+ }
+ DBUG_PRINT("info",("Format_description_log_event::server_version_split:"
+ " '%s' %d %d %d", server_version,
+ server_version_split[0],
+ server_version_split[1], server_version_split[2]));
+}
+
+
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
@@ -2697,7 +2856,7 @@ void Load_log_event::pack_info(Protocol *protocol)
{
char *buf, *end;
- if (!(buf= my_malloc(get_query_buffer_length(), MYF(MY_WME))))
+ if (!(buf= (char*) my_malloc(get_query_buffer_length(), MYF(MY_WME))))
return;
print_query(TRUE, buf, &end, 0, 0);
protocol->store(buf, end-buf, &my_charset_bin);
@@ -2721,7 +2880,7 @@ bool Load_log_event::write_data_header(IO_CACHE* file)
buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
buf[L_DB_LEN_OFFSET] = (char)db_len;
int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
- return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN) != 0;
+ return my_b_safe_write(file, (uchar*)buf, LOAD_HEADER_LEN) != 0;
}
@@ -2735,13 +2894,13 @@ bool Load_log_event::write_data_body(IO_CACHE* file)
return 1;
if (num_fields && fields && field_lens)
{
- if (my_b_safe_write(file, (byte*)field_lens, num_fields) ||
- my_b_safe_write(file, (byte*)fields, field_block_len))
+ if (my_b_safe_write(file, (uchar*)field_lens, num_fields) ||
+ my_b_safe_write(file, (uchar*)fields, field_block_len))
return 1;
}
- return (my_b_safe_write(file, (byte*)table_name, table_name_len + 1) ||
- my_b_safe_write(file, (byte*)db, db_len + 1) ||
- my_b_safe_write(file, (byte*)fname, fname_len));
+ return (my_b_safe_write(file, (uchar*)table_name, table_name_len + 1) ||
+ my_b_safe_write(file, (uchar*)db, db_len + 1) ||
+ my_b_safe_write(file, (uchar*)fname, fname_len));
}
@@ -3047,30 +3206,32 @@ void Load_log_event::set_fields(const char* affected_db,
Does the data loading job when executing a LOAD DATA on the slave
SYNOPSIS
- Load_log_event::exec_event
- net
- rli
- use_rli_only_for_errors - if set to 1, rli is provided to
- Load_log_event::exec_event only for this
- function to have RPL_LOG_NAME and
- rli->last_slave_error, both being used by
- error reports. rli's position advancing
- is skipped (done by the caller which is
- Execute_load_log_event::exec_event).
- - if set to 0, rli is provided for full use,
- i.e. for error reports and position
- advancing.
+ Load_log_event::do_apply_event
+ net
+ rli
+ use_rli_only_for_errors - if set to 1, rli is provided to
+ Load_log_event::do_apply_event
+ only for this function to have
+ RPL_LOG_NAME and
+ rli->last_slave_error, both being
+ used by error reports. rli's
+ position advancing is skipped (done
+ by the caller which is
+ Execute_load_log_event::do_apply_event).
+ - if set to 0, rli is provided for
+ full use, i.e. for error reports and
+ position advancing.
DESCRIPTION
Does the data loading job when executing a LOAD DATA on the slave
-
+
RETURN VALUE
- 0 Success
+ 0 Success
1 Failure
*/
-int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
- bool use_rli_only_for_errors)
+int Load_log_event::do_apply_event(NET* net, RELAY_LOG_INFO const *rli,
+ bool use_rli_only_for_errors)
{
LEX_STRING new_db;
new_db.length= db_len;
@@ -3079,33 +3240,39 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
DBUG_ASSERT(thd->query == 0);
thd->query_length= 0; // Should not be needed
thd->query_error= 0;
- clear_all_errors(thd, rli);
+ clear_all_errors(thd, const_cast<RELAY_LOG_INFO*>(rli));
- /* see Query_log_event::exec_event() and BUG#13360 */
+ /* see Query_log_event::do_apply_event() and BUG#13360 */
DBUG_ASSERT(!rli->m_table_map.count());
/*
- Usually mysql_init_query() is called by mysql_parse(), but we need it here
+ Usually lex_start() is called by mysql_parse(), but we need it here
as the present method does not call mysql_parse().
*/
- mysql_init_query(thd, 0, 0);
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
+
if (!use_rli_only_for_errors)
{
- /* Saved for InnoDB, see comment in Query_log_event::exec_event() */
- rli->future_group_master_log_pos= log_pos;
+ /*
+ Saved for InnoDB, see comment in
+ Query_log_event::do_apply_event()
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->future_group_master_log_pos= log_pos;
DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
}
/*
- We test replicate_*_db rules. Note that we have already prepared the file
- to load, even if we are going to ignore and delete it now. So it is
- possible that we did a lot of disk writes for nothing. In other words, a
- big LOAD DATA INFILE on the master will still consume a lot of space on
- the slave (space in the relay log + space of temp files: twice the space
- of the file to load...) even if it will finally be ignored.
- TODO: fix this; this can be done by testing rules in
- Create_file_log_event::exec_event() and then discarding Append_block and
- al. Another way is do the filtering in the I/O thread (more efficient: no
- disk writes at all).
+ We test replicate_*_db rules. Note that we have already prepared
+ the file to load, even if we are going to ignore and delete it
+ now. So it is possible that we did a lot of disk writes for
+ nothing. In other words, a big LOAD DATA INFILE on the master will
+ still consume a lot of space on the slave (space in the relay log
+ + space of temp files: twice the space of the file to load...)
+ even if it will finally be ignored. TODO: fix this; this can be
+ done by testing rules in Create_file_log_event::do_apply_event()
+ and then discarding Append_block and al. Another way is do the
+ filtering in the I/O thread (more efficient: no disk writes at
+ all).
Note: We do not need to execute reset_one_shot_variables() if this
@@ -3114,8 +3281,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
its companion query. If the SET is ignored because of
db_ok(), the companion query will also be ignored, and if
the companion query is ignored in the db_ok() test of
- ::exec_event(), then the companion SET also have so we
- don't need to reset_one_shot_variables().
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
*/
if (rpl_filter->db_ok(thd->db))
{
@@ -3227,10 +3394,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
ex.skip_lines = skip_lines;
List<Item> field_list;
- thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables);
- set_fields(tables.db, field_list, &thd->main_lex.select_lex.context);
+ thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
+ set_fields(tables.db, field_list, &thd->lex->select_lex.context);
thd->variables.pseudo_thread_id= thread_id;
- List<Item> set_fields;
if (net)
{
// mysql_load will use thd->net to read the file
@@ -3241,10 +3407,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
thd->net.pkt_nr = net->pkt_nr;
}
/*
- It is safe to use set_fields twice because we are not going to
+ It is safe to use tmp_list twice because we are not going to
update it inside mysql_load().
*/
- if (mysql_load(thd, &ex, &tables, field_list, set_fields, set_fields,
+ List<Item> tmp_list;
+ if (mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
handle_dup, ignore, net != 0))
thd->query_error= 1;
if (thd->cuted_fields)
@@ -3321,7 +3488,7 @@ Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
return 1;
}
- return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) );
+ return ( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rli) );
}
#endif
@@ -3364,7 +3531,7 @@ void Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
print_header(&cache, print_event_info, FALSE);
my_b_printf(&cache, "\tRotate to ");
if (new_log_ident)
- my_b_write(&cache, (byte*) new_log_ident, (uint)ident_len);
+ my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len);
my_b_printf(&cache, " pos: %s\n", llstr(pos, buf));
}
#endif /* MYSQL_CLIENT */
@@ -3415,6 +3582,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
ident_offset = post_header_len;
set_if_smaller(ident_len,FN_REFLEN-1);
new_log_ident= my_strndup(buf + ident_offset, (uint) ident_len, MYF(MY_WME));
+ DBUG_PRINT("debug", ("new_log_ident: '%s'", new_log_ident));
DBUG_VOID_RETURN;
}
@@ -3429,13 +3597,14 @@ bool Rotate_log_event::write(IO_CACHE* file)
char buf[ROTATE_HEADER_LEN];
int8store(buf + R_POS_OFFSET, pos);
return (write_header(file, ROTATE_HEADER_LEN + ident_len) ||
- my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
- my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
+ my_b_safe_write(file, (uchar*)buf, ROTATE_HEADER_LEN) ||
+ my_b_safe_write(file, (uchar*)new_log_ident, (uint) ident_len));
}
#endif
+
/*
- Rotate_log_event::exec_event()
+ Rotate_log_event::do_apply_event()
Got a rotate log event from the master
@@ -3452,34 +3621,52 @@ bool Rotate_log_event::write(IO_CACHE* file)
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
+int Rotate_log_event::do_update_pos(RELAY_LOG_INFO *rli)
{
- DBUG_ENTER("Rotate_log_event::exec_event");
+ DBUG_ENTER("Rotate_log_event::do_update_pos");
+#ifndef DBUG_OFF
+ char buf[32];
+#endif
+
+ DBUG_PRINT("info", ("server_id=%lu; ::server_id=%lu",
+ (ulong) this->server_id, (ulong) ::server_id));
+ DBUG_PRINT("info", ("new_log_ident: %s", this->new_log_ident));
+ DBUG_PRINT("info", ("pos: %s", llstr(this->pos, buf)));
pthread_mutex_lock(&rli->data_lock);
rli->event_relay_log_pos= my_b_tell(rli->cur_log);
/*
- If we are in a transaction: the only normal case is when the I/O thread was
- copying a big transaction, then it was stopped and restarted: we have this
- in the relay log:
+ If we are in a transaction or in a group: the only normal case is
+ when the I/O thread was copying a big transaction, then it was
+ stopped and restarted: we have this in the relay log:
+
BEGIN
...
ROTATE (a fake one)
...
COMMIT or ROLLBACK
- In that case, we don't want to touch the coordinates which correspond to
- the beginning of the transaction.
- Starting from 5.0.0, there also are some rotates from the slave itself, in
- the relay log.
+
+ In that case, we don't want to touch the coordinates which
+ correspond to the beginning of the transaction. Starting from
+ 5.0.0, there also are some rotates from the slave itself, in the
+ relay log, which shall not change the group positions.
*/
- if (!(thd->options & OPTION_BEGIN))
+ if ((server_id != ::server_id || rli->replicate_same_server_id) &&
+ !rli->is_in_group())
{
+ DBUG_PRINT("info", ("old group_master_log_name: '%s' "
+ "old group_master_log_pos: %lu",
+ rli->group_master_log_name,
+ (ulong) rli->group_master_log_pos));
memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
rli->notify_group_master_log_name_update();
rli->group_master_log_pos= pos;
+ strmake(rli->group_relay_log_name, rli->event_relay_log_name,
+ sizeof(rli->group_relay_log_name) - 1);
+ rli->notify_group_relay_log_name_update();
rli->group_relay_log_pos= rli->event_relay_log_pos;
- DBUG_PRINT("info", ("group_master_log_name: '%s' "
- "group_master_log_pos: %lu",
+ DBUG_PRINT("info", ("new group_master_log_name: '%s' "
+ "new group_master_log_pos: %lu",
rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
/*
@@ -3498,8 +3685,28 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
flush_relay_log_info(rli);
+
DBUG_RETURN(0);
}
+
+
+Log_event::enum_skip_reason
+Rotate_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rli);
+
+ switch (reason) {
+ case Log_event::EVENT_SKIP_NOT:
+ case Log_event::EVENT_SKIP_COUNT:
+ return Log_event::EVENT_SKIP_NOT;
+
+ case Log_event::EVENT_SKIP_IGNORE:
+ return Log_event::EVENT_SKIP_IGNORE;
+ }
+ DBUG_ASSERT(0);
+ return Log_event::EVENT_SKIP_NOT; // To keep compiler happy
+}
+
#endif
@@ -3558,8 +3765,8 @@ const char* Intvar_log_event::get_var_type_name()
#ifndef MYSQL_CLIENT
bool Intvar_log_event::write(IO_CACHE* file)
{
- byte buf[9];
- buf[I_TYPE_OFFSET]= (byte) type;
+ uchar buf[9];
+ buf[I_TYPE_OFFSET]= (uchar) type;
int8store(buf + I_VAL_OFFSET, val);
return (write_header(file, sizeof(buf)) ||
my_b_safe_write(file, buf, sizeof(buf)));
@@ -3606,12 +3813,18 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
/*
- Intvar_log_event::exec_event()
+ Intvar_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
-int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
+int Intvar_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
+ /*
+ We are now in a statement until the associated query log event has
+ been processed.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
+
switch (type) {
case LAST_INSERT_ID_EVENT:
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
@@ -3621,9 +3834,33 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
thd->force_one_auto_inc_interval(val);
break;
}
+ return 0;
+}
+
+int Intvar_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
rli->inc_event_relay_log_pos();
return 0;
}
+
+
+Log_event::enum_skip_reason
+Intvar_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
#endif
@@ -3657,7 +3894,7 @@ Rand_log_event::Rand_log_event(const char* buf,
#ifndef MYSQL_CLIENT
bool Rand_log_event::write(IO_CACHE* file)
{
- byte buf[16];
+ uchar buf[16];
int8store(buf + RAND_SEED1_OFFSET, seed1);
int8store(buf + RAND_SEED2_OFFSET, seed2);
return (write_header(file, sizeof(buf)) ||
@@ -3686,13 +3923,43 @@ void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Rand_log_event::exec_event(struct st_relay_log_info* rli)
+int Rand_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
+ /*
+ We are now in a statement until the associated query log event has
+ been processed.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
+
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
+ return 0;
+}
+
+int Rand_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
rli->inc_event_relay_log_pos();
return 0;
}
+
+
+Log_event::enum_skip_reason
+Rand_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
#endif /* !MYSQL_CLIENT */
@@ -3734,7 +4001,7 @@ Xid_log_event(const char* buf,
bool Xid_log_event::write(IO_CACHE* file)
{
return write_header(file, sizeof(xid)) ||
- my_b_safe_write(file, (byte*) &xid, sizeof(xid));
+ my_b_safe_write(file, (uchar*) &xid, sizeof(xid));
}
#endif
@@ -3759,12 +4026,12 @@ void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Xid_log_event::exec_event(struct st_relay_log_info* rli)
+int Xid_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
/* For a slave Xid_log_event is COMMIT */
general_log_print(thd, COM_QUERY,
"COMMIT /* implicit, from Xid_log_event */");
- return end_trans(thd, COMMIT) || Log_event::exec_event(rli);
+ return end_trans(thd, COMMIT);
}
#endif /* !MYSQL_CLIENT */
@@ -3782,7 +4049,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
if (is_null)
{
- buf= my_malloc(val_offset + 5, MYF(MY_WME));
+ if (!(buf= (char*) my_malloc(val_offset + 5, MYF(MY_WME))))
+ return;
strmov(buf + val_offset, "NULL");
event_len= val_offset + 4;
}
@@ -3792,28 +4060,37 @@ void User_var_log_event::pack_info(Protocol* protocol)
case REAL_RESULT:
double real_val;
float8get(real_val, val);
- buf= my_malloc(val_offset + FLOATING_POINT_BUFFER, MYF(MY_WME));
+ if (!(buf= (char*) my_malloc(val_offset + FLOATING_POINT_BUFFER,
+ MYF(MY_WME))))
+ return;
event_len+= my_sprintf(buf + val_offset,
(buf + val_offset, "%.14g", real_val));
break;
case INT_RESULT:
- buf= my_malloc(val_offset + 22, MYF(MY_WME));
+ if (!(buf= (char*) my_malloc(val_offset + 22, MYF(MY_WME))))
+ return;
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
break;
case DECIMAL_RESULT:
{
- buf= my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, MYF(MY_WME));
+ if (!(buf= (char*) my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH,
+ MYF(MY_WME))))
+ return;
String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin);
my_decimal dec;
- binary2my_decimal(E_DEC_FATAL_ERROR, val+2, &dec, val[0], val[1]);
+ binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0],
+ val[1]);
my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
event_len= str.length() + val_offset;
break;
}
case STRING_RESULT:
/* 15 is for 'COLLATE' and other chars */
- buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME));
+ buf= (char*) my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15,
+ MYF(MY_WME));
CHARSET_INFO *cs;
+ if (!buf)
+ return;
if (!(cs= get_charset(charset_number, MYF(0))))
{
strmov(buf+val_offset, "???");
@@ -3835,11 +4112,11 @@ void User_var_log_event::pack_info(Protocol* protocol)
}
buf[0]= '@';
buf[1]= '`';
+ memcpy(buf+2, name, name_len);
buf[2+name_len]= '`';
buf[3+name_len]= '=';
- memcpy(buf+2, name, name_len);
protocol->store(buf, event_len, &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf, MYF(0));
}
#endif /* !MYSQL_CLIENT */
@@ -3879,7 +4156,7 @@ bool User_var_log_event::write(IO_CACHE* file)
char buf[UV_NAME_LEN_SIZE];
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
- char buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
+ uchar buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
uint buf1_length;
ulong event_length;
@@ -3888,7 +4165,7 @@ bool User_var_log_event::write(IO_CACHE* file)
if ((buf1[0]= is_null))
{
buf1_length= 1;
- val_len= 0;
+ val_len= 0; // Length of 'pos'
}
else
{
@@ -3913,7 +4190,7 @@ bool User_var_log_event::write(IO_CACHE* file)
break;
}
case STRING_RESULT:
- pos= val;
+ pos= (uchar*) val;
break;
case ROW_RESULT:
default:
@@ -3928,10 +4205,10 @@ bool User_var_log_event::write(IO_CACHE* file)
event_length= sizeof(buf)+ name_len + buf1_length + val_len;
return (write_header(file, event_length) ||
- my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
- my_b_safe_write(file, (byte*) name, name_len) ||
- my_b_safe_write(file, (byte*) buf1, buf1_length) ||
- my_b_safe_write(file, (byte*) pos, val_len));
+ my_b_safe_write(file, (uchar*) buf, sizeof(buf)) ||
+ my_b_safe_write(file, (uchar*) name, name_len) ||
+ my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
+ my_b_safe_write(file, pos, val_len));
}
#endif
@@ -3953,7 +4230,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
}
my_b_printf(&cache, "SET @`");
- my_b_write(&cache, (byte*) name, (uint) (name_len));
+ my_b_write(&cache, (uchar*) name, (uint) (name_len));
my_b_printf(&cache, "`");
if (is_null)
@@ -3984,7 +4261,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
dec.len= 10;
dec.buf= dec_buf;
- bin2decimal(val+2, &dec, precision, scale);
+ bin2decimal((uchar*) val+2, &dec, precision, scale);
decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
str_buf[str_len]= 0;
my_b_printf(&cache, ":=%s%s\n", str_buf, print_event_info->delimiter);
@@ -4042,11 +4319,11 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
/*
- User_var_log_event::exec_event()
+ User_var_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int User_var_log_event::exec_event(struct st_relay_log_info* rli)
+int User_var_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
Item *it= 0;
CHARSET_INFO *charset;
@@ -4058,6 +4335,12 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
double real_val;
longlong int_val;
+ /*
+ We are now in a statement until the associated query log event has
+ been processed.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
+
if (is_null)
{
it= new Item_null();
@@ -4079,7 +4362,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
break;
case DECIMAL_RESULT:
{
- Item_decimal *dec= new Item_decimal(val+2, val[0], val[1]);
+ Item_decimal *dec= new Item_decimal((uchar*) val+2, val[0], val[1]);
it= dec;
val= (char *)dec->val_decimal(NULL);
val_len= sizeof(my_decimal);
@@ -4108,9 +4391,31 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
e.update_hash(val, val_len, type, charset, DERIVATION_IMPLICIT, 0);
free_root(thd->mem_root,0);
+ return 0;
+}
+
+int User_var_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
rli->inc_event_relay_log_pos();
return 0;
}
+
+Log_event::enum_skip_reason
+User_var_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead
+ of 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
#endif /* !MYSQL_CLIENT */
@@ -4150,7 +4455,7 @@ void Slave_log_event::pack_info(Protocol *protocol)
#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
- struct st_relay_log_info* rli)
+ RELAY_LOG_INFO* rli)
:Log_event(thd_arg, 0, 0) , mem_pool(0), master_host(0)
{
DBUG_ENTER("Slave_log_event");
@@ -4222,7 +4527,7 @@ bool Slave_log_event::write(IO_CACHE* file)
// log and host are already there
return (write_header(file, event_length) ||
- my_b_safe_write(file, (byte*) mem_pool, event_length));
+ my_b_safe_write(file, (uchar*) mem_pool, event_length));
}
#endif
@@ -4260,11 +4565,11 @@ Slave_log_event::Slave_log_event(const char* buf, uint event_len)
#ifndef MYSQL_CLIENT
-int Slave_log_event::exec_event(struct st_relay_log_info* rli)
+int Slave_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
if (mysql_bin_log.is_open())
mysql_bin_log.write(this);
- return Log_event::exec_event(rli);
+ return 0;
}
#endif /* !MYSQL_CLIENT */
@@ -4293,21 +4598,21 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
/*
- Stop_log_event::exec_event()
-
- The master stopped.
- We used to clean up all temporary tables but this is useless as, as the
- master has shut down properly, it has written all DROP TEMPORARY TABLE
- (prepared statements' deletion is TODO only when we binlog prep stmts).
- We used to clean up slave_load_tmpdir, but this is useless as it has been
- cleared at the end of LOAD DATA INFILE.
- So we have nothing to do here.
- The place were we must do this cleaning is in Start_log_event_v3::exec_event(),
- not here. Because if we come here, the master was sane.
+ Stop_log_event::do_apply_event()
+
+ The master stopped. We used to clean up all temporary tables but
+ this is useless as, as the master has shut down properly, it has
+ written all DROP TEMPORARY TABLE (prepared statements' deletion is
+ TODO only when we binlog prep stmts). We used to clean up
+ slave_load_tmpdir, but this is useless as it has been cleared at the
+ end of LOAD DATA INFILE. So we have nothing to do here. The place
+ were we must do this cleaning is in
+ Start_log_event_v3::do_apply_event(), not here. Because if we come
+ here, the master was sane.
*/
#ifndef MYSQL_CLIENT
-int Stop_log_event::exec_event(struct st_relay_log_info* rli)
+int Stop_log_event::do_update_pos(RELAY_LOG_INFO *rli)
{
/*
We do not want to update master_log pos because we get a rotate event
@@ -4325,6 +4630,7 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
}
return 0;
}
+
#endif /* !MYSQL_CLIENT */
#endif /* HAVE_REPLICATION */
@@ -4364,8 +4670,8 @@ bool Create_file_log_event::write_data_body(IO_CACHE* file)
bool res;
if ((res= Load_log_event::write_data_body(file)) || fake_base)
return res;
- return (my_b_safe_write(file, (byte*) "", 1) ||
- my_b_safe_write(file, (byte*) block, block_len));
+ return (my_b_safe_write(file, (uchar*) "", 1) ||
+ my_b_safe_write(file, (uchar*) block, block_len));
}
@@ -4376,7 +4682,7 @@ bool Create_file_log_event::write_data_body(IO_CACHE* file)
bool Create_file_log_event::write_data_header(IO_CACHE* file)
{
bool res;
- byte buf[CREATE_FILE_HEADER_LEN];
+ uchar buf[CREATE_FILE_HEADER_LEN];
if ((res= Load_log_event::write_data_header(file)) || fake_base)
return res;
int4store(buf + CF_FILE_ID_OFFSET, file_id);
@@ -4412,7 +4718,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
uint header_len= description_event->common_header_len;
uint8 load_header_len= description_event->post_header_len[LOAD_EVENT-1];
uint8 create_file_header_len= description_event->post_header_len[CREATE_FILE_EVENT-1];
- if (!(event_buf= my_memdup((byte*) buf, len, MYF(MY_WME))) ||
+ if (!(event_buf= (char*) my_memdup(buf, len, MYF(MY_WME))) ||
copy_log_event(event_buf,len,
((buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
load_header_len + header_len :
@@ -4515,11 +4821,11 @@ void Create_file_log_event::pack_info(Protocol *protocol)
/*
- Create_file_log_event::exec_event()
+ Create_file_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
+int Create_file_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
char proc_info[17+FN_REFLEN+10], *fname_buf;
char *ext;
@@ -4569,7 +4875,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
fname_buf);
goto err;
}
- if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ if (my_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
{
rli->report(ERROR_LEVEL, my_errno,
"Error in Create_file event: write to '%s' failed",
@@ -4584,7 +4890,7 @@ err:
if (fd >= 0)
my_close(fd, MYF(0));
thd->proc_info= 0;
- return error ? 1 : Log_event::exec_event(rli);
+ return error == 0;
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -4638,11 +4944,11 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len,
#ifndef MYSQL_CLIENT
bool Append_block_log_event::write(IO_CACHE* file)
{
- byte buf[APPEND_BLOCK_HEADER_LEN];
+ uchar buf[APPEND_BLOCK_HEADER_LEN];
int4store(buf + AB_FILE_ID_OFFSET, file_id);
return (write_header(file, APPEND_BLOCK_HEADER_LEN + block_len) ||
my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
- my_b_safe_write(file, (byte*) block, block_len));
+ my_b_safe_write(file, (uchar*) block, block_len));
}
#endif
@@ -4692,15 +4998,15 @@ int Append_block_log_event::get_create_or_append() const
}
/*
- Append_block_log_event::exec_event()
+ Append_block_log_event::do_apply_event()
*/
-int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
+int Append_block_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
char proc_info[17+FN_REFLEN+10], *fname= proc_info+17;
int fd;
int error = 1;
- DBUG_ENTER("Append_block_log_event::exec_event");
+ DBUG_ENTER("Append_block_log_event::do_apply_event");
fname= strmov(proc_info, "Making temp file ");
slave_load_file_stem(fname, file_id, server_id, ".data");
@@ -4726,7 +5032,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
get_type_str(), fname);
goto err;
}
- if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ if (my_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
{
rli->report(ERROR_LEVEL, my_errno,
"Error in %s event: write to '%s' failed",
@@ -4739,7 +5045,7 @@ err:
if (fd >= 0)
my_close(fd, MYF(0));
thd->proc_info= 0;
- DBUG_RETURN(error ? error : Log_event::exec_event(rli));
+ DBUG_RETURN(error);
}
#endif
@@ -4783,7 +5089,7 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
#ifndef MYSQL_CLIENT
bool Delete_file_log_event::write(IO_CACHE* file)
{
- byte buf[DELETE_FILE_HEADER_LEN];
+ uchar buf[DELETE_FILE_HEADER_LEN];
int4store(buf + DF_FILE_ID_OFFSET, file_id);
return (write_header(file, sizeof(buf)) ||
my_b_safe_write(file, buf, sizeof(buf)));
@@ -4823,18 +5129,18 @@ void Delete_file_log_event::pack_info(Protocol *protocol)
#endif
/*
- Delete_file_log_event::exec_event()
+ Delete_file_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
+int Delete_file_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
char fname[FN_REFLEN+10];
char *ext= slave_load_file_stem(fname, file_id, server_id, ".data");
(void) my_delete(fname, MYF(MY_WME));
strmov(ext, ".info");
(void) my_delete(fname, MYF(MY_WME));
- return Log_event::exec_event(rli);
+ return 0;
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -4879,7 +5185,7 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
#ifndef MYSQL_CLIENT
bool Execute_load_log_event::write(IO_CACHE* file)
{
- byte buf[EXEC_LOAD_HEADER_LEN];
+ uchar buf[EXEC_LOAD_HEADER_LEN];
int4store(buf + EL_FILE_ID_OFFSET, file_id);
return (write_header(file, sizeof(buf)) ||
my_b_safe_write(file, buf, sizeof(buf)));
@@ -4920,10 +5226,10 @@ void Execute_load_log_event::pack_info(Protocol *protocol)
/*
- Execute_load_log_event::exec_event()
+ Execute_load_log_event::do_apply_event()
*/
-int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
+int Execute_load_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
char fname[FN_REFLEN+10];
char *ext;
@@ -4955,14 +5261,15 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
lev->thd = thd;
/*
- lev->exec_event should use rli only for errors
- i.e. should not advance rli's position.
- lev->exec_event is the place where the table is loaded (it calls
- mysql_load()).
+ lev->do_apply_event should use rli only for errors i.e. should
+ not advance rli's position.
+
+ lev->do_apply_event is the place where the table is loaded (it
+ calls mysql_load()).
*/
- rli->future_group_master_log_pos= log_pos;
- if (lev->exec_event(0,rli,1))
+ const_cast<RELAY_LOG_INFO*>(rli)->future_group_master_log_pos= log_pos;
+ if (lev->do_apply_event(0,rli,1))
{
/*
We want to indicate the name of the file that could not be loaded
@@ -5003,7 +5310,7 @@ err:
my_close(fd, MYF(0));
end_io_cache(&file);
}
- return error ? error : Log_event::exec_event(rli);
+ return error;
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -5095,12 +5402,12 @@ ulong Execute_load_query_log_event::get_post_header_size_for_derived()
bool
Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
{
- char buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
+ uchar buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
int4store(buf, file_id);
int4store(buf + 4, fn_pos_start);
int4store(buf + 4 + 4, fn_pos_end);
- *(buf + 4 + 4 + 4)= (char)dup_handling;
- return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+ *(buf + 4 + 4 + 4)= (uchar) dup_handling;
+ return my_b_safe_write(file, buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
}
#endif
@@ -5123,19 +5430,19 @@ void Execute_load_query_log_event::print(FILE* file,
if (local_fname)
{
- my_b_write(&cache, (byte*) query, fn_pos_start);
+ my_b_write(&cache, (uchar*) query, fn_pos_start);
my_b_printf(&cache, " LOCAL INFILE \'");
my_b_printf(&cache, local_fname);
my_b_printf(&cache, "\'");
if (dup_handling == LOAD_DUP_REPLACE)
my_b_printf(&cache, " REPLACE");
my_b_printf(&cache, " INTO");
- my_b_write(&cache, (byte*) query + fn_pos_end, q_len-fn_pos_end);
+ my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end);
my_b_printf(&cache, "%s\n", print_event_info->delimiter);
}
else
{
- my_b_write(&cache, (byte*) query, q_len);
+ my_b_write(&cache, (uchar*) query, q_len);
my_b_printf(&cache, "%s\n", print_event_info->delimiter);
}
@@ -5149,7 +5456,7 @@ void Execute_load_query_log_event::print(FILE* file,
void Execute_load_query_log_event::pack_info(Protocol *protocol)
{
char *buf, *pos;
- if (!(buf= my_malloc(9 + db_len + q_len + 10 + 21, MYF(MY_WME))))
+ if (!(buf= (char*) my_malloc(9 + db_len + q_len + 10 + 21, MYF(MY_WME))))
return;
pos= buf;
if (db && db_len)
@@ -5171,7 +5478,7 @@ void Execute_load_query_log_event::pack_info(Protocol *protocol)
int
-Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
+Execute_load_query_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
char *p;
char *buf;
@@ -5179,8 +5486,8 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
char *fname_end;
int error;
- buf= my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
- (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
+ buf= (char*) my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
+ (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", buf= NULL;);
@@ -5213,7 +5520,7 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
p= strmake(p, STRING_WITH_LEN(" INTO"));
p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
- error= Query_log_event::exec_event(rli, buf, p-buf);
+ error= Query_log_event::do_apply_event(rli, buf, p-buf);
/* Forging file name for deletion in same buffer */
*fname_end= 0;
@@ -5248,7 +5555,7 @@ bool sql_ex_info::write_data(IO_CACHE* file)
write_str(file, line_term, (uint) line_term_len) ||
write_str(file, line_start, (uint) line_start_len) ||
write_str(file, escaped, (uint) escaped_len) ||
- my_b_safe_write(file,(byte*) &opt_flags,1));
+ my_b_safe_write(file,(uchar*) &opt_flags,1));
}
else
{
@@ -5260,7 +5567,7 @@ bool sql_ex_info::write_data(IO_CACHE* file)
old_ex.escaped= *escaped;
old_ex.opt_flags= opt_flags;
old_ex.empty_flags=empty_flags;
- return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)) != 0;
+ return my_b_safe_write(file, (uchar*) &old_ex, sizeof(old_ex)) != 0;
}
}
@@ -5269,7 +5576,7 @@ bool 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)
+char *sql_ex_info::init(char *buf, char *buf_end, bool use_new_format)
{
cached_new_format = use_new_format;
if (use_new_format)
@@ -5282,11 +5589,12 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
the case when we have old format because we will be reusing net buffer
to read the actual file before we write out the Create_file event.
*/
- if (read_str(&buf, buf_end, &field_term, &field_term_len) ||
- read_str(&buf, buf_end, &enclosed, &enclosed_len) ||
- read_str(&buf, buf_end, &line_term, &line_term_len) ||
- read_str(&buf, buf_end, &line_start, &line_start_len) ||
- read_str(&buf, buf_end, &escaped, &escaped_len))
+ const char *ptr= buf;
+ if (read_str(&ptr, buf_end, (const char **) &field_term, &field_term_len) ||
+ read_str(&ptr, buf_end, (const char **) &enclosed, &enclosed_len) ||
+ read_str(&ptr, buf_end, (const char **) &line_term, &line_term_len) ||
+ read_str(&ptr, buf_end, (const char **) &line_start, &line_start_len) ||
+ read_str(&ptr, buf_end, (const char **) &escaped, &escaped_len))
return 0;
opt_flags = *buf++;
}
@@ -5354,7 +5662,10 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
}
else
- m_cols.bitmap= 0; // to not free it
+ {
+ // Needed because bitmap_init() does not set it to null on failure
+ m_cols.bitmap= 0;
+ }
}
#endif
@@ -5391,28 +5702,66 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
m_flags= uint2korr(post_start);
- byte const *const var_start= (const byte *)buf + common_header_len +
- post_header_len;
- byte const *const ptr_width= var_start;
+ uchar const *const var_start=
+ (const uchar *)buf + common_header_len + post_header_len;
+ uchar const *const ptr_width= var_start;
uchar *ptr_after_width= (uchar*) ptr_width;
+ DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
m_width = net_field_length(&ptr_after_width);
+ DBUG_PRINT("debug", ("m_width=%lu", m_width));
+ /* if bitmap_init fails, catched in is_valid() */
+ if (likely(!bitmap_init(&m_cols,
+ m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
+ (m_width + 7) & ~7UL,
+ false)))
+ {
+ DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
+ memcpy(m_cols.bitmap, ptr_after_width, (m_width + 7) / 8);
+ ptr_after_width+= (m_width + 7) / 8;
+ DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
+ }
+ else
+ {
+ // Needed because bitmap_init() does not set it to null on failure
+ m_cols.bitmap= NULL;
+ DBUG_VOID_RETURN;
+ }
+
+ m_cols_ai.bitmap= m_cols.bitmap; /* See explanation in is_valid() */
- const uint byte_count= (m_width + 7) / 8;
- const byte* const ptr_rows_data= var_start + byte_count + 1;
+ if (event_type == UPDATE_ROWS_EVENT)
+ {
+ DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
- my_size_t const data_size= event_len - (ptr_rows_data - (const byte *) buf);
+ /* if bitmap_init fails, catched in is_valid() */
+ if (likely(!bitmap_init(&m_cols_ai,
+ m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
+ (m_width + 7) & ~7UL,
+ false)))
+ {
+ DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
+ memcpy(m_cols_ai.bitmap, ptr_after_width, (m_width + 7) / 8);
+ ptr_after_width+= (m_width + 7) / 8;
+ DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ }
+ else
+ {
+ // Needed because bitmap_init() does not set it to null on failure
+ m_cols_ai.bitmap= 0;
+ DBUG_VOID_RETURN;
+ }
+ }
+
+ const uchar* const ptr_rows_data= (const uchar*) ptr_after_width;
+
+ size_t const data_size= event_len - (ptr_rows_data - (const uchar *) buf);
DBUG_PRINT("info",("m_table_id: %lu m_flags: %d m_width: %lu data_size: %lu",
m_table_id, m_flags, m_width, data_size));
- m_rows_buf= (byte*)my_malloc(data_size, MYF(MY_WME));
+ m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME));
if (likely((bool)m_rows_buf))
{
- /* if bitmap_init fails, catched in is_valid() */
- if (likely(!bitmap_init(&m_cols,
- m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- (m_width + 7) & ~7UL,
- false)))
- memcpy(m_cols.bitmap, ptr_after_width, byte_count);
m_rows_end= m_rows_buf + data_size;
m_rows_cur= m_rows_end;
memcpy(m_rows_buf, ptr_rows_data, data_size);
@@ -5428,12 +5777,34 @@ Rows_log_event::~Rows_log_event()
if (m_cols.bitmap == m_bitbuf) // no my_malloc happened
m_cols.bitmap= 0; // so no my_free in bitmap_free
bitmap_free(&m_cols); // To pair with bitmap_init().
- my_free((gptr)m_rows_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*)m_rows_buf, MYF(MY_ALLOW_ZERO_PTR));
}
+int Rows_log_event::get_data_size()
+{
+ int const type_code= get_type_code();
+
+ uchar buf[sizeof(m_width)+1];
+ uchar *end= net_store_length(buf, (m_width + 7) / 8);
+
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
+ return 6 + no_bytes_in_map(&m_cols) + (end - buf) +
+ (type_code == UPDATE_ROWS_EVENT ? no_bytes_in_map(&m_cols_ai) : 0) +
+ (m_rows_cur - m_rows_buf););
+ int data_size= ROWS_HEADER_LEN;
+ data_size+= no_bytes_in_map(&m_cols);
+ data_size+= end - buf;
+
+ if (type_code == UPDATE_ROWS_EVENT)
+ data_size+= no_bytes_in_map(&m_cols_ai);
+
+ data_size+= (m_rows_cur - m_rows_buf);
+ return data_size;
+}
+
+
#ifndef MYSQL_CLIENT
-int Rows_log_event::do_add_row_data(byte *const row_data,
- my_size_t const length)
+int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
{
/*
When the table has a primary key, we would probably want, by default, to
@@ -5448,7 +5819,7 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("row_data", (const char*)row_data, min(length, 32));
+ DBUG_DUMP("row_data", row_data, min(length, 32));
#endif
DBUG_ASSERT(m_rows_buf <= m_rows_cur);
@@ -5456,15 +5827,14 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
DBUG_ASSERT(m_rows_cur <= m_rows_end);
/* The cast will always work since m_rows_cur <= m_rows_end */
- if (static_cast<my_size_t>(m_rows_end - m_rows_cur) < length)
+ if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
{
- my_size_t const block_size= 1024;
- my_ptrdiff_t const old_alloc= m_rows_end - m_rows_buf;
+ size_t const block_size= 1024;
my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf;
my_ptrdiff_t const new_alloc=
- block_size * ((cur_size + length) / block_size + block_size - 1);
+ block_size * ((cur_size + length + block_size - 1) / block_size);
- byte* const new_buf= (byte*)my_realloc((gptr)m_rows_buf, new_alloc,
+ uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc,
MYF(MY_ALLOW_ZERO_PTR|MY_WME));
if (unlikely(!new_buf))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
@@ -5483,7 +5853,7 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
m_rows_end= m_rows_buf + new_alloc;
}
- DBUG_ASSERT(m_rows_cur + length < m_rows_end);
+ DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
memcpy(m_rows_cur, row_data, length);
m_rows_cur+= length;
m_row_count++;
@@ -5492,162 +5862,17 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-/*
- Unpack a row into table->record[0].
-
- SYNOPSIS
- unpack_row()
- rli Relay log info
- table Table to unpack into
- colcnt Number of columns to read from record
- row Packed row data
- cols Pointer to columns data to fill in
- row_end Pointer to variable that will hold the value of the
- one-after-end position for the row
- master_reclength
- Pointer to variable that will be set to the length of the
- record on the master side
- rw_set Pointer to bitmap that holds either the read_set or the
- write_set of the table
-
- DESCRIPTION
-
- The function will always unpack into the table->record[0]
- record. This is because there are too many dependencies on
- where the various member functions of Field and subclasses
- expect to write.
-
- The row is assumed to only consist of the fields for which the
- bitset represented by 'arr' and 'bits'; the other parts of the
- record are left alone.
-
- At most 'colcnt' columns are read: if the table is larger than
- that, the remaining fields are not filled in.
-
- RETURN VALUE
-
- Error code, or zero if no error. The following error codes can
- be returned:
-
- ER_NO_DEFAULT_FOR_FIELD
- Returned if one of the fields existing on the slave but not on
- the master does not have a default value (and isn't nullable)
- */
-static int
-unpack_row(RELAY_LOG_INFO *rli,
- TABLE *table, uint const colcnt,
- char const *row, MY_BITMAP const *cols,
- char const **row_end, ulong *master_reclength,
- MY_BITMAP* const rw_set, Log_event_type const event_type)
-{
- byte *const record= table->record[0];
- DBUG_ENTER("unpack_row");
- DBUG_ASSERT(record && row);
- DBUG_PRINT("enter", ("row: 0x%lx table->record[0]: 0x%lx", (long) row, (long) record));
- my_size_t master_null_bytes= table->s->null_bytes;
-
- if (colcnt != table->s->fields)
- {
- Field **fptr= &table->field[colcnt-1];
- do
- master_null_bytes= (*fptr)->last_null_byte();
- while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF &&
- fptr-- > table->field);
-
- /*
- If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time,
- there were no nullable fields nor BIT fields at all in the
- columns that are common to the master and the slave. In that
- case, there is only one null byte holding the X bit.
-
- OBSERVE! There might still be nullable columns following the
- common columns, so table->s->null_bytes might be greater than 1.
- */
- if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF)
- master_null_bytes= 1;
- }
-
- DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
- memcpy(record, row, master_null_bytes); // [1]
- int error= 0;
-
- bitmap_set_all(rw_set);
-
- Field **const begin_ptr = table->field;
- Field **field_ptr;
- char const *ptr= row + master_null_bytes;
- Field **const end_ptr= begin_ptr + colcnt;
- for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
- {
- Field *const f= *field_ptr;
-
- if (bitmap_is_set(cols, field_ptr - begin_ptr))
- {
- DBUG_ASSERT((char *)table->record[0] <= f->ptr);
- DBUG_ASSERT(f->ptr < (char *)table->record[0] + table->s->reclength +
- (f->pack_length_in_rec() == 0));
- DBUG_PRINT("info", ("unpacking column '%s' to 0x%lx", f->field_name,
- (long) f->ptr));
- ptr= f->unpack(f->ptr, ptr);
- /* Field...::unpack() cannot return 0 */
- DBUG_ASSERT(ptr != NULL);
- }
- else
- bitmap_clear_bit(rw_set, field_ptr - begin_ptr);
- }
-
- *row_end = ptr;
- if (master_reclength)
- {
- if (*field_ptr)
- *master_reclength = (*field_ptr)->ptr - (char*) table->record[0];
- else
- *master_reclength = table->s->reclength;
- }
-
- /*
- Set properties for remaining columns, if there are any. We let the
- corresponding bit in the write_set be set, to write the value if
- it was not there already. We iterate over all remaining columns,
- even if there were an error, to get as many error messages as
- possible. We are still able to return a pointer to the next row,
- so redo that.
-
- This generation of error messages is only relevant when inserting
- new rows.
- */
- for ( ; *field_ptr ; ++field_ptr)
- {
- uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
- Field *const f= *field_ptr;
-
- DBUG_PRINT("info", ("processing column '%s' @ 0x%lx", f->field_name,
- (long) f->ptr));
- if (event_type == WRITE_ROWS_EVENT && (f->flags & mask) == mask)
- {
- rli->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD,
- ER(ER_NO_DEFAULT_FOR_FIELD),
- (*field_ptr)->field_name);
- error = ER_NO_DEFAULT_FOR_FIELD;
- }
- else
- f->set_default();
- }
-
- DBUG_RETURN(error);
-}
-
-int Rows_log_event::exec_event(st_relay_log_info *rli)
+int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
- DBUG_ENTER("Rows_log_event::exec_event(st_relay_log_info*)");
+ DBUG_ENTER("Rows_log_event::do_apply_event(st_relay_log_info*)");
int error= 0;
- char const *row_start= (char const *)m_rows_buf;
+ uchar const *row_start= m_rows_buf;
/*
- If m_table_id == ~0UL, then we have a dummy event that does
- not contain any data. In that case, we just remove all tables in
- the tables_to_lock list, close the thread tables, step the relay
- log position, and return with success.
+ If m_table_id == ~0UL, then we have a dummy event that does not
+ contain any data. In that case, we just remove all tables in the
+ tables_to_lock list, close the thread tables, and return with
+ success.
*/
if (m_table_id == ~0UL)
{
@@ -5657,16 +5882,16 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
*/
DBUG_ASSERT(get_flags(STMT_END_F));
- rli->clear_tables_to_lock();
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
close_thread_tables(thd);
thd->clear_error();
- rli->inc_event_relay_log_pos();
DBUG_RETURN(0);
}
/*
'thd' has been set by exec_relay_log_event(), just before calling
- exec_event(). We still check here to prevent future coding errors.
+ do_apply_event(). We still check here to prevent future coding
+ errors.
*/
DBUG_ASSERT(rli->sql_thd == thd);
@@ -5682,20 +5907,38 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
/*
lock_tables() reads the contents of thd->lex, so they must be
- initialized. Contrary to in Table_map_log_event::exec_event() we don't
- call mysql_init_query() as that may reset the binlog format.
+ initialized. Contrary to in
+ Table_map_log_event::do_apply_event() we don't call
+ mysql_init_query() as that may reset the binlog format.
*/
- lex_start(thd, NULL, 0);
+ lex_start(thd);
while ((error= lock_tables(thd, rli->tables_to_lock,
rli->tables_to_lock_count, &need_reopen)))
{
if (!need_reopen)
{
- rli->report(ERROR_LEVEL, error,
- "Error in %s event: when locking tables",
- get_type_str());
- rli->clear_tables_to_lock();
+ if (thd->query_error || thd->is_fatal_error)
+ {
+ /*
+ Error reporting borrowed from Query_log_event with many excessive
+ simplifications (we don't honour --slave-skip-errors)
+ */
+ uint actual_error= thd->net.last_errno;
+ rli->report(ERROR_LEVEL, actual_error,
+ "Error '%s' in %s event: when locking tables",
+ (actual_error ? thd->net.last_error :
+ "unexpected success or fatal error"),
+ get_type_str());
+ thd->is_fatal_error= 1;
+ }
+ else
+ {
+ rli->report(ERROR_LEVEL, error,
+ "Error in %s event: when locking tables",
+ get_type_str());
+ }
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
DBUG_RETURN(error);
}
@@ -5713,10 +5956,11 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
need to add code to assert that is the case.
*/
thd->binlog_flush_pending_rows_event(false);
- close_tables_for_reopen(thd, &rli->tables_to_lock);
+ TABLE_LIST *tables= rli->tables_to_lock;
+ close_tables_for_reopen(thd, &tables);
- if ((error= open_tables(thd, &rli->tables_to_lock,
- &rli->tables_to_lock_count, 0)))
+ uint tables_count= rli->tables_to_lock_count;
+ if ((error= open_tables(thd, &tables, &tables_count, 0)))
{
if (thd->query_error || thd->is_fatal_error)
{
@@ -5731,38 +5975,68 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
"unexpected success or fatal error"));
thd->query_error= 1;
}
- rli->clear_tables_to_lock();
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
DBUG_RETURN(error);
}
}
+
/*
- When the open and locking succeeded, we add all the tables to
- the table map and remove them from tables to lock.
+ When the open and locking succeeded, we check all tables to
+ ensure that they still have the correct type.
+
+ We can use a down cast here since we know that every table added
+ to the tables_to_lock is a RPL_TABLE_LIST.
+ */
+
+ {
+ RPL_TABLE_LIST *ptr= rli->tables_to_lock;
+ for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ {
+ if (ptr->m_tabledef.compatible_with(rli, ptr->table))
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ thd->query_error= 1;
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
+ DBUG_RETURN(ERR_BAD_TABLE_DEF);
+ }
+ }
+ }
+
+ /*
+ ... and then we add all the tables to the table map and remove
+ them from tables to lock.
We also invalidate the query cache for all the tables, since
they will now be changed.
+
+ TODO [/Matz]: Maybe the query cache should not be invalidated
+ here? It might be that a table is not changed, even though it
+ was locked for the statement. We do know that each
+ Rows_log_event contain at least one row, so after processing one
+ Rows_log_event, we can invalidate the query cache for the
+ associated table.
*/
- TABLE_LIST *ptr;
- for (ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
+ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
{
- rli->m_table_map.set_table(ptr->table_id, ptr->table);
+ const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.set_table(ptr->table_id, ptr->table);
}
#ifdef HAVE_QUERY_CACHE
query_cache.invalidate_locked_for_write(rli->tables_to_lock);
#endif
- rli->clear_tables_to_lock();
+ const_cast<RELAY_LOG_INFO*>(rli)->clear_tables_to_lock();
}
DBUG_ASSERT(rli->tables_to_lock == NULL && rli->tables_to_lock_count == 0);
- TABLE* table= rli->m_table_map.get_table(m_table_id);
+ TABLE* table= const_cast<RELAY_LOG_INFO*>(rli)->m_table_map.get_table(m_table_id);
if (table)
{
/*
table == NULL means that this table should not be replicated
- (this was set up by Table_map_log_event::exec_event() which
- tested replicate-* rules).
+ (this was set up by Table_map_log_event::do_apply_event()
+ which tested replicate-* rules).
*/
/*
@@ -5791,16 +6065,27 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
/* A small test to verify that objects have consistent types */
DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+ /*
+ Now we are in a statement and will stay in a statement until we
+ see a STMT_END_F.
+
+ We set this flag here, before actually applying any rows, in
+ case the SQL thread is stopped and we need to detect that we're
+ inside a statement and halting abruptly might cause problems
+ when restarting.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->set_flag(RELAY_LOG_INFO::IN_STMT);
+
error= do_before_row_operations(table);
- while (error == 0 && row_start < (const char*) m_rows_end)
+ while (error == 0 && row_start < m_rows_end)
{
- char const *row_end= NULL;
+ uchar const *row_end= NULL;
if ((error= do_prepare_row(thd, rli, table, row_start, &row_end)))
break; // We should perform the after-row operation even in
// the case of error
DBUG_ASSERT(row_end != NULL); // cannot happen
- DBUG_ASSERT(row_end <= (const char*)m_rows_end);
+ DBUG_ASSERT(row_end <= m_rows_end);
/* in_use can have been set to NULL in close_tables_for_reopen */
THD* old_thd= table->in_use;
@@ -5819,7 +6104,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
break;
default:
- rli->report(ERROR_LEVEL, error,
+ rli->report(ERROR_LEVEL, thd->net.last_errno,
"Error in %s event: row application failed",
get_type_str());
thd->query_error= 1;
@@ -5829,7 +6114,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
row_start= row_end;
}
DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
- rli->abort_slave=1;);
+ const_cast<RELAY_LOG_INFO*>(rli)->abort_slave= 1;);
error= do_after_row_operations(table, error);
if (!cache_stmt)
{
@@ -5840,11 +6125,12 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
if (error)
{ /* error has occured during the transaction */
- rli->report(ERROR_LEVEL, error,
+ rli->report(ERROR_LEVEL, thd->net.last_errno,
"Error in %s event: error during transaction execution "
"on table %s.%s",
get_type_str(), table->s->db.str,
table->s->table_name.str);
+
/*
If one day we honour --skip-slave-errors in row-based replication, and
the error should be skipped, then we would clear mappings, rollback,
@@ -5857,11 +6143,64 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
rollback at the caller along with sbr.
*/
thd->reset_current_stmt_binlog_row_based();
- rli->cleanup_context(thd, 0); /* rollback at caller in step with sbr */
+ const_cast<RELAY_LOG_INFO*>(rli)->cleanup_context(thd, error);
thd->query_error= 1;
DBUG_RETURN(error);
}
+ /*
+ This code would ideally be placed in do_update_pos() instead, but
+ since we have no access to table there, we do the setting of
+ last_event_start_time here instead.
+ */
+ if (table && (table->s->primary_key == MAX_KEY) &&
+ !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
+ {
+ /*
+ ------------ Temporary fix until WL#2975 is implemented ---------
+
+ This event is not the last one (no STMT_END_F). If we stop now
+ (in case of terminate_slave_thread()), how will we restart? We
+ have to restart from Table_map_log_event, but as this table is
+ not transactional, the rows already inserted will still be
+ present, and idempotency is not guaranteed (no PK) so we risk
+ that repeating leads to double insert. So we desperately try to
+ continue, hope we'll eventually leave this buggy situation (by
+ executing the final Rows_log_event). If we are in a hopeless
+ wait (reached end of last relay log and nothing gets appended
+ there), we timeout after one minute, and notify DBA about the
+ problem. When WL#2975 is implemented, just remove the member
+ st_relay_log_info::last_event_start_time and all its occurences.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->last_event_start_time= time(0);
+ }
+
+ DBUG_RETURN(0);
+}
+
+Log_event::enum_skip_reason
+Rows_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ If the slave skip counter is 1 and this event does not end a
+ statement, then we should not start executing on the next event.
+ Otherwise, we defer the decision to the normal skipping logic.
+ */
+ if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
+int
+Rows_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
+ DBUG_ENTER("Rows_log_event::do_update_pos");
+ int error= 0;
+
+ DBUG_PRINT("info", ("flags: %s",
+ get_flags(STMT_END_F) ? "STMT_END_F " : ""));
+
if (get_flags(STMT_END_F))
{
/*
@@ -5880,6 +6219,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
replicate-ignore rules).
*/
thd->binlog_flush_pending_rows_event(true);
+
/*
If this event is not in a transaction, the call below will, if some
transactional storage engines are involved, commit the statement into
@@ -5890,6 +6230,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
binlog.
*/
error= ha_autocommit_or_rollback(thd, 0);
+
/*
Now what if this is not a transactional engine? we still need to
flush the pending event to the binlog; we did it with
@@ -5902,11 +6243,16 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
thd->reset_current_stmt_binlog_row_based();
rli->cleanup_context(thd, 0);
- rli->transaction_end(thd);
-
if (error == 0)
{
/*
+ Indicate that a statement is finished.
+ Step the group log position if we are not in a transaction,
+ otherwise increase the event log position.
+ */
+ rli->stmt_done(log_pos, when);
+
+ /*
Clear any errors pushed in thd->net.last_err* if for example "no key
found" (as this is allowed). This is a safety measure; apparently
those errors (e.g. when executing a Delete_rows_log_event of a
@@ -5915,7 +6261,6 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
do not become visible. We still prefer to wipe them out.
*/
thd->clear_error();
- error= Log_event::exec_event(rli);
}
else
rli->report(ERROR_LEVEL, error,
@@ -5923,42 +6268,21 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
"table `%s`.`%s`",
get_type_str(), table->s->db.str,
table->s->table_name.str);
- DBUG_RETURN(error);
}
-
- if (table && (table->s->primary_key == MAX_KEY) && !cache_stmt)
+ else
{
- /*
- ------------ Temporary fix until WL#2975 is implemented ---------
-
- This event is not the last one (no STMT_END_F). If we stop now
- (in case of terminate_slave_thread()), how will we restart? We
- have to restart from Table_map_log_event, but as this table is
- not transactional, the rows already inserted will still be
- present, and idempotency is not guaranteed (no PK) so we risk
- that repeating leads to double insert. So we desperately try to
- continue, hope we'll eventually leave this buggy situation (by
- executing the final Rows_log_event). If we are in a hopeless
- wait (reached end of last relay log and nothing gets appended
- there), we timeout after one minute, and notify DBA about the
- problem. When WL#2975 is implemented, just remove the member
- st_relay_log_info::unsafe_to_stop_at and all its occurences.
- */
- rli->unsafe_to_stop_at= time(0);
+ rli->inc_event_relay_log_pos();
}
- DBUG_ASSERT(error == 0);
- thd->clear_error();
- rli->inc_event_relay_log_pos();
-
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
+
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
#ifndef MYSQL_CLIENT
bool Rows_log_event::write_data_header(IO_CACHE *file)
{
- byte buf[ROWS_HEADER_LEN]; // No need to init the buffer
+ uchar buf[ROWS_HEADER_LEN]; // No need to init the buffer
DBUG_ASSERT(m_table_id != ~0UL);
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
{
@@ -5977,17 +6301,33 @@ bool Rows_log_event::write_data_body(IO_CACHE*file)
Note that this should be the number of *bits*, not the number of
bytes.
*/
- char sbuf[sizeof(m_width)];
+ uchar sbuf[sizeof(m_width)];
my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
+ bool res= false;
+ uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
+ DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
+
+ DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
+ res= res || my_b_safe_write(file, sbuf, (size_t) (sbuf_end - sbuf));
+
+ DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
+ res= res || my_b_safe_write(file, (uchar*) m_cols.bitmap,
+ no_bytes_in_map(&m_cols));
+ /*
+ TODO[refactor write]: Remove the "down cast" here (and elsewhere).
+ */
+ if (get_type_code() == UPDATE_ROWS_EVENT)
+ {
+ DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ res= res || my_b_safe_write(file, (uchar*) m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ }
+ DBUG_DUMP("rows", m_rows_buf, data_size);
+ res= res || my_b_safe_write(file, m_rows_buf, (size_t) data_size);
- char *const sbuf_end= net_store_length((char*) sbuf, (uint) m_width);
- DBUG_ASSERT(static_cast<my_size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
+ return res;
- return (my_b_safe_write(file, reinterpret_cast<byte*>(sbuf),
- sbuf_end - sbuf) ||
- my_b_safe_write(file, reinterpret_cast<byte*>(m_cols.bitmap),
- no_bytes_in_map(&m_cols)) ||
- my_b_safe_write(file, m_rows_buf, data_size));
}
#endif
@@ -5997,7 +6337,7 @@ void Rows_log_event::pack_info(Protocol *protocol)
char buf[256];
char const *const flagstr=
get_flags(STMT_END_F) ? " flags: STMT_END_F" : "";
- my_size_t bytes= my_snprintf(buf, sizeof(buf),
+ size_t bytes= my_snprintf(buf, sizeof(buf),
"table_id: %lu%s", m_table_id, flagstr);
protocol->store(buf, bytes, &my_charset_bin);
}
@@ -6014,16 +6354,16 @@ void Rows_log_event::print_helper(FILE *file,
{
bool const last_stmt_event= get_flags(STMT_END_F);
print_header(head, print_event_info, !last_stmt_event);
- my_b_printf(head, "\t%s: table id %lu", name, m_table_id);
+ my_b_printf(head, "\t%s: table id %lu%s\n",
+ name, m_table_id,
+ last_stmt_event ? " flags: STMT_END_F" : "");
print_base64(body, print_event_info, !last_stmt_event);
}
if (get_flags(STMT_END_F))
{
- my_b_copy_to_file(head, file);
- my_b_copy_to_file(body, file);
- reinit_io_cache(head, WRITE_CACHE, 0, FALSE, TRUE);
- reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
+ copy_event_cache_to_file_and_reinit(head, file);
+ copy_event_cache_to_file_and_reinit(body, file);
}
}
#endif
@@ -6069,7 +6409,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
m_data_size+= 1 + m_colcnt; // COLCNT and column types
/* If malloc fails, catched in is_valid() */
- if ((m_memory= my_malloc(m_colcnt, MYF(MY_WME))))
+ if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
{
m_coltype= reinterpret_cast<uchar*>(m_memory);
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
@@ -6104,7 +6444,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("event buffer", buf, event_len);
+ DBUG_DUMP("event buffer", (uchar*) buf, event_len);
#endif
/* Read the post-header */
@@ -6132,29 +6472,29 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
const char *const vpart= buf + common_header_len + post_header_len;
/* Extract the length of the various parts from the buffer */
- byte const* const ptr_dblen= (byte const*)vpart + 0;
+ uchar const *const ptr_dblen= (uchar const*)vpart + 0;
m_dblen= *(uchar*) ptr_dblen;
/* Length of database name + counter + terminating null */
- byte const* const ptr_tbllen= ptr_dblen + m_dblen + 2;
+ uchar const *const ptr_tbllen= ptr_dblen + m_dblen + 2;
m_tbllen= *(uchar*) ptr_tbllen;
/* Length of table name + counter + terminating null */
- byte const* const ptr_colcnt= ptr_tbllen + m_tbllen + 2;
+ uchar const *const ptr_colcnt= ptr_tbllen + m_tbllen + 2;
uchar *ptr_after_colcnt= (uchar*) ptr_colcnt;
m_colcnt= net_field_length(&ptr_after_colcnt);
DBUG_PRINT("info",("m_dblen: %lu off: %ld m_tbllen: %lu off: %ld m_colcnt: %lu off: %ld",
- m_dblen, (long) (ptr_dblen-(const byte*)vpart),
- m_tbllen, (long) (ptr_tbllen-(const byte*)vpart),
- m_colcnt, (long) (ptr_colcnt-(const byte*)vpart)));
+ m_dblen, (long) (ptr_dblen-(const uchar*)vpart),
+ m_tbllen, (long) (ptr_tbllen-(const uchar*)vpart),
+ m_colcnt, (long) (ptr_colcnt-(const uchar*)vpart)));
/* Allocate mem for all fields in one go. If fails, catched in is_valid() */
- m_memory= my_multi_malloc(MYF(MY_WME),
- &m_dbnam, m_dblen + 1,
- &m_tblnam, m_tbllen + 1,
- &m_coltype, m_colcnt,
- NULL);
+ m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ &m_dbnam, (uint) m_dblen + 1,
+ &m_tblnam, (uint) m_tbllen + 1,
+ &m_coltype, (uint) m_colcnt,
+ NullS);
if (m_memory)
{
@@ -6185,10 +6525,13 @@ Table_map_log_event::~Table_map_log_event()
*/
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int Table_map_log_event::exec_event(st_relay_log_info *rli)
+int Table_map_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
{
- DBUG_ENTER("Table_map_log_event::exec_event(st_relay_log_info*)");
-
+ RPL_TABLE_LIST *table_list;
+ char *db_mem, *tname_mem;
+ size_t dummy_len;
+ void *memory;
+ DBUG_ENTER("Table_map_log_event::do_apply_event(st_relay_log_info*)");
DBUG_ASSERT(rli->sql_thd == thd);
/* Step the query id to mark what columns that are actually used. */
@@ -6196,19 +6539,13 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
thd->query_id= next_query_id();
pthread_mutex_unlock(&LOCK_thread_count);
- TABLE_LIST *table_list;
- char *db_mem, *tname_mem;
- void *const memory=
- my_multi_malloc(MYF(MY_WME),
- &table_list, sizeof(TABLE_LIST),
- &db_mem, NAME_LEN + 1,
- &tname_mem, NAME_LEN + 1,
- NULL);
-
- if (memory == NULL)
+ if (!(memory= my_multi_malloc(MYF(MY_WME),
+ &table_list, (uint) sizeof(RPL_TABLE_LIST),
+ &db_mem, (uint) NAME_LEN + 1,
+ &tname_mem, (uint) NAME_LEN + 1,
+ NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- uint dummy_len;
bzero(table_list, sizeof(*table_list));
table_list->db = db_mem;
table_list->alias= table_list->table_name = tname_mem;
@@ -6224,7 +6561,7 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
if (!rpl_filter->db_ok(table_list->db) ||
(rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list)))
{
- my_free((gptr) memory, MYF(MY_WME));
+ my_free(memory, MYF(MY_WME));
}
else
{
@@ -6233,7 +6570,8 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
initialized, so we should call lex_start(); to be even safer, we
call mysql_init_query() which does a more complete set of inits.
*/
- mysql_init_query(thd, NULL, 0);
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
/*
Check if the slave is set to use SBR. If so, it should switch
to using RBR until the end of the "statement", i.e., next
@@ -6246,11 +6584,27 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
}
/*
- Open the table if it is not already open and add the table to table map.
- Note that for any table that should not be replicated, a filter is needed.
+ Open the table if it is not already open and add the table to
+ table map. Note that for any table that should not be
+ replicated, a filter is needed.
+
+ The creation of a new TABLE_LIST is used to up-cast the
+ table_list consisting of RPL_TABLE_LIST items. This will work
+ since the only case where the argument to open_tables() is
+ changed, is when thd->lex->query_tables == table_list, i.e.,
+ when the statement requires prelocking. Since this is not
+ executed when a statement is executed, this case will not occur.
+ As a precaution, an assertion is added to ensure that the bad
+ case is not a fact.
+
+ Either way, the memory in the list is *never* released
+ internally in the open_tables() function, hence we take a copy
+ of the pointer to make sure that it's not lost.
*/
uint count;
- if ((error= open_tables(thd, &table_list, &count, 0)))
+ DBUG_ASSERT(thd->lex->query_tables != table_list);
+ TABLE_LIST *tmp_table_list= table_list;
+ if ((error= open_tables(thd, &tmp_table_list, &count, 0)))
{
if (thd->query_error || thd->is_fatal_error)
{
@@ -6277,50 +6631,61 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli)
*/
DBUG_ASSERT(m_table->in_use);
- table_def const def(m_coltype, m_colcnt);
- if (def.compatible_with(rli, m_table))
- {
- thd->query_error= 1;
- error= ERR_BAD_TABLE_DEF;
- goto err;
- /* purecov: end */
- }
+ /*
+ Use placement new to construct the table_def instance in the
+ memory allocated for it inside table_list.
+
+ The memory allocated by the table_def structure (i.e., not the
+ memory allocated *for* the table_def structure) is released
+ inside st_relay_log_info::clear_tables_to_lock() by calling the
+ table_def destructor explicitly.
+ */
+ new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt);
+ table_list->m_tabledef_valid= TRUE;
/*
We record in the slave's information that the table should be
locked by linking the table into the list of tables to lock.
*/
table_list->next_global= table_list->next_local= rli->tables_to_lock;
- rli->tables_to_lock= table_list;
- rli->tables_to_lock_count++;
+ const_cast<RELAY_LOG_INFO*>(rli)->tables_to_lock= table_list;
+ const_cast<RELAY_LOG_INFO*>(rli)->tables_to_lock_count++;
/* 'memory' is freed in clear_tables_to_lock */
}
- /*
- We explicitly do not call Log_event::exec_event() here since we do not
- want the relay log position to be flushed to disk. The flushing will be
- done by the last Rows_log_event that either ends a statement (outside a
- transaction) or a transaction.
-
- A table map event can *never* end a transaction or a statement, so we
- just step the relay log position.
- */
-
- if (likely(!error))
- rli->inc_event_relay_log_pos();
DBUG_RETURN(error);
err:
- my_free((gptr) memory, MYF(MY_WME));
+ my_free(memory, MYF(MY_WME));
DBUG_RETURN(error);
}
+
+Log_event::enum_skip_reason
+Table_map_log_event::do_shall_skip(RELAY_LOG_INFO *rli)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ if (rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rli);
+}
+
+int Table_map_log_event::do_update_pos(RELAY_LOG_INFO *rli)
+{
+ rli->inc_event_relay_log_pos();
+ return 0;
+}
+
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
#ifndef MYSQL_CLIENT
bool Table_map_log_event::write_data_header(IO_CACHE *file)
{
DBUG_ASSERT(m_table_id != ~0UL);
- byte buf[TABLE_MAP_HEADER_LEN];
+ uchar buf[TABLE_MAP_HEADER_LEN];
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
{
int4store(buf + 0, m_table_id);
@@ -6340,20 +6705,19 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file)
DBUG_ASSERT(m_dblen < 128);
DBUG_ASSERT(m_tbllen < 128);
- byte const dbuf[]= { m_dblen };
- byte const tbuf[]= { m_tbllen };
+ uchar const dbuf[]= { (uchar) m_dblen };
+ uchar const tbuf[]= { (uchar) m_tbllen };
- char cbuf[sizeof(m_colcnt)];
- char *const cbuf_end= net_store_length((char*) cbuf, (uint) m_colcnt);
- DBUG_ASSERT(static_cast<my_size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
+ uchar cbuf[sizeof(m_colcnt)];
+ uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
return (my_b_safe_write(file, dbuf, sizeof(dbuf)) ||
- my_b_safe_write(file, (const byte*)m_dbnam, m_dblen+1) ||
+ my_b_safe_write(file, (const uchar*)m_dbnam, m_dblen+1) ||
my_b_safe_write(file, tbuf, sizeof(tbuf)) ||
- my_b_safe_write(file, (const byte*)m_tblnam, m_tbllen+1) ||
- my_b_safe_write(file, reinterpret_cast<byte*>(cbuf),
- cbuf_end - (char*) cbuf) ||
- my_b_safe_write(file, reinterpret_cast<byte*>(m_coltype), m_colcnt));
+ my_b_safe_write(file, (const uchar*)m_tblnam, m_tbllen+1) ||
+ my_b_safe_write(file, cbuf, (size_t) (cbuf_end - cbuf)) ||
+ my_b_safe_write(file, m_coltype, m_colcnt));
}
#endif
@@ -6368,7 +6732,7 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file)
void Table_map_log_event::pack_info(Protocol *protocol)
{
char buf[256];
- my_size_t bytes= my_snprintf(buf, sizeof(buf),
+ size_t bytes= my_snprintf(buf, sizeof(buf),
"table_id: %lu (%s.%s)",
m_table_id, m_dbnam, m_tblnam);
protocol->store(buf, bytes, &my_charset_bin);
@@ -6442,10 +6806,23 @@ int Write_rows_log_event::do_before_row_operations(TABLE *table)
lex->duplicates flag.
*/
thd->lex->sql_command= SQLCOM_REPLACE;
-
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); // Needed for ndbcluster
- table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); // Needed for ndbcluster
- table->file->extra(HA_EXTRA_IGNORE_NO_KEY); // Needed for ndbcluster
+ /*
+ Do not raise the error flag in case of hitting to an unique attribute
+ */
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ /*
+ NDB specific: update from ndb master wrapped as Write_rows
+ */
+ /*
+ so that the event should be applied to replace slave's row
+ */
+ table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ /*
+ NDB specific: if update from ndb master wrapped as Write_rows
+ does not find the row it's assumed idempotent binlog applying
+ is taking place; don't raise the error.
+ */
+ table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
/*
TODO: the cluster team (Tomas?) says that it's better if the engine knows
how many rows are going to be inserted, then it can allocate needed memory
@@ -6473,15 +6850,26 @@ int Write_rows_log_event::do_before_row_operations(TABLE *table)
int Write_rows_log_event::do_after_row_operations(TABLE *table, int error)
{
- if (error == 0)
- error= table->file->ha_end_bulk_insert();
- return error;
+ int local_error= 0;
+ table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
+ table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
+ /*
+ reseting the extra with
+ table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY);
+ fires bug#27077
+ todo: explain or fix
+ */
+ if ((local_error= table->file->ha_end_bulk_insert()))
+ {
+ table->file->print_error(local_error, MYF(0));
+ }
+ return error? error : local_error;
}
-int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO const *rli,
TABLE *table,
- char const *const row_start,
- char const **const row_end)
+ uchar const *const row_start,
+ uchar const **const row_end)
{
DBUG_ASSERT(table != NULL);
DBUG_ASSERT(row_start && row_end);
@@ -6546,7 +6934,7 @@ namespace {
*/
static int
copy_extra_record_fields(TABLE *table,
- my_size_t master_reclength,
+ size_t master_reclength,
my_ptrdiff_t master_fields)
{
DBUG_PRINT("info", ("Copying to 0x%lx "
@@ -6603,7 +6991,7 @@ copy_extra_record_fields(TABLE *table,
/* Nothing to do */
break;
- case FIELD_TYPE_BIT:
+ case MYSQL_TYPE_BIT:
Field_bit *f= static_cast<Field_bit*>(*field_ptr);
if (f->bit_len > 0)
{
@@ -6619,6 +7007,42 @@ copy_extra_record_fields(TABLE *table,
return 0; // All OK
}
+#define DBUG_PRINT_BITSET(N,FRM,BS) \
+ do { \
+ char buf[256]; \
+ for (uint i = 0 ; i < (BS)->n_bits ; ++i) \
+ buf[i] = bitmap_is_set((BS), i) ? '1' : '0'; \
+ buf[(BS)->n_bits] = '\0'; \
+ DBUG_PRINT((N), ((FRM), buf)); \
+ } while (0)
+
+
+/**
+ Check if an error is a duplicate key error.
+
+ This function is used to check if an error code is one of the
+ duplicate key error, i.e., and error code for which it is sensible
+ to do a <code>get_dup_key()</code> to retrieve the duplicate key.
+
+ @param errcode The error code to check.
+
+ @return <code>true</code> if the error code is such that
+ <code>get_dup_key()</code> will return true, <code>false</code>
+ otherwise.
+ */
+bool
+is_duplicate_key_error(int errcode)
+{
+ switch (errcode)
+ {
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ return true;
+ }
+ return false;
+}
+
+
/*
Replace the provided record in the database.
@@ -6651,6 +7075,12 @@ replace_record(THD *thd, TABLE *table,
int keynum;
auto_afree_ptr<char> key(NULL);
+#ifndef DBUG_OFF
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_PRINT_BITSET("debug", "write_set = %s", table->write_set);
+ DBUG_PRINT_BITSET("debug", "read_set = %s", table->read_set);
+#endif
+
while ((error= table->file->ha_write_row(table->record[0])))
{
if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT)
@@ -6661,7 +7091,7 @@ replace_record(THD *thd, TABLE *table,
if ((keynum= table->file->get_dup_key(error)) < 0)
{
/* We failed to retrieve the duplicate key */
- DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
+ DBUG_RETURN(error);
}
/*
@@ -6678,7 +7108,10 @@ replace_record(THD *thd, TABLE *table,
{
error= table->file->rnd_pos(table->record[1], table->file->dup_ref);
if (error)
+ {
+ table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
+ }
}
else
{
@@ -6694,13 +7127,16 @@ replace_record(THD *thd, TABLE *table,
DBUG_RETURN(ENOMEM);
}
- key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0);
- error= table->file->index_read_idx(table->record[1], keynum,
- (const byte*)key.get(),
- table->key_info[keynum].key_length,
+ key_copy((uchar*)key.get(), table->record[0], table->key_info + keynum, 0);
+ error= table->file->index_read_idx(table->record[1], keynum,
+ (const uchar*)key.get(),
+ HA_WHOLE_KEY,
HA_READ_KEY_EXACT);
if (error)
+ {
+ table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
+ }
}
/*
@@ -6733,15 +7169,21 @@ replace_record(THD *thd, TABLE *table,
{
error=table->file->ha_update_row(table->record[1],
table->record[0]);
+ if (error)
+ table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
}
else
{
if ((error= table->file->ha_delete_row(table->record[1])))
+ {
+ table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
+ }
/* Will retry ha_write_row() with the offending row removed. */
}
}
+
DBUG_RETURN(error);
}
@@ -6772,20 +7214,75 @@ void Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
*/
static bool record_compare(TABLE *table)
{
+ /*
+ Need to set the X bit and the filler bits in both records since
+ there are engines that do not set it correctly.
+
+ In addition, since MyISAM checks that one hasn't tampered with the
+ record, it is necessary to restore the old bytes into the record
+ after doing the comparison.
+
+ TODO[record format ndb]: Remove it once NDB returns correct
+ records. Check that the other engines also return correct records.
+ */
+
+ bool result= FALSE;
+ uchar saved_x[2], saved_filler[2];
+
+ if (table->s->null_bytes > 0)
+ {
+ for (int i = 0 ; i < 2 ; ++i)
+ {
+ saved_x[i]= table->record[i][0];
+ saved_filler[i]= table->record[i][table->s->null_bytes - 1];
+ table->record[i][0]|= 1U;
+ table->record[i][table->s->null_bytes - 1]|=
+ 256U - (1U << table->s->last_null_bit_pos);
+ }
+ }
+
if (table->s->blob_fields + table->s->varchar_fields == 0)
- return cmp_record(table,record[1]);
+ {
+ result= cmp_record(table,record[1]);
+ goto record_compare_exit;
+ }
+
/* Compare null bits */
if (memcmp(table->null_flags,
table->null_flags+table->s->rec_buff_length,
table->s->null_bytes))
- return TRUE; // Diff in NULL value
+ {
+ result= TRUE; // Diff in NULL value
+ goto record_compare_exit;
+ }
+
/* Compare updated fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
- return TRUE;
+ {
+ result= TRUE;
+ goto record_compare_exit;
+ }
}
- return FALSE;
+
+record_compare_exit:
+ /*
+ Restore the saved bytes.
+
+ TODO[record format ndb]: Remove this code once NDB returns the
+ correct record format.
+ */
+ if (table->s->null_bytes > 0)
+ {
+ for (int i = 0 ; i < 2 ; ++i)
+ {
+ table->record[i][0]= saved_x[i];
+ table->record[i][table->s->null_bytes - 1]= saved_filler[i];
+ }
+ }
+
+ return result;
}
@@ -6813,14 +7310,16 @@ static bool record_compare(TABLE *table)
<code>table->record[1]</code>, error code otherwise.
*/
-static int find_and_fetch_row(TABLE *table, byte *key)
+static int find_and_fetch_row(TABLE *table, uchar *key)
{
- DBUG_ENTER("find_and_fetch_row(TABLE *table, byte *key, byte *record)");
+ DBUG_ENTER("find_and_fetch_row(TABLE *table, uchar *key, uchar *record)");
DBUG_PRINT("enter", ("table: 0x%lx, key: 0x%lx record: 0x%lx",
(long) table, (long) key, (long) table->record[1]));
DBUG_ASSERT(table->in_use != NULL);
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+
if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
table->s->primary_key < MAX_KEY)
{
@@ -6868,8 +7367,8 @@ static int find_and_fetch_row(TABLE *table, byte *key)
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("table->record[0]", (char *)table->record[0], table->s->reclength);
- DBUG_DUMP("table->record[1]", (char *)table->record[1], table->s->reclength);
+ DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength);
#endif
/*
@@ -6881,8 +7380,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
my_ptrdiff_t const pos=
table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
table->record[1][pos]= 0xFF;
- if ((error= table->file->index_read(table->record[1], key,
- table->key_info->key_length,
+ if ((error= table->file->index_read(table->record[1], key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT)))
{
table->file->print_error(error, MYF(0));
@@ -6895,8 +7393,8 @@ static int find_and_fetch_row(TABLE *table, byte *key)
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("table->record[0]", (char *)table->record[0], table->s->reclength);
- DBUG_DUMP("table->record[1]", (char *)table->record[1], table->s->reclength);
+ DBUG_DUMP("table->record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("table->record[1]", table->record[1], table->s->reclength);
#endif
/*
Below is a minor "optimization". If the key (i.e., key number
@@ -6921,15 +7419,22 @@ static int find_and_fetch_row(TABLE *table, byte *key)
while (record_compare(table))
{
int error;
+
/*
We need to set the null bytes to ensure that the filler bit
are all set when returning. There are storage engines that
just set the necessary bits on the bytes and don't set the
filler bits correctly.
+
+ TODO[record format ndb]: Remove this code once NDB returns the
+ correct record format.
*/
- my_ptrdiff_t const pos=
- table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
- table->record[1][pos]= 0xFF;
+ if (table->s->null_bytes > 0)
+ {
+ table->record[1][table->s->null_bytes - 1]|=
+ 256U - (1U << table->s->last_null_bit_pos);
+ }
+
if ((error= table->file->index_next(table->record[1])))
{
table->file->print_error(error, MYF(0));
@@ -6955,19 +7460,12 @@ static int find_and_fetch_row(TABLE *table, byte *key)
/* Continue until we find the right record or have made a full loop */
do
{
- /*
- We need to set the null bytes to ensure that the filler bit
- are all set when returning. There are storage engines that
- just set the necessary bits on the bytes and don't set the
- filler bits correctly.
- */
- my_ptrdiff_t const pos=
- table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
- table->record[1][pos]= 0xFF;
error= table->file->rnd_next(table->record[1]);
- switch (error)
- {
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("record[1]", table->record[1], table->s->reclength);
+
+ switch (error) {
case 0:
case HA_ERR_RECORD_DELETED:
break;
@@ -6979,6 +7477,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
default:
table->file->print_error(error, MYF(0));
+ DBUG_PRINT("info", ("Record not found"));
table->file->ha_rnd_end();
DBUG_RETURN(error);
}
@@ -6988,6 +7487,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
/*
Have to restart the scan to be able to fetch the next row.
*/
+ DBUG_PRINT("info", ("Record %sfound", restart_count == 2 ? "not " : ""));
table->file->ha_rnd_end();
DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
@@ -7050,16 +7550,17 @@ int Delete_rows_log_event::do_before_row_operations(TABLE *table)
if (table->s->keys > 0)
{
- m_memory=
- my_multi_malloc(MYF(MY_WME),
- &m_after_image, table->s->reclength,
- &m_key, table->key_info->key_length,
- NULL);
+ m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ &m_after_image,
+ (uint) table->s->reclength,
+ &m_key,
+ (uint) table->key_info->key_length,
+ NullS);
}
else
{
- m_after_image= (byte*)my_malloc(table->s->reclength, MYF(MY_WME));
- m_memory= (gptr)m_after_image;
+ m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME));
+ m_memory= (uchar*)m_after_image;
m_key= NULL;
}
if (!m_memory)
@@ -7080,10 +7581,10 @@ int Delete_rows_log_event::do_after_row_operations(TABLE *table, int error)
return error;
}
-int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO const *rli,
TABLE *table,
- char const *const row_start,
- char const **const row_end)
+ uchar const *const row_start,
+ uchar const **const row_end)
{
int error;
DBUG_ASSERT(row_start && row_end);
@@ -7146,16 +7647,55 @@ void Delete_rows_log_event::print(FILE *file,
*/
#if !defined(MYSQL_CLIENT)
Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid, MY_BITMAP const *cols,
+ ulong tid,
+ MY_BITMAP const *cols_bi,
+ MY_BITMAP const *cols_ai,
+ bool is_transactional)
+: Rows_log_event(thd_arg, tbl_arg, tid, cols_bi, is_transactional)
+#ifdef HAVE_REPLICATION
+ , m_memory(NULL), m_key(NULL)
+
+#endif
+{
+ init(cols_ai);
+}
+
+Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid,
+ MY_BITMAP const *cols,
bool is_transactional)
: Rows_log_event(thd_arg, tbl_arg, tid, cols, is_transactional)
#ifdef HAVE_REPLICATION
, m_memory(NULL), m_key(NULL)
#endif
{
+ init(cols);
+}
+
+void Update_rows_log_event::init(MY_BITMAP const *cols)
+{
+ /* if bitmap_init fails, catched in is_valid() */
+ if (likely(!bitmap_init(&m_cols_ai,
+ m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
+ (m_width + 7) & ~7UL,
+ false)))
+ {
+ /* Cols can be zero if this is a dummy binrows event */
+ if (likely(cols != NULL))
+ memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
+ }
}
#endif /* !defined(MYSQL_CLIENT) */
+
+Update_rows_log_event::~Update_rows_log_event()
+{
+ if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
+ m_cols_ai.bitmap= 0; // so no my_free in bitmap_free
+ bitmap_free(&m_cols_ai); // To pair with bitmap_init().
+}
+
+
/*
Constructor used by slave to read the event from the binary log.
*/
@@ -7183,16 +7723,17 @@ int Update_rows_log_event::do_before_row_operations(TABLE *table)
if (table->s->keys > 0)
{
- m_memory=
- my_multi_malloc(MYF(MY_WME),
- &m_after_image, table->s->reclength,
- &m_key, table->key_info->key_length,
- NULL);
+ m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ &m_after_image,
+ (uint) table->s->reclength,
+ &m_key,
+ (uint) table->key_info->key_length,
+ NullS);
}
else
{
- m_after_image= (byte*)my_malloc(table->s->reclength, MYF(MY_WME));
- m_memory= (gptr)m_after_image;
+ m_after_image= (uchar*) my_malloc(table->s->reclength, MYF(MY_WME));
+ m_memory= m_after_image;
m_key= NULL;
}
if (!m_memory)
@@ -7215,10 +7756,10 @@ int Update_rows_log_event::do_after_row_operations(TABLE *table, int error)
return error;
}
-int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO const *rli,
TABLE *table,
- char const *const row_start,
- char const **const row_end)
+ uchar const *const row_start,
+ uchar const **const row_end)
{
int error;
DBUG_ASSERT(row_start && row_end);
@@ -7238,9 +7779,9 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
error= unpack_row(rli, table, m_width, row_start, &m_cols, row_end,
&m_master_reclength, table->read_set, UPDATE_ROWS_EVENT);
store_record(table, record[1]);
- char const *next_start = *row_end;
+ uchar const *next_start = *row_end;
/* m_after_image is the after image for the update */
- error= unpack_row(rli, table, m_width, next_start, &m_cols, row_end,
+ error= unpack_row(rli, table, m_width, next_start, &m_cols_ai, row_end,
&m_master_reclength, table->write_set, UPDATE_ROWS_EVENT);
bmove_align(m_after_image, table->record[0], table->s->reclength);
restore_record(table, record[1]);
@@ -7250,8 +7791,8 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("record[0]", (const char *)table->record[0], table->s->reclength);
- DBUG_DUMP("m_after_image", (const char *)m_after_image, table->s->reclength);
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("m_after_image", m_after_image, table->s->reclength);
#endif
/*
@@ -7312,3 +7853,113 @@ void Update_rows_log_event::print(FILE *file,
}
#endif
+
+Incident_log_event::Incident_log_event(const char *buf, uint event_len,
+ const Format_description_log_event *descr_event)
+ : Log_event(buf, descr_event)
+{
+ DBUG_ENTER("Incident_log_event::Incident_log_event");
+ uint8 const common_header_len=
+ descr_event->common_header_len;
+ uint8 const post_header_len=
+ descr_event->post_header_len[INCIDENT_EVENT-1];
+
+ DBUG_PRINT("info",("event_len: %u; common_header_len: %d; post_header_len: %d",
+ event_len, common_header_len, post_header_len));
+
+ m_incident= static_cast<Incident>(uint2korr(buf + common_header_len));
+ char const *ptr= buf + common_header_len + post_header_len;
+ char const *const str_end= buf + event_len;
+ uint8 len= 0; // Assignment to keep compiler happy
+ const char *str= NULL; // Assignment to keep compiler happy
+ read_str(&ptr, str_end, &str, &len);
+ m_message.str= const_cast<char*>(str);
+ m_message.length= len;
+ DBUG_PRINT("info", ("m_incident: %d", m_incident));
+ DBUG_VOID_RETURN;
+}
+
+
+Incident_log_event::~Incident_log_event()
+{
+}
+
+
+const char *
+Incident_log_event::description() const
+{
+ static const char *const description[]= {
+ "NOTHING", // Not used
+ "LOST_EVENTS"
+ };
+
+ DBUG_PRINT("info", ("m_incident: %d", m_incident));
+
+ DBUG_ASSERT(0 <= m_incident);
+ DBUG_ASSERT((size_t) m_incident <= sizeof(description)/sizeof(*description));
+
+ return description[m_incident];
+}
+
+
+#ifndef MYSQL_CLIENT
+void Incident_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ if (m_message.length > 0)
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s)",
+ m_incident, description());
+ else
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s): %s",
+ m_incident, description(), m_message.str);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+void
+Incident_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+ print_header(&cache, print_event_info, FALSE);
+ my_b_printf(&cache, "\n# Incident: %s", description());
+}
+#endif
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int
+Incident_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
+{
+ DBUG_ENTER("Incident_log_event::do_apply_event");
+ slave_print_msg(ERROR_LEVEL, rli, ER_SLAVE_INCIDENT,
+ ER(ER_SLAVE_INCIDENT),
+ description(),
+ m_message.length > 0 ? m_message.str : "<none>");
+ DBUG_RETURN(1);
+}
+#endif
+
+bool
+Incident_log_event::write_data_header(IO_CACHE *file)
+{
+ DBUG_ENTER("Incident_log_event::write_data_header");
+ DBUG_PRINT("enter", ("m_incident: %d", m_incident));
+ uchar buf[sizeof(int16)];
+ int2store(buf, (int16) m_incident);
+ DBUG_RETURN(my_b_safe_write(file, buf, sizeof(buf)));
+}
+
+bool
+Incident_log_event::write_data_body(IO_CACHE *file)
+{
+ DBUG_ENTER("Incident_log_event::write_data_body");
+ DBUG_RETURN(write_str(file, m_message.str, m_message.length));
+}
+
+
diff --git a/sql/log_event.h b/sql/log_event.h
index 76525bd3009..6787aa08016 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,6 +22,7 @@
#endif
#include <my_bitmap.h>
+#include "rpl_constants.h"
#define LOG_READ_EOF -1
#define LOG_READ_BOGUS -2
@@ -199,7 +199,7 @@ struct sql_ex_info
#define TABLE_MAP_HEADER_LEN 8
#define EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN (4 + 4 + 4 + 1)
#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
-
+#define INCIDENT_HEADER_LEN 2
/*
Max number of possible extra bytes in a replication event compared to a
packet (i.e. a query) sent from client to master;
@@ -271,6 +271,9 @@ struct sql_ex_info
*/
#define Q_CATALOG_NZ_CODE 6
+#define Q_LC_TIME_NAMES_CODE 7
+
+#define Q_CHARSET_DATABASE_CODE 8
/* Intvar event post-header */
#define I_TYPE_OFFSET 0
@@ -423,12 +426,18 @@ struct sql_ex_info
either, as the manual says (because a too big in-memory temp table is
automatically written to disk).
*/
-#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \
-OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS)
+#define OPTIONS_WRITTEN_TO_BIN_LOG \
+ (OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \
+ OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NOT_AUTOCOMMIT)
-#if OPTIONS_WRITTEN_TO_BIN_LOG != ((1L << 14) | (1L << 26) | (1L << 27))
+/* Shouldn't be defined before */
+#define EXPECTED_OPTIONS \
+ ((ULL(1) << 14) | (ULL(1) << 26) | (ULL(1) << 27) | (ULL(1) << 19))
+
+#if OPTIONS_WRITTEN_TO_BIN_LOG != EXPECTED_OPTIONS
#error OPTIONS_WRITTEN_TO_BIN_LOG must NOT change their values!
#endif
+#undef EXPECTED_OPTIONS /* You shouldn't use this one */
enum Log_event_type
{
@@ -460,10 +469,28 @@ enum Log_event_type
XID_EVENT= 16,
BEGIN_LOAD_QUERY_EVENT= 17,
EXECUTE_LOAD_QUERY_EVENT= 18,
+
TABLE_MAP_EVENT = 19,
- WRITE_ROWS_EVENT = 20,
- UPDATE_ROWS_EVENT = 21,
- DELETE_ROWS_EVENT = 22,
+
+ /*
+ These event numbers were used for 5.1.0 to 5.1.15 and are
+ therefore obsolete.
+ */
+ PRE_GA_WRITE_ROWS_EVENT = 20,
+ PRE_GA_UPDATE_ROWS_EVENT = 21,
+ PRE_GA_DELETE_ROWS_EVENT = 22,
+
+ /*
+ These event numbers are used from 5.1.16 and forward
+ */
+ WRITE_ROWS_EVENT = 23,
+ UPDATE_ROWS_EVENT = 24,
+ DELETE_ROWS_EVENT = 25,
+
+ /*
+ Something out of the ordinary happened on the master
+ */
+ INCIDENT_EVENT= 26,
/*
Add new events here - right above this comment!
@@ -495,6 +522,7 @@ class THD;
class Format_description_log_event;
struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
#ifdef MYSQL_CLIENT
/*
@@ -525,9 +553,12 @@ typedef struct st_print_event_info
bool charset_inited;
char charset[6]; // 3 variables, each of them storable in 2 bytes
char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
+ uint lc_time_names_number;
+ uint charset_database_number;
st_print_event_info()
:flags2_inited(0), sql_mode_inited(0),
- auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
+ auto_increment_increment(1),auto_increment_offset(1), charset_inited(0),
+ lc_time_names_number(0), charset_database_number(0)
{
/*
Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
@@ -537,16 +568,19 @@ typedef struct st_print_event_info
bzero(db, sizeof(db));
bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str));
- strcpy(delimiter, ";");
- uint const flags = MYF(MY_WME | MY_NABP);
- init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
- init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
+ delimiter[0]= ';';
+ delimiter[1]= 0;
+ myf const flags = MYF(MY_WME | MY_NABP);
+ open_cached_file(&head_cache, NULL, NULL, 0, flags);
+ open_cached_file(&body_cache, NULL, NULL, 0, flags);
}
~st_print_event_info() {
- end_io_cache(&head_cache);
- end_io_cache(&body_cache);
+ close_cached_file(&head_cache);
+ close_cached_file(&body_cache);
}
+ bool init_ok() /* tells if construction was successful */
+ { return my_b_inited(&head_cache) && my_b_inited(&body_cache); }
/* Settings on how to print the events */
@@ -577,6 +611,40 @@ typedef struct st_print_event_info
class Log_event
{
public:
+ /**
+ Enumeration of what kinds of skipping (and non-skipping) that can
+ occur when the slave executes an event.
+
+ @see shall_skip
+ @see do_shall_skip
+ */
+ enum enum_skip_reason {
+ /**
+ Don't skip event.
+ */
+ EVENT_SKIP_NOT,
+
+ /**
+ Skip event by ignoring it.
+
+ This means that the slave skip counter will not be changed.
+ */
+ EVENT_SKIP_IGNORE,
+
+ /**
+ Skip event and decrease skip counter.
+ */
+ EVENT_SKIP_COUNT
+ };
+
+
+ /*
+ The following type definition is to be used whenever data is placed
+ and manipulated in a common buffer. Use this typedef for buffers
+ that contain data containing binary and character data.
+ */
+ typedef unsigned char Byte;
+
/*
The offset in the log where this event originally appeared (it is
preserved in relay logs, making SHOW SLAVE STATUS able to print
@@ -651,16 +719,14 @@ public:
static void init_show_field_list(List<Item>* field_list);
#ifdef HAVE_REPLICATION
int net_send(Protocol *protocol, const char* log_name, my_off_t pos);
+
/*
pack_info() is used by SHOW BINLOG EVENTS; as print() it prepares and sends
a string to display to the user, so it resembles print().
*/
+
virtual void pack_info(Protocol *protocol);
- /*
- The SQL slave thread calls exec_event() to execute the event; this is where
- the slave's data is modified.
- */
- virtual int exec_event(struct st_relay_log_info* rli);
+
#endif /* HAVE_REPLICATION */
virtual const char* get_db()
{
@@ -687,7 +753,7 @@ public:
static void operator delete(void *ptr, size_t size)
{
- my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
}
/* Placement version of the above operators */
@@ -733,6 +799,128 @@ public:
*description_event);
/* returns the human readable name of the event's type */
const char* get_type_str();
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+public:
+
+ /**
+ Apply the event to the database.
+
+ This function represents the public interface for applying an
+ event.
+
+ @see do_apply_event
+ */
+ int apply_event(RELAY_LOG_INFO const *rli) {
+ return do_apply_event(rli);
+ }
+
+
+ /**
+ Update the relay log position.
+
+ This function represents the public interface for "stepping over"
+ the event and will update the relay log information.
+
+ @see do_update_pos
+ */
+ int update_pos(RELAY_LOG_INFO *rli)
+ {
+ return do_update_pos(rli);
+ }
+
+ /**
+ Decide if the event shall be skipped, and the reason for skipping
+ it.
+
+ @see do_shall_skip
+ */
+ enum_skip_reason shall_skip(RELAY_LOG_INFO *rli)
+ {
+ return do_shall_skip(rli);
+ }
+
+protected:
+
+ /**
+ Primitive to apply an event to the database.
+
+ This is where the change to the database is made.
+
+ @note The primitive is protected instead of private, since there
+ is a hierarchy of actions to be performed in some cases.
+
+ @see Format_description_log_event::do_apply_event()
+
+ @param rli Pointer to relay log info structure
+
+ @retval 0 Event applied successfully
+ @retval errno Error code if event application failed
+ */
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli)
+ {
+ return 0; /* Default implementation does nothing */
+ }
+
+
+ /**
+ Advance relay log coordinates.
+
+ This function is called to advance the relay log coordinates to
+ just after the event. It is essential that both the relay log
+ coordinate and the group log position is updated correctly, since
+ this function is used also for skipping events.
+
+ Normally, each implementation of do_update_pos() shall:
+
+ - Update the event position to refer to the position just after
+ the event.
+
+ - Update the group log position to refer to the position just
+ after the event <em>if the event is last in a group</em>
+
+ @param rli Pointer to relay log info structure
+
+ @retval 0 Coordinates changed successfully
+ @retval errno Error code if advancing failed (usually just
+ 1). Observe that handler errors are returned by the
+ do_apply_event() function, and not by this one.
+ */
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+
+
+ /**
+ Decide if this event shall be skipped or not and the reason for
+ skipping it.
+
+ The default implementation decide that the event shall be skipped
+ if either:
+
+ - the server id of the event is the same as the server id of the
+ server and <code>rli->replicate_same_server_id</code> is true,
+ or
+
+ - if <code>rli->slave_skip_counter</code> is greater than zero.
+
+ @see do_apply_event
+ @see do_update_pos
+
+ @retval Log_event::EVENT_SKIP_NOT
+ The event shall not be skipped and should be applied.
+
+ @retval Log_event::EVENT_SKIP_IGNORE
+ The event shall be skipped by just ignoring it, i.e., the slave
+ skip counter shall not be changed. This happends if, for example,
+ the originating server id of the event is the same as the server
+ id of the slave.
+
+ @retval Log_event::EVENT_SKIP_COUNT
+ The event shall be skipped because the slave skip counter was
+ non-zero. The caller shall decrease the counter by one.
+ */
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+
+#endif
};
/*
@@ -758,7 +946,7 @@ public:
class Query_log_event: public Log_event
{
protected:
- char* data_buf;
+ Log_event::Byte* data_buf;
public:
const char* query;
const char* catalog;
@@ -773,10 +961,10 @@ public:
uint16 error_code;
ulong thread_id;
/*
- For events created by Query_log_event::exec_event (and
- Load_log_event::exec_event()) we need the *original* thread id, to be able
- to log the event with the original (=master's) thread id (fix for
- BUG#1686).
+ For events created by Query_log_event::do_apply_event (and
+ Load_log_event::do_apply_event()) we need the *original* thread
+ id, to be able to log the event with the original (=master's)
+ thread id (fix for BUG#1686).
*/
ulong slave_proxy_id;
@@ -829,17 +1017,17 @@ public:
char charset[6];
uint time_zone_len; /* 0 means uninited */
const char *time_zone_str;
+ uint lc_time_names_number; /* 0 means en_US */
+ uint charset_database_number;
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans, bool suppress_use);
+ bool using_trans, bool suppress_use,
+ THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
- int exec_event(struct st_relay_log_info* rli, const char *query_arg,
- uint32 q_len_arg);
#endif /* HAVE_REPLICATION */
#else
void print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
@@ -853,7 +1041,7 @@ public:
~Query_log_event()
{
if (data_buf)
- my_free((gptr) data_buf, MYF(0));
+ my_free((uchar*) data_buf, MYF(0));
}
Log_event_type get_type_code() { return QUERY_EVENT; }
#ifndef MYSQL_CLIENT
@@ -868,6 +1056,16 @@ public:
*/
virtual ulong get_post_header_size_for_derived() { return 0; }
/* Writes derived event-specific part of post header. */
+
+public: /* !!! Public in this patch to allow old usage */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+
+ int do_apply_event(RELAY_LOG_INFO const *rli,
+ const char *query_arg,
+ uint32 q_len_arg);
+#endif /* HAVE_REPLICATION */
};
@@ -916,9 +1114,8 @@ public:
uint16 master_port;
#ifndef MYSQL_CLIENT
- Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
+ Slave_log_event(THD* thd_arg, RELAY_LOG_INFO* rli);
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
@@ -931,6 +1128,11 @@ public:
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file);
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const* rli);
+#endif
};
#endif /* HAVE_REPLICATION */
@@ -1000,12 +1202,6 @@ public:
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli)
- {
- return exec_event(thd->slave_net,rli,0);
- }
- int exec_event(NET* net, struct st_relay_log_info* rli,
- bool use_rli_only_for_errors);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1037,6 +1233,17 @@ public:
+ LOAD_HEADER_LEN
+ sql_ex.data_size() + field_block_len + num_fields);
}
+
+public: /* !!! Public in this patch to allow old usage */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const* rli)
+ {
+ return do_apply_event(thd->slave_net,rli,0);
+ }
+
+ int do_apply_event(NET *net, RELAY_LOG_INFO const *rli,
+ bool use_rli_only_for_errors);
+#endif
};
extern char server_version[SERVER_VERSION_LENGTH];
@@ -1094,7 +1301,6 @@ public:
Start_log_event_v3();
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
Start_log_event_v3() {}
@@ -1114,6 +1320,22 @@ public:
return START_V3_HEADER_LEN; //no variable-sized part
}
virtual bool is_artificial_event() { return artificial_event; }
+
+protected:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO*)
+ {
+ /*
+ Events from ourself should be skipped, but they should not
+ decrease the slave skip counter.
+ */
+ if (this->server_id == ::server_id)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::EVENT_SKIP_NOT;
+ }
+#endif
};
@@ -1136,18 +1358,12 @@ public:
uint8 number_of_event_types;
/* The list of post-headers' lengthes */
uint8 *post_header_len;
+ uchar server_version_split[3];
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
-
-#ifndef MYSQL_CLIENT
-#ifdef HAVE_REPLICATION
- int exec_event(struct st_relay_log_info* rli);
-#endif /* HAVE_REPLICATION */
-#endif
-
Format_description_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event);
- ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
+ ~Format_description_log_event() { my_free((uchar*)post_header_len, MYF(0)); }
Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file);
@@ -1167,6 +1383,15 @@ public:
*/
return FORMAT_DESCRIPTION_HEADER_LEN;
}
+
+ void calc_server_version_split();
+
+protected:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
};
@@ -1190,7 +1415,6 @@ public:
{}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1205,6 +1429,13 @@ public:
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
};
@@ -1231,7 +1462,6 @@ class Rand_log_event: public Log_event
{}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1245,6 +1475,13 @@ class Rand_log_event: public Log_event
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
};
/*****************************************************************************
@@ -1268,7 +1505,6 @@ class Xid_log_event: public Log_event
Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1282,6 +1518,11 @@ class Xid_log_event: public Log_event
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
};
/*****************************************************************************
@@ -1311,7 +1552,6 @@ public:
val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
{ is_null= !val; }
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
@@ -1323,6 +1563,13 @@ public:
bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; }
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
};
@@ -1337,7 +1584,6 @@ public:
#ifndef MYSQL_CLIENT
Stop_log_event() :Log_event()
{}
- int exec_event(struct st_relay_log_info* rli);
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
@@ -1348,6 +1594,22 @@ public:
~Stop_log_event() {}
Log_event_type get_type_code() { return STOP_EVENT;}
bool is_valid() const { return 1; }
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli)
+ {
+ /*
+ Events from ourself should be skipped, but they should not
+ decrease the slave skip counter.
+ */
+ if (this->server_id == ::server_id)
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::EVENT_SKIP_NOT;
+ }
+#endif
};
/*****************************************************************************
@@ -1374,7 +1636,6 @@ public:
ulonglong pos_arg, uint flags);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1385,7 +1646,7 @@ public:
~Rotate_log_event()
{
if (flags & DUP_NAME)
- my_free((gptr) new_log_ident, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) new_log_ident, MYF(MY_ALLOW_ZERO_PTR));
}
Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
@@ -1393,6 +1654,12 @@ public:
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file);
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
};
@@ -1427,7 +1694,6 @@ public:
bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1461,6 +1727,11 @@ public:
*/
bool write_base(IO_CACHE* file);
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
};
@@ -1493,7 +1764,6 @@ public:
Append_block_log_event(THD* thd, const char* db_arg, char* block_arg,
uint block_len_arg, bool using_trans);
#ifdef HAVE_REPLICATION
- int exec_event(struct st_relay_log_info* rli);
void pack_info(Protocol* protocol);
virtual int get_create_or_append() const;
#endif /* HAVE_REPLICATION */
@@ -1511,6 +1781,11 @@ public:
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
};
@@ -1530,7 +1805,6 @@ public:
Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1547,6 +1821,11 @@ public:
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
};
@@ -1566,7 +1845,6 @@ public:
Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1582,6 +1860,11 @@ public:
bool write(IO_CACHE* file);
const char* get_db() { return db; }
#endif
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
};
@@ -1651,7 +1934,6 @@ public:
bool using_trans, bool suppress_use);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
- int exec_event(struct st_relay_log_info* rli);
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
@@ -1670,7 +1952,12 @@ public:
#ifndef MYSQL_CLIENT
bool write_post_header_for_derived(IO_CACHE* file);
#endif
- };
+
+private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
+};
#ifdef MYSQL_CLIENT
@@ -1710,14 +1997,17 @@ public:
TYPE_CODE = TABLE_MAP_EVENT
};
+ /**
+ Enumeration of the errors that can be returned.
+ */
enum enum_error
{
- ERR_OPEN_FAILURE = -1, /* Failure to open table */
- ERR_OK = 0, /* No error */
- ERR_TABLE_LIMIT_EXCEEDED = 1, /* No more room for tables */
- ERR_OUT_OF_MEM = 2, /* Out of memory */
- ERR_BAD_TABLE_DEF = 3, /* Table definition does not match */
- ERR_RBR_TO_SBR = 4 /* daisy-chanining RBR to SBR not allowed */
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
};
enum enum_flag
@@ -1765,7 +2055,6 @@ public:
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- virtual int exec_event(struct st_relay_log_info *rli);
virtual void pack_info(Protocol *protocol);
#endif
@@ -1775,21 +2064,27 @@ public:
private:
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+#endif
+
#ifndef MYSQL_CLIENT
- TABLE *m_table;
+ TABLE *m_table;
#endif
char const *m_dbnam;
- my_size_t m_dblen;
+ size_t m_dblen;
char const *m_tblnam;
- my_size_t m_tbllen;
+ size_t m_tbllen;
ulong m_colcnt;
- unsigned char *m_coltype;
+ uchar *m_coltype;
- gptr m_memory;
+ uchar *m_memory;
ulong m_table_id;
flag_set m_flags;
- my_size_t m_data_size;
+ size_t m_data_size;
};
@@ -1797,7 +2092,7 @@ private:
Row level log event class.
- Common base class for all row-level log events.
+ Common base class for all row-containing log events.
RESPONSIBILITIES
@@ -1811,6 +2106,19 @@ private:
class Rows_log_event : public Log_event
{
public:
+ /**
+ Enumeration of the errors that can be returned.
+ */
+ enum enum_error
+ {
+ ERR_OPEN_FAILURE = -1, /**< Failure to open table */
+ ERR_OK = 0, /**< No error */
+ ERR_TABLE_LIMIT_EXCEEDED = 1, /**< No more room for tables */
+ ERR_OUT_OF_MEM = 2, /**< Out of memory */
+ ERR_BAD_TABLE_DEF = 3, /**< Table definition does not match */
+ ERR_RBR_TO_SBR = 4 /**< daisy-chanining RBR to SBR not allowed */
+ };
+
/*
These definitions allow you to combine the flags into an
appropriate flag set using the normal bitwise operators. The
@@ -1818,7 +2126,6 @@ public:
accepted by the compiler, which is then used to set the real set
of flags.
*/
-
enum enum_flag
{
/* Last event of a statement */
@@ -1841,12 +2148,11 @@ public:
virtual ~Rows_log_event();
- void set_flags(flag_set flags) { m_flags |= flags; }
- void clear_flags(flag_set flags) { m_flags &= ~flags; }
- flag_set get_flags(flag_set flags) const { return m_flags & flags; }
+ void set_flags(flag_set flags_arg) { m_flags |= flags_arg; }
+ void clear_flags(flag_set flags_arg) { m_flags &= ~flags_arg; }
+ flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; }
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- virtual int exec_event(struct st_relay_log_info *rli);
virtual void pack_info(Protocol *protocol);
#endif
@@ -1856,24 +2162,17 @@ public:
#endif
#ifndef MYSQL_CLIENT
- int add_row_data(byte *data, my_size_t length)
+ int add_row_data(uchar *data, size_t length)
{
return do_add_row_data(data,length);
}
#endif
/* Member functions to implement superclass interface */
- virtual int get_data_size()
- {
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
- return 6 + 1 + no_bytes_in_map(&m_cols) +
- (m_rows_cur - m_rows_buf););
- return ROWS_HEADER_LEN + 1 + no_bytes_in_map(&m_cols) +
- (m_rows_cur - m_rows_buf);
- }
+ virtual int get_data_size();
MY_BITMAP const *get_cols() const { return &m_cols; }
- my_size_t get_width() const { return m_width; }
+ size_t get_width() const { return m_width; }
ulong get_table_id() const { return m_table_id; }
#ifndef MYSQL_CLIENT
@@ -1881,9 +2180,14 @@ public:
virtual bool write_data_body(IO_CACHE *file);
virtual const char *get_db() { return m_table->s->db.str; }
#endif
+ /*
+ Check that malloc() succeeded in allocating memory for the rows
+ buffer and the COLS vector. Checking that an Update_rows_log_event
+ is valid is done in the Update_rows_log_event::is_valid()
+ function.
+ */
virtual bool is_valid() const
{
- /* that's how we check malloc() succeeded */
return m_rows_buf && m_cols.bitmap;
}
@@ -1907,7 +2211,7 @@ protected:
#endif
#ifndef MYSQL_CLIENT
- virtual int do_add_row_data(byte *data, my_size_t length);
+ virtual int do_add_row_data(uchar *data, size_t length);
#endif
#ifndef MYSQL_CLIENT
@@ -1916,20 +2220,34 @@ protected:
ulong m_table_id; /* Table ID */
MY_BITMAP m_cols; /* Bitmap denoting columns available */
ulong m_width; /* The width of the columns bitmap */
+ /*
+ Bitmap for columns available in the after image, if present. These
+ fields are only available for Update_rows events. Observe that the
+ width of both the before image COLS vector and the after image
+ COLS vector is the same: the number of columns of the table on the
+ master.
+ */
+ MY_BITMAP m_cols_ai;
+
ulong m_master_reclength; /* Length of record on master side */
- /* Bit buffer in the same memory as the class */
+ /* Bit buffers in the same memory as the class */
uint32 m_bitbuf[128/(sizeof(uint32)*8)];
+ uint32 m_bitbuf_ai[128/(sizeof(uint32)*8)];
- byte *m_rows_buf; /* The rows in packed format */
- byte *m_rows_cur; /* One-after the end of the data */
- byte *m_rows_end; /* One-after the end of the allocated space */
+ uchar *m_rows_buf; /* The rows in packed format */
+ uchar *m_rows_cur; /* One-after the end of the data */
+ uchar *m_rows_end; /* One-after the end of the allocated space */
flag_set m_flags; /* Flags for row-level events */
private:
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+ virtual int do_update_pos(RELAY_LOG_INFO *rli);
+ virtual enum_skip_reason do_shall_skip(RELAY_LOG_INFO *rli);
+
/*
Primitive to prepare for a sequence of row executions.
@@ -1977,8 +2295,9 @@ private:
RETURN VALUE
Error code, if something went wrong, 0 otherwise.
*/
- virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
- char const *row_start, char const **row_end) = 0;
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start,
+ uchar const **row_end) = 0;
/*
Primitive to do the actual execution necessary for a row.
@@ -2026,9 +2345,9 @@ public:
bool is_transactional,
MY_BITMAP *cols,
uint fields,
- const byte *before_record
+ const uchar *before_record
__attribute__((unused)),
- const byte *after_record)
+ const uchar *after_record)
{
return thd->binlog_write_row(table, is_transactional,
cols, fields, after_record);
@@ -2043,13 +2362,13 @@ private:
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- gptr m_memory;
- byte *m_after_image;
+ uchar *m_memory;
+ uchar *m_after_image;
virtual int do_before_row_operations(TABLE *table);
virtual int do_after_row_operations(TABLE *table, int error);
- virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
- char const *row_start, char const **row_end);
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
virtual int do_exec_row(TABLE *table);
#endif
};
@@ -2077,10 +2396,20 @@ public:
};
#ifndef MYSQL_CLIENT
- Update_rows_log_event(THD*, TABLE*, ulong table_id,
- MY_BITMAP const *cols, bool is_transactional);
+ Update_rows_log_event(THD*, TABLE*, ulong table_id,
+ MY_BITMAP const *cols_bi,
+ MY_BITMAP const *cols_ai,
+ bool is_transactional);
+
+ Update_rows_log_event(THD*, TABLE*, ulong table_id,
+ MY_BITMAP const *cols,
+ bool is_transactional);
+
+ void init(MY_BITMAP const *cols);
#endif
+ virtual ~Update_rows_log_event();
+
#ifdef HAVE_REPLICATION
Update_rows_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
@@ -2091,15 +2420,20 @@ public:
bool is_transactional,
MY_BITMAP *cols,
uint fields,
- const byte *before_record,
- const byte *after_record)
+ const uchar *before_record,
+ const uchar *after_record)
{
return thd->binlog_update_row(table, is_transactional,
cols, fields, before_record, after_record);
}
#endif
-private:
+ virtual bool is_valid() const
+ {
+ return Rows_log_event::is_valid() && m_cols_ai.bitmap;
+ }
+
+protected:
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
@@ -2107,14 +2441,14 @@ private:
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- gptr m_memory;
- byte *m_key;
- byte *m_after_image;
+ uchar *m_memory;
+ uchar *m_key;
+ uchar *m_after_image;
virtual int do_before_row_operations(TABLE *table);
virtual int do_after_row_operations(TABLE *table, int error);
- virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
- char const *row_start, char const **row_end);
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
virtual int do_exec_row(TABLE *table);
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
};
@@ -2161,8 +2495,8 @@ public:
bool is_transactional,
MY_BITMAP *cols,
uint fields,
- const byte *before_record,
- const byte *after_record
+ const uchar *before_record,
+ const uchar *after_record
__attribute__((unused)))
{
return thd->binlog_delete_row(table, is_transactional,
@@ -2170,7 +2504,7 @@ public:
}
#endif
-private:
+protected:
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
@@ -2178,16 +2512,116 @@ private:
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
- gptr m_memory;
- byte *m_key;
- byte *m_after_image;
+ uchar *m_memory;
+ uchar *m_key;
+ uchar *m_after_image;
virtual int do_before_row_operations(TABLE *table);
virtual int do_after_row_operations(TABLE *table, int error);
- virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
- char const *row_start, char const **row_end);
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
virtual int do_exec_row(TABLE *table);
#endif
};
+
+#include "log_event_old.h"
+
+/**
+ Class representing an incident, an occurance out of the ordinary,
+ that happened on the master.
+
+ The event is used to inform the slave that something out of the
+ ordinary happened on the master that might cause the database to be
+ in an inconsistent state.
+
+ <table id="IncidentFormat">
+ <caption>Incident event format</caption>
+ <tr>
+ <th>Symbol</th>
+ <th>Size<br/>(bytes)</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>INCIDENT</td>
+ <td align="right">2</td>
+ <td>Incident number as an unsigned integer</td>
+ </tr>
+ <tr>
+ <td>MSGLEN</td>
+ <td align="right">1</td>
+ <td>Message length as an unsigned integer</td>
+ </tr>
+ <tr>
+ <td>MESSAGE</td>
+ <td align="right">MSGLEN</td>
+ <td>The message, if present. Not null terminated.</td>
+ </tr>
+ </table>
+ */
+class Incident_log_event : public Log_event {
+public:
+#ifndef MYSQL_CLIENT
+ Incident_log_event(THD *thd_arg, Incident incident)
+ : Log_event(thd_arg, 0, FALSE), m_incident(incident)
+ {
+ DBUG_ENTER("Incident_log_event::Incident_log_event");
+ DBUG_PRINT("enter", ("m_incident: %d", m_incident));
+ m_message.str= NULL; /* Just as a precaution */
+ m_message.length= 0;
+ DBUG_VOID_RETURN;
+ }
+
+ Incident_log_event(THD *thd_arg, Incident incident, LEX_STRING const msg)
+ : Log_event(thd_arg, 0, FALSE), m_incident(incident)
+ {
+ DBUG_ENTER("Incident_log_event::Incident_log_event");
+ DBUG_PRINT("enter", ("m_incident: %d", m_incident));
+ m_message= msg;
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+#ifndef MYSQL_CLIENT
+ void pack_info(Protocol*);
+#endif
+
+ Incident_log_event(const char *buf, uint event_len,
+ const Format_description_log_event *descr_event);
+
+ virtual ~Incident_log_event();
+
+#ifdef MYSQL_CLIENT
+ virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+#endif
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_apply_event(RELAY_LOG_INFO const *rli);
+#endif
+
+ virtual bool write_data_header(IO_CACHE *file);
+ virtual bool write_data_body(IO_CACHE *file);
+
+ virtual Log_event_type get_type_code() { return INCIDENT_EVENT; }
+
+ virtual bool is_valid() const { return 1; }
+ virtual int get_data_size() {
+ return INCIDENT_HEADER_LEN + 1 + m_message.length;
+ }
+
+private:
+ const char *description() const;
+
+ Incident m_incident;
+ LEX_STRING m_message;
+};
+
+static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
+ FILE *file)
+{
+ return
+ my_b_copy_to_file(cache, file) ||
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+}
+
#endif /* _log_event_h */
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
new file mode 100644
index 00000000000..e6a9dd50c08
--- /dev/null
+++ b/sql/log_event_old.cc
@@ -0,0 +1,104 @@
+
+#include "mysql_priv.h"
+#include "log_event_old.h"
+#include "rpl_record_old.h"
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int
+Write_rows_log_event_old::do_prepare_row(THD *thd,
+ RELAY_LOG_INFO const *rli,
+ TABLE *table,
+ uchar const *row_start,
+ uchar const **row_end)
+{
+ DBUG_ASSERT(table != NULL);
+ DBUG_ASSERT(row_start && row_end);
+
+ int error;
+ error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
+ table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->write_set, PRE_GA_WRITE_ROWS_EVENT);
+ bitmap_copy(table->read_set, table->write_set);
+ return error;
+}
+
+
+int
+Delete_rows_log_event_old::do_prepare_row(THD *thd,
+ RELAY_LOG_INFO const *rli,
+ TABLE *table,
+ uchar const *row_start,
+ uchar const **row_end)
+{
+ int error;
+ DBUG_ASSERT(row_start && row_end);
+ /*
+ This assertion actually checks that there is at least as many
+ columns on the slave as on the master.
+ */
+ DBUG_ASSERT(table->s->fields >= m_width);
+
+ error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
+ table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->read_set, PRE_GA_DELETE_ROWS_EVENT);
+ /*
+ If we will access rows using the random access method, m_key will
+ be set to NULL, so we do not need to make a key copy in that case.
+ */
+ if (m_key)
+ {
+ KEY *const key_info= table->key_info;
+
+ key_copy(m_key, table->record[0], key_info, 0);
+ }
+
+ return error;
+}
+
+
+int Update_rows_log_event_old::do_prepare_row(THD *thd,
+ RELAY_LOG_INFO const *rli,
+ TABLE *table,
+ uchar const *row_start,
+ uchar const **row_end)
+{
+ int error;
+ DBUG_ASSERT(row_start && row_end);
+ /*
+ This assertion actually checks that there is at least as many
+ columns on the slave as on the master.
+ */
+ DBUG_ASSERT(table->s->fields >= m_width);
+
+ /* record[0] is the before image for the update */
+ error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
+ table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->read_set, PRE_GA_UPDATE_ROWS_EVENT);
+ row_start = *row_end;
+ /* m_after_image is the after image for the update */
+ error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
+ table, m_width, m_after_image,
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->write_set, PRE_GA_UPDATE_ROWS_EVENT);
+
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("m_after_image", m_after_image, table->s->reclength);
+
+ /*
+ If we will access rows using the random access method, m_key will
+ be set to NULL, so we do not need to make a key copy in that case.
+ */
+ if (m_key)
+ {
+ KEY *const key_info= table->key_info;
+
+ key_copy(m_key, table->record[0], key_info, 0);
+ }
+
+ return error;
+}
+
+#endif
diff --git a/sql/log_event_old.h b/sql/log_event_old.h
new file mode 100644
index 00000000000..7c2932360f5
--- /dev/null
+++ b/sql/log_event_old.h
@@ -0,0 +1,127 @@
+/* Copyright 2007 MySQL AB. All rights reserved.
+
+ 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; version 2 of the License.
+
+ 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 LOG_EVENT_OLD_H
+#define LOG_EVENT_OLD_H
+
+/*
+ Need to include this file at the proper position of log_event.h
+ */
+
+
+class Write_rows_log_event_old : public Write_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT
+ };
+
+#if !defined(MYSQL_CLIENT)
+ Write_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
+ MY_BITMAP const *cols, bool is_transactional)
+ : Write_rows_log_event(thd, table, table_id, cols, is_transactional)
+ {
+ }
+#endif
+#if defined(HAVE_REPLICATION)
+ Write_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Write_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
+#endif
+};
+
+
+class Update_rows_log_event_old : public Update_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT
+ };
+
+#if !defined(MYSQL_CLIENT)
+ Update_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
+ MY_BITMAP const *cols, bool is_transactional)
+ : Update_rows_log_event(thd, table, table_id, cols, is_transactional)
+ {
+ }
+#endif
+#if defined(HAVE_REPLICATION)
+ Update_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Update_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
+#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
+};
+
+
+class Delete_rows_log_event_old : public Delete_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT
+ };
+
+#if !defined(MYSQL_CLIENT)
+ Delete_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
+ MY_BITMAP const *cols, bool is_transactional)
+ : Delete_rows_log_event(thd, table, table_id, cols, is_transactional)
+ {
+ }
+#endif
+#if defined(HAVE_REPLICATION)
+ Delete_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Delete_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
+ uchar const *row_start, uchar const **row_end);
+#endif
+};
+
+
+#endif
+
diff --git a/sql/matherr.c b/sql/matherr.c
index ea0c15d2feb..4998d8b4961 100644
--- a/sql/matherr.c
+++ b/sql/matherr.c
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
index 71c8d588de7..5d9d6d834b4 100644
--- a/sql/mf_iocache.cc
+++ b/sql/mf_iocache.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -41,8 +40,8 @@ extern "C" {
** Returns 0 if record read
*/
-int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
- uint Count __attribute__((unused)))
+int _my_b_net_read(register IO_CACHE *info, uchar *Buffer,
+ size_t Count __attribute__((unused)))
{
ulong read_length;
NET *net= &(current_thd)->net;
@@ -62,7 +61,7 @@ int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
DBUG_RETURN(1);
}
/* to set up stuff for my_b_get (no _) */
- info->read_end = (info->read_pos = (byte*) net->read_pos) + read_length;
+ info->read_end = (info->read_pos = (uchar*) net->read_pos) + read_length;
Buffer[0] = info->read_pos[0]; /* length is always 1 */
/*
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 30a271df064..1f0ebf32795 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -119,7 +118,7 @@ int my_decimal2string(uint mask, const my_decimal *d,
E_DEC_OVERFLOW
*/
-int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
+int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
int scale)
{
int err1= E_DEC_OK, err2;
@@ -192,7 +191,7 @@ int str2my_decimal(uint mask, const char *from, uint length,
}
-my_decimal *date2my_decimal(TIME *ltime, my_decimal *dec)
+my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec)
{
longlong date;
date = (ltime->year*100L + ltime->month)*100L + ltime->day;
@@ -209,6 +208,17 @@ my_decimal *date2my_decimal(TIME *ltime, my_decimal *dec)
}
+void my_decimal_trim(ulong *precision, uint *scale)
+{
+ if (!(*precision) && !(*scale))
+ {
+ *precision= 10;
+ *scale= 0;
+ return;
+ }
+}
+
+
#ifndef DBUG_OFF
/* routines for debugging print */
@@ -234,7 +244,7 @@ print_decimal(const my_decimal *dec)
/* print decimal with its binary representation */
void
-print_decimal_buff(const my_decimal *dec, const byte* ptr, int length)
+print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length)
{
print_decimal(dec);
fprintf(DBUG_FILE, "Record: ");
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 9e2dea26700..f9ba99a4509 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,13 +36,17 @@ C_MODE_END
/* maximum length of buffer in our big digits (uint32) */
#define DECIMAL_BUFF_LENGTH 9
+
+/* the number of digits that my_decimal can possibly contain */
+#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9)
+
/*
maximum guaranteed precision of number in decimal digits (number of our
digits * number of decimal digits in one our big digit - number of decimal
- digits in one our big digit decreased on 1 (because we always put decimal
+ digits in one our big digit decreased by 1 (because we always put decimal
point on the border of our big digits))
*/
-#define DECIMAL_MAX_PRECISION ((DECIMAL_BUFF_LENGTH * 9) - 8*2)
+#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
#define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31
@@ -51,7 +54,7 @@ C_MODE_END
maximum length of string representation (number of maximum decimal
digits + 1 position for sign + 1 position for decimal point)
*/
-#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_PRECISION + 2)
+#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
/*
maximum size of packet length
*/
@@ -111,7 +114,7 @@ public:
#ifndef DBUG_OFF
void print_decimal(const my_decimal *dec);
-void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length);
+void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length);
const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
#else
#define dbug_decimal_as_string(A) NULL
@@ -201,16 +204,15 @@ void my_decimal2decimal(const my_decimal *from, my_decimal *to)
}
-int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
+int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
int scale);
inline
-int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec,
+int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
int scale)
{
- return check_result(mask, bin2decimal((char *)bin, (decimal_t*) d, prec,
- scale));
+ return check_result(mask, bin2decimal(bin, (decimal_t*) d, prec, scale));
}
@@ -297,7 +299,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d)
}
-my_decimal *date2my_decimal(TIME *ltime, my_decimal *dec);
+my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec);
#endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */
@@ -396,5 +398,8 @@ int my_decimal_intg(const my_decimal *a)
}
+void my_decimal_trim(ulong *precision, uint *scale);
+
+
#endif /*my_decimal_h*/
diff --git a/sql/my_lock.c b/sql/my_lock.c
index 69884df22f8..f66d7282f72 100644
--- a/sql/my_lock.c
+++ b/sql/my_lock.c
@@ -1,9 +1,8 @@
-/* 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
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 09cc4b5c219..f5d66696cab 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,8 +35,11 @@
#include <signal.h>
#include <thr_lock.h>
#include <my_base.h> /* Needed by field.h */
+#include <queues.h>
#include "sql_bitmap.h"
#include "sql_array.h"
+#include "sql_plugin.h"
+#include "scheduler.h"
/* TODO convert all these three maps to Bitmap classes */
typedef ulonglong table_map; /* Used for table bits in join */
@@ -46,7 +48,6 @@ typedef Bitmap<64> key_map; /* Used for finding keys */
#else
typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
#endif
-typedef ulong key_part_map; /* Used for finding key parts */
typedef ulong nesting_map; /* Used for flags of nesting constructs */
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
@@ -57,10 +58,10 @@ typedef ulonglong nested_join_map;
/* query_id */
typedef ulonglong query_id_t;
-extern query_id_t query_id;
+extern query_id_t global_query_id;
/* increment query_id and return it. */
-inline query_id_t next_query_id() { return query_id++; }
+inline query_id_t next_query_id() { return global_query_id++; }
/* useful constants */
extern const key_map key_map_empty;
@@ -72,35 +73,41 @@ extern const char *primary_key_name;
#include "unireg.h"
void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
-gptr sql_alloc(unsigned size);
-gptr sql_calloc(unsigned size);
+void *sql_alloc(size_t);
+void *sql_calloc(size_t);
char *sql_strdup(const char *str);
-char *sql_strmake(const char *str,uint len);
-gptr sql_memdup(const void * ptr,unsigned size);
+char *sql_strmake(const char *str, size_t len);
+void *sql_memdup(const void * ptr, size_t size);
void sql_element_free(void *ptr);
-char *sql_strmake_with_convert(const char *str, uint32 arg_length,
+char *sql_strmake_with_convert(const char *str, size_t arg_length,
CHARSET_INFO *from_cs,
- uint32 max_res_length,
- CHARSET_INFO *to_cs, uint32 *result_length);
+ size_t max_res_length,
+ CHARSET_INFO *to_cs, size_t *result_length);
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
-#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
-#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
+void net_set_write_timeout(NET *net, uint timeout);
+void net_set_read_timeout(NET *net, uint timeout);
+
+#define x_free(A) { my_free((uchar*) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
+#define safeFree(x) { if(x) { my_free((uchar*) x,MYF(0)); x = NULL; } }
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
-#define WARN_DEPRECATED(Thd,Ver,Old,New) \
- do { \
- DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) >= 0); \
- push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
- ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
- (Old), (Ver), (New)); \
+#define WARN_DEPRECATED(Thd,Ver,Old,New) \
+ do { \
+ DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
+ if (((uchar*)Thd) != NULL) \
+ push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \
+ ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
+ (Old), (Ver), (New)); \
+ else \
+ sql_print_warning("The syntax %s is deprecated and will be removed " \
+ "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0)
-
extern CHARSET_INFO *system_charset_info, *files_charset_info ;
extern CHARSET_INFO *national_charset_info, *table_alias_charset;
@@ -141,6 +148,7 @@ typedef struct my_locale_st
extern MY_LOCALE my_locale_en_US;
extern MY_LOCALE *my_locales[];
+extern MY_LOCALE *my_default_lc_time_names;
MY_LOCALE *my_locale_by_name(const char *name);
MY_LOCALE *my_locale_by_number(uint number);
@@ -167,7 +175,7 @@ MY_LOCALE *my_locale_by_number(uint number);
Feel free to raise this by the smallest amount you can to get the
"execution_constants" test to pass.
*/
-#define STACK_MIN_SIZE 10788 // Abort if less stack during eval.
+#define STACK_MIN_SIZE 12000 // Abort if less stack during eval.
#define STACK_MIN_SIZE_FOR_OPEN 1024*80
#define STACK_BUFF_ALLOC 256 // For stack overrun checks
@@ -251,13 +259,12 @@ MY_LOCALE *my_locale_by_number(uint number);
#define MAX_CONNECT_ERRORS 10 // errors before disabling host
#ifdef __NETWARE__
-#define IF_NETWARE(A,B) (A)
+#define IF_NETWARE(A,B) A
#else
-#define IF_NETWARE(A,B) (B)
+#define IF_NETWARE(A,B) B
#endif
#if defined(__WIN__)
-#define IF_WIN(A,B) (A)
#undef FLUSH_TIME
#define FLUSH_TIME 1800 /* Flush every half hour */
@@ -266,7 +273,6 @@ MY_LOCALE *my_locale_by_number(uint number);
#define WAIT_PRIOR 0
#define QUERY_PRIOR 2
#else
-#define IF_WIN(A,B) (B)
#define INTERRUPT_PRIOR 10
#define CONNECT_PRIOR 9
#define WAIT_PRIOR 8
@@ -279,7 +285,6 @@ MY_LOCALE *my_locale_by_number(uint number);
#define TEST_MIT_THREAD 4
#define TEST_BLOCKING 8
#define TEST_KEEP_TMP_TABLES 16
-#define TEST_NO_THREADS 32 /* For debugging under Linux */
#define TEST_READCHECK 64 /* Force use of readcheck */
#define TEST_NO_EXTRA 128
#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
@@ -307,60 +312,58 @@ MY_LOCALE *my_locale_by_number(uint number);
TODO: separate three contexts above, move them to separate bitfields.
*/
-#define SELECT_DISTINCT (LL(1) << 0) // SELECT, user
-#define SELECT_STRAIGHT_JOIN (LL(1) << 1) // SELECT, user
-#define SELECT_DESCRIBE (LL(1) << 2) // SELECT, user
-#define SELECT_SMALL_RESULT (LL(1) << 3) // SELECT, user
-#define SELECT_BIG_RESULT (LL(1) << 4) // SELECT, user
-#define OPTION_FOUND_ROWS (LL(1) << 5) // SELECT, user
-#define OPTION_TO_QUERY_CACHE (LL(1) << 6) // SELECT, user
-#define SELECT_NO_JOIN_CACHE (LL(1) << 7) // intern
-#define OPTION_BIG_TABLES (LL(1) << 8) // THD, user
-#define OPTION_BIG_SELECTS (LL(1) << 9) // THD, user
-#define OPTION_LOG_OFF (LL(1) << 10) // THD, user
-#define OPTION_QUOTE_SHOW_CREATE (LL(1) << 11) // THD, user
-#define TMP_TABLE_ALL_COLUMNS (LL(1) << 12) // SELECT, intern
-#define OPTION_WARNINGS (LL(1) << 13) // THD, user
-#define OPTION_AUTO_IS_NULL (LL(1) << 14) // THD, user, binlog
-#define OPTION_FOUND_COMMENT (LL(1) << 15) // SELECT, intern, parser
-#define OPTION_SAFE_UPDATES (LL(1) << 16) // THD, user
-#define OPTION_BUFFER_RESULT (LL(1) << 17) // SELECT, user
-#define OPTION_BIN_LOG (LL(1) << 18) // THD, user
-#define OPTION_NOT_AUTOCOMMIT (LL(1) << 19) // THD, user
-#define OPTION_BEGIN (LL(1) << 20) // THD, intern
-#define OPTION_TABLE_LOCK (LL(1) << 21) // THD, intern
-#define OPTION_QUICK (LL(1) << 22) // SELECT (for DELETE)
-#define OPTION_KEEP_LOG (LL(1) << 23) // Keep binlog on rollback
+#define SELECT_DISTINCT (ULL(1) << 0) // SELECT, user
+#define SELECT_STRAIGHT_JOIN (ULL(1) << 1) // SELECT, user
+#define SELECT_DESCRIBE (ULL(1) << 2) // SELECT, user
+#define SELECT_SMALL_RESULT (ULL(1) << 3) // SELECT, user
+#define SELECT_BIG_RESULT (ULL(1) << 4) // SELECT, user
+#define OPTION_FOUND_ROWS (ULL(1) << 5) // SELECT, user
+#define OPTION_TO_QUERY_CACHE (ULL(1) << 6) // SELECT, user
+#define SELECT_NO_JOIN_CACHE (ULL(1) << 7) // intern
+#define OPTION_BIG_TABLES (ULL(1) << 8) // THD, user
+#define OPTION_BIG_SELECTS (ULL(1) << 9) // THD, user
+#define OPTION_LOG_OFF (ULL(1) << 10) // THD, user
+#define OPTION_QUOTE_SHOW_CREATE (ULL(1) << 11) // THD, user, unused
+#define TMP_TABLE_ALL_COLUMNS (ULL(1) << 12) // SELECT, intern
+#define OPTION_WARNINGS (ULL(1) << 13) // THD, user
+#define OPTION_AUTO_IS_NULL (ULL(1) << 14) // THD, user, binlog
+#define OPTION_FOUND_COMMENT (ULL(1) << 15) // SELECT, intern, parser
+#define OPTION_SAFE_UPDATES (ULL(1) << 16) // THD, user
+#define OPTION_BUFFER_RESULT (ULL(1) << 17) // SELECT, user
+#define OPTION_BIN_LOG (ULL(1) << 18) // THD, user
+#define OPTION_NOT_AUTOCOMMIT (ULL(1) << 19) // THD, user
+#define OPTION_BEGIN (ULL(1) << 20) // THD, intern
+#define OPTION_TABLE_LOCK (ULL(1) << 21) // THD, intern
+#define OPTION_QUICK (ULL(1) << 22) // SELECT (for DELETE)
+#define OPTION_KEEP_LOG (ULL(1) << 23) // THD, user
/* The following is used to detect a conflict with DISTINCT */
-#define SELECT_ALL (LL(1) << 24) // SELECT, user, parser
-
-/* Set if we are updating a non-transaction safe table */
-#define OPTION_STATUS_NO_TRANS_UPDATE (LL(1) << 25) // THD, intern
+#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser
/* The following can be set when importing tables in a 'wrong order'
to suppress foreign key checks */
-#define OPTION_NO_FOREIGN_KEY_CHECKS (LL(1) << 26) // THD, user, binlog
+#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog
/* The following speeds up inserts to InnoDB tables by suppressing unique
key checks in some cases */
-#define OPTION_RELAXED_UNIQUE_CHECKS (LL(1) << 27) // THD, user, binlog
-#define SELECT_NO_UNLOCK (LL(1) << 28) // SELECT, intern
-#define OPTION_SCHEMA_TABLE (LL(1) << 29) // SELECT, intern
+#define OPTION_RELAXED_UNIQUE_CHECKS (ULL(1) << 27) // THD, user, binlog
+#define SELECT_NO_UNLOCK (ULL(1) << 28) // SELECT, intern
+#define OPTION_SCHEMA_TABLE (ULL(1) << 29) // SELECT, intern
/* Flag set if setup_tables already done */
-#define OPTION_SETUP_TABLES_DONE (LL(1) << 30) // intern
+#define OPTION_SETUP_TABLES_DONE (ULL(1) << 30) // intern
/* If not set then the thread will ignore all warnings with level notes. */
-#define OPTION_SQL_NOTES (LL(1) << 31) // THD, user
-/*
+#define OPTION_SQL_NOTES (ULL(1) << 31) // THD, user
+/*
Force the used temporary table to be a MyISAM table (because we will use
fulltext functions when reading from it.
*/
-#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32)
+#define TMP_TABLE_FORCE_MYISAM (ULL(1) << 32)
+
/*
Maximum length of time zone name that we support
(Time zone name is char(64) in db). mysqlbinlog needs it.
*/
-#define MAX_TIME_ZONE_NAME_LENGTH 72
+#define MAX_TIME_ZONE_NAME_LENGTH (NAME_LEN + 1)
/* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT
@@ -382,7 +385,7 @@ MY_LOCALE *my_locale_by_number(uint number);
#define MODE_NO_KEY_OPTIONS 8192
#define MODE_NO_TABLE_OPTIONS 16384
#define MODE_NO_FIELD_OPTIONS 32768
-#define MODE_MYSQL323 65536
+#define MODE_MYSQL323 65536L
#define MODE_MYSQL40 (MODE_MYSQL323*2)
#define MODE_ANSI (MODE_MYSQL40*2)
#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
@@ -397,6 +400,8 @@ MY_LOCALE *my_locale_by_number(uint number);
#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
#define MODE_NO_ENGINE_SUBSTITUTION (MODE_HIGH_NOT_PRECEDENCE*2)
+#define MODE_PAD_CHAR_TO_FULL_LENGTH (ULL(1) << 31)
+
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
use strictly more than 64 bits by adding one more define above, you should
@@ -404,8 +409,9 @@ MY_LOCALE *my_locale_by_number(uint number);
updated (to store more bytes on disk).
NOTE: When adding new SQL_MODE types, make sure to also add them to
- ../scripts/mysql_create_system_tables.sh and
- ../scripts/mysql_fix_privilege_tables.sql
+ the scripts used for creating the MySQL system tables
+ in scripts/mysql_system_tables.sql and scripts/mysql_system_tables_fix.sql
+
*/
#define RAID_BLOCK_SIZE 1024
@@ -420,7 +426,11 @@ MY_LOCALE *my_locale_by_number(uint number);
#define UNCACHEABLE_EXPLAIN 8
/* Don't evaluate subqueries in prepare even if they're not correlated */
#define UNCACHEABLE_PREPARE 16
+/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
+#define UNCACHEABLE_UNITED 32
+/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
+#define UNDEF_POS (-1)
#ifdef EXTRA_DEBUG
/*
Sync points allow us to force the server to reach a certain line of code
@@ -491,8 +501,8 @@ class THD;
typedef struct st_sql_list {
uint elements;
- byte *first;
- byte **next;
+ uchar *first;
+ uchar **next;
st_sql_list() {} /* Remove gcc warning */
inline void empty()
@@ -501,7 +511,7 @@ typedef struct st_sql_list {
first=0;
next= &first;
}
- inline void link_in_list(byte *element,byte **next_ptr)
+ inline void link_in_list(uchar *element,uchar **next_ptr)
{
elements++;
(*next)=element;
@@ -538,11 +548,6 @@ inline THD *_current_thd(void)
}
#define current_thd _current_thd()
-/* below functions are required for plugins as THD class is opaque */
-my_bool thd_in_lock_tables(const THD *thd);
-my_bool thd_tablespace_op(const THD *thd);
-const char *thd_proc_info(THD *thd, const char *info);
-void **thd_ha_data(const THD *thd, const struct handlerton *hton);
/*
External variables
@@ -557,7 +562,6 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "sql_list.h"
#include "sql_map.h"
#include "my_decimal.h"
-#include "sql_plugin.h"
#include "handler.h"
#include "parse_file.h"
#include "table.h"
@@ -588,7 +592,7 @@ class THD;
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables);
+ TABLE_LIST *tables, bool no_errors);
bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
bool is_proc, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
@@ -611,8 +615,11 @@ void get_default_definer(THD *thd, LEX_USER *definer);
LEX_USER *create_default_definer(THD *thd);
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
LEX_USER *get_current_user(THD *thd, LEX_USER *user);
-bool check_string_length(LEX_STRING *str,
- const char *err_msg, uint max_length);
+bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
+ uint max_byte_length);
+bool check_string_char_length(LEX_STRING *str, const char *err_msg,
+ uint max_char_length, CHARSET_INFO *cs,
+ bool no_error);
enum enum_mysql_completiontype {
ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
@@ -628,6 +635,7 @@ Item *negate_expression(THD *thd, Item *expr);
#include "sql_acl.h"
#include "tztime.h"
#ifdef MYSQL_SERVER
+#include "sql_servers.h"
#include "opt_range.h"
#ifdef HAVE_QUERY_CACHE
@@ -635,6 +643,7 @@ struct Query_cache_query_flags
{
unsigned int client_long_flag:1;
unsigned int client_protocol_41:1;
+ unsigned int result_in_binary_protocol:1;
unsigned int more_results_exists:1;
unsigned int pkt_nr;
uint character_set_client_num;
@@ -645,6 +654,8 @@ struct Query_cache_query_flags
ulong sql_mode;
ulong max_sort_length;
ulong group_concat_max_len;
+ ulong default_week_format;
+ ulong div_precision_increment;
MY_LOCALE *lc_time_names;
};
#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
@@ -661,6 +672,11 @@ struct Query_cache_query_flags
query_cache.send_result_to_client(A, B, C)
#define query_cache_invalidate_by_MyISAM_filename_ref \
&query_cache_invalidate_by_MyISAM_filename
+/* note the "maybe": it's a read without mutex */
+#define query_cache_maybe_disabled(T) \
+ (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
+#define query_cache_is_cacheable_query(L) \
+ (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
#else
#define QUERY_CACHE_FLAGS_SIZE 0
#define query_cache_store_query(A, B)
@@ -677,6 +693,8 @@ struct Query_cache_query_flags
#define query_cache_abort(A)
#define query_cache_end_of_result(A)
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
+#define query_cache_maybe_disabled(T) 1
+#define query_cache_is_cacheable_query(L) 0
#endif /*HAVE_QUERY_CACHE*/
/*
@@ -773,11 +791,26 @@ check_and_unset_inject_value(int value)
#endif
-uint build_table_path(char *buff, size_t bufflen, const char *db,
- const char *table, const char *ext);
void write_bin_log(THD *thd, bool clear_error,
char const *query, ulong query_length);
+/* sql_connect.cc */
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count);
+pthread_handler_t handle_one_connection(void *arg);
+bool init_new_connection_handler_thread();
+void reset_mqh(LEX_USER *lu, bool get_them);
+bool check_mqh(THD *thd, uint check_command);
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
+int check_for_max_user_connections(THD *thd, USER_CONN *uc);
+void decrease_user_connections(USER_CONN *uc);
+void thd_init_client_charset(THD *thd, uint cs_number);
+bool setup_connection_thread_globals(THD *thd);
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+
bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -798,14 +831,17 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
char *new_table_name, char *new_table_alias,
bool skip_error);
-bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
-void mysql_parse(THD *thd,char *inBuf,uint length);
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
+ bool force_switch);
+
+void mysql_parse(THD *thd, const char *inBuf, uint length,
+ const char ** semicolon);
+
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
bool alloc_query(THD *thd, const char *packet, uint packet_length);
void mysql_init_select(LEX *lex);
void mysql_reset_thd_for_next_command(THD *thd);
-void mysql_init_query(THD *thd, uchar *buf, uint length);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
@@ -813,16 +849,14 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
-pthread_handler_t handle_one_connection(void *arg);
pthread_handler_t handle_bootstrap(void *arg);
-void end_thread(THD *thd,bool put_in_cache);
-void flush_thread_cache();
bool 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);
void log_slow_statement(THD *thd);
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
+bool compare_record(TABLE *table);
bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
@@ -855,9 +889,9 @@ my_bool is_partition_management(LEX *lex);
All methods presume that there is at least one field to change.
*/
-void set_field_ptr(Field **ptr, const byte *new_buf, const byte *old_buf);
-void set_key_field_ptr(KEY *key_info, const byte *new_buf,
- const byte *old_buf);
+void set_field_ptr(Field **ptr, const uchar *new_buf, const uchar *old_buf);
+void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
+ const uchar *old_buf);
bool mysql_backup_table(THD* thd, TABLE_LIST* table_list);
bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
@@ -891,6 +925,8 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
+bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
@@ -926,27 +962,26 @@ int prepare_create_field(create_field *sql_field,
longlong table_flags);
bool mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
- List<create_field> &fields, List<Key> &keys,
- bool tmp_table, uint select_field_count,
- bool use_copy_create_info);
+ Alter_info *alter_info,
+ bool tmp_table, uint select_field_count);
+bool mysql_create_table_no_lock(THD *thd, const char *db,
+ const char *table_name,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ bool tmp_table, uint select_field_count);
bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
- List<create_field> &fields,
- List<Key> &keys,
- uint order_num, ORDER *order, bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok);
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
+ Alter_info *alter_info,
+ uint order_num, ORDER *order, bool ignore);
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
- HA_CREATE_INFO *create_info,
- Table_ident *src_table);
+ TABLE_LIST *src_table,
+ HA_CREATE_INFO *create_info);
bool mysql_rename_table(handlerton *base, const char *old_db,
const char * old_name, const char *new_db,
const char * new_name, uint flags);
-bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
-bool mysql_drop_index(THD *thd, TABLE_LIST *table_list,
- ALTER_INFO *alter_info);
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
Item **conds, uint order_num, ORDER *order);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
@@ -962,13 +997,15 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields,
List<Item> &update_values, enum_duplicates duplic,
- COND **where, bool select_insert);
+ COND **where, bool select_insert,
+ bool check_fields, bool abort_on_warning);
bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
bool ignore);
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list);
+void prepare_triggers_for_insert_stmt(TABLE *table);
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SQL_LIST *order, ha_rows rows, ulonglong options,
@@ -984,10 +1021,17 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
bool *refresh, uint flags);
-bool reopen_name_locked_table(THD* thd, TABLE_LIST* table);
+bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in);
+TABLE *table_cache_insert_placeholder(THD *thd, const char *key,
+ uint key_length);
+bool lock_table_name_if_not_cached(THD *thd, const char *db,
+ const char *table_name, TABLE **table);
TABLE *find_locked_table(THD *thd, const char *db,const char *table_name);
+bool reopen_table(TABLE *table);
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh);
-bool close_data_tables(THD *thd,const char *db, const char *table_name);
+void close_data_files_and_morph_locks(THD *thd, const char *db,
+ const char *table_name);
+void close_handle_and_leave_table_as_lock(TABLE *table);
bool wait_for_tables(THD *thd);
bool table_is_used(TABLE *table, bool wait_for_name_lock);
TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name);
@@ -1074,9 +1118,10 @@ int add_status_vars(SHOW_VAR *list);
void remove_status_vars(SHOW_VAR *list);
void init_status_vars();
void free_status_vars();
+void reset_status_vars();
/* information schema */
-extern LEX_STRING information_schema_name;
+extern LEX_STRING INFORMATION_SCHEMA_NAME;
extern const LEX_STRING partition_keywords[];
LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
const char* str, uint length,
@@ -1092,9 +1137,12 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
-bool get_schema_tables_result(JOIN *join);
+bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place);
+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
+
#define is_schema_db(X) \
- !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
+ !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X))
/* sql_prepare.cc */
@@ -1125,7 +1173,7 @@ void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table);
/* sql_base.cc */
#define TMP_TABLE_KEY_EXTRA 8
void set_item_name(Item *item,char *pos,uint length);
-bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
+bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types type,
char *length, char *decimal,
uint type_modifier,
Item *default_value, Item *on_update_value,
@@ -1146,9 +1194,12 @@ bool push_new_name_resolution_context(THD *thd,
TABLE_LIST *left_op,
TABLE_LIST *right_op);
void add_join_on(TABLE_LIST *b,Item *expr);
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields);
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
+ SELECT_LEX *lex);
bool add_proc_to_list(THD *thd, Item *item);
-TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
+void unlink_open_table(THD *thd, TABLE *find, bool unlock);
+void drop_open_table(THD *thd, TABLE *table, const char *db_name,
+ const char *table_name);
void update_non_unique_table_error(TABLE_LIST *update,
const char *operation,
TABLE_LIST *duplicate);
@@ -1157,9 +1208,29 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond, int *error);
extern Item **not_found_item;
+
+/*
+ This enumeration type is used only by the function find_item_in_list
+ to return the info on how an item has been resolved against a list
+ of possibly aliased items.
+ The item can be resolved:
+ - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS)
+ - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS)
+ - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS)
+ - ignoring the alias name in cases when SQL requires to ignore aliases
+ (e.g. when the resolved field reference contains a table name or
+ when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS)
+*/
+enum enum_resolution_type {
+ NOT_RESOLVED=0,
+ RESOLVED_IGNORING_ALIAS,
+ RESOLVED_BEHIND_ALIAS,
+ RESOLVED_WITH_NO_ALIAS,
+ RESOLVED_AGAINST_ALIAS
+};
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
- bool *unaliased);
+ enum_resolution_type *resolution);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd, Name_resolution_context *context,
@@ -1217,7 +1288,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
st_table_list *TABLE_LIST::*link,
const char *db_name,
const char *table_name);
-TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias);
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
bool close_temporary_table(THD *thd, TABLE_LIST *table_list);
@@ -1233,14 +1305,13 @@ char *make_default_log_name(char *buff,const char* log_ext);
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition_table(THD *thd, TABLE *table,
- ALTER_INFO *alter_info,
+ Alter_info *alter_info,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
- List<create_field> *create_list,
- List<Key> *key_list, char *db,
+ char *db,
const char *table_name,
uint fast_alter_partition);
-uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
+uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
handlerton *old_db_type,
bool *partition_changed,
@@ -1272,20 +1343,16 @@ typedef struct st_lock_param_type
ulonglong deleted;
THD *thd;
HA_CREATE_INFO *create_info;
- ALTER_INFO *alter_info;
- List<create_field> *create_list;
- List<create_field> new_create_list;
- List<Key> *key_list;
- List<Key> new_key_list;
+ Alter_info *alter_info;
TABLE *table;
KEY *key_info_buffer;
const char *db;
const char *table_name;
- const void *pack_frm_data;
+ uchar *pack_frm_data;
enum thr_lock_type old_lock_type;
uint key_count;
uint db_options;
- uint pack_frm_len;
+ size_t pack_frm_len;
partition_info *part_info;
} ALTER_PARTITION_PARAM_TYPE;
@@ -1377,7 +1444,16 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
+/* Functions to work with system tables. */
+bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
+ Open_tables_state *backup);
+void close_system_tables(THD *thd, Open_tables_state *backup);
+TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
+
bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE);
+bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
+ LEX_STRING *connect_string,
+ bool have_lock = FALSE);
void copy_field_from_tmp_record(Field *field,int offset);
bool fill_record(THD *thd, Field **field, List<Item> &values,
bool ignore_errors);
@@ -1439,16 +1515,16 @@ void print_plan(JOIN* join,uint idx, double record_count, double read_time,
#endif
void mysql_print_status();
/* key.cc */
-int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
- uint *key_length);
-void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
-void key_restore(byte *to_record, byte *from_key, KEY *key_info,
+int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
+ uint *key_length, uint *keypart);
+void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, uint key_length);
+void key_restore(uchar *to_record, uchar *from_key, KEY *key_info,
uint key_length);
-bool key_cmp_if_same(TABLE *form,const byte *key,uint index,uint key_length);
+bool key_cmp_if_same(TABLE *form,const uchar *key,uint index,uint key_length);
void key_unpack(String *to,TABLE *form,uint index);
bool is_key_used(TABLE *table, uint idx, const MY_BITMAP *fields);
-int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length);
-int key_rec_cmp(void *key_info, byte *a, byte *b);
+int key_cmp(KEY_PART_INFO *key_part, const uchar *key, uint key_length);
+int key_rec_cmp(void *key_info, uchar *a, uchar *b);
bool init_errmessage(void);
#endif /* MYSQL_SERVER */
@@ -1473,7 +1549,7 @@ bool slow_log_print(THD *thd, const char *query, uint query_length,
bool general_log_print(THD *thd, enum enum_server_command command,
const char *format,...);
-bool fn_format_relative_to_data_home(my_string to, const char *name,
+bool fn_format_relative_to_data_home(char * to, const char *name,
const char *dir, const char *extension);
#ifdef MYSQL_SERVER
File open_binlog(IO_CACHE *log, const char *log_file_name,
@@ -1482,6 +1558,12 @@ File open_binlog(IO_CACHE *log, const char *log_file_name,
/* mysqld.cc */
extern void MYSQLerror(const char*);
void refresh_status(THD *thd);
+my_bool mysql_rm_tmp_tables(void);
+void handle_connection_in_main_thread(THD *thd);
+void create_thread_to_handle_connection(THD *thd);
+void unlink_thd(THD *thd);
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+void flush_thread_cache();
/* item_func.cc */
extern bool check_reserved_words(LEX_STRING *name);
@@ -1489,8 +1571,10 @@ extern bool check_reserved_words(LEX_STRING *name);
/* strfunc.cc */
ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
char **err_pos, uint *err_len, bool *set_warning);
-uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
-uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs);
+uint find_type(const TYPELIB *lib, const char *find, uint length,
+ bool part_match);
+uint find_type2(const TYPELIB *lib, const char *find, uint length,
+ CHARSET_INFO *cs);
void unhex_type2(TYPELIB *lib);
uint check_word(TYPELIB *lib, const char *val, const char *end,
const char **end_of_word);
@@ -1516,7 +1600,7 @@ extern int creating_table; // How many mysql_create_table() are running
External variables
*/
-extern time_t start_time;
+extern time_t server_start_time;
extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[],
def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
@@ -1526,7 +1610,7 @@ extern const LEX_STRING command_name[];
extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
-extern const char *in_left_expr_name, *in_additional_cond;
+extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
extern const char * const triggers_file_ext;
extern const char * const trigname_file_ext;
extern Eq_creator eq_creator;
@@ -1541,10 +1625,11 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
extern double log_10[32];
+extern double log_01[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
extern ulonglong thd_startup_options;
-extern ulong refresh_version,flush_version, thread_id;
+extern ulong thread_id;
extern ulong binlog_cache_use, binlog_cache_disk_use;
extern ulong aborted_threads,aborted_connects;
extern ulong delayed_insert_timeout;
@@ -1564,7 +1649,7 @@ extern ulong max_prepared_stmt_count, prepared_stmt_count;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size;
-extern ulong rpl_recovery_rank, thread_cache_size;
+extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
extern ulong back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
@@ -1584,7 +1669,7 @@ extern ulong log_output_options;
extern my_bool opt_log_queries_not_using_indexes;
extern bool opt_disable_networking, opt_skip_show_db;
extern my_bool opt_character_set_client_handshake;
-extern bool volatile abort_loop, shutdown_in_progress, grant_option;
+extern bool volatile abort_loop, shutdown_in_progress;
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, opt_myisam_use_mmap;
@@ -1592,6 +1677,7 @@ extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_readonly, lower_case_file_system;
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
extern my_bool opt_secure_auth;
+extern char* opt_secure_file_priv;
extern my_bool opt_log_slow_admin_statements;
extern my_bool sp_automatic_privileges, opt_noacl;
extern my_bool opt_old_style_user_limits, trust_function_creators;
@@ -1626,6 +1712,7 @@ extern pthread_mutex_t LOCK_server_started;
extern pthread_cond_t COND_server_started;
extern int mysqld_server_started;
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
+extern rw_lock_t LOCK_system_variables_hash;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_cond_t COND_global_read_lock;
extern pthread_attr_t connection_attrib;
@@ -1634,7 +1721,7 @@ extern I_List<NAMED_LIST> key_caches;
extern MY_BITMAP temp_pool;
extern String my_empty_string;
extern const String my_null_string;
-extern SHOW_VAR init_vars[], status_vars[], internal_vars[];
+extern SHOW_VAR status_vars[];
extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables;
extern struct system_status_var global_status_var;
@@ -1649,21 +1736,19 @@ extern TABLE *unused_tables;
extern const char* any_db;
extern struct my_option my_long_options[];
extern const LEX_STRING view_type;
+extern scheduler_functions thread_scheduler;
+extern TYPELIB thread_handling_typelib;
+extern uint8 uc_update_queries[SQLCOM_END+1];
extern uint sql_command_flags[];
extern TYPELIB log_output_typelib;
/* optional things, have_* variables */
-extern SHOW_COMP_OPTION have_innodb;
-extern SHOW_COMP_OPTION have_csv_db;
-extern SHOW_COMP_OPTION have_ndbcluster;
-extern SHOW_COMP_OPTION have_partition_db;
-
extern handlerton *partition_hton;
extern handlerton *myisam_hton;
extern handlerton *heap_hton;
-extern SHOW_COMP_OPTION have_openssl, have_symlink, have_dlopen;
+extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
extern SHOW_COMP_OPTION have_query_cache;
extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
extern SHOW_COMP_OPTION have_crypt;
@@ -1683,7 +1768,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
-#define MYSQL_OPEN_IGNORE_LOCKED_TABLES 0x0008
+#define MYSQL_OPEN_TEMPORARY_ONLY 0x0008
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
@@ -1731,8 +1816,8 @@ int rea_create_table(THD *thd, const char *path,
List<create_field> &create_field,
uint key_count,KEY *key_info,
handler *file);
-int format_number(uint inputflag,uint max_length,my_string pos,uint length,
- my_string *errpos);
+int format_number(uint inputflag,uint max_length,char * pos,uint length,
+ char * *errpos);
/* table.cc */
TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
@@ -1745,29 +1830,30 @@ void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg);
int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag, uint ha_open_flags,
TABLE *outparam, bool is_create_table);
-int readfrm(const char *name, const void** data, uint* length);
-int writefrm(const char* name, const void* data, uint len);
+int readfrm(const char *name, uchar **data, size_t *length);
+int writefrm(const char* name, const uchar* data, size_t len);
int closefrm(TABLE *table, bool free_share);
-int read_string(File file, gptr *to, uint length);
+int read_string(File file, uchar* *to, size_t length);
void free_blobs(TABLE *table);
int set_zone(int nr,int min_zone,int max_zone);
ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
-my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *not_exist);
-bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
+my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
+bool str_to_time_with_warn(const char *str,uint length,MYSQL_TIME *l_time);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
- TIME *l_time, uint flags);
-void localtime_to_TIME(TIME *to, struct tm *from);
-void calc_time_from_sec(TIME *to, long seconds, long microseconds);
+ MYSQL_TIME *l_time, uint flags);
+void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
+void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
-void make_truncated_value_warning(THD *thd, const char *str_val,
+void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ const char *str_val,
uint str_length, timestamp_type time_type,
const char *field_name);
-bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval);
-bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
+bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval);
+bool calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign,
longlong *seconds_out, long *microseconds_out);
extern LEX_STRING interval_type_to_name[];
@@ -1779,18 +1865,20 @@ extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
DATE_TIME_FORMAT *format);
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
timestamp_type type);
-extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
+extern bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
timestamp_type type, String *str);
-void make_datetime(const DATE_TIME_FORMAT *format, const TIME *l_time,
+void make_datetime(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
-void make_date(const DATE_TIME_FORMAT *format, const TIME *l_time,
+void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
-void make_time(const DATE_TIME_FORMAT *format, const TIME *l_time,
+void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
-int my_time_compare(TIME *a, TIME *b);
+int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
+ulonglong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
int test_if_number(char *str,int *res,bool allow_wildcards);
-void change_byte(byte *,uint,char,char);
+void change_byte(uchar *,uint,char,char);
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select,
int use_record_cache, bool print_errors);
@@ -1802,14 +1890,15 @@ ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
ha_rows max_rows, bool sort_positions,
ha_rows *examined_rows);
void filesort_free_buffers(TABLE *table, bool full);
-void change_double_for_sort(double nr,byte *to);
-double my_double_round(double value, int dec, bool truncate);
+void change_double_for_sort(double nr,uchar *to);
+double my_double_round(double value, longlong dec, bool dec_unsigned,
+ bool truncate);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
-uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
+uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
void find_date(char *pos,uint *vek,uint flag);
-TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
+TYPELIB *convert_strings_to_array_type(char * *typelibs, char * *end);
TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings);
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
@@ -1844,7 +1933,7 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db,
/* from hostname.cc */
struct in_addr;
-my_string ip_to_hostname(struct in_addr *in,uint *errors);
+char * ip_to_hostname(struct in_addr *in,uint *errors);
void inc_host_errors(struct in_addr *in);
void reset_host_errors(struct in_addr *in);
bool hostname_cache_init();
@@ -1958,7 +2047,6 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->const_table= 0;
table->null_row= 0;
table->status= STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->s->keys_in_use;
table->maybe_null= table_list->outer_join;
TABLE_LIST *embedding= table_list->embedding;
while (!table->maybe_null && embedding)
@@ -1969,6 +2057,8 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
+ table->covering_keys= table->s->keys_for_keyread;
+ table->merge_keys.clear_all();
}
@@ -2007,7 +2097,7 @@ inline bool is_user_table(TABLE * table)
#ifndef EMBEDDED_LIBRARY
extern "C" void unireg_abort(int exit_code) __attribute__((noreturn));
void kill_delayed_threads(void);
-bool check_stack_overrun(THD *thd, long margin, char *dummy);
+bool check_stack_overrun(THD *thd, long margin, uchar *dummy);
#else
#define unireg_abort(exit_code) DBUG_RETURN(exit_code)
inline void kill_delayed_threads(void) {}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 7bf6035020f..9ab5e29996c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,6 +17,7 @@
#include <m_ctype.h>
#include <my_dir.h>
#include "slave.h"
+#include "rpl_mi.h"
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
@@ -30,22 +30,17 @@
#include "rpl_injector.h"
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
-#define OPT_INNODB_DEFAULT 1
-#else
-#define OPT_INNODB_DEFAULT 0
-#endif
-#define OPT_BDB_DEFAULT 0
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
-#define OPT_NDBCLUSTER_DEFAULT 0
#if defined(NOT_ENOUGH_TESTED) \
&& defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000
#define OPT_NDB_SHM_DEFAULT 1
#else
#define OPT_NDB_SHM_DEFAULT 0
#endif
-#else
-#define OPT_NDBCLUSTER_DEFAULT 0
+#endif
+
+#ifndef DEFAULT_SKIP_THREAD_PRIORITY
+#define DEFAULT_SKIP_THREAD_PRIORITY 0
#endif
#include <thr_alarm.h>
@@ -56,10 +51,6 @@
#define mysqld_charset &my_charset_latin1
-#ifndef DBUG_OFF
-#define ONE_THREAD
-#endif
-
#ifdef HAVE_purify
#define IF_PURIFY(A,B) (A)
#else
@@ -196,12 +187,6 @@ inline void reset_floating_point_exceptions()
} /* cplusplus */
-
-#if defined(HAVE_LINUXTHREADS)
-#define THR_KILL_SIGNAL SIGINT
-#else
-#define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads
-#endif
#define MYSQL_KILL_SIGNAL SIGTERM
#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
@@ -231,8 +216,10 @@ static const char *sql_mode_names[]=
"ERROR_FOR_DIVISION_BY_ZERO",
"TRADITIONAL", "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE",
"NO_ENGINE_SUBSTITUTION",
+ "PAD_CHAR_TO_FULL_LENGTH",
NullS
};
+
static const unsigned int sql_mode_names_len[]=
{
/*REAL_AS_FLOAT*/ 13,
@@ -265,8 +252,10 @@ static const unsigned int sql_mode_names_len[]=
/*TRADITIONAL*/ 11,
/*NO_AUTO_CREATE_USER*/ 19,
/*HIGH_NOT_PRECEDENCE*/ 19,
- /*NO_ENGINE_SUBSTITUTION*/ 22
+ /*NO_ENGINE_SUBSTITUTION*/ 22,
+ /*PAD_CHAR_TO_FULL_LENGTH*/ 23
};
+
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
sql_mode_names,
(unsigned int *)sql_mode_names_len };
@@ -279,6 +268,20 @@ static TYPELIB tc_heuristic_recover_typelib=
array_elements(tc_heuristic_recover_names)-1,"",
tc_heuristic_recover_names, NULL
};
+
+static const char *thread_handling_names[]=
+{ "one-thread-per-connection", "no-threads",
+#if HAVE_POOL_OF_THREADS == 1
+ "pool-of-threads",
+#endif
+ NullS};
+
+TYPELIB thread_handling_typelib=
+{
+ array_elements(thread_handling_names) - 1, "",
+ thread_handling_names, NULL
+};
+
const char *first_keyword= "first", *binary_keyword= "BINARY";
const char *my_localhost= "localhost", *delayed_user= "DELAYED";
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
@@ -314,7 +317,6 @@ static bool lower_case_table_names_used= 0;
static bool volatile select_thread_in_use, signal_thread_in_use;
static bool volatile ready_to_exit;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
-static my_bool opt_ndbcluster;
static my_bool opt_short_log_format= 0;
static uint kill_cached_threads, wake_thread;
static ulong killed_threads, thread_created;
@@ -326,6 +328,7 @@ static char *mysqld_user, *mysqld_chroot, *log_error_file_ptr;
static char *opt_init_slave, *language_ptr, *opt_init_connect;
static char *default_character_set_name;
static char *character_set_filesystem_name;
+static char *lc_time_names_name;
static char *my_bind_addr_str;
static char *default_collation_name;
static char *default_storage_engine_str;
@@ -348,7 +351,15 @@ bool opt_endinfo, using_udf_functions;
my_bool locked_in_memory;
bool opt_using_transactions, using_update_log;
bool volatile abort_loop;
-bool volatile shutdown_in_progress, grant_option;
+bool volatile shutdown_in_progress;
+/**
+ @brief 'grant_option' is used to indicate if privileges needs
+ to be checked, in which case the lock, LOCK_grant, is used
+ to protect access to the grant table.
+ @note This flag is dropped in 5.1
+ @see grant_init()
+ */
+bool volatile grant_option;
my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted
my_bool opt_reckless_slave = 0;
@@ -357,7 +368,7 @@ my_bool opt_local_infile, opt_slave_compressed_protocol;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
-my_bool opt_innodb;
+bool slave_warning_issued = false;
/*
Legacy global handlerton. These will be removed (please do not add more).
@@ -366,47 +377,10 @@ handlerton *heap_hton;
handlerton *myisam_hton;
handlerton *partition_hton;
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
-extern ulong innobase_fast_shutdown;
-extern ulong innobase_large_page_size;
-extern char *innobase_home, *innobase_tmpdir, *innobase_logdir;
-extern long innobase_lock_scan_time;
-extern long innobase_mirrored_log_groups, innobase_log_files_in_group;
-extern longlong innobase_log_file_size;
-extern long innobase_log_buffer_size;
-extern longlong innobase_buffer_pool_size;
-extern long innobase_additional_mem_pool_size;
-extern long innobase_file_io_threads, innobase_lock_wait_timeout;
-extern long innobase_force_recovery;
-extern long innobase_open_files;
-extern char *innobase_data_home_dir, *innobase_data_file_path;
-extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
-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_doublewrite,
- innobase_use_checksums,
- innobase_use_large_pages,
- innobase_use_native_aio,
- innobase_file_per_table, innobase_locks_unsafe_for_binlog,
- innobase_create_status_file;
-extern "C" {
-extern ulong srv_max_buf_pool_modified_pct;
-extern ulong srv_max_purge_lag;
-extern ulong srv_auto_extend_increment;
-extern ulong srv_n_spin_wait_rounds;
-extern ulong srv_n_free_tickets_to_enter;
-extern ulong srv_thread_sleep_delay;
-extern ulong srv_thread_concurrency;
-extern ulong srv_commit_concurrency;
-extern ulong srv_flush_log_at_trx_commit;
-}
-#endif
-
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
const char *opt_ndbcluster_connectstring= 0;
const char *opt_ndb_connectstring= 0;
-char opt_ndb_constrbuf[1024];
+char opt_ndb_constrbuf[1024]= {0};
unsigned opt_ndb_constrbuf_len= 0;
my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
ulong opt_ndb_cache_check_time;
@@ -426,6 +400,7 @@ extern enum ndb_distribution opt_ndb_distribution_id;
my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
+char* opt_secure_file_priv= 0;
my_bool opt_log_slow_admin_statements= 0;
my_bool lower_case_file_system= 0;
my_bool opt_large_pages= 0;
@@ -442,11 +417,12 @@ my_bool opt_noacl;
my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
-const char *binlog_format_names[]= {"STATEMENT", "ROW", "MIXED", NullS};
+const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
TYPELIB binlog_format_typelib=
- { array_elements(binlog_format_names)-1,"",
+ { array_elements(binlog_format_names) - 1, "",
binlog_format_names, NULL };
-
+ulong opt_binlog_format_id= (ulong) BINLOG_FORMAT_UNSPEC;
+const char *opt_binlog_format= binlog_format_names[opt_binlog_format_id];
#ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */
#endif
@@ -463,10 +439,11 @@ ulong thread_stack, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout, slave_trans_retries;
-ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong thread_cache_size=0, thread_pool_size= 0;
+ulong binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
-ulong refresh_version, flush_version; /* Increments on each reload */
-query_id_t query_id;
+ulong refresh_version; /* Increments on each reload */
+query_id_t global_query_id;
ulong 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;
@@ -498,7 +475,8 @@ ulong rpl_recovery_rank=0;
const char *log_output_str= "TABLE";
double log_10[32]; /* 10 potences */
-time_t start_time;
+double log_01[32];
+time_t server_start_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
char *default_tz_name;
@@ -514,16 +492,18 @@ key_map key_map_full(0); // Will be initialized later
const char *opt_date_time_formats[3];
char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
-struct passwd *user_info;
char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *myisam_stats_method_str="nulls_unequal";
+
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
+const char *in_having_cond= "<IN HAVING>";
+
my_decimal decimal_zero;
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
@@ -533,7 +513,6 @@ Lt_creator lt_creator;
Ge_creator ge_creator;
Le_creator le_creator;
-
FILE *bootstrap_file;
int bootstrap_error;
FILE *stderror_file=0;
@@ -554,7 +533,9 @@ CHARSET_INFO *system_charset_info, *files_charset_info ;
CHARSET_INFO *national_charset_info, *table_alias_charset;
CHARSET_INFO *character_set_filesystem;
-SHOW_COMP_OPTION have_openssl, have_symlink, have_dlopen, have_query_cache;
+MY_LOCALE *my_default_lc_time_names;
+
+SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen, have_query_cache;
SHOW_COMP_OPTION have_geometry, have_rtree_keys;
SHOW_COMP_OPTION have_crypt, have_compress;
@@ -581,6 +562,7 @@ pthread_mutex_t LOCK_prepared_stmt_count;
pthread_mutex_t LOCK_des_key_file;
#endif
rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
+rw_lock_t LOCK_system_variables_hash;
pthread_cond_t COND_refresh, COND_thread_count, COND_global_read_lock;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
@@ -612,13 +594,19 @@ static ulong opt_specialflag, opt_myisam_block_size;
static char *opt_update_logname, *opt_binlog_index_name;
static char *opt_tc_heuristic_recover;
static char *mysql_home_ptr, *pidfile_name_ptr;
+static int defaults_argc;
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()
+#ifndef EMBEDDED_LIBRARY
+struct passwd *user_info;
+static pthread_t select_thread;
+static uint thr_kill_signal;
+#endif
+
/* OS specific variables */
#ifdef __WIN__
@@ -671,6 +659,8 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
+scheduler_functions thread_scheduler;
+
#define SSL_VARS_NOT_STATIC
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
@@ -695,10 +685,10 @@ struct st_VioSSLFd *ssl_acceptor_fd;
/* Function declarations */
-static void start_signal_handler(void);
pthread_handler_t signal_hand(void *arg);
static void mysql_init_variables(void);
-static void get_options(int argc,char **argv);
+static void get_options(int *argc,char **argv);
+static my_bool get_one_option(int, const struct my_option *, char *);
static void set_server_version(void);
static int init_thread_environment();
static char *get_relative_path(const char *path);
@@ -706,7 +696,6 @@ static void fix_paths(void);
pthread_handler_t handle_connections_sockets(void *arg);
pthread_handler_t kill_server_thread(void *arg);
static void bootstrap(FILE *file);
-static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
pthread_handler_t handle_connections_namedpipes(void *arg);
@@ -716,12 +705,21 @@ pthread_handler_t handle_connections_shared_memory(void *arg);
#endif
pthread_handler_t handle_slave(void *arg);
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
+static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
+ const char *option);
static void clean_up(bool print_message);
+static int test_if_case_insensitive(const char *dir_name);
+
+#ifndef EMBEDDED_LIBRARY
+static void usage(void);
+static void start_signal_handler(void);
+static void close_server_sock();
static void clean_up_mutexes(void);
static void wait_for_signal_thread_to_end(void);
-static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file();
static void end_ssl();
+#endif
+
#ifndef EMBEDDED_LIBRARY
/****************************************************************************
@@ -761,7 +759,6 @@ static void close_connections(void)
DBUG_PRINT("info",("Waiting for select thread"));
#ifndef DONT_USE_THR_ALARM
- if (pthread_kill(select_thread,THR_CLIENT_ALARM))
break; // allready dead
#endif
set_timespec(abstime, 2);
@@ -847,6 +844,7 @@ static void close_connections(void)
continue;
tmp->killed= THD::KILL_CONNECTION;
+ thread_scheduler.post_kill_notification(tmp);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -862,7 +860,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
- Events::get_instance()->deinit();
+ Events::deinit();
end_slave();
if (thread_count)
@@ -911,7 +909,6 @@ static void close_connections(void)
DBUG_PRINT("quit",("close_connections thread"));
DBUG_VOID_RETURN;
}
-#endif /*EMBEDDED_LIBRARY*/
static void close_server_sock()
@@ -954,12 +951,14 @@ static void close_server_sock()
#endif
}
+#endif /*EMBEDDED_LIBRARY*/
+
void kill_mysql(void)
{
DBUG_ENTER("kill_mysql");
-#ifdef SIGNALS_DONT_BREAK_READ
+#if defined(SIGNALS_DONT_BREAK_READ) && !defined(EMBEDDED_LIBRARY)
abort_loop=1; // Break connection loops
close_server_sock(); // Force accept to wake up
#endif
@@ -1037,7 +1036,7 @@ static void __cdecl kill_server(int sig_ptr)
kill_in_progress=TRUE;
abort_loop=1; // This should be set
if (sig != 0) // 0 is not a valid signal number
- my_sigset(sig,SIG_IGN);
+ my_sigset(sig, SIG_IGN); /* purify inspected */
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
@@ -1138,6 +1137,8 @@ extern "C" void unireg_abort(int exit_code)
DBUG_ENTER("unireg_abort");
if (exit_code)
sql_print_error("Aborting\n");
+ else if (opt_help)
+ usage();
clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
wait_for_signal_thread_to_end();
@@ -1171,6 +1172,7 @@ void clean_up(bool print_message)
my_tz_free();
my_database_names_free();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ servers_free(1);
acl_free(1);
grant_free();
#endif
@@ -1194,7 +1196,7 @@ void clean_up(bool print_message)
if (tc_log)
tc_log->close();
xid_cache_free();
- delete_elements(&key_caches, (void (*)(const char*, gptr)) free_key_cache);
+ delete_elements(&key_caches, (void (*)(const char*, uchar*)) free_key_cache);
multi_keycache_free();
free_status_vars();
end_thr_alarm(1); /* Free allocated memory */
@@ -1217,6 +1219,7 @@ void clean_up(bool print_message)
#endif
x_free(opt_bin_logname);
x_free(opt_relay_logname);
+ x_free(opt_secure_file_priv);
bitmap_free(&temp_pool);
free_max_user_conn();
#ifdef HAVE_REPLICATION
@@ -1224,7 +1227,9 @@ void clean_up(bool print_message)
#endif
delete binlog_filter;
delete rpl_filter;
+#ifndef EMBEDDED_LIBRARY
end_ssl();
+#endif
vio_end();
#ifdef USE_REGEX
my_regex_end();
@@ -1236,8 +1241,9 @@ void clean_up(bool print_message)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
#endif
+ thread_scheduler.end();
finish_client_errs();
- my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
+ my_free((uchar*) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
@@ -1257,6 +1263,8 @@ void clean_up(bool print_message)
} /* clean_up */
+#ifndef EMBEDDED_LIBRARY
+
/*
This is mainly needed when running with purify, but it's still nice to
know that all child threads have died when mysqld exits
@@ -1299,7 +1307,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
- Events::get_instance()->destroy_mutexes();
+ Events::destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@@ -1316,6 +1324,7 @@ static void clean_up_mutexes()
(void) rwlock_destroy(&LOCK_sys_init_connect);
(void) rwlock_destroy(&LOCK_sys_init_slave);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
+ (void) rwlock_destroy(&LOCK_system_variables_hash);
(void) pthread_mutex_destroy(&LOCK_global_read_lock);
(void) pthread_mutex_destroy(&LOCK_uuid_generator);
(void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
@@ -1327,10 +1336,14 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_manager);
}
+#endif /*EMBEDDED_LIBRARY*/
+
+
/****************************************************************************
** Init IP and UNIX socket
****************************************************************************/
+#ifndef EMBEDDED_LIBRARY
static void set_ports()
{
char *env;
@@ -1355,13 +1368,12 @@ static void set_ports()
}
}
-#ifndef EMBEDDED_LIBRARY
/* Change to run as another user if started with --user */
static struct passwd *check_user(const char *user)
{
#if !defined(__WIN__) && !defined(__NETWARE__)
- struct passwd *user_info;
+ struct passwd *tmp_user_info;
uid_t user_id= geteuid();
// Don't bother if we aren't superuser
@@ -1369,12 +1381,14 @@ static struct passwd *check_user(const char *user)
{
if (user)
{
- // Don't give a warning, if real user is same as given with --user
- user_info= getpwnam(user);
- if ((!user_info || user_id != user_info->pw_uid) &&
+ /* Don't give a warning, if real user is same as given with --user */
+ /* purecov: begin tested */
+ tmp_user_info= getpwnam(user);
+ if ((!tmp_user_info || user_id != tmp_user_info->pw_uid) &&
global_system_variables.log_warnings)
sql_print_warning(
"One can only use the --user switch if running as root\n");
+ /* purecov: end */
}
return NULL;
}
@@ -1387,23 +1401,22 @@ static struct passwd *check_user(const char *user)
}
return NULL;
}
+ /* purecov: begin tested */
if (!strcmp(user,"root"))
return NULL; // Avoid problem with dynamic libraries
- if (!(user_info= getpwnam(user)))
+ if (!(tmp_user_info= getpwnam(user)))
{
// Allow a numeric uid to be used
const char *pos;
for (pos= user; my_isdigit(mysqld_charset,*pos); pos++) ;
if (*pos) // Not numeric id
goto err;
- if (!(user_info= getpwuid(atoi(user))))
+ if (!(tmp_user_info= getpwuid(atoi(user))))
goto err;
- else
- return user_info;
}
- else
- return user_info;
+ return tmp_user_info;
+ /* purecov: end */
err:
sql_print_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
@@ -1412,10 +1425,11 @@ err:
return NULL;
}
-static void set_user(const char *user, struct passwd *user_info)
+static void set_user(const char *user, struct passwd *user_info_arg)
{
+ /* purecov: begin tested */
#if !defined(__WIN__) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info != 0);
+ DBUG_ASSERT(user_info_arg != 0);
#ifdef HAVE_INITGROUPS
/*
We can get a SIGSEGV when calling initgroups() on some systems when NSS
@@ -1424,33 +1438,34 @@ static void set_user(const char *user, struct passwd *user_info)
output a specific message to help the user resolve this problem.
*/
calling_initgroups= TRUE;
- initgroups((char*) user, user_info->pw_gid);
+ initgroups((char*) user, user_info_arg->pw_gid);
calling_initgroups= FALSE;
#endif
- if (setgid(user_info->pw_gid) == -1)
+ if (setgid(user_info_arg->pw_gid) == -1)
{
sql_perror("setgid");
unireg_abort(1);
}
- if (setuid(user_info->pw_uid) == -1)
+ if (setuid(user_info_arg->pw_uid) == -1)
{
sql_perror("setuid");
unireg_abort(1);
}
#endif
+ /* purecov: end */
}
-static void set_effective_user(struct passwd *user_info)
+static void set_effective_user(struct passwd *user_info_arg)
{
#if !defined(__WIN__) && !defined(__NETWARE__)
- DBUG_ASSERT(user_info != 0);
- if (setregid((gid_t)-1, user_info->pw_gid) == -1)
+ DBUG_ASSERT(user_info_arg != 0);
+ if (setregid((gid_t)-1, user_info_arg->pw_gid) == -1)
{
sql_perror("setregid");
unireg_abort(1);
}
- if (setreuid((uid_t)-1, user_info->pw_uid) == -1)
+ if (setreuid((uid_t)-1, user_info_arg->pw_uid) == -1)
{
sql_perror("setreuid");
unireg_abort(1);
@@ -1487,6 +1502,9 @@ static void network_init(void)
DBUG_ENTER("network_init");
LINT_INIT(ret);
+ if (thread_scheduler.init())
+ unireg_abort(1); /* purecov: inspected */
+
set_ports();
if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
@@ -1644,18 +1662,6 @@ static void network_init(void)
#endif /*!EMBEDDED_LIBRARY*/
-void MYSQLerror(const char *s)
-{
- THD *thd=current_thd;
- char *yytext= (char*) thd->lex->tok_start;
- /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
- if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
- s=ER(ER_SYNTAX_ERROR);
- my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
- (yytext ? (char*) yytext : ""),
- thd->lex->yylineno);
-}
-
#ifndef EMBEDDED_LIBRARY
/*
@@ -1705,21 +1711,55 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
if (thd && ! thd->bootstrap)
{
statistic_increment(killed_threads, &LOCK_status);
- end_thread(thd,0);
+ thread_scheduler.end_thread(thd,0); /* purecov: inspected */
}
DBUG_VOID_RETURN; /* purecov: deadcode */
}
-void end_thread(THD *thd, bool put_in_cache)
+/*
+ Unlink thd from global list of available connections and free thd
+
+ SYNOPSIS
+ unlink_thd()
+ thd Thread handler
+
+ NOTES
+ LOCK_thread_count is locked and left locked
+*/
+
+void unlink_thd(THD *thd)
{
- DBUG_ENTER("end_thread");
+ DBUG_ENTER("unlink_thd");
+ DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
thd->cleanup();
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
delete thd;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Store thread in cache for reuse by new connections
+
+ SYNOPSIS
+ cache_thread()
- if (put_in_cache && cached_thread_count < thread_cache_size &&
+ NOTES
+ LOCK_thread_count has to be locked
+
+ RETURN
+ 0 Thread was not put in cache
+ 1 Thread is to be reused by new connection.
+ (ie, caller should return, not abort with pthread_exit())
+*/
+
+
+static bool cache_thread()
+{
+ safe_mutex_assert_owner(&LOCK_thread_count);
+ if (cached_thread_count < thread_cache_size &&
! abort_loop && !kill_cached_threads)
{
/* Don't kill the thread, just put it in cache for reuse */
@@ -1732,31 +1772,62 @@ void end_thread(THD *thd, bool put_in_cache)
pthread_cond_signal(&COND_flush_thread_cache);
if (wake_thread)
{
+ THD *thd;
wake_thread--;
- thd=thread_cache.get();
- thd->real_id=pthread_self();
+ thd= thread_cache.get();
thd->thread_stack= (char*) &thd; // For store_globals
(void) thd->store_globals();
+ /*
+ THD::mysys_var::abort is associated with physical thread rather
+ than with THD object. So we need to reset this flag before using
+ this thread for handling of new THD object/connection.
+ */
+ thd->mysys_var->abort= 0;
thd->thr_create_time= time(NULL);
threads.append(thd);
- pthread_mutex_unlock(&LOCK_thread_count);
- DBUG_VOID_RETURN;
+ return(1);
}
}
+ return(0);
+}
+
+
+/*
+ End thread for the current connection
+
+ SYNOPSIS
+ one_thread_per_connection_end()
+ thd Thread handler
+ put_in_cache Store thread in cache, if there is room in it
+ Normally this is true in all cases except when we got
+ out of resources initializing the current thread
+
+ NOTES
+ If thread is cached, we will wait until thread is scheduled to be
+ reused and then we will return.
+ If thread is not cached, we end the thread.
+
+ RETURN
+ 0 Signal to handle_one_connection to reuse connection
+*/
+
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
+{
+ DBUG_ENTER("one_thread_per_connection_end");
+ unlink_thd(thd);
+ if (put_in_cache)
+ put_in_cache= cache_thread();
+ pthread_mutex_unlock(&LOCK_thread_count);
+ if (put_in_cache)
+ DBUG_RETURN(0); // Thread is reused
- /* Tell main we are ready */
- (void) pthread_mutex_unlock(&LOCK_thread_count);
/* It's safe to broadcast outside a lock (COND... is not deleted here) */
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
(void) pthread_cond_broadcast(&COND_thread_count);
-#ifdef ONE_THREAD
- if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux
-#endif
- {
- my_thread_end();
- pthread_exit(0);
- }
- DBUG_VOID_RETURN;
+
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(0); // Impossible
}
@@ -1791,6 +1862,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
}
#endif
+
/******************************************************************************
Setup a signal thread with handles all signals.
Because Linux doesn't support schemas use a mutex to check that
@@ -1810,6 +1882,7 @@ static void init_signals(void)
#endif
}
+
static void start_signal_handler(void)
{
// Save vm id of this process
@@ -1817,6 +1890,7 @@ static void start_signal_handler(void)
create_pid_file();
}
+
static void check_data_home(const char *path)
{}
@@ -2037,6 +2111,7 @@ static void init_signals(void)
}
+
static void start_signal_handler(void)
{
// Save vm id of this process
@@ -2065,7 +2140,10 @@ static void check_data_home(const char *path)
extern "C" sig_handler handle_segfault(int sig)
{
+ time_t curr_time;
+ struct tm tm;
THD *thd=current_thd;
+
/*
Strictly speaking, one needs a mutex here
but since we have got SIGSEGV already, things are a mess
@@ -2079,11 +2157,17 @@ extern "C" sig_handler handle_segfault(int sig)
}
segfaulted = 1;
+
+ curr_time= time(NULL);
+ localtime_r(&curr_time, &tm);
+
fprintf(stderr,"\
-mysqld got signal %d;\n\
+%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
+ tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
sig);
fprintf(stderr, "\
We will try our best to scrape up some info that will hopefully help diagnose\n\
@@ -2093,14 +2177,15 @@ and this may fail.\n\n");
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
- fprintf(stderr, "max_connections=%lu\n", max_connections);
+ fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
fprintf(stderr, "threads_connected=%u\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
-key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\
+key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
- max_connections)/ 1024);
+ thread_scheduler.max_threads +
+ max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
@@ -2119,7 +2204,7 @@ the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n",
if (!(test_flags & TEST_NO_STACKTRACE))
{
fprintf(stderr,"thd: 0x%lx\n",(long) thd);
- print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
+ print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0,
thread_stack);
}
if (thd)
@@ -2173,6 +2258,8 @@ bugs.\n");
#define SA_NODEFER 0
#endif
+#ifndef EMBEDDED_LIBRARY
+
static void init_signals(void)
{
sigset_t set;
@@ -2180,7 +2267,9 @@ static void init_signals(void)
DBUG_ENTER("init_signals");
if (test_flags & TEST_SIGINT)
- my_sigset(THR_KILL_SIGNAL,end_thread_signal);
+ {
+ my_sigset(thr_kill_signal, end_thread_signal);
+ }
my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
@@ -2235,17 +2324,19 @@ static void init_signals(void)
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
+ if (thd_lib_detected != THD_LIB_LT)
sigaddset(&set,THR_SERVER_ALARM);
if (test_flags & TEST_SIGINT)
- sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
- sigdelset(&set,THR_CLIENT_ALARM); // For alarms
+ {
+ // May be SIGINT
+ sigdelset(&set, thr_kill_signal);
+ }
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_sigmask(SIG_SETMASK,&set,NULL);
DBUG_VOID_RETURN;
}
-#ifndef EMBEDDED_LIBRARY
static void start_signal_handler(void)
{
int error;
@@ -2300,26 +2391,22 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
This should actually be '+ max_number_of_slaves' instead of +10,
but the +10 should be quite safe.
*/
- init_thr_alarm(max_connections +
+ init_thr_alarm(thread_scheduler.max_threads +
global_system_variables.max_insert_delayed_threads + 10);
-#if SIGINT != THR_KILL_SIGNAL
- if (test_flags & TEST_SIGINT)
+ if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
{
(void) sigemptyset(&set); // Setup up SIGINT for debug
(void) sigaddset(&set,SIGINT); // For debugging
(void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
}
-#endif
(void) sigemptyset(&set); // Setup up SIGINT for debug
#ifdef USE_ONE_SIGNAL_HAND
(void) sigaddset(&set,THR_SERVER_ALARM); // For alarms
#endif
#ifndef IGNORE_SIGHUP_SIGQUIT
(void) sigaddset(&set,SIGQUIT);
-#if THR_CLIENT_ALARM != SIGHUP
(void) sigaddset(&set,SIGHUP);
#endif
-#endif
(void) sigaddset(&set,SIGTERM);
(void) sigaddset(&set,SIGTSTP);
@@ -2419,11 +2506,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
}
return(0); /* purecov: deadcode */
}
-#endif /*!EMBEDDED_LIBRARY*/
static void check_data_home(const char *path)
{}
+#endif /*!EMBEDDED_LIBRARY*/
#endif /* __WIN__*/
@@ -2446,6 +2533,14 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
*/
if ((thd= current_thd))
{
+ /*
+ TODO: There are two exceptions mechanism (THD and sp_rcontext),
+ this could be improved by having a common stack of handlers.
+ */
+ if (thd->handle_error(error,
+ MYSQL_ERROR::WARN_LEVEL_ERROR))
+ DBUG_RETURN(0);
+
if (thd->spcont &&
thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{
@@ -2488,6 +2583,7 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
}
+#ifndef EMBEDDED_LIBRARY
static void *my_str_malloc_mysqld(size_t size)
{
return my_malloc(size, MYF(MY_FAE));
@@ -2496,24 +2592,13 @@ static void *my_str_malloc_mysqld(size_t size)
static void my_str_free_mysqld(void *ptr)
{
- my_free((gptr)ptr, MYF(MY_FAE));
+ my_free((uchar*)ptr, MYF(MY_FAE));
}
+#endif /* EMBEDDED_LIBRARY */
#ifdef __WIN__
-struct utsname
-{
- char nodename[FN_REFLEN];
-};
-
-
-int uname(struct utsname *a)
-{
- return -1;
-}
-
-
pthread_handler_t handle_shutdown(void *arg)
{
MSG msg;
@@ -2541,16 +2626,18 @@ int STDCALL handle_kill(ulong ctrl_type)
}
#endif
+#if !defined(EMBEDDED_LIBRARY)
static const char *load_default_groups[]= {
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
"mysql_cluster",
#endif
"mysqld","server", MYSQL_BASE_VERSION, 0, 0};
-#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
+#if defined(__WIN__)
static const int load_default_groups_sz=
sizeof(load_default_groups)/sizeof(load_default_groups[0]);
#endif
+#endif /*!EMBEDDED_LIBRARY*/
/*
@@ -2598,13 +2685,21 @@ static bool init_global_datetime_format(timestamp_type format_type,
static int init_common_variables(const char *conf_file_name, int argc,
char **argv, const char **groups)
{
- char buff[FN_REFLEN];
+ char buff[FN_REFLEN], *s;
umask(((~my_umask) & 0666));
my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
max_system_variables.pseudo_thread_id= (ulong)~0;
- start_time=time((time_t*) 0);
+ server_start_time= time((time_t*) 0);
+ rpl_filter= new Rpl_filter;
+ binlog_filter= new Rpl_filter;
+ if (!rpl_filter || !binlog_filter)
+ {
+ sql_perror("Could not allocate replication and binlog filters");
+ exit(1);
+ }
+
if (init_thread_environment())
return 1;
mysql_init_variables();
@@ -2612,7 +2707,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
#ifdef HAVE_TZNAME
{
struct tm tm_tmp;
- localtime_r(&start_time,&tm_tmp);
+ localtime_r(&server_start_time,&tm_tmp);
strmake(system_time_zone, tzname[tm_tmp.tm_isdst != 0 ? 1 : 0],
sizeof(system_time_zone)-1);
@@ -2634,8 +2729,14 @@ static int init_common_variables(const char *conf_file_name, int argc,
*/
mysql_bin_log.init_pthread_objects();
- if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
- strmov(glob_hostname,"mysql");
+ if (gethostname(glob_hostname,sizeof(glob_hostname)) < 0)
+ {
+ strmake(glob_hostname, STRING_WITH_LEN("localhost"));
+ sql_print_warning("gethostname failed, using '%s' as hostname",
+ glob_hostname);
+ strmake(pidfile_name, STRING_WITH_LEN("mysql"));
+ }
+ else
strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5);
strmov(fn_ext(pidfile_name),".pid"); // Add proper extension
@@ -2650,7 +2751,8 @@ static int init_common_variables(const char *conf_file_name, int argc,
load_defaults(conf_file_name, groups, &argc, &argv);
defaults_argv=argv;
- get_options(argc,argv);
+ defaults_argc=argc;
+ get_options(&defaults_argc, defaults_argv);
set_server_version();
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
@@ -2662,10 +2764,6 @@ static int init_common_variables(const char *conf_file_name, int argc,
{
my_use_large_pages= 1;
my_large_page_size= opt_large_page_size;
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- innobase_use_large_pages= 1;
- innobase_large_page_size= opt_large_page_size;
-#endif
}
#endif /* HAVE_LARGE_PAGES */
@@ -2728,15 +2826,43 @@ static int init_common_variables(const char *conf_file_name, int argc,
if (item_create_init())
return 1;
item_init();
- set_var_init();
+ if (set_var_init())
+ return 1;
+#ifdef HAVE_REPLICATION
+ if (init_replication_sys_vars())
+ return 1;
+#endif
mysys_uses_curses=0;
#ifdef USE_REGEX
my_regex_init(&my_charset_latin1);
#endif
- if (!(default_charset_info= get_charset_by_csname(default_character_set_name,
- MY_CS_PRIMARY,
- MYF(MY_WME))))
- return 1;
+ /*
+ Process a comma-separated character set list and choose
+ the first available character set. This is mostly for
+ test purposes, to be able to start "mysqld" even if
+ the requested character set is not available (see bug#18743).
+ */
+ for (;;)
+ {
+ char *next_character_set_name= strchr(default_character_set_name, ',');
+ if (next_character_set_name)
+ *next_character_set_name++= '\0';
+ if (!(default_charset_info=
+ get_charset_by_csname(default_character_set_name,
+ MY_CS_PRIMARY, MYF(MY_WME))))
+ {
+ if (next_character_set_name)
+ {
+ default_character_set_name= next_character_set_name;
+ default_collation_name= 0; // Ignore collation
+ }
+ else
+ return 1; // Eof of the list
+ }
+ else
+ break;
+ }
+
if (default_collation_name)
{
CHARSET_INFO *default_collation;
@@ -2769,6 +2895,14 @@ static int init_common_variables(const char *conf_file_name, int argc,
return 1;
global_system_variables.character_set_filesystem= character_set_filesystem;
+ if (!(my_default_lc_time_names=
+ my_locale_by_name(lc_time_names_name)))
+ {
+ sql_print_error("Unknown locale: '%s'", lc_time_names_name);
+ return 1;
+ }
+ global_system_variables.lc_time_names= my_default_lc_time_names;
+
sys_init_connect.value_length= 0;
if ((sys_init_connect.value= opt_init_connect))
sys_init_connect.value_length= strlen(opt_init_connect);
@@ -2794,15 +2928,13 @@ static int init_common_variables(const char *conf_file_name, int argc,
"--log-slow-queries option, log tables are used. "
"To enable logging to files use the --log-output option.");
- if (!opt_logname)
- opt_logname= make_default_log_name(buff, ".log");
- sys_var_general_log_path.value= my_strdup(opt_logname, MYF(0));
- sys_var_general_log_path.value_length= strlen(opt_logname);
+ s= opt_logname ? opt_logname : make_default_log_name(buff, ".log");
+ sys_var_general_log_path.value= my_strdup(s, MYF(0));
+ sys_var_general_log_path.value_length= strlen(s);
- if (!opt_slow_logname)
- opt_slow_logname= make_default_log_name(buff, "-slow.log");
- sys_var_slow_log_path.value= my_strdup(opt_slow_logname, MYF(0));
- sys_var_slow_log_path.value_length= strlen(opt_slow_logname);
+ s= opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
+ sys_var_slow_log_path.value= my_strdup(s, MYF(0));
+ sys_var_slow_log_path.value_length= strlen(s);
if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
@@ -2881,6 +3013,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ (void) my_rwlock_init(&LOCK_system_variables_hash, NULL);
(void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
@@ -2914,7 +3047,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
- Events::get_instance()->init_mutexes();
+ Events::init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@@ -3002,6 +3135,8 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
#endif /* HAVE_OPENSSL */
+#ifndef EMBEDDED_LIBRARY
+
static void init_ssl()
{
#ifdef HAVE_OPENSSL
@@ -3014,13 +3149,14 @@ static void init_ssl()
DBUG_PRINT("info",("ssl_acceptor_fd: 0x%lx", (long) ssl_acceptor_fd));
if (!ssl_acceptor_fd)
{
+ sql_print_warning("Failed to setup SSL");
opt_use_ssl = 0;
- have_openssl= SHOW_OPTION_DISABLED;
+ have_ssl= SHOW_OPTION_DISABLED;
}
}
else
{
- have_openssl= SHOW_OPTION_DISABLED;
+ have_ssl= SHOW_OPTION_DISABLED;
}
if (des_key_file)
load_des_key_file(des_key_file);
@@ -3039,6 +3175,8 @@ static void end_ssl()
#endif /* HAVE_OPENSSL */
}
+#endif /* EMBEDDED_LIBRARY */
+
static int init_server_components()
{
@@ -3054,7 +3192,7 @@ static int init_server_components()
query_cache_set_min_res_unit(query_cache_min_res_unit);
query_cache_init();
query_cache_resize(query_cache_size);
- randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
+ randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
#ifdef HAVE_REPLICATION
@@ -3063,11 +3201,15 @@ static int init_server_components()
/* Setup logs */
- /* enable old-fashioned error log */
- if (opt_error_log)
+ /*
+ Enable old-fashioned error log, except when the user has requested
+ help information. Since the implementation of plugin server
+ variables the help output is now written much later.
+ */
+ if (opt_error_log && !opt_help)
{
if (!log_error_file_ptr[0])
- fn_format(log_error_file, glob_hostname, mysql_data_home, ".err",
+ fn_format(log_error_file, pidfile_name, mysql_data_home, ".err",
MY_REPLACE_EXT); /* replace '.<domain>' by '.err', bug#4997 */
else
fn_format(log_error_file, log_error_file_ptr, mysql_data_home, ".err",
@@ -3148,16 +3290,23 @@ with --log-bin instead.");
"--log-slave-updates work.");
unireg_abort(1);
}
-
- if (!opt_bin_log && (global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC))
+ if (!opt_bin_log)
+ if (opt_binlog_format_id != BINLOG_FORMAT_UNSPEC)
{
sql_print_error("You need to use --log-bin to make "
"--binlog-format work.");
unireg_abort(1);
}
- if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC)
+ else
{
global_system_variables.binlog_format= BINLOG_FORMAT_MIXED;
+ }
+ else
+ if (opt_binlog_format_id == BINLOG_FORMAT_UNSPEC)
+ global_system_variables.binlog_format= BINLOG_FORMAT_MIXED;
+ else
+ {
+ DBUG_ASSERT(global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC);
}
/* Check that we have not let the format to unspecified at this point */
@@ -3212,12 +3361,51 @@ server.");
using_update_log=1;
}
- if (plugin_init(opt_bootstrap))
+ if (plugin_init(&defaults_argc, defaults_argv,
+ (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
+ (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0)))
{
- sql_print_error("Failed to init plugins.");
- return 1;
+ sql_print_error("Failed to initialize plugins.");
+ unireg_abort(1);
+ }
+
+ if (opt_help)
+ unireg_abort(0);
+
+ /* we do want to exit if there are any other unknown options */
+ if (defaults_argc > 1)
+ {
+ int ho_error;
+ char **tmp_argv= defaults_argv;
+ struct my_option no_opts[]=
+ {
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+ };
+ /*
+ We need to eat any 'loose' arguments first before we conclude
+ that there are unprocessed options.
+ But we need to preserve defaults_argv pointer intact for
+ free_defaults() to work. Thus we use a copy here.
+ */
+ my_getopt_skip_unknown= 0;
+
+ if ((ho_error= handle_options(&defaults_argc, &tmp_argv, no_opts,
+ get_one_option)))
+ unireg_abort(ho_error);
+
+ if (defaults_argc)
+ {
+ fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n"
+ "Use --verbose --help to get a list of available options\n",
+ my_progname, *tmp_argv);
+ unireg_abort(1);
+ }
}
+ /* if the errmsg.sys is not loaded, terminate to maintain behaviour */
+ if (!errmesg[0][0])
+ unireg_abort(1);
+
/* We have to initialize the storage engines before CSV logging */
if (ha_init())
{
@@ -3246,7 +3434,8 @@ server.");
else
{
/* fall back to the log files if tables are not present */
- if (have_csv_db == SHOW_OPTION_NO)
+ LEX_STRING csv_name={C_STRING_WITH_LEN("csv")};
+ if (!plugin_is_ready(&csv_name, MYSQL_STORAGE_ENGINE_PLUGIN))
{
/* purecov: begin inspected */
sql_print_error("CSV engine is not present, falling back to the "
@@ -3266,11 +3455,16 @@ server.");
/*
Check that the default storage engine is actually available.
*/
+ if (default_storage_engine_str)
{
LEX_STRING name= { default_storage_engine_str,
strlen(default_storage_engine_str) };
- handlerton *hton= ha_resolve_by_name(0, &name);
- if (hton == NULL)
+ plugin_ref plugin;
+ handlerton *hton;
+
+ if ((plugin= ha_resolve_by_name(0, &name)))
+ hton= plugin_data(plugin, handlerton*);
+ else
{
sql_print_error("Unknown/unsupported table type: %s",
default_storage_engine_str);
@@ -3284,9 +3478,17 @@ server.");
default_storage_engine_str);
unireg_abort(1);
}
- hton= myisam_hton;
+ DBUG_ASSERT(global_system_variables.table_plugin);
+ }
+ else
+ {
+ /*
+ Need to unlock as global_system_variables.table_plugin
+ was acquired during plugin_init()
+ */
+ plugin_unlock(0, global_system_variables.table_plugin);
+ global_system_variables.table_plugin= plugin;
}
- global_system_variables.table_type= hton;
}
tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
@@ -3294,7 +3496,7 @@ server.");
(TC_LOG *) &tc_log_mmap) :
(TC_LOG *) &tc_log_dummy);
- if (tc_log->open(opt_bin_logname))
+ if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
unireg_abort(1);
@@ -3312,7 +3514,7 @@ server.");
#ifdef HAVE_REPLICATION
if (opt_bin_log && expire_logs_days)
{
- long purge_time= time(0) - expire_logs_days*24*60*60;
+ time_t purge_time= time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
mysql_bin_log.purge_logs_before_date(purge_time);
}
@@ -3357,6 +3559,8 @@ server.");
}
+#ifndef EMBEDDED_LIBRARY
+
static void create_maintenance_thread()
{
if (flush_time && flush_time != ~(ulong) 0L)
@@ -3370,7 +3574,6 @@ static void create_maintenance_thread()
static void create_shutdown_thread()
{
-#if !defined(EMBEDDED_LIBRARY)
#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
pthread_t hThread;
@@ -3379,10 +3582,11 @@ static void create_shutdown_thread()
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
-#endif
-#endif // EMBEDDED_LIBRARY
+#endif /* __WIN__ */
}
+#endif /* EMBEDDED_LIBRARY */
+
#if (defined(__NT__) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
static void handle_connections_methods()
@@ -3447,8 +3651,9 @@ void decrement_handler_count()
{
pthread_mutex_lock(&LOCK_thread_count);
handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
pthread_cond_signal(&COND_handler_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ my_thread_end();
}
#else
#define decrement_handler_count()
@@ -3462,15 +3667,15 @@ int win_main(int argc, char **argv)
int main(int argc, char **argv)
#endif
{
- rpl_filter= new Rpl_filter;
- binlog_filter= new Rpl_filter;
- if (!rpl_filter || !binlog_filter)
- {
- sql_perror("Could not allocate replication and binlog filters");
- exit(1);
- }
-
MY_INIT(argv[0]); // init my_sys library & pthreads
+ /* nothing should come before this line ^^^ */
+
+ /* Set signal used to kill MySQL */
+#if defined(SIGUSR2)
+ thr_kill_signal= thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2;
+#else
+ thr_kill_signal= SIGINT;
+#endif
/*
Perform basic logger initialization logger. Should be called after
@@ -3560,7 +3765,7 @@ int main(int argc, char **argv)
We have enough space for fiddling with the argv, continue
*/
check_data_home(mysql_real_data_home);
- if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
+ if (my_setwd(mysql_real_data_home,MYF(MY_WME)) && !opt_help)
unireg_abort(1); /* purecov: inspected */
mysql_data_home= mysql_data_home_buff;
mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
@@ -3608,6 +3813,11 @@ we force server id to 2, but this MySQL server will not act as a slave.");
freopen(log_error_file,"a+",stderr);
FreeConsole(); // Remove window
}
+ else
+ {
+ /* Don't show error dialog box when on foreground: it stops the server */
+ SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ }
#endif
/*
@@ -3623,7 +3833,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
error_handler_hook= my_message_sql;
start_signal_handler(); // Creates pidfile
- if (acl_init(opt_noacl) ||
+ if (mysql_rm_tmp_tables() || acl_init(opt_noacl) ||
my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
{
abort_loop=1;
@@ -3642,12 +3852,16 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
(void) grant_init();
+ if (!opt_bootstrap)
+ servers_init(0);
+
if (!opt_noacl)
{
#ifdef HAVE_DLOPEN
udf_init();
#endif
}
+
init_status_vars();
if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
opt_skip_slave_start= 1;
@@ -3683,21 +3897,22 @@ we force server id to 2, but this MySQL server will not act as a slave.");
create_shutdown_thread();
create_maintenance_thread();
+ if (Events::init(opt_noacl))
+ unireg_abort(1);
+
sql_print_information(ER(ER_STARTUP),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) ""
: mysqld_unix_port),
mysqld_port,
MYSQL_COMPILATION_COMMENT);
- // Signal threads waiting for server to be started
+
+ /* Signal threads waiting for server to be started */
+ pthread_mutex_lock(&LOCK_server_started);
mysqld_server_started= 1;
pthread_cond_signal(&COND_server_started);
+ pthread_mutex_unlock(&LOCK_server_started);
- if (!opt_noacl)
- {
- if (Events::get_instance()->init())
- unireg_abort(1);
- }
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
#else
@@ -3963,7 +4178,7 @@ static void bootstrap(FILE *file)
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
thd->security_ctx->master_access= ~(ulong)0;
- thd->thread_id=thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thread_count++;
bootstrap_file=file;
@@ -4006,6 +4221,74 @@ static bool read_init_file(char *file_name)
#ifndef EMBEDDED_LIBRARY
+
+/*
+ Simple scheduler that use the main thread to handle the request
+
+ NOTES
+ This is only used for debugging, when starting mysqld with
+ --thread-handling=no-threads or --one-thread
+
+ When we enter this function, LOCK_thread_count is hold!
+*/
+
+void handle_connection_in_main_thread(THD *thd)
+{
+ safe_mutex_assert_owner(&LOCK_thread_count);
+ thread_cache_size=0; // Safety
+ threads.append(thd);
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ handle_one_connection((void*) thd);
+}
+
+
+/*
+ Scheduler that uses one thread per connection
+*/
+
+void create_thread_to_handle_connection(THD *thd)
+{
+ if (cached_thread_count > wake_thread)
+ {
+ /* Get thread from cache */
+ thread_cache.append(thd);
+ wake_thread++;
+ pthread_cond_signal(&COND_thread_cache);
+ }
+ else
+ {
+ /* Create new thread to handle connection */
+ int error;
+ thread_created++;
+ threads.append(thd);
+ DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
+ thd->connect_time = time(NULL);
+ if ((error=pthread_create(&thd->real_id,&connection_attrib,
+ handle_one_connection,
+ (void*) thd)))
+ {
+ /* purify: begin inspected */
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %d)",
+ error));
+ thread_count--;
+ thd->killed= THD::KILL_CONNECTION; // Safety
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ statistic_increment(aborted_connects,&LOCK_status);
+ net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
+ (void) pthread_mutex_lock(&LOCK_thread_count);
+ close_connection(thd,0,0);
+ delete thd;
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ return;
+ /* purecov: end */
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info",("Thread created"));
+}
+
+
/*
Create new thread to handle incoming connection.
@@ -4027,10 +4310,9 @@ static bool read_init_file(char *file_name)
static void create_new_thread(THD *thd)
{
+ NET *net=&thd->net;
DBUG_ENTER("create_new_thread");
- NET *net=&thd->net; // For easy ref
- net->read_timeout = (uint) connect_timeout;
if (protocol_version > 9)
net->return_errno=1;
@@ -4043,64 +4325,15 @@ static void create_new_thread(THD *thd)
DBUG_VOID_RETURN;
}
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id=thread_id++;
-
- thd->real_id=pthread_self(); // Keep purify happy
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
/* Start a new thread to handle connection */
thread_count++;
-#ifdef ONE_THREAD
- if (test_flags & TEST_NO_THREADS) // For debugging under Linux
- {
- thread_cache_size=0; // Safety
- threads.append(thd);
- thd->real_id=pthread_self();
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- handle_one_connection((void*) thd);
- }
- else
-#endif
- {
- if (thread_count-delayed_insert_threads > max_used_connections)
- max_used_connections=thread_count-delayed_insert_threads;
-
- if (cached_thread_count > wake_thread)
- {
- thread_cache.append(thd);
- wake_thread++;
- pthread_cond_signal(&COND_thread_cache);
- }
- else
- {
- int error;
- thread_created++;
- threads.append(thd);
- DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
- thd->connect_time = time(NULL);
- if ((error=pthread_create(&thd->real_id,&connection_attrib,
- handle_one_connection,
- (void*) thd)))
- {
- DBUG_PRINT("error",
- ("Can't create thread to handle request (error %d)",
- error));
- thread_count--;
- thd->killed= THD::KILL_CONNECTION; // Safety
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- statistic_increment(aborted_connects,&LOCK_status);
- net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
- (void) pthread_mutex_lock(&LOCK_thread_count);
- close_connection(thd,0,0);
- delete thd;
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- DBUG_VOID_RETURN;
- }
- }
- (void) pthread_mutex_unlock(&LOCK_thread_count);
+ if (thread_count - delayed_insert_threads > max_used_connections)
+ max_used_connections= thread_count - delayed_insert_threads;
- }
- DBUG_PRINT("info",("Thread created"));
+ thread_scheduler.add_connection(thd);
DBUG_VOID_RETURN;
}
#endif /* EMBEDDED_LIBRARY */
@@ -4324,12 +4557,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
}
if (sock == unix_sock)
thd->security_ctx->host=(char*) my_localhost;
-#ifdef __WIN__
- /* Set default wait_timeout */
- ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
- (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout,
- sizeof(wait_timeout));
-#endif
+
create_new_thread(thd);
}
@@ -4676,11 +4904,6 @@ enum options_mysqld
OPT_STORAGE_ENGINE, OPT_INIT_FILE,
OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
- OPT_BDB_HOME, OPT_BDB_LOG,
- OPT_BDB_TMP, OPT_BDB_SYNC,
- OPT_BDB_LOCK, OPT_BDB,
- OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
- OPT_BDB_DATA_DIRECT, OPT_BDB_LOG_DIRECT,
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
@@ -4699,29 +4922,15 @@ enum options_mysqld
OPT_WANT_CORE, OPT_CONCURRENT_INSERT,
OPT_MEMLOCK, OPT_MYISAM_RECOVER,
OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
- OPT_SKIP_SLAVE_START, OPT_SKIP_INNOBASE,
+ OPT_SKIP_SLAVE_START, OPT_SAFE_SHOW_DB,
OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
OPT_ABORT_SLAVE_EVENT_COUNT,
- OPT_INNODB_DATA_HOME_DIR,
- OPT_INNODB_DATA_FILE_PATH,
- OPT_INNODB_LOG_GROUP_HOME_DIR,
- OPT_INNODB_LOG_ARCH_DIR,
- OPT_INNODB_LOG_ARCHIVE,
- OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
- OPT_INNODB_FLUSH_METHOD,
- OPT_INNODB_DOUBLEWRITE,
- OPT_INNODB_CHECKSUMS,
- OPT_INNODB_FAST_SHUTDOWN,
- OPT_INNODB_FILE_PER_TABLE, OPT_CRASH_BINLOG_INNODB,
- OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
- OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG,
- OPT_INNODB, OPT_ISAM,
- OPT_ENGINE_CONDITION_PUSHDOWN,
- OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT,
+ OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDB_CONNECTSTRING,
+ OPT_NDB_USE_EXACT_COUNT, OPT_NDB_USE_TRANSACTIONS,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
OPT_NDB_MGMD, OPT_NDB_NODEID,
@@ -4783,33 +4992,6 @@ enum options_mysqld
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
OPT_WAIT_TIMEOUT, OPT_MYISAM_REPAIR_THREADS,
- OPT_INNODB_MIRRORED_LOG_GROUPS,
- OPT_INNODB_LOG_FILES_IN_GROUP,
- OPT_INNODB_LOG_FILE_SIZE,
- OPT_INNODB_LOG_BUFFER_SIZE,
- OPT_INNODB_BUFFER_POOL_SIZE,
- OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
- OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
- OPT_INNODB_MAX_PURGE_LAG,
- OPT_INNODB_FILE_IO_THREADS,
- OPT_INNODB_LOCK_WAIT_TIMEOUT,
- OPT_INNODB_THREAD_CONCURRENCY,
- OPT_INNODB_COMMIT_CONCURRENCY,
- OPT_INNODB_FORCE_RECOVERY,
- OPT_INNODB_STATUS_FILE,
- OPT_INNODB_MAX_DIRTY_PAGES_PCT,
- OPT_INNODB_TABLE_LOCKS,
- OPT_INNODB_SUPPORT_XA,
- OPT_INNODB_OPEN_FILES,
- OPT_INNODB_AUTOEXTEND_INCREMENT,
- OPT_INNODB_SYNC_SPIN_LOOPS,
- OPT_INNODB_CONCURRENCY_TICKETS,
- OPT_INNODB_THREAD_SLEEP_DELAY,
- OPT_BDB_CACHE_SIZE,
- OPT_BDB_CACHE_PARTS,
- OPT_BDB_LOG_BUFFER_SIZE,
- OPT_BDB_MAX_LOCK,
- OPT_BDB_REGION_SIZE,
OPT_ERROR_LOG_FILE,
OPT_DEFAULT_WEEK_FORMAT,
OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
@@ -4819,7 +5001,6 @@ enum options_mysqld
OPT_SYNC_REPLICATION,
OPT_SYNC_REPLICATION_SLAVE_ID,
OPT_SYNC_REPLICATION_TIMEOUT,
- OPT_BDB_NOSYNC,
OPT_ENABLE_SHARED_MEMORY,
OPT_SHARED_MEMORY_BASE_NAME,
OPT_OLD_PASSWORDS,
@@ -4829,6 +5010,7 @@ enum options_mysqld
OPT_DEFAULT_COLLATION,
OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
OPT_CHARACTER_SET_FILESYSTEM,
+ OPT_LC_TIME_NAMES,
OPT_INIT_CONNECT,
OPT_INIT_SLAVE,
OPT_SECURE_AUTH,
@@ -4849,12 +5031,16 @@ enum options_mysqld
OPT_OLD_STYLE_USER_LIMITS,
OPT_LOG_SLOW_ADMIN_STATEMENTS,
OPT_TABLE_LOCK_WAIT_TIMEOUT,
+ OPT_PLUGIN_LOAD,
OPT_PLUGIN_DIR,
OPT_LOG_OUTPUT,
OPT_PORT_OPEN_TIMEOUT,
OPT_GENERAL_LOG,
OPT_SLOW_LOG,
- OPT_MERGE
+ OPT_THREAD_HANDLING,
+ OPT_INNODB_ROLLBACK_ON_TIMEOUT,
+ OPT_SECURE_FILE_PRIV,
+ OPT_OLD_MODE
};
@@ -4863,12 +5049,12 @@ enum options_mysqld
struct my_option my_long_options[] =
{
{"help", '?', "Display this help and exit.",
- (gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ (uchar**) &opt_help, (uchar**) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
#ifdef HAVE_REPLICATION
{"abort-slave-event-count", OPT_ABORT_SLAVE_EVENT_COUNT,
"Option used by mysql-test for debugging and testing of replication.",
- (gptr*) &abort_slave_event_count, (gptr*) &abort_slave_event_count,
+ (uchar**) &abort_slave_event_count, (uchar**) &abort_slave_event_count,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
{"allow-suspicious-udfs", OPT_ALLOW_SUSPICIOUS_UDFS,
@@ -4876,35 +5062,36 @@ struct my_option my_long_options[] =
"without corresponding xxx_init() or xxx_deinit(). That also means "
"that one can load any function from any library, for example exit() "
"from libc.so",
- (gptr*) &opt_allow_suspicious_udfs, (gptr*) &opt_allow_suspicious_udfs,
+ (uchar**) &opt_allow_suspicious_udfs, (uchar**) &opt_allow_suspicious_udfs,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set transaction isolation level 'serializable'.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"auto-increment-increment", OPT_AUTO_INCREMENT,
"Auto-increment columns are incremented by this",
- (gptr*) &global_system_variables.auto_increment_increment,
- (gptr*) &max_system_variables.auto_increment_increment, 0, GET_ULONG,
+ (uchar**) &global_system_variables.auto_increment_increment,
+ (uchar**) &max_system_variables.auto_increment_increment, 0, GET_ULONG,
OPT_ARG, 1, 1, 65535, 0, 1, 0 },
{"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET,
"Offset added to Auto-increment columns. Used when auto-increment-increment != 1",
- (gptr*) &global_system_variables.auto_increment_offset,
- (gptr*) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG,
+ (uchar**) &global_system_variables.auto_increment_offset,
+ (uchar**) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG,
1, 1, 65535, 0, 1, 0 },
{"automatic-sp-privileges", OPT_SP_AUTOMATIC_PRIVILEGES,
"Creating and dropping stored procedures alters ACLs. Disable with --skip-automatic-sp-privileges.",
- (gptr*) &sp_automatic_privileges, (gptr*) &sp_automatic_privileges,
+ (uchar**) &sp_automatic_privileges, (uchar**) &sp_automatic_privileges,
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"basedir", 'b',
"Path to installation directory. All paths are usually resolved relative to this.",
- (gptr*) &mysql_home_ptr, (gptr*) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &mysql_home_ptr, (uchar**) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"big-tables", OPT_BIG_TABLES,
"Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.",
- (gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR,
+ (uchar**) &my_bind_addr_str, (uchar**) &my_bind_addr_str, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog_format", OPT_BINLOG_FORMAT,
+ "Does not have any effect without '--log-bin'. "
"Tell the master the form of binary logging to use: either 'row' for "
"row-based binary logging, or 'statement' for statement-based binary "
"logging, or 'mixed'. 'mixed' is statement-based binary logging except "
@@ -4912,11 +5099,11 @@ struct my_option my_long_options[] =
"involve user-defined functions (i.e. UDFs) or the UUID() function; for "
"those, row-based binary logging is automatically used. "
#ifdef HAVE_NDB_BINLOG
- "If ndbcluster is enabled, the default is 'row'."
+ "If ndbcluster is enabled and binlog_format is `mixed', the format switches"
+ " to 'row' and back implicitly per each query accessing a NDB table."
#endif
- , 0, 0, 0, GET_STR, REQUIRED_ARG,
- BINLOG_FORMAT_MIXED
- , 0, 0, 0, 0, 0 },
+ ,(uchar**) &opt_binlog_format, (uchar**) &opt_binlog_format,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-do-db", OPT_BINLOG_DO_DB,
"Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4927,72 +5114,74 @@ struct my_option my_long_options[] =
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"The value has to be a multiple of 256.",
- (gptr*) &opt_binlog_rows_event_max_size,
- (gptr*) &opt_binlog_rows_event_max_size, 0,
+ (uchar**) &opt_binlog_rows_event_max_size,
+ (uchar**) &opt_binlog_rows_event_max_size, 0,
GET_ULONG, REQUIRED_ARG,
/* def_value */ 1024, /* min_value */ 256, /* max_value */ ULONG_MAX,
/* sub_size */ 0, /* block_size */ 256,
/* app_type */ 0
},
+#ifndef DISABLE_GRANT_OPTIONS
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
"Don't ignore client side character set value sent during handshake.",
- (gptr*) &opt_character_set_client_handshake,
- (gptr*) &opt_character_set_client_handshake,
+ (uchar**) &opt_character_set_client_handshake,
+ (uchar**) &opt_character_set_client_handshake,
0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"character-set-filesystem", OPT_CHARACTER_SET_FILESYSTEM,
"Set the filesystem character set.",
- (gptr*) &character_set_filesystem_name,
- (gptr*) &character_set_filesystem_name,
+ (uchar**) &character_set_filesystem_name,
+ (uchar**) &character_set_filesystem_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"character-set-server", 'C', "Set the default character set.",
- (gptr*) &default_character_set_name, (gptr*) &default_character_set_name,
+ (uchar**) &default_character_set_name, (uchar**) &default_character_set_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"character-sets-dir", OPT_CHARSETS_DIR,
- "Directory where character sets are.", (gptr*) &charsets_dir,
- (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "Directory where character sets are.", (uchar**) &charsets_dir,
+ (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"chroot", 'r', "Chroot mysqld daemon during startup.",
- (gptr*) &mysqld_chroot, (gptr*) &mysqld_chroot, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &mysqld_chroot, (uchar**) &mysqld_chroot, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.",
- (gptr*) &default_collation_name, (gptr*) &default_collation_name,
+ (uchar**) &default_collation_name, (uchar**) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"completion-type", OPT_COMPLETION_TYPE, "Default completion type.",
- (gptr*) &global_system_variables.completion_type,
- (gptr*) &max_system_variables.completion_type, 0, GET_ULONG,
+ (uchar**) &global_system_variables.completion_type,
+ (uchar**) &max_system_variables.completion_type, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 2, 0, 1, 0},
{"concurrent-insert", OPT_CONCURRENT_INSERT,
"Use concurrent insert with MyISAM. Disable with --concurrent-insert=0",
- (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
+ (uchar**) &myisam_concurrent_insert, (uchar**) &myisam_concurrent_insert,
0, GET_LONG, OPT_ARG, 1, 0, 2, 0, 0, 0},
{"console", OPT_CONSOLE, "Write error output on screen; Don't remove the console window on windows.",
- (gptr*) &opt_console, (gptr*) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
+ (uchar**) &opt_console, (uchar**) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
{"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"datadir", 'h', "Path to the database root.", (gptr*) &mysql_data_home,
- (gptr*) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"datadir", 'h', "Path to the database root.", (uchar**) &mysql_data_home,
+ (uchar**) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF
- {"debug", '#', "Debug log.", (gptr*) &default_dbug_option,
- (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug", '#', "Debug log.", (uchar**) &default_dbug_option,
+ (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"default-character-set", 'C', "Set the default character set (deprecated option, use --character-set-server instead).",
- (gptr*) &default_character_set_name, (gptr*) &default_character_set_name,
+ (uchar**) &default_character_set_name, (uchar**) &default_character_set_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation (deprecated option, use --collation-server instead).",
- (gptr*) &default_collation_name, (gptr*) &default_collation_name,
+ (uchar**) &default_collation_name, (uchar**) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"default-storage-engine", OPT_STORAGE_ENGINE,
"Set the default storage engine (table type) for tables.",
- (gptr*)&default_storage_engine_str, (gptr*)&default_storage_engine_str,
+ (uchar**)&default_storage_engine_str, (uchar**)&default_storage_engine_str,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-table-type", OPT_STORAGE_ENGINE,
"(deprecated) Use --default-storage-engine.",
- (gptr*)&default_storage_engine_str, (gptr*)&default_storage_engine_str,
+ (uchar**)&default_storage_engine_str, (uchar**)&default_storage_engine_str,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-time-zone", OPT_DEFAULT_TIME_ZONE, "Set the default time zone.",
- (gptr*) &default_tz_name, (gptr*) &default_tz_name,
+ (uchar**) &default_tz_name, (uchar**) &default_tz_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"delay-key-write", OPT_DELAY_KEY_WRITE, "Type of DELAY_KEY_WRITE.",
0,0,0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -5002,41 +5191,41 @@ struct my_option my_long_options[] =
#ifdef HAVE_OPENSSL
{"des-key-file", OPT_DES_KEY_FILE,
"Load keys for des_encrypt() and des_encrypt from given file.",
- (gptr*) &des_key_file, (gptr*) &des_key_file, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &des_key_file, (uchar**) &des_key_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
#endif /* HAVE_OPENSSL */
#ifdef HAVE_REPLICATION
{"disconnect-slave-event-count", OPT_DISCONNECT_SLAVE_EVENT_COUNT,
"Option used by mysql-test for debugging and testing of replication.",
- (gptr*) &disconnect_slave_event_count,
- (gptr*) &disconnect_slave_event_count, 0, GET_INT, REQUIRED_ARG, 0, 0, 0,
+ (uchar**) &disconnect_slave_event_count,
+ (uchar**) &disconnect_slave_event_count, 0, GET_INT, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
#endif /* HAVE_REPLICATION */
{"enable-locking", OPT_ENABLE_LOCK,
"Deprecated option, use --external-locking instead.",
- (gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
+ (uchar**) &opt_external_locking, (uchar**) &opt_external_locking,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef __NT__
{"enable-named-pipe", OPT_HAVE_NAMED_PIPE, "Enable the named pipe (NT).",
- (gptr*) &opt_enable_named_pipe, (gptr*) &opt_enable_named_pipe, 0, GET_BOOL,
+ (uchar**) &opt_enable_named_pipe, (uchar**) &opt_enable_named_pipe, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.",
- (gptr*) &opt_do_pstack, (gptr*) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0,
+ (uchar**) &opt_do_pstack, (uchar**) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
{"engine-condition-pushdown",
OPT_ENGINE_CONDITION_PUSHDOWN,
"Push supported query conditions to the storage engine.",
- (gptr*) &global_system_variables.engine_condition_pushdown,
- (gptr*) &global_system_variables.engine_condition_pushdown,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ (uchar**) &global_system_variables.engine_condition_pushdown,
+ (uchar**) &global_system_variables.engine_condition_pushdown,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
/* See how it's handled in get_one_option() */
{"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.",
- (gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
+ (uchar**) &opt_external_locking, (uchar**) &opt_external_locking,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -5044,132 +5233,55 @@ struct my_option my_long_options[] =
easier to do */
{"gdb", OPT_DEBUGGING,
"Set up signals usable for debugging",
- (gptr*) &opt_debugging, (gptr*) &opt_debugging,
+ (uchar**) &opt_debugging, (uchar**) &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"general-log", OPT_GENERAL_LOG,
- "Enable|disable general log", (gptr*) &opt_log,
- (gptr*) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ "Enable|disable general log", (uchar**) &opt_log,
+ (uchar**) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_LARGE_PAGES
{"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \
Disable with --skip-large-pages.",
- (gptr*) &opt_large_pages, (gptr*) &opt_large_pages, 0, GET_BOOL, NO_ARG, 0, 0, 0,
+ (uchar**) &opt_large_pages, (uchar**) &opt_large_pages, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
#endif
{"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection",
- (gptr*) &opt_init_connect, (gptr*) &opt_init_connect, 0, GET_STR_ALLOC,
+ (uchar**) &opt_init_connect, (uchar**) &opt_init_connect, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DISABLE_GRANT_OPTIONS
{"init-file", OPT_INIT_FILE, "Read SQL commands from this file at startup.",
- (gptr*) &opt_init_file, (gptr*) &opt_init_file, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &opt_init_file, (uchar**) &opt_init_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
+#endif
{"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed when a slave connects to this master",
- (gptr*) &opt_init_slave, (gptr*) &opt_init_slave, 0, GET_STR_ALLOC,
+ (uchar**) &opt_init_slave, (uchar**) &opt_init_slave, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"innodb", OPT_INNODB, "Enable InnoDB (if this version of MySQL supports it). \
-Disable with --skip-innodb (will save memory).",
- (gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, OPT_INNODB_DEFAULT, 0, 0,
- 0, 0, 0},
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- {"innodb_checksums", OPT_INNODB_CHECKSUMS, "Enable InnoDB checksums validation (enabled by default). \
-Disable with --skip-innodb-checksums.", (gptr*) &innobase_use_checksums,
- (gptr*) &innobase_use_checksums, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
-#endif
- {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH,
- "Path to individual files and their sizes.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- {"innodb_data_home_dir", OPT_INNODB_DATA_HOME_DIR,
- "The common part for InnoDB table spaces.", (gptr*) &innobase_data_home_dir,
- (gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
- 0},
- {"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, "Enable InnoDB doublewrite buffer (enabled by default). \
-Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
- (gptr*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- {"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN,
- "Speeds up the shutdown process of the InnoDB storage engine. Possible "
- "values are 0, 1 (faster)"
- /*
- NetWare can't close unclosed files, can't automatically kill remaining
- threads, etc, so on this OS we disable the crash-like InnoDB shutdown.
- */
-#ifndef __NETWARE__
- " or 2 (fastest - crash-like)"
-#endif
- ".",
- (gptr*) &innobase_fast_shutdown,
- (gptr*) &innobase_fast_shutdown, 0, GET_ULONG, OPT_ARG, 1, 0,
- IF_NETWARE(1,2), 0, 0, 0},
- {"innodb_file_per_table", OPT_INNODB_FILE_PER_TABLE,
- "Stores each InnoDB table to an .ibd file in the database dir.",
- (gptr*) &innobase_file_per_table,
- (gptr*) &innobase_file_per_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"innodb_flush_log_at_trx_commit", OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
- "Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second).",
- (gptr*) &srv_flush_log_at_trx_commit,
- (gptr*) &srv_flush_log_at_trx_commit,
- 0, GET_ULONG, OPT_ARG, 1, 0, 2, 0, 0, 0},
- {"innodb_flush_method", OPT_INNODB_FLUSH_METHOD,
- "With which method to flush data.", (gptr*) &innobase_unix_file_flush_method,
- (gptr*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
- 0, 0, 0},
- {"innodb_locks_unsafe_for_binlog", OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
- "Force InnoDB to not use next-key locking, to use only row-level locking.",
- (gptr*) &innobase_locks_unsafe_for_binlog,
- (gptr*) &innobase_locks_unsafe_for_binlog, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"innodb_log_arch_dir", OPT_INNODB_LOG_ARCH_DIR,
- "Where full logs should be archived.", (gptr*) &innobase_log_arch_dir,
- (gptr*) &innobase_log_arch_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"innodb_log_archive", OPT_INNODB_LOG_ARCHIVE,
- "Set to 1 if you want to have logs archived.", 0, 0, 0, GET_LONG, OPT_ARG,
- 0, 0, 0, 0, 0, 0},
- {"innodb_log_group_home_dir", OPT_INNODB_LOG_GROUP_HOME_DIR,
- "Path to InnoDB log files.", (gptr*) &innobase_log_group_home_dir,
- (gptr*) &innobase_log_group_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 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},
- {"innodb_max_purge_lag", OPT_INNODB_MAX_PURGE_LAG,
- "Desired maximum length of the purge queue (0 = no limit)",
- (gptr*) &srv_max_purge_lag,
- (gptr*) &srv_max_purge_lag, 0, GET_LONG, REQUIRED_ARG, 0, 0, ~0L,
- 0, 1L, 0},
- {"innodb_status_file", OPT_INNODB_STATUS_FILE,
- "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
- (gptr*) &innobase_create_status_file, (gptr*) &innobase_create_status_file,
- 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"innodb_support_xa", OPT_INNODB_SUPPORT_XA,
- "Enable InnoDB support for the XA two-phase commit",
- (gptr*) &global_system_variables.innodb_support_xa,
- (gptr*) &global_system_variables.innodb_support_xa,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
- {"innodb_table_locks", OPT_INNODB_TABLE_LOCKS,
- "Enable InnoDB locking in LOCK TABLES",
- (gptr*) &global_system_variables.innodb_table_locks,
- (gptr*) &global_system_variables.innodb_table_locks,
- 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
-#endif /* End WITH_INNOBASE_STORAGE_ENGINE */
- {"language", 'L',
+ {"language", 'L',
"Client error messages in given language. May be given as a full path.",
- (gptr*) &language_ptr, (gptr*) &language_ptr, 0, GET_STR, REQUIRED_ARG,
+ (uchar**) &language_ptr, (uchar**) &language_ptr, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
+ {"lc-time-names", OPT_LC_TIME_NAMES,
+ "Set the language used for the month names and the days of the week.",
+ (uchar**) &lc_time_names_name,
+ (uchar**) &lc_time_names_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"local-infile", OPT_LOCAL_INFILE,
"Enable/disable LOAD DATA LOCAL INFILE (takes values 1|0).",
- (gptr*) &opt_local_infile,
- (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG,
+ (uchar**) &opt_local_infile,
+ (uchar**) &opt_local_infile, 0, GET_BOOL, OPT_ARG,
1, 0, 0, 0, 0, 0},
- {"log", 'l', "Log connections and queries to file.", (gptr*) &opt_logname,
- (gptr*) &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"log", 'l', "Log connections and queries to file.", (uchar**) &opt_logname,
+ (uchar**) &opt_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-bin", OPT_BIN_LOG,
"Log update queries in binary format. Optional (but strongly recommended "
"to avoid replication problems if server's hostname changes) argument "
"should be the chosen location for the binary log files.",
- (gptr*) &opt_bin_logname, (gptr*) &opt_bin_logname, 0, GET_STR_ALLOC,
+ (uchar**) &opt_bin_logname, (uchar**) &opt_bin_logname, 0, GET_STR_ALLOC,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-bin-index", OPT_BIN_LOG_INDEX,
"File that holds the names for last binary log files.",
- (gptr*) &opt_binlog_index_name, (gptr*) &opt_binlog_index_name, 0, GET_STR,
+ (uchar**) &opt_binlog_index_name, (uchar**) &opt_binlog_index_name, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_REMOVED_IN_5_1_OR_6_0
/*
@@ -5180,7 +5292,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
*/
{"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
"(deprecated) Use log-bin-trust-function-creators.",
- (gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0,
+ (uchar**) &trust_function_creators, (uchar**) &trust_function_creators, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
/*
@@ -5194,13 +5306,13 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
"Note that if ALL connections to this server ALWAYS use row-based binary "
"logging, the security issues do not exist and the binary logging cannot "
"break, so you can safely set this to 1."
- ,(gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0,
+ ,(uchar**) &trust_function_creators, (uchar**) &trust_function_creators, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-error", OPT_ERROR_LOG_FILE, "Error log file.",
- (gptr*) &log_error_file_ptr, (gptr*) &log_error_file_ptr, 0, GET_STR,
+ (uchar**) &log_error_file_ptr, (uchar**) &log_error_file_ptr, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-isam", OPT_ISAM_LOG, "Log all MyISAM changes to file.",
- (gptr*) &myisam_log_filename, (gptr*) &myisam_log_filename, 0, GET_STR,
+ (uchar**) &myisam_log_filename, (uchar**) &myisam_log_filename, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-long-format", '0',
"Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.",
@@ -5209,165 +5321,161 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
{"log-output", OPT_LOG_OUTPUT,
"Syntax: log-output[=value[,value...]], where \"value\" could be TABLE, "
"FILE or NONE.",
- (gptr*) &log_output_str, (gptr*) &log_output_str, 0,
+ (uchar**) &log_output_str, (uchar**) &log_output_str, 0,
GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES,
"Log queries that are executed without benefit of any index to the slow log if it is open.",
- (gptr*) &opt_log_queries_not_using_indexes, (gptr*) &opt_log_queries_not_using_indexes,
+ (uchar**) &opt_log_queries_not_using_indexes, (uchar**) &opt_log_queries_not_using_indexes,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-short-format", OPT_SHORT_LOG_FORMAT,
"Don't log extra information to update and slow-query logs.",
- (gptr*) &opt_short_log_format, (gptr*) &opt_short_log_format,
+ (uchar**) &opt_short_log_format, (uchar**) &opt_short_log_format,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-slave-updates", OPT_LOG_SLAVE_UPDATES,
"Tells the slave to log the updates from the slave thread to the binary log. You will need to turn it on if you plan to daisy-chain the slaves.",
- (gptr*) &opt_log_slave_updates, (gptr*) &opt_log_slave_updates, 0, GET_BOOL,
+ (uchar**) &opt_log_slave_updates, (uchar**) &opt_log_slave_updates, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-slow-admin-statements", OPT_LOG_SLOW_ADMIN_STATEMENTS,
"Log slow OPTIMIZE, ANALYZE, ALTER and other administrative statements to the slow log if it is open.",
- (gptr*) &opt_log_slow_admin_statements,
- (gptr*) &opt_log_slow_admin_statements,
+ (uchar**) &opt_log_slow_admin_statements,
+ (uchar**) &opt_log_slow_admin_statements,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-slow-queries", OPT_SLOW_QUERY_LOG,
"Log slow queries to this log file. Defaults logging to hostname-slow.log file. Must be enabled to activate other slow log options.",
- (gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 0, GET_STR, OPT_ARG,
+ (uchar**) &opt_slow_logname, (uchar**) &opt_slow_logname, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"log-tc", OPT_LOG_TC,
"Path to transaction coordinator log (used for transactions that affect "
"more than one storage engine, when binary log is disabled)",
- (gptr*) &opt_tc_log_file, (gptr*) &opt_tc_log_file, 0, GET_STR,
+ (uchar**) &opt_tc_log_file, (uchar**) &opt_tc_log_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_MMAP
{"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
- (gptr*) &opt_tc_log_size, (gptr*) &opt_tc_log_size, 0, GET_ULONG,
+ (uchar**) &opt_tc_log_size, (uchar**) &opt_tc_log_size, 0, GET_ULONG,
REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0L, 0, TC_LOG_PAGE_SIZE, 0},
#endif
{"log-update", OPT_UPDATE_LOG,
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option justs turns on --log-bin instead.",
- (gptr*) &opt_update_logname, (gptr*) &opt_update_logname, 0, GET_STR,
+ (uchar**) &opt_update_logname, (uchar**) &opt_update_logname, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-warnings", 'W', "Log some not critical warnings to the log file.",
- (gptr*) &global_system_variables.log_warnings,
- (gptr*) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0,
+ (uchar**) &global_system_variables.log_warnings,
+ (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, 0,
0, 0, 0},
{"low-priority-updates", OPT_LOW_PRIORITY_UPDATES,
"INSERT/DELETE/UPDATE has lower priority than selects.",
- (gptr*) &global_system_variables.low_priority_updates,
- (gptr*) &max_system_variables.low_priority_updates,
+ (uchar**) &global_system_variables.low_priority_updates,
+ (uchar**) &max_system_variables.low_priority_updates,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"master-connect-retry", OPT_MASTER_CONNECT_RETRY,
"The number of seconds the slave thread will sleep before retrying to connect to the master in case the master goes down or the connection is lost.",
- (gptr*) &master_connect_retry, (gptr*) &master_connect_retry, 0, GET_UINT,
+ (uchar**) &master_connect_retry, (uchar**) &master_connect_retry, 0, GET_UINT,
REQUIRED_ARG, 60, 0, 0, 0, 0, 0},
{"master-host", OPT_MASTER_HOST,
"Master hostname or IP address for replication. If not set, the slave thread will not be started. Note that the setting of master-host will be ignored if there exists a valid master.info file.",
- (gptr*) &master_host, (gptr*) &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
+ (uchar**) &master_host, (uchar**) &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
0, 0, 0, 0},
{"master-info-file", OPT_MASTER_INFO_FILE,
"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,
+ (uchar**) &master_info_file, (uchar**) &master_info_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"master-password", OPT_MASTER_PASSWORD,
"The password the slave thread will authenticate with when connecting to the master. If not set, an empty password is assumed.The value in master.info will take precedence if it can be read.",
- (gptr*)&master_password, (gptr*)&master_password, 0,
+ (uchar**)&master_password, (uchar**)&master_password, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"master-port", OPT_MASTER_PORT,
"The port the master is listening on. If not set, the compiled setting of MYSQL_PORT is assumed. If you have not tinkered with configure options, this should be 3306. The value in master.info will take precedence if it can be read.",
- (gptr*) &master_port, (gptr*) &master_port, 0, GET_UINT, REQUIRED_ARG,
+ (uchar**) &master_port, (uchar**) &master_port, 0, GET_UINT, REQUIRED_ARG,
MYSQL_PORT, 0, 0, 0, 0, 0},
{"master-retry-count", OPT_MASTER_RETRY_COUNT,
"The number of tries the slave will make to connect to the master before giving up.",
- (gptr*) &master_retry_count, (gptr*) &master_retry_count, 0, GET_ULONG,
+ (uchar**) &master_retry_count, (uchar**) &master_retry_count, 0, GET_ULONG,
REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0},
{"master-ssl", OPT_MASTER_SSL,
"Enable the slave to connect to the master using SSL.",
- (gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ (uchar**) &master_ssl, (uchar**) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"master-ssl-ca", OPT_MASTER_SSL_CA,
"Master SSL CA file. Only applies if you have enabled master-ssl.",
- (gptr*) &master_ssl_ca, (gptr*) &master_ssl_ca, 0, GET_STR, OPT_ARG,
+ (uchar**) &master_ssl_ca, (uchar**) &master_ssl_ca, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"master-ssl-capath", OPT_MASTER_SSL_CAPATH,
"Master SSL CA path. Only applies if you have enabled master-ssl.",
- (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
+ (uchar**) &master_ssl_capath, (uchar**) &master_ssl_capath, 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",
- (gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG,
+ (uchar**) &master_ssl_cert, (uchar**) &master_ssl_cert, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"master-ssl-cipher", OPT_MASTER_SSL_CIPHER,
"Master SSL cipher. Only applies if you have enabled master-ssl.",
- (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
+ (uchar**) &master_ssl_cipher, (uchar**) &master_ssl_capath, 0, GET_STR, OPT_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.",
- (gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG,
+ (uchar**) &master_ssl_key, (uchar**) &master_ssl_key, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"master-user", OPT_MASTER_USER,
"The username the slave thread will use for authentication when connecting to the master. The user must have FILE privilege. If the master user is not set, user test is assumed. The value in master.info will take precedence if it can be read.",
- (gptr*) &master_user, (gptr*) &master_user, 0, GET_STR, REQUIRED_ARG, 0, 0,
+ (uchar**) &master_user, (uchar**) &master_user, 0, GET_STR, REQUIRED_ARG, 0, 0,
0, 0, 0, 0},
#ifdef HAVE_REPLICATION
{"max-binlog-dump-events", OPT_MAX_BINLOG_DUMP_EVENTS,
"Option used by mysql-test for debugging and testing of replication.",
- (gptr*) &max_binlog_dump_events, (gptr*) &max_binlog_dump_events, 0,
+ (uchar**) &max_binlog_dump_events, (uchar**) &max_binlog_dump_events, 0,
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_REPLICATION */
- {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (gptr*) &locked_in_memory,
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (uchar**) &locked_in_memory,
+ (uchar**) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"myisam-recover", OPT_MYISAM_RECOVER,
"Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
+ (uchar**) &myisam_recover_options_str, (uchar**) &myisam_recover_options_str, 0,
GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"ndbcluster", OPT_NDBCLUSTER, "Enable NDB Cluster (if this version of MySQL supports it). \
-Disable with --skip-ndbcluster (will save memory).",
- (gptr*) &opt_ndbcluster, (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG,
- OPT_NDBCLUSTER_DEFAULT, 0, 0, 0, 0, 0},
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
{"ndb-connectstring", OPT_NDB_CONNECTSTRING,
"Connect string for ndbcluster.",
- (gptr*) &opt_ndb_connectstring,
- (gptr*) &opt_ndb_connectstring,
+ (uchar**) &opt_ndb_connectstring,
+ (uchar**) &opt_ndb_connectstring,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-mgmd-host", OPT_NDB_MGMD,
"Set host and port for ndb_mgmd. Syntax: hostname[:port]",
- (gptr*) &opt_ndb_mgmd,
- (gptr*) &opt_ndb_mgmd,
+ (uchar**) &opt_ndb_mgmd,
+ (uchar**) &opt_ndb_mgmd,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-nodeid", OPT_NDB_NODEID,
"Nodeid for this mysqlserver in the cluster.",
- (gptr*) &opt_ndb_nodeid,
- (gptr*) &opt_ndb_nodeid,
+ (uchar**) &opt_ndb_nodeid,
+ (uchar**) &opt_ndb_nodeid,
0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-autoincrement-prefetch-sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
"Specify number of autoincrement values that are prefetched.",
- (gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
- (gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz,
+ (uchar**) &global_system_variables.ndb_autoincrement_prefetch_sz,
+ (uchar**) &global_system_variables.ndb_autoincrement_prefetch_sz,
0, GET_ULONG, REQUIRED_ARG, 32, 1, 256, 0, 0, 0},
{"ndb-distribution", OPT_NDB_DISTRIBUTION,
"Default distribution for new tables in ndb",
- (gptr*) &opt_ndb_distribution,
- (gptr*) &opt_ndb_distribution,
+ (uchar**) &opt_ndb_distribution,
+ (uchar**) &opt_ndb_distribution,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"ndb-force-send", OPT_NDB_FORCE_SEND,
"Force send of buffers to ndb immediately without waiting for "
"other threads.",
- (gptr*) &global_system_variables.ndb_force_send,
- (gptr*) &global_system_variables.ndb_force_send,
+ (uchar**) &global_system_variables.ndb_force_send,
+ (uchar**) &global_system_variables.ndb_force_send,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb_force_send", OPT_NDB_FORCE_SEND,
"same as --ndb-force-send.",
- (gptr*) &global_system_variables.ndb_force_send,
- (gptr*) &global_system_variables.ndb_force_send,
+ (uchar**) &global_system_variables.ndb_force_send,
+ (uchar**) &global_system_variables.ndb_force_send,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb-extra-logging", OPT_NDB_EXTRA_LOGGING,
"Turn on more logging in the error log.",
- (gptr*) &ndb_extra_logging,
- (gptr*) &ndb_extra_logging,
+ (uchar**) &ndb_extra_logging,
+ (uchar**) &ndb_extra_logging,
0, GET_INT, OPT_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_NDB_BINLOG
{"ndb-report-thresh-binlog-epoch-slip", OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP,
@@ -5375,104 +5483,113 @@ Disable with --skip-ndbcluster (will save memory).",
"E.g. 3 means that if the difference between what epoch has been received "
"from the storage nodes and what has been applied to the binlog is 3 or more, "
"a status message will be sent to the cluster log.",
- (gptr*) &ndb_report_thresh_binlog_epoch_slip,
- (gptr*) &ndb_report_thresh_binlog_epoch_slip,
+ (uchar**) &ndb_report_thresh_binlog_epoch_slip,
+ (uchar**) &ndb_report_thresh_binlog_epoch_slip,
0, GET_ULONG, REQUIRED_ARG, 3, 0, 256, 0, 0, 0},
{"ndb-report-thresh-binlog-mem-usage", OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE,
"Threshold on percentage of free memory before reporting binlog status. E.g. "
"10 means that if amount of available memory for receiving binlog data from "
"the storage nodes goes below 10%, "
"a status message will be sent to the cluster log.",
- (gptr*) &ndb_report_thresh_binlog_mem_usage,
- (gptr*) &ndb_report_thresh_binlog_mem_usage,
+ (uchar**) &ndb_report_thresh_binlog_mem_usage,
+ (uchar**) &ndb_report_thresh_binlog_mem_usage,
0, GET_ULONG, REQUIRED_ARG, 10, 0, 100, 0, 0, 0},
#endif
{"ndb-use-exact-count", OPT_NDB_USE_EXACT_COUNT,
"Use exact records count during query planning and for fast "
"select count(*), disable for faster queries.",
- (gptr*) &global_system_variables.ndb_use_exact_count,
- (gptr*) &global_system_variables.ndb_use_exact_count,
+ (uchar**) &global_system_variables.ndb_use_exact_count,
+ (uchar**) &global_system_variables.ndb_use_exact_count,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT,
"same as --ndb-use-exact-count.",
- (gptr*) &global_system_variables.ndb_use_exact_count,
- (gptr*) &global_system_variables.ndb_use_exact_count,
+ (uchar**) &global_system_variables.ndb_use_exact_count,
+ (uchar**) &global_system_variables.ndb_use_exact_count,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"ndb-use-transactions", OPT_NDB_USE_TRANSACTIONS,
+ "Use transactions for large inserts, if enabled then large "
+ "inserts will be split into several smaller transactions",
+ (uchar**) &global_system_variables.ndb_use_transactions,
+ (uchar**) &global_system_variables.ndb_use_transactions,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"ndb_use_transactions", OPT_NDB_USE_TRANSACTIONS,
+ "same as --ndb-use-transactions.",
+ (uchar**) &global_system_variables.ndb_use_transactions,
+ (uchar**) &global_system_variables.ndb_use_transactions,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"ndb-shm", OPT_NDB_SHM,
"Use shared memory connections when available.",
- (gptr*) &opt_ndb_shm,
- (gptr*) &opt_ndb_shm,
+ (uchar**) &opt_ndb_shm,
+ (uchar**) &opt_ndb_shm,
0, GET_BOOL, OPT_ARG, OPT_NDB_SHM_DEFAULT, 0, 0, 0, 0, 0},
{"ndb-optimized-node-selection", OPT_NDB_OPTIMIZED_NODE_SELECTION,
"Select nodes for transactions in a more optimal way.",
- (gptr*) &opt_ndb_optimized_node_selection,
- (gptr*) &opt_ndb_optimized_node_selection,
+ (uchar**) &opt_ndb_optimized_node_selection,
+ (uchar**) &opt_ndb_optimized_node_selection,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{ "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME,
"A dedicated thread is created to, at the given millisecons interval, invalidate the query cache if another MySQL server in the cluster has changed the data in the database.",
- (gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &opt_ndb_cache_check_time, (uchar**) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
0, 0, LONG_TIMEOUT, 0, 1, 0},
{"ndb-index-stat-enable", OPT_NDB_INDEX_STAT_ENABLE,
"Use ndb index statistics in query optimization.",
- (gptr*) &global_system_variables.ndb_index_stat_enable,
- (gptr*) &max_system_variables.ndb_index_stat_enable,
+ (uchar**) &global_system_variables.ndb_index_stat_enable,
+ (uchar**) &max_system_variables.ndb_index_stat_enable,
0, GET_BOOL, OPT_ARG, 0, 0, 1, 0, 0, 0},
#endif
{"ndb-use-copying-alter-table",
OPT_NDB_USE_COPYING_ALTER_TABLE,
"Force ndbcluster to always copy tables at alter table (should only be used if on-line alter table fails).",
- (gptr*) &global_system_variables.ndb_use_copying_alter_table,
- (gptr*) &global_system_variables.ndb_use_copying_alter_table,
+ (uchar**) &global_system_variables.ndb_use_copying_alter_table,
+ (uchar**) &global_system_variables.ndb_use_copying_alter_table,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"new", 'n', "Use very new possible 'unsafe' functions.",
- (gptr*) &global_system_variables.new_mode,
- (gptr*) &max_system_variables.new_mode,
+ (uchar**) &global_system_variables.new_mode,
+ (uchar**) &max_system_variables.new_mode,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef NOT_YET
{"no-mix-table-types", OPT_NO_MIX_TYPE, "Don't allow commands with uses two different table types.",
- (gptr*) &opt_no_mix_types, (gptr*) &opt_no_mix_types, 0, GET_BOOL, NO_ARG,
+ (uchar**) &opt_no_mix_types, (uchar**) &opt_no_mix_types, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
#endif
{"old-alter-table", OPT_OLD_ALTER_TABLE,
"Use old, non-optimized alter table.",
- (gptr*) &global_system_variables.old_alter_table,
- (gptr*) &max_system_variables.old_alter_table, 0, GET_BOOL, NO_ARG,
+ (uchar**) &global_system_variables.old_alter_table,
+ (uchar**) &max_system_variables.old_alter_table, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).",
- (gptr*) &global_system_variables.old_passwords,
- (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
+ (uchar**) &global_system_variables.old_passwords,
+ (uchar**) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
-#ifdef ONE_THREAD
{"one-thread", OPT_ONE_THREAD,
- "Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG,
- NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
+ "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS,
"Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)",
- (gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits,
+ (uchar**) &opt_old_style_user_limits, (uchar**) &opt_old_style_user_limits,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.",
- (gptr*) &pidfile_name_ptr, (gptr*) &pidfile_name_ptr, 0, GET_STR,
+ (uchar**) &pidfile_name_ptr, (uchar**) &pidfile_name_ptr, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port,
- (gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"port", 'P', "Port number to use for connection.", (uchar**) &mysqld_port,
+ (uchar**) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"port-open-timeout", OPT_PORT_OPEN_TIMEOUT,
"Maximum time in seconds to wait for the port to become free. "
- "(Default: no wait)", (gptr*) &mysqld_port_timeout,
- (gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "(Default: no wait)", (uchar**) &mysqld_port_timeout,
+ (uchar**) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"relay-log", OPT_RELAY_LOG,
"The location and name to use for relay logs.",
- (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
+ (uchar**) &opt_relay_logname, (uchar**) &opt_relay_logname, 0,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"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,
+ (uchar**) &opt_relaylog_index_name, (uchar**) &opt_relaylog_index_name, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"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,
+ (uchar**) &relay_log_info_file, (uchar**) &relay_log_info_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-do-db", OPT_REPLICATE_DO_DB,
"Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.%.",
@@ -5494,8 +5611,8 @@ thread is in the relay logs.",
"In replication, if set to 1, do not skip events having our server id. \
Default value is 0 (to break infinite loops in circular replication). \
Can't be set to 1 if --log-slave-updates is used.",
- (gptr*) &replicate_same_server_id,
- (gptr*) &replicate_same_server_id,
+ (uchar**) &replicate_same_server_id,
+ (uchar**) &replicate_same_server_id,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE,
@@ -5507,19 +5624,19 @@ Can't be set to 1 if --log-slave-updates is used.",
// In replication, we may need to tell the other servers how to connect
{"report-host", OPT_REPORT_HOST,
"Hostname or IP of the slave to be reported to to the master during slave registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset if you do not want the slave to register itself with the master. Note that it is not sufficient for the master to simply read the IP of the slave off the socket once the slave connects. Due to NAT and other routing issues, that IP may not be valid for connecting to the slave from the master or other hosts.",
- (gptr*) &report_host, (gptr*) &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
+ (uchar**) &report_host, (uchar**) &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
0, 0, 0, 0},
{"report-password", OPT_REPORT_PASSWORD, "Undocumented.",
- (gptr*) &report_password, (gptr*) &report_password, 0, GET_STR,
+ (uchar**) &report_password, (uchar**) &report_password, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"report-port", OPT_REPORT_PORT,
"Port for connecting to slave reported to the master during slave registration. Set it only if the slave is listening on a non-default port or if you have a special tunnel from the master or other clients to the slave. If not sure, leave this option unset.",
- (gptr*) &report_port, (gptr*) &report_port, 0, GET_UINT, REQUIRED_ARG,
+ (uchar**) &report_port, (uchar**) &report_port, 0, GET_UINT, REQUIRED_ARG,
MYSQL_PORT, 0, 0, 0, 0, 0},
- {"report-user", OPT_REPORT_USER, "Undocumented.", (gptr*) &report_user,
- (gptr*) &report_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"report-user", OPT_REPORT_USER, "Undocumented.", (uchar**) &report_user,
+ (uchar**) &report_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.",
- (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG,
+ (uchar**) &rpl_recovery_rank, (uchar**) &rpl_recovery_rank, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -5530,39 +5647,45 @@ Can't be set to 1 if --log-slave-updates is used.",
#endif
{"safe-user-create", OPT_SAFE_USER_CREATE,
"Don't allow new user creation by the user who has no write privileges to the mysql.user table.",
- (gptr*) &opt_safe_user_create, (gptr*) &opt_safe_user_create, 0, GET_BOOL,
+ (uchar**) &opt_safe_user_create, (uchar**) &opt_safe_user_create, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"safemalloc-mem-limit", OPT_SAFEMALLOC_MEM_LIMIT,
"Simulate memory shortage when compiled with the --with-debug=full option.",
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.",
- (gptr*) &opt_secure_auth, (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG,
+ (uchar**) &opt_secure_auth, (uchar**) &opt_secure_auth, 0, GET_BOOL, NO_ARG,
my_bool(0), 0, 0, 0, 0, 0},
+ {"secure-file-priv", OPT_SECURE_FILE_PRIV,
+ "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory",
+ (uchar**) &opt_secure_file_priv, (uchar**) &opt_secure_file_priv, 0,
+ GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"server-id", OPT_SERVER_ID,
"Uniquely identifies the server instance in the community of replication partners.",
- (gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0,
+ (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
{"set-variable", 'O',
"Change the value of a variable. Please note that this option is deprecated;you can set variables directly with --variable-name=value.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_SMEM
{"shared-memory", OPT_ENABLE_SHARED_MEMORY,
- "Enable the shared memory.",(gptr*) &opt_enable_shared_memory, (gptr*) &opt_enable_shared_memory,
+ "Enable the shared memory.",(uchar**) &opt_enable_shared_memory, (uchar**) &opt_enable_shared_memory,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
#ifdef HAVE_SMEM
{"shared-memory-base-name",OPT_SHARED_MEMORY_BASE_NAME,
- "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
+ "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO,
"Show user and password in SHOW SLAVE HOSTS on this master",
- (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0,
+ (uchar**) &opt_show_slave_auth_info, (uchar**) &opt_show_slave_auth_info, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DISABLE_GRANT_OPTIONS
{"skip-grant-tables", OPT_SKIP_GRANT,
"Start without grant tables. This gives all users FULL ACCESS to all tables!",
- (gptr*) &opt_noacl, (gptr*) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
+ (uchar**) &opt_noacl, (uchar**) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
+#endif
{"skip-host-cache", OPT_SKIP_HOST_CACHE, "Don't cache host names.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"skip-locking", OPT_SKIP_LOCK,
@@ -5587,37 +5710,37 @@ Can't be set to 1 if --log-slave-updates is used.",
"Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
0, 0, 0, 0},
{"skip-slave-start", OPT_SKIP_SLAVE_START,
- "If set, slave is not autostarted.", (gptr*) &opt_skip_slave_start,
- (gptr*) &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ "If set, slave is not autostarted.", (uchar**) &opt_skip_slave_start,
+ (uchar**) &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"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. Deprecated 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},
+ "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ DEFAULT_SKIP_THREAD_PRIORITY, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
{"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,
+ (uchar**) &slave_load_tmpdir, (uchar**) &slave_load_tmpdir, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"slave-skip-errors", OPT_SLAVE_SKIP_ERRORS,
"Tells the slave thread to continue replication when a query returns an error from the provided list.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"slow-query-log", OPT_SLOW_LOG,
- "Enable|disable slow query log", (gptr*) &opt_slow_log,
- (gptr*) &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ "Enable|disable slow query log", (uchar**) &opt_slow_log,
+ (uchar**) &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"socket", OPT_SOCKET, "Socket file to use for connection.",
- (gptr*) &mysqld_unix_port, (gptr*) &mysqld_unix_port, 0, GET_STR,
+ (uchar**) &mysqld_unix_port, (uchar**) &mysqld_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
{"sporadic-binlog-dump-fail", OPT_SPORADIC_BINLOG_DUMP_FAIL,
"Option used by mysql-test for debugging and testing of replication.",
- (gptr*) &opt_sporadic_binlog_dump_fail,
- (gptr*) &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
+ (uchar**) &opt_sporadic_binlog_dump_fail,
+ (uchar**) &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
#endif /* HAVE_REPLICATION */
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
@@ -5626,7 +5749,7 @@ log and this option does nothing anymore.",
0, 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
"Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
- (gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
+ (uchar**) &sql_mode_str, (uchar**) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
#ifdef HAVE_OPENSSL
#include "sslopt-longopts.h"
@@ -5637,23 +5760,28 @@ log and this option does nothing anymore.",
NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"symbolic-links", 's', "Enable symbolic link support.",
- (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
+ (uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG,
+ /*
+ The system call realpath() produces warnings under valgrind and
+ purify. These are not suppressed: instead we disable symlinks
+ option if compiled with valgrind support.
+ */
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
{"sysdate-is-now", OPT_SYSDATE_IS_NOW,
"Non-default option to alias SYSDATE() to NOW() to make it safe-replicable. Since 5.0, SYSDATE() returns a `dynamic' value different for different invocations, even within the same statement.",
- (gptr*) &global_system_variables.sysdate_is_now,
+ (uchar**) &global_system_variables.sysdate_is_now,
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
{"tc-heuristic-recover", OPT_TC_HEURISTIC_RECOVER,
"Decision to use in heuristic recover process. Possible values are COMMIT or ROLLBACK.",
- (gptr*) &opt_tc_heuristic_recover, (gptr*) &opt_tc_heuristic_recover,
+ (uchar**) &opt_tc_heuristic_recover, (uchar**) &opt_tc_heuristic_recover,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"temp-pool", OPT_TEMP_POOL,
"Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.",
- (gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
+ (uchar**) &use_temp_pool, (uchar**) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
{"timed_mutexes", OPT_TIMED_MUTEXES,
"Specify whether to time mutexes (only InnoDB mutexes are currently supported)",
- (gptr*) &timed_mutexes, (gptr*) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
+ (uchar**) &timed_mutexes, (uchar**) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
0, 0, 0, 0, 0},
{"tmpdir", 't',
"Path for temporary files. Several paths may be specified, separated by a "
@@ -5663,83 +5791,83 @@ log and this option does nothing anymore.",
"colon (:)"
#endif
", in this case they are used in a round-robin fashion.",
- (gptr*) &opt_mysql_tmpdir,
- (gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ (uchar**) &opt_mysql_tmpdir,
+ (uchar**) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"transaction-isolation", OPT_TX_ISOLATION,
"Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
{"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; use --symbolic-links instead.",
- (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
+ (uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG,
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
{"verbose", 'v', "Used with --help option for detailed help",
- (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"warnings", 'W', "Deprecated; use --log-warnings instead.",
- (gptr*) &global_system_variables.log_warnings,
- (gptr*) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, ~0L,
+ (uchar**) &global_system_variables.log_warnings,
+ (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, ~0L,
0, 0, 0},
{ "back_log", OPT_BACK_LOG,
"The number of outstanding connection requests MySQL can have. This comes into play when the main MySQL thread gets very many connection requests in a very short time.",
- (gptr*) &back_log, (gptr*) &back_log, 0, GET_ULONG,
+ (uchar**) &back_log, (uchar**) &back_log, 0, GET_ULONG,
REQUIRED_ARG, 50, 1, 65535, 0, 1, 0 },
{"binlog_cache_size", OPT_BINLOG_CACHE_SIZE,
"The size of the cache to hold the SQL statements for the binary log during a transaction. If you often use big, multi-statement transactions you can increase this to get more performance.",
- (gptr*) &binlog_cache_size, (gptr*) &binlog_cache_size, 0, GET_ULONG,
+ (uchar**) &binlog_cache_size, (uchar**) &binlog_cache_size, 0, GET_ULONG,
REQUIRED_ARG, 32*1024L, IO_SIZE, ~0L, 0, IO_SIZE, 0},
{"bulk_insert_buffer_size", OPT_BULK_INSERT_BUFFER_SIZE,
"Size of tree cache used in bulk insert optimisation. Note that this is a limit per thread!",
- (gptr*) &global_system_variables.bulk_insert_buff_size,
- (gptr*) &max_system_variables.bulk_insert_buff_size,
+ (uchar**) &global_system_variables.bulk_insert_buff_size,
+ (uchar**) &max_system_variables.bulk_insert_buff_size,
0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, ~0L, 0, 1, 0},
{"connect_timeout", OPT_CONNECT_TIMEOUT,
"The number of seconds the mysqld server is waiting for a connect packet before responding with 'Bad handshake'.",
- (gptr*) &connect_timeout, (gptr*) &connect_timeout,
+ (uchar**) &connect_timeout, (uchar**) &connect_timeout,
0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 },
{ "date_format", OPT_DATE_FORMAT,
"The DATE format (For future).",
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "datetime_format", OPT_DATETIME_FORMAT,
"The DATETIME/TIMESTAMP format (for future).",
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATETIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "default_week_format", OPT_DEFAULT_WEEK_FORMAT,
"The default week format used by WEEK() functions.",
- (gptr*) &global_system_variables.default_week_format,
- (gptr*) &max_system_variables.default_week_format,
+ (uchar**) &global_system_variables.default_week_format,
+ (uchar**) &max_system_variables.default_week_format,
0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0},
{"delayed_insert_limit", OPT_DELAYED_INSERT_LIMIT,
"After inserting delayed_insert_limit rows, the INSERT DELAYED handler will check if there are any SELECT statements pending. If so, it allows these to execute before continuing.",
- (gptr*) &delayed_insert_limit, (gptr*) &delayed_insert_limit, 0, GET_ULONG,
+ (uchar**) &delayed_insert_limit, (uchar**) &delayed_insert_limit, 0, GET_ULONG,
REQUIRED_ARG, DELAYED_LIMIT, 1, ~0L, 0, 1, 0},
{"delayed_insert_timeout", OPT_DELAYED_INSERT_TIMEOUT,
"How long a INSERT DELAYED thread should wait for INSERT statements before terminating.",
- (gptr*) &delayed_insert_timeout, (gptr*) &delayed_insert_timeout, 0,
+ (uchar**) &delayed_insert_timeout, (uchar**) &delayed_insert_timeout, 0,
GET_ULONG, REQUIRED_ARG, DELAYED_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{ "delayed_queue_size", OPT_DELAYED_QUEUE_SIZE,
"What size queue (in rows) should be allocated for handling INSERT DELAYED. If the queue becomes full, any client that does INSERT DELAYED will wait until there is room in the queue again.",
- (gptr*) &delayed_queue_size, (gptr*) &delayed_queue_size, 0, GET_ULONG,
+ (uchar**) &delayed_queue_size, (uchar**) &delayed_queue_size, 0, GET_ULONG,
REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1, 0},
{"div_precision_increment", OPT_DIV_PRECINCREMENT,
"Precision of the result of '/' operator will be increased on that value.",
- (gptr*) &global_system_variables.div_precincrement,
- (gptr*) &max_system_variables.div_precincrement, 0, GET_ULONG,
+ (uchar**) &global_system_variables.div_precincrement,
+ (uchar**) &max_system_variables.div_precincrement, 0, GET_ULONG,
REQUIRED_ARG, 4, 0, DECIMAL_MAX_SCALE, 0, 0, 0},
{"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
"If non-zero, binary logs will be purged after expire_logs_days "
"days; possible purges happen at startup and at binary log rotation.",
- (gptr*) &expire_logs_days,
- (gptr*) &expire_logs_days, 0, GET_ULONG,
+ (uchar**) &expire_logs_days,
+ (uchar**) &expire_logs_days, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
{ "flush_time", OPT_FLUSH_TIME,
"A dedicated thread is created to flush all tables at the given interval.",
- (gptr*) &flush_time, (gptr*) &flush_time, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &flush_time, (uchar**) &flush_time, 0, GET_ULONG, REQUIRED_ARG,
FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0},
{ "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX,
"List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE)",
@@ -5747,148 +5875,70 @@ log and this option does nothing anymore.",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "ft_max_word_len", OPT_FT_MAX_WORD_LEN,
"The maximum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.",
- (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_ULONG,
+ (uchar**) &ft_max_word_len, (uchar**) &ft_max_word_len, 0, GET_ULONG,
REQUIRED_ARG, HA_FT_MAXCHARLEN, 10, HA_FT_MAXCHARLEN, 0, 1, 0},
{ "ft_min_word_len", OPT_FT_MIN_WORD_LEN,
"The minimum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.",
- (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len, 0, GET_ULONG,
+ (uchar**) &ft_min_word_len, (uchar**) &ft_min_word_len, 0, GET_ULONG,
REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN, 0, 1, 0},
{ "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT,
"Number of best matches to use for query expansion",
- (gptr*) &ft_query_expansion_limit, (gptr*) &ft_query_expansion_limit, 0, GET_ULONG,
+ (uchar**) &ft_query_expansion_limit, (uchar**) &ft_query_expansion_limit, 0, GET_ULONG,
REQUIRED_ARG, 20, 0, 1000, 0, 1, 0},
{ "ft_stopword_file", OPT_FT_STOPWORD_FILE,
"Use stopwords from this file instead of built-in list.",
- (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR,
+ (uchar**) &ft_stopword_file, (uchar**) &ft_stopword_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "group_concat_max_len", OPT_GROUP_CONCAT_MAX_LEN,
"The maximum length of the result of function group_concat.",
- (gptr*) &global_system_variables.group_concat_max_len,
- (gptr*) &max_system_variables.group_concat_max_len, 0, GET_ULONG,
+ (uchar**) &global_system_variables.group_concat_max_len,
+ (uchar**) &max_system_variables.group_concat_max_len, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0},
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- {"innodb_additional_mem_pool_size", OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
- "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
- (gptr*) &innobase_additional_mem_pool_size,
- (gptr*) &innobase_additional_mem_pool_size, 0, GET_LONG, REQUIRED_ARG,
- 1*1024*1024L, 512*1024L, ~0L, 0, 1024, 0},
- {"innodb_autoextend_increment", OPT_INNODB_AUTOEXTEND_INCREMENT,
- "Data file autoextend increment in megabytes",
- (gptr*) &srv_auto_extend_increment,
- (gptr*) &srv_auto_extend_increment,
- 0, GET_LONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0},
- {"innodb_buffer_pool_size", OPT_INNODB_BUFFER_POOL_SIZE,
- "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
- (gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0,
- GET_LL, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, LONGLONG_MAX, 0,
- 1024*1024L, 0},
- {"innodb_commit_concurrency", OPT_INNODB_COMMIT_CONCURRENCY,
- "Helps in performance tuning in heavily concurrent environments.",
- (gptr*) &srv_commit_concurrency, (gptr*) &srv_commit_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0},
- {"innodb_concurrency_tickets", OPT_INNODB_CONCURRENCY_TICKETS,
- "Number of times a thread is allowed to enter InnoDB within the same \
- SQL query after it has once got the ticket",
- (gptr*) &srv_n_free_tickets_to_enter,
- (gptr*) &srv_n_free_tickets_to_enter,
- 0, GET_LONG, REQUIRED_ARG, 500L, 1L, ~0L, 0, 1L, 0},
- {"innodb_file_io_threads", OPT_INNODB_FILE_IO_THREADS,
- "Number of file I/O threads in InnoDB.", (gptr*) &innobase_file_io_threads,
- (gptr*) &innobase_file_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 4, 64, 0,
- 1, 0},
- {"innodb_force_recovery", OPT_INNODB_FORCE_RECOVERY,
- "Helps to save your data in case the disk image of the database becomes corrupt.",
- (gptr*) &innobase_force_recovery, (gptr*) &innobase_force_recovery, 0,
- GET_LONG, REQUIRED_ARG, 0, 0, 6, 0, 1, 0},
- {"innodb_lock_wait_timeout", OPT_INNODB_LOCK_WAIT_TIMEOUT,
- "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.",
- (gptr*) &innobase_lock_wait_timeout, (gptr*) &innobase_lock_wait_timeout,
- 0, GET_LONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0},
- {"innodb_log_buffer_size", OPT_INNODB_LOG_BUFFER_SIZE,
- "The size of the buffer which InnoDB uses to write log to the log files on disk.",
- (gptr*) &innobase_log_buffer_size, (gptr*) &innobase_log_buffer_size, 0,
- GET_LONG, REQUIRED_ARG, 1024*1024L, 256*1024L, ~0L, 0, 1024, 0},
- {"innodb_log_file_size", OPT_INNODB_LOG_FILE_SIZE,
- "Size of each log file in a log group.",
- (gptr*) &innobase_log_file_size, (gptr*) &innobase_log_file_size, 0,
- GET_LL, REQUIRED_ARG, 5*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 0,
- 1024*1024L, 0},
- {"innodb_log_files_in_group", OPT_INNODB_LOG_FILES_IN_GROUP,
- "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
- (gptr*) &innobase_log_files_in_group, (gptr*) &innobase_log_files_in_group,
- 0, GET_LONG, REQUIRED_ARG, 2, 2, 100, 0, 1, 0},
- {"innodb_mirrored_log_groups", OPT_INNODB_MIRRORED_LOG_GROUPS,
- "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
- (gptr*) &innobase_mirrored_log_groups,
- (gptr*) &innobase_mirrored_log_groups, 0, GET_LONG, REQUIRED_ARG, 1, 1, 10,
- 0, 1, 0},
- {"innodb_open_files", OPT_INNODB_OPEN_FILES,
- "How many files at the maximum InnoDB keeps open at the same time.",
- (gptr*) &innobase_open_files, (gptr*) &innobase_open_files, 0,
- GET_LONG, REQUIRED_ARG, 300L, 10L, ~0L, 0, 1L, 0},
- {"innodb_sync_spin_loops", OPT_INNODB_SYNC_SPIN_LOOPS,
- "Count of spin-loop rounds in InnoDB mutexes",
- (gptr*) &srv_n_spin_wait_rounds,
- (gptr*) &srv_n_spin_wait_rounds,
- 0, GET_LONG, REQUIRED_ARG, 20L, 0L, ~0L, 0, 1L, 0},
- {"innodb_thread_concurrency", OPT_INNODB_THREAD_CONCURRENCY,
- "Helps in performance tuning in heavily concurrent environments. "
- "Sets the maximum number of threads allowed inside InnoDB. Value 0"
- " will disable the thread throttling.",
- (gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 8, 0, 1000, 0, 1, 0},
- {"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
- "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
- " disable a sleep",
- (gptr*) &srv_thread_sleep_delay,
- (gptr*) &srv_thread_sleep_delay,
- 0, GET_LONG, REQUIRED_ARG, 10000L, 0L, ~0L, 0, 1L, 0},
-#endif /* WITH_INNOBASE_STORAGE_ENGINE */
{"interactive_timeout", OPT_INTERACTIVE_TIMEOUT,
"The number of seconds the server waits for activity on an interactive connection before closing it.",
- (gptr*) &global_system_variables.net_interactive_timeout,
- (gptr*) &max_system_variables.net_interactive_timeout, 0,
+ (uchar**) &global_system_variables.net_interactive_timeout,
+ (uchar**) &max_system_variables.net_interactive_timeout, 0,
GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{"join_buffer_size", OPT_JOIN_BUFF_SIZE,
"The size of the buffer that is used for full joins.",
- (gptr*) &global_system_variables.join_buff_size,
- (gptr*) &max_system_variables.join_buff_size, 0, GET_ULONG,
+ (uchar**) &global_system_variables.join_buff_size,
+ (uchar**) &max_system_variables.join_buff_size, 0, GET_ULONG,
REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD,
IO_SIZE, 0},
{"key_buffer_size", OPT_KEY_BUFFER_SIZE,
"The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.",
- (gptr*) &dflt_key_cache_var.param_buff_size,
- (gptr*) 0,
+ (uchar**) &dflt_key_cache_var.param_buff_size,
+ (uchar**) 0,
0, (GET_ULL | GET_ASK_ADDR),
REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, MALLOC_OVERHEAD,
IO_SIZE, 0},
{"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD,
"This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache",
- (gptr*) &dflt_key_cache_var.param_age_threshold,
- (gptr*) 0,
+ (uchar**) &dflt_key_cache_var.param_age_threshold,
+ (uchar**) 0,
0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG,
300, 100, ~0L, 0, 100, 0},
{"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,
"The default size of key cache blocks",
- (gptr*) &dflt_key_cache_var.param_block_size,
- (gptr*) 0,
+ (uchar**) &dflt_key_cache_var.param_block_size,
+ (uchar**) 0,
0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG,
KEY_CACHE_BLOCK_SIZE , 512, 1024*16, MALLOC_OVERHEAD, 512, 0},
{"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT,
"The minimum percentage of warm blocks in key cache",
- (gptr*) &dflt_key_cache_var.param_division_limit,
- (gptr*) 0,
+ (uchar**) &dflt_key_cache_var.param_division_limit,
+ (uchar**) 0,
0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100,
1, 100, 0, 1, 0},
{"long_query_time", OPT_LONG_QUERY_TIME,
"Log all queries that have taken more than long_query_time seconds to execute to file.",
- (gptr*) &global_system_variables.long_query_time,
- (gptr*) &max_system_variables.long_query_time, 0, GET_ULONG,
+ (uchar**) &global_system_variables.long_query_time,
+ (uchar**) &max_system_variables.long_query_time, 0, GET_ULONG,
REQUIRED_ARG, 10, 1, LONG_TIMEOUT, 0, 1, 0},
{"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES,
"If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive. Should be set to 2 if you are using a case insensitive file system",
- (gptr*) &lower_case_table_names,
- (gptr*) &lower_case_table_names, 0, GET_UINT, OPT_ARG,
+ (uchar**) &lower_case_table_names,
+ (uchar**) &lower_case_table_names, 0, GET_UINT, OPT_ARG,
#ifdef FN_NO_CASE_SENCE
1
#else
@@ -5897,351 +5947,370 @@ log and this option does nothing anymore.",
, 0, 2, 0, 1, 0},
{"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
"Max packetlength to send/receive from to server.",
- (gptr*) &global_system_variables.max_allowed_packet,
- (gptr*) &max_system_variables.max_allowed_packet, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_allowed_packet,
+ (uchar**) &max_system_variables.max_allowed_packet, 0, GET_ULONG,
REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
- (gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0,
+ (uchar**) &max_binlog_cache_size, (uchar**) &max_binlog_cache_size, 0,
GET_ULONG, REQUIRED_ARG, ~0L, IO_SIZE, ~0L, 0, IO_SIZE, 0},
{"max_binlog_size", OPT_MAX_BINLOG_SIZE,
"Binary log will be rotated automatically when the size exceeds this \
value. Will also apply to relay logs if max_relay_log_size is 0. \
The minimum value for this variable is 4096.",
- (gptr*) &max_binlog_size, (gptr*) &max_binlog_size, 0, GET_ULONG,
+ (uchar**) &max_binlog_size, (uchar**) &max_binlog_size, 0, GET_ULONG,
REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0},
{"max_connect_errors", OPT_MAX_CONNECT_ERRORS,
"If there is more than this number of interrupted connections from a host this host will be blocked from further connections.",
- (gptr*) &max_connect_errors, (gptr*) &max_connect_errors, 0, GET_ULONG,
+ (uchar**) &max_connect_errors, (uchar**) &max_connect_errors, 0, GET_ULONG,
REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0},
// Default max_connections of 151 is larger than Apache's default max
// children, to avoid "too many connections" error in a common setup
{"max_connections", OPT_MAX_CONNECTIONS,
- "The number of simultaneous clients allowed.", (gptr*) &max_connections,
- (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 16384, 0, 1,
+ "The number of simultaneous clients allowed.", (uchar**) &max_connections,
+ (uchar**) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 100000, 0, 1,
0},
{"max_delayed_threads", OPT_MAX_DELAYED_THREADS,
"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*) &global_system_variables.max_insert_delayed_threads,
- (gptr*) &max_system_variables.max_insert_delayed_threads,
+ (uchar**) &global_system_variables.max_insert_delayed_threads,
+ (uchar**) &max_system_variables.max_insert_delayed_threads,
0, GET_ULONG, REQUIRED_ARG, 20, 0, 16384, 0, 1, 0},
{"max_error_count", OPT_MAX_ERROR_COUNT,
"Max number of errors/warnings to store for a statement.",
- (gptr*) &global_system_variables.max_error_count,
- (gptr*) &max_system_variables.max_error_count,
+ (uchar**) &global_system_variables.max_error_count,
+ (uchar**) &max_system_variables.max_error_count,
0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 0, 65535, 0, 1, 0},
{"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE,
"Don't allow creation of heap tables bigger than this.",
- (gptr*) &global_system_variables.max_heap_table_size,
- (gptr*) &max_system_variables.max_heap_table_size, 0, GET_ULL,
+ (uchar**) &global_system_variables.max_heap_table_size,
+ (uchar**) &max_system_variables.max_heap_table_size, 0, GET_ULL,
REQUIRED_ARG, 16*1024*1024L, 16384, MAX_MEM_TABLE_SIZE,
MALLOC_OVERHEAD, 1024, 0},
{"max_join_size", OPT_MAX_JOIN_SIZE,
"Joins that are probably going to read more than max_join_size records return an error.",
- (gptr*) &global_system_variables.max_join_size,
- (gptr*) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
+ (uchar**) &global_system_variables.max_join_size,
+ (uchar**) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
~0L, 1, ~0L, 0, 1, 0},
{"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
"Max number of bytes in sorted records.",
- (gptr*) &global_system_variables.max_length_for_sort_data,
- (gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_length_for_sort_data,
+ (uchar**) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT,
"Maximum number of prepared statements in the server.",
- (gptr*) &max_prepared_stmt_count, (gptr*) &max_prepared_stmt_count,
+ (uchar**) &max_prepared_stmt_count, (uchar**) &max_prepared_stmt_count,
0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024, 0, 1, 0},
{"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
"If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the minimum value for this variable is 4096.",
- (gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
+ (uchar**) &max_relay_log_size, (uchar**) &max_relay_log_size, 0, GET_ULONG,
REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
{ "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
"Limit assumed max number of seeks when looking up rows based on a key",
- (gptr*) &global_system_variables.max_seeks_for_key,
- (gptr*) &max_system_variables.max_seeks_for_key, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_seeks_for_key,
+ (uchar**) &max_system_variables.max_seeks_for_key, 0, GET_ULONG,
REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0 },
{"max_sort_length", OPT_MAX_SORT_LENGTH,
"The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).",
- (gptr*) &global_system_variables.max_sort_length,
- (gptr*) &max_system_variables.max_sort_length, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_sort_length,
+ (uchar**) &max_system_variables.max_sort_length, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_sp_recursion_depth", OPT_MAX_SP_RECURSION_DEPTH,
"Maximum stored procedure recursion depth. (discussed with docs).",
- (gptr*) &global_system_variables.max_sp_recursion_depth,
- (gptr*) &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_sp_recursion_depth,
+ (uchar**) &max_system_variables.max_sp_recursion_depth, 0, GET_ULONG,
OPT_ARG, 0, 0, 255, 0, 1, 0 },
{"max_tmp_tables", OPT_MAX_TMP_TABLES,
"Maximum number of temporary tables a client can keep open at a time.",
- (gptr*) &global_system_variables.max_tmp_tables,
- (gptr*) &max_system_variables.max_tmp_tables, 0, GET_ULONG,
+ (uchar**) &global_system_variables.max_tmp_tables,
+ (uchar**) &max_system_variables.max_tmp_tables, 0, GET_ULONG,
REQUIRED_ARG, 32, 1, ~0L, 0, 1, 0},
{"max_user_connections", OPT_MAX_USER_CONNECTIONS,
"The maximum number of active connections for a single user (0 = no limit).",
- (gptr*) &max_user_connections, (gptr*) &max_user_connections, 0, GET_UINT,
+ (uchar**) &max_user_connections, (uchar**) &max_user_connections, 0, GET_UINT,
REQUIRED_ARG, 0, 1, ~0, 0, 1, 0},
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
"After this many write locks, allow some read locks to run in between.",
- (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG,
+ (uchar**) &max_write_lock_count, (uchar**) &max_write_lock_count, 0, GET_ULONG,
REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0},
{"multi_range_count", OPT_MULTI_RANGE_COUNT,
"Number of key ranges to request at once.",
- (gptr*) &global_system_variables.multi_range_count,
- (gptr*) &max_system_variables.multi_range_count, 0,
+ (uchar**) &global_system_variables.multi_range_count,
+ (uchar**) &max_system_variables.multi_range_count, 0,
GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0},
{"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
"Block size to be used for MyISAM index pages.",
- (gptr*) &opt_myisam_block_size,
- (gptr*) &opt_myisam_block_size, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &opt_myisam_block_size,
+ (uchar**) &opt_myisam_block_size, 0, GET_ULONG, REQUIRED_ARG,
MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH,
0, MI_MIN_KEY_BLOCK_LENGTH, 0},
{"myisam_data_pointer_size", OPT_MYISAM_DATA_POINTER_SIZE,
"Default pointer size to be used for MyISAM tables.",
- (gptr*) &myisam_data_pointer_size,
- (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &myisam_data_pointer_size,
+ (uchar**) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
6, 2, 7, 0, 1, 0},
{"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
"Deprecated option",
- (gptr*) &global_system_variables.myisam_max_extra_sort_file_size,
- (gptr*) &max_system_variables.myisam_max_extra_sort_file_size,
+ (uchar**) &global_system_variables.myisam_max_extra_sort_file_size,
+ (uchar**) &max_system_variables.myisam_max_extra_sort_file_size,
0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH,
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,
+ (uchar**) &global_system_variables.myisam_max_sort_file_size,
+ (uchar**) &max_system_variables.myisam_max_sort_file_size, 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,
+ (uchar**) &global_system_variables.myisam_repair_threads,
+ (uchar**) &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,
- (gptr*) &max_system_variables.myisam_sort_buff_size, 0,
+ (uchar**) &global_system_variables.myisam_sort_buff_size,
+ (uchar**) &max_system_variables.myisam_sort_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
{"myisam_use_mmap", OPT_MYISAM_USE_MMAP,
"Use memory mapping for reading and writing MyISAM tables",
- (gptr*) &opt_myisam_use_mmap,
- (gptr*) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0,
+ (uchar**) &opt_myisam_use_mmap,
+ (uchar**) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0,
0, 0, 0, 0, 0},
{"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
"Specifies how MyISAM index statistics collection code should threat NULLs. "
"Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
"\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
- (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
+ (uchar**) &myisam_stats_method_str, (uchar**) &myisam_stats_method_str, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
"Buffer length for TCP/IP and socket communication.",
- (gptr*) &global_system_variables.net_buffer_length,
- (gptr*) &max_system_variables.net_buffer_length, 0, GET_ULONG,
+ (uchar**) &global_system_variables.net_buffer_length,
+ (uchar**) &max_system_variables.net_buffer_length, 0, GET_ULONG,
REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0},
{"net_read_timeout", OPT_NET_READ_TIMEOUT,
"Number of seconds to wait for more data from a connection before aborting the read.",
- (gptr*) &global_system_variables.net_read_timeout,
- (gptr*) &max_system_variables.net_read_timeout, 0, GET_ULONG,
+ (uchar**) &global_system_variables.net_read_timeout,
+ (uchar**) &max_system_variables.net_read_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_READ_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{"net_retry_count", OPT_NET_RETRY_COUNT,
"If a read on a communication port is interrupted, retry this many times before giving up.",
- (gptr*) &global_system_variables.net_retry_count,
- (gptr*) &max_system_variables.net_retry_count,0,
+ (uchar**) &global_system_variables.net_retry_count,
+ (uchar**) &max_system_variables.net_retry_count,0,
GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, ~0L, 0, 1, 0},
{"net_write_timeout", OPT_NET_WRITE_TIMEOUT,
"Number of seconds to wait for a block to be written to a connection before aborting the write.",
- (gptr*) &global_system_variables.net_write_timeout,
- (gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG,
+ (uchar**) &global_system_variables.net_write_timeout,
+ (uchar**) &max_system_variables.net_write_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
+ { "old", OPT_OLD_MODE, "Use compatible behavior.",
+ (uchar**) &global_system_variables.old_mode,
+ (uchar**) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"open_files_limit", OPT_OPEN_FILES_LIMIT,
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
- (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,
+ (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0},
{"optimizer_prune_level", OPT_OPTIMIZER_PRUNE_LEVEL,
"Controls the heuristic(s) applied during query optimization to prune less-promising partial plans from the optimizer search space. Meaning: 0 - do not apply any heuristic, thus perform exhaustive search; 1 - prune plans based on number of retrieved rows.",
- (gptr*) &global_system_variables.optimizer_prune_level,
- (gptr*) &max_system_variables.optimizer_prune_level,
+ (uchar**) &global_system_variables.optimizer_prune_level,
+ (uchar**) &max_system_variables.optimizer_prune_level,
0, GET_ULONG, OPT_ARG, 1, 0, 1, 0, 1, 0},
{"optimizer_search_depth", OPT_OPTIMIZER_SEARCH_DEPTH,
"Maximum depth of search performed by the query optimizer. Values larger than the number of relations in a query result in better query plans, but take longer to compile a query. Smaller values than the number of tables in a relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to MAX_TABLES+2, the optimizer will switch to the original find_best (used for testing/comparison).",
- (gptr*) &global_system_variables.optimizer_search_depth,
- (gptr*) &max_system_variables.optimizer_search_depth,
+ (uchar**) &global_system_variables.optimizer_search_depth,
+ (uchar**) &max_system_variables.optimizer_search_depth,
0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0},
{"plugin_dir", OPT_PLUGIN_DIR,
"Directory for plugins.",
- (gptr*) &opt_plugin_dir_ptr, (gptr*) &opt_plugin_dir_ptr, 0,
+ (uchar**) &opt_plugin_dir_ptr, (uchar**) &opt_plugin_dir_ptr, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
+ {"plugin_load", OPT_PLUGIN_LOAD,
+ "Optional colon separated list of plugins to load, where each plugin is "
+ "identified by name and path to library seperated by an equals.",
+ (uchar**) &opt_plugin_load, (uchar**) &opt_plugin_load, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
"The size of the buffer that is allocated when preloading indexes",
- (gptr*) &global_system_variables.preload_buff_size,
- (gptr*) &max_system_variables.preload_buff_size, 0, GET_ULONG,
+ (uchar**) &global_system_variables.preload_buff_size,
+ (uchar**) &max_system_variables.preload_buff_size, 0, GET_ULONG,
REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0},
{"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE,
"Allocation block size for query parsing and execution",
- (gptr*) &global_system_variables.query_alloc_block_size,
- (gptr*) &max_system_variables.query_alloc_block_size, 0, GET_ULONG,
+ (uchar**) &global_system_variables.query_alloc_block_size,
+ (uchar**) &max_system_variables.query_alloc_block_size, 0, GET_ULONG,
REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0},
#ifdef HAVE_QUERY_CACHE
{"query_cache_limit", OPT_QUERY_CACHE_LIMIT,
"Don't cache results that are bigger than this.",
- (gptr*) &query_cache_limit, (gptr*) &query_cache_limit, 0, GET_ULONG,
+ (uchar**) &query_cache_limit, (uchar**) &query_cache_limit, 0, GET_ULONG,
REQUIRED_ARG, 1024*1024L, 0, (longlong) ULONG_MAX, 0, 1, 0},
{"query_cache_min_res_unit", OPT_QUERY_CACHE_MIN_RES_UNIT,
"minimal size of unit in wich space for results is allocated (last unit will be trimed after writing all result data.",
- (gptr*) &query_cache_min_res_unit, (gptr*) &query_cache_min_res_unit,
+ (uchar**) &query_cache_min_res_unit, (uchar**) &query_cache_min_res_unit,
0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE,
0, (longlong) ULONG_MAX, 0, 1, 0},
#endif /*HAVE_QUERY_CACHE*/
{"query_cache_size", OPT_QUERY_CACHE_SIZE,
"The memory allocated to store results from old queries.",
- (gptr*) &query_cache_size, (gptr*) &query_cache_size, 0, GET_ULONG,
+ (uchar**) &query_cache_size, (uchar**) &query_cache_size, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1024, 0},
#ifdef HAVE_QUERY_CACHE
{"query_cache_type", OPT_QUERY_CACHE_TYPE,
"0 = OFF = Don't cache or retrieve results. 1 = ON = Cache all results except SELECT SQL_NO_CACHE ... queries. 2 = DEMAND = Cache only SELECT SQL_CACHE ... queries.",
- (gptr*) &global_system_variables.query_cache_type,
- (gptr*) &max_system_variables.query_cache_type,
+ (uchar**) &global_system_variables.query_cache_type,
+ (uchar**) &max_system_variables.query_cache_type,
0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0},
{"query_cache_wlock_invalidate", OPT_QUERY_CACHE_WLOCK_INVALIDATE,
"Invalidate queries in query cache on LOCK for write",
- (gptr*) &global_system_variables.query_cache_wlock_invalidate,
- (gptr*) &max_system_variables.query_cache_wlock_invalidate,
+ (uchar**) &global_system_variables.query_cache_wlock_invalidate,
+ (uchar**) &max_system_variables.query_cache_wlock_invalidate,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
#endif /*HAVE_QUERY_CACHE*/
{"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE,
"Persistent buffer for query parsing and execution",
- (gptr*) &global_system_variables.query_prealloc_size,
- (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
+ (uchar**) &global_system_variables.query_prealloc_size,
+ (uchar**) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE,
~0L, 0, 1024, 0},
{"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE,
"Allocation block size for storing ranges during optimization",
- (gptr*) &global_system_variables.range_alloc_block_size,
- (gptr*) &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
+ (uchar**) &global_system_variables.range_alloc_block_size,
+ (uchar**) &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 4096, ~0L, 0, 1024, 0},
{"read_buffer_size", OPT_RECORD_BUFFER,
"Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.",
- (gptr*) &global_system_variables.read_buff_size,
- (gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &global_system_variables.read_buff_size,
+ (uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE,
0},
{"read_only", OPT_READONLY,
"Make all non-temporary tables read-only, with the exception for replication (slave) threads and users with the SUPER privilege",
- (gptr*) &opt_readonly,
- (gptr*) &opt_readonly,
+ (uchar**) &opt_readonly,
+ (uchar**) &opt_readonly,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
{"read_rnd_buffer_size", OPT_RECORD_RND_BUFFER,
"When reading rows in sorted order after a sort, the rows are read through this buffer to avoid a disk seeks. If not set, then it's set to the value of record_buffer.",
- (gptr*) &global_system_variables.read_rnd_buff_size,
- (gptr*) &max_system_variables.read_rnd_buff_size, 0,
+ (uchar**) &global_system_variables.read_rnd_buff_size,
+ (uchar**) &max_system_variables.read_rnd_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
{"record_buffer", OPT_RECORD_BUFFER,
"Alias for read_buffer_size",
- (gptr*) &global_system_variables.read_buff_size,
- (gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &global_system_variables.read_buff_size,
+ (uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, SSIZE_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
#ifdef HAVE_REPLICATION
{"relay_log_purge", OPT_RELAY_LOG_PURGE,
"0 = do not purge relay logs. 1 = purge them as soon as they are no more needed.",
- (gptr*) &relay_log_purge,
- (gptr*) &relay_log_purge, 0, GET_BOOL, NO_ARG,
+ (uchar**) &relay_log_purge,
+ (uchar**) &relay_log_purge, 0, GET_BOOL, NO_ARG,
1, 0, 1, 0, 1, 0},
{"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT,
"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,
+ (uchar**) &relay_log_space_limit,
+ (uchar**) &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L,
(longlong) ULONG_MAX, 0, 1, 0},
{"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL,
"Use compression on master/slave protocol.",
- (gptr*) &opt_slave_compressed_protocol,
- (gptr*) &opt_slave_compressed_protocol,
+ (uchar**) &opt_slave_compressed_protocol,
+ (uchar**) &opt_slave_compressed_protocol,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
{"slave_net_timeout", OPT_SLAVE_NET_TIMEOUT,
"Number of seconds to wait for more data from a master/slave connection before aborting the read.",
- (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
+ (uchar**) &slave_net_timeout, (uchar**) &slave_net_timeout, 0,
GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES,
"Number of times the slave SQL thread will retry a transaction in case "
"it failed with a deadlock or elapsed lock wait timeout, "
"before giving up and stopping.",
- (gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
+ (uchar**) &slave_trans_retries, (uchar**) &slave_trans_retries, 0,
GET_ULONG, REQUIRED_ARG, 10L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
- (gptr*) &slow_launch_time, (gptr*) &slow_launch_time, 0, GET_ULONG,
+ (uchar**) &slow_launch_time, (uchar**) &slow_launch_time, 0, GET_ULONG,
REQUIRED_ARG, 2L, 0L, LONG_TIMEOUT, 0, 1, 0},
{"sort_buffer_size", OPT_SORT_BUFFER,
"Each thread that needs to do a sort allocates a buffer of this size.",
- (gptr*) &global_system_variables.sortbuff_size,
- (gptr*) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &global_system_variables.sortbuff_size,
+ (uchar**) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD,
1, 0},
{"sync-binlog", OPT_SYNC_BINLOG,
"Synchronously flush binary log to disk after every #th event. "
"Use 0 (default) to disable synchronous flushing.",
- (gptr*) &sync_binlog_period, (gptr*) &sync_binlog_period, 0, GET_ULONG,
+ (uchar**) &sync_binlog_period, (uchar**) &sync_binlog_period, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0},
{"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.",
- (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
+ (uchar**) &opt_sync_frm, (uchar**) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
0, 0, 0, 0},
{"table_cache", OPT_TABLE_OPEN_CACHE,
"Deprecated; use --table_open_cache instead.",
- (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG,
+ (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG,
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
{"table_definition_cache", OPT_TABLE_DEF_CACHE,
"The number of cached table definitions.",
- (gptr*) &table_def_size, (gptr*) &table_def_size,
+ (uchar**) &table_def_size, (uchar**) &table_def_size,
0, GET_ULONG, REQUIRED_ARG, 128, 1, 512*1024L, 0, 1, 0},
{"table_open_cache", OPT_TABLE_OPEN_CACHE,
"The number of cached open tables.",
- (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG,
+ (uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG,
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
{"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT,
"Timeout in seconds to wait for a table level lock before returning an "
"error. Used only if the connection has active cursors.",
- (gptr*) &table_lock_wait_timeout, (gptr*) &table_lock_wait_timeout,
+ (uchar**) &table_lock_wait_timeout, (uchar**) &table_lock_wait_timeout,
0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0},
{"thread_cache_size", OPT_THREAD_CACHE_SIZE,
"How many threads we should keep in a cache for reuse.",
- (gptr*) &thread_cache_size, (gptr*) &thread_cache_size, 0, GET_ULONG,
+ (uchar**) &thread_cache_size, (uchar**) &thread_cache_size, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 16384, 0, 1, 0},
{"thread_concurrency", OPT_THREAD_CONCURRENCY,
"Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.",
- (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG,
+ (uchar**) &concurrency, (uchar**) &concurrency, 0, GET_ULONG, REQUIRED_ARG,
DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0},
+#if HAVE_POOL_OF_THREADS == 1
+ {"thread_pool_size", OPT_THREAD_CACHE_SIZE,
+ "How many threads we should create to handle query requests in case of 'thread_handling=pool-of-threads'",
+ (uchar**) &thread_pool_size, (uchar**) &thread_pool_size, 0, GET_ULONG,
+ REQUIRED_ARG, 20, 1, 16384, 0, 1, 0},
+#endif
{"thread_stack", OPT_THREAD_STACK,
- "The stack size for each thread.", (gptr*) &thread_stack,
- (gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
+ "The stack size for each thread.", (uchar**) &thread_stack,
+ (uchar**) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
1024L*128L, ~0L, 0, 1024, 0},
{ "time_format", OPT_TIME_FORMAT,
"The TIME format (for future).",
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
- (gptr*) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
+ (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"tmp_table_size", OPT_TMP_TABLE_SIZE,
"If an in-memory temporary table exceeds this size, MySQL will automatically convert it to an on-disk MyISAM table.",
- (gptr*) &global_system_variables.tmp_table_size,
- (gptr*) &max_system_variables.tmp_table_size, 0, GET_ULL,
+ (uchar**) &global_system_variables.tmp_table_size,
+ (uchar**) &max_system_variables.tmp_table_size, 0, GET_ULL,
REQUIRED_ARG, 16*1024*1024L, 1024, MAX_MEM_TABLE_SIZE, 0, 1, 0},
{"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE,
- "Allocation block size for transactions to be stored in binary log",
- (gptr*) &global_system_variables.trans_alloc_block_size,
- (gptr*) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG,
+ "Allocation block size for various transaction-related structures",
+ (uchar**) &global_system_variables.trans_alloc_block_size,
+ (uchar**) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG,
REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0},
{"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE,
- "Persistent buffer for transactions to be stored in binary log",
- (gptr*) &global_system_variables.trans_prealloc_size,
- (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
+ "Persistent buffer for various transaction-related structures",
+ (uchar**) &global_system_variables.trans_prealloc_size,
+ (uchar**) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0},
+ {"thread_handling", OPT_THREAD_HANDLING,
+ "Define threads usage for handling queries: "
+ "one-thread-per-connection or no-threads", 0, 0,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT,
"1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).",
- (gptr*) &global_system_variables.updatable_views_with_limit,
- (gptr*) &max_system_variables.updatable_views_with_limit,
+ (uchar**) &global_system_variables.updatable_views_with_limit,
+ (uchar**) &max_system_variables.updatable_views_with_limit,
0, GET_ULONG, REQUIRED_ARG, 1, 0, 1, 0, 1, 0},
{"wait_timeout", OPT_WAIT_TIMEOUT,
"The number of seconds the server waits for activity on a connection before closing it.",
- (gptr*) &global_system_variables.net_wait_timeout,
- (gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG,
+ (uchar**) &global_system_variables.net_wait_timeout,
+ (uchar**) &max_system_variables.net_wait_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT),
0, 1, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
@@ -6265,7 +6334,7 @@ static int show_starttime(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long) (thd->query_start() - start_time);
+ *((long *)buff)= (long) (thd->query_start() - server_start_time);
return 0;
}
@@ -6279,10 +6348,11 @@ static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff)
static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff)
{
- var->type= SHOW_CHAR;
+ var->type= SHOW_MY_BOOL;
pthread_mutex_lock(&LOCK_active_mi);
- var->value= const_cast<char*>((active_mi && active_mi->slave_running &&
- active_mi->rli.slave_running) ? "ON" : "OFF");
+ var->value= buff;
+ *((my_bool *)buff)= (my_bool) (active_mi && active_mi->slave_running &&
+ active_mi->rli.slave_running);
pthread_mutex_unlock(&LOCK_active_mi);
return 0;
}
@@ -6498,12 +6568,20 @@ static int show_ssl_ctx_get_session_cache_mode(THD *thd, SHOW_VAR *var, char *bu
return 0;
}
-/* Functions relying on SSL */
+/*
+ Functions relying on SSL
+ Note: In the show_ssl_* functions, we need to check if we have a
+ valid vio-object since this isn't always true, specifically
+ when session_status or global_status is requested from
+ inside an Event.
+ */
static int show_ssl_get_version(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_CHAR;
- var->value= const_cast<char*>(thd->net.vio->ssl_arg ?
- SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
+ if( thd->vio_ok() && thd->net.vio->ssl_arg )
+ var->value= const_cast<char*>(SSL_get_version((SSL*) thd->net.vio->ssl_arg));
+ else
+ var->value= (char *)"";
return 0;
}
@@ -6511,9 +6589,10 @@ static int show_ssl_session_reused(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long)thd->net.vio->ssl_arg ?
- SSL_session_reused((SSL*) thd->net.vio->ssl_arg) :
- 0;
+ if( thd->vio_ok() && thd->net.vio->ssl_arg )
+ *((long *)buff)= (long)SSL_session_reused((SSL*) thd->net.vio->ssl_arg);
+ else
+ *((long *)buff)= 0;
return 0;
}
@@ -6521,9 +6600,10 @@ static int show_ssl_get_default_timeout(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long)thd->net.vio->ssl_arg ?
- SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg) :
- 0;
+ if( thd->vio_ok() && thd->net.vio->ssl_arg )
+ *((long *)buff)= (long)SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg);
+ else
+ *((long *)buff)= 0;
return 0;
}
@@ -6531,9 +6611,10 @@ static int show_ssl_get_verify_mode(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long)thd->net.vio->ssl_arg ?
- SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg) :
- 0;
+ if( thd->net.vio && thd->net.vio->ssl_arg )
+ *((long *)buff)= (long)SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg);
+ else
+ *((long *)buff)= 0;
return 0;
}
@@ -6541,17 +6622,20 @@ static int show_ssl_get_verify_depth(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONG;
var->value= buff;
- *((long *)buff)= (long)thd->net.vio->ssl_arg ?
- SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg) :
- 0;
+ if( thd->vio_ok() && thd->net.vio->ssl_arg )
+ *((long *)buff)= (long)SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg);
+ else
+ *((long *)buff)= 0;
return 0;
}
static int show_ssl_get_cipher(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_CHAR;
- var->value= const_cast<char*>(thd->net.vio->ssl_arg ?
- SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "");
+ if( thd->vio_ok() && thd->net.vio->ssl_arg )
+ var->value= const_cast<char*>(SSL_get_cipher((SSL*) thd->net.vio->ssl_arg));
+ else
+ var->value= (char *)"";
return 0;
}
@@ -6559,7 +6643,7 @@ static int show_ssl_get_cipher_list(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_CHAR;
var->value= buff;
- if (thd->net.vio->ssl_arg)
+ if (thd->vio_ok() && thd->net.vio->ssl_arg)
{
int i;
const char *p;
@@ -6598,6 +6682,7 @@ SHOW_VAR status_vars[]= {
{"Com_analyze", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ANALYZE]), SHOW_LONG_STATUS},
{"Com_backup_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BACKUP_TABLE]), SHOW_LONG_STATUS},
{"Com_begin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BEGIN]), SHOW_LONG_STATUS},
+ {"Com_call_procedure", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CALL]), SHOW_LONG_STATUS},
{"Com_change_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_DB]), SHOW_LONG_STATUS},
{"Com_change_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_MASTER]), SHOW_LONG_STATUS},
{"Com_check", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECK]), SHOW_LONG_STATUS},
@@ -6820,6 +6905,7 @@ static void print_version(void)
server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT);
}
+#ifndef EMBEDDED_LIBRARY
static void usage(void)
{
if (!(default_charset_info= get_charset_by_csname(default_character_set_name,
@@ -6855,17 +6941,17 @@ Starts the MySQL database server\n");
#endif
print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
puts("");
- fix_paths();
set_ports();
- my_print_help(my_long_options);
- my_print_variables(my_long_options);
+ /* Print out all the options including plugin supplied options */
+ my_print_help_inc_plugins(my_long_options, sizeof(my_long_options)/sizeof(my_option));
puts("\n\
To see what values a running MySQL server is using, type\n\
'mysqladmin variables' instead of 'mysqld --verbose --help'.\n");
}
}
+#endif /*!EMBEDDED_LIBRARY*/
/*
@@ -6897,10 +6983,12 @@ static void mysql_init_variables(void)
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
+ opt_secure_file_priv= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
segfaulted= kill_in_progress= 0;
cleanup_done= 0;
+ defaults_argc= 0;
defaults_argv= 0;
server_id_supplied= 0;
test_flags= select_errors= dropping_tables= ha_open_options=0;
@@ -6921,7 +7009,7 @@ static void mysql_init_variables(void)
prepared_stmt_count= 0;
errmesg= 0;
mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS;
- bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
+ bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
bzero((char *) &global_status_var, sizeof(global_status_var));
opt_large_pages= 0;
key_map_full.set_all();
@@ -6948,8 +7036,8 @@ static void mysql_init_variables(void)
OPTION_QUOTE_SHOW_CREATE | OPTION_SQL_NOTES);
protocol_version= PROTOCOL_VERSION;
what_to_log= ~ (1L << (uint) COM_TIME);
- refresh_version= flush_version= 1L; /* Increments on each reload */
- query_id= thread_id= 1L;
+ refresh_version= 1L; /* Increments on each reload */
+ global_query_id= thread_id= 1L;
strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF";
myisam_stats_method_str= "nulls_unequal";
@@ -6985,10 +7073,10 @@ static void mysql_init_variables(void)
default_collation_name= compiled_default_collation_name;
sys_charset_system.value= (char*) system_charset_info->csname;
character_set_filesystem_name= (char*) "binary";
-
+ lc_time_names_name= (char*) "en_US";
/* Set default values for some option variables */
default_storage_engine_str= (char*) "MyISAM";
- global_system_variables.table_type= myisam_hton;
+ global_system_variables.table_plugin= NULL;
global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
max_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
@@ -7009,41 +7097,18 @@ static void mysql_init_variables(void)
"d:t:i:o,/tmp/mysqld.trace");
#endif
opt_error_log= IF_WIN(1,0);
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- have_innodb= SHOW_OPTION_YES;
-#else
- have_innodb= SHOW_OPTION_NO;
-#endif
-#ifdef WITH_CSV_STORAGE_ENGINE
- have_csv_db= SHOW_OPTION_YES;
-#else
- have_csv_db= SHOW_OPTION_NO;
-#endif
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- have_ndbcluster= SHOW_OPTION_DISABLED;
-#else
- have_ndbcluster= SHOW_OPTION_NO;
-#endif
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- have_partition_db= SHOW_OPTION_YES;
-#else
- have_partition_db= SHOW_OPTION_NO;
-#endif
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- have_ndbcluster=SHOW_OPTION_DISABLED;
global_system_variables.ndb_index_stat_enable=FALSE;
max_system_variables.ndb_index_stat_enable=TRUE;
global_system_variables.ndb_index_stat_cache_entries=32;
max_system_variables.ndb_index_stat_cache_entries=~0L;
global_system_variables.ndb_index_stat_update_freq=20;
max_system_variables.ndb_index_stat_update_freq=~0L;
-#else
- have_ndbcluster=SHOW_OPTION_NO;
#endif
#ifdef HAVE_OPENSSL
- have_openssl=SHOW_OPTION_YES;
+ have_ssl=SHOW_OPTION_YES;
#else
- have_openssl=SHOW_OPTION_NO;
+ have_ssl=SHOW_OPTION_NO;
#endif
#ifdef HAVE_BROKEN_REALPATH
have_symlink=SHOW_OPTION_NO;
@@ -7098,6 +7163,18 @@ static void mysql_init_variables(void)
/* Allow Win32 and NetWare users to move MySQL anywhere */
{
char prg_dev[LIBLEN];
+#if defined __WIN__
+ char executing_path_name[LIBLEN];
+ if (!test_if_hard_path(my_progname))
+ {
+ // we don't want to use GetModuleFileName inside of my_path since
+ // my_path is a generic path dereferencing function and here we care
+ // only about the executing binary.
+ GetModuleFileName(NULL, executing_path_name, sizeof(executing_path_name));
+ my_path(prg_dev, executing_path_name, NULL);
+ }
+ else
+#endif
my_path(prg_dev,my_progname,"mysql/bin");
strcat(prg_dev,"/../"); // Remove 'bin' to get base dir
cleanup_dirname(mysql_home,prg_dev);
@@ -7174,7 +7251,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case 'T':
test_flags= argument ? (uint) atoi(argument) : 0;
- test_flags&= ~TEST_NO_THREADS;
opt_endinfo=1;
break;
case (int) OPT_BIG_TABLES:
@@ -7196,11 +7272,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_INIT_RPL_ROLE:
{
int role;
- if ((role=find_type(argument, &rpl_role_typelib, 2)) <= 0)
- {
- fprintf(stderr, "Unknown replication role: %s\n", argument);
- exit(1);
- }
+ role= find_type_or_exit(argument, &rpl_role_typelib, opt->name);
rpl_status = (role == 1) ? RPL_AUTH_MASTER : RPL_IDLE_SLAVE;
break;
}
@@ -7256,18 +7328,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_BINLOG_FORMAT:
{
int id;
- if ((id= find_type(argument, &binlog_format_typelib, 2)) <= 0)
- {
- fprintf(stderr,
- "Unknown binary log format: '%s' "
- "(should be one of '%s', '%s', '%s')\n",
- argument,
- binlog_format_names[BINLOG_FORMAT_STMT],
- binlog_format_names[BINLOG_FORMAT_ROW],
- binlog_format_names[BINLOG_FORMAT_MIXED]);
- exit(1);
- }
- global_system_variables.binlog_format= id-1;
+ id= find_type_or_exit(argument, &binlog_format_typelib, opt->name);
+ global_system_variables.binlog_format= opt_binlog_format_id= id - 1;
break;
}
case (int)OPT_BINLOG_DO_DB:
@@ -7326,43 +7388,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
{
log_output_str= argument;
- if ((log_output_options=
- find_bit_type(argument, &log_output_typelib)) == ~(ulong) 0)
- {
- fprintf(stderr, "Unknown option to log-output: %s\n", argument);
- exit(1);
- }
- }
+ log_output_options=
+ find_bit_type_or_exit(argument, &log_output_typelib, opt->name);
+ }
break;
}
#endif
case OPT_EVENT_SCHEDULER:
- if (!argument)
- Events::opt_event_scheduler= Events::EVENTS_DISABLED;
- else
- {
- int type;
- /*
- type= 5 1 2 3 4
- (DISABLE ) - (OFF | ON) - (0 | 1)
- */
- switch ((type=find_type(argument, &Events::opt_typelib, 1))) {
- case 0:
- fprintf(stderr, "Unknown option to event-scheduler: %s\n",argument);
+ if (Events::set_opt_event_scheduler(argument))
exit(1);
- case 5: /* OPT_DISABLED */
- Events::opt_event_scheduler= Events::EVENTS_DISABLED;
- break;
- case 2: /* OPT_ON */
- case 4: /* 1 */
- Events::opt_event_scheduler= Events::EVENTS_ON;
- break;
- case 1: /* OPT_OFF */
- case 3: /* 0 */
- Events::opt_event_scheduler= Events::EVENTS_OFF;
- break;
- }
- }
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
@@ -7406,11 +7440,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_skip_show_db=1;
opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
break;
-#ifdef ONE_THREAD
- case (int) OPT_ONE_THREAD:
- test_flags |= TEST_NO_THREADS;
-#endif
- break;
case (int) OPT_WANT_CORE:
test_flags |= TEST_CORE_ON_SIGNAL;
break;
@@ -7451,6 +7480,29 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_STANDALONE: /* Dummy option for NT */
break;
#endif
+ /*
+ The following change issues a deprecation warning if the slave
+ configuration is specified either in the my.cnf file or on
+ the command-line. See BUG#21490.
+ */
+ case OPT_MASTER_HOST:
+ case OPT_MASTER_USER:
+ case OPT_MASTER_PASSWORD:
+ case OPT_MASTER_PORT:
+ case OPT_MASTER_CONNECT_RETRY:
+ case OPT_MASTER_SSL:
+ case OPT_MASTER_SSL_KEY:
+ case OPT_MASTER_SSL_CERT:
+ case OPT_MASTER_SSL_CAPATH:
+ case OPT_MASTER_SSL_CIPHER:
+ case OPT_MASTER_SSL_CA:
+ if (!slave_warning_issued) //only show the warning once
+ {
+ slave_warning_issued = true;
+ WARN_DEPRECATED(NULL, "5.2", "for replication startup options",
+ "'CHANGE MASTER'");
+ }
+ break;
case OPT_CONSOLE:
if (opt_console)
opt_error_log= 0; // Force logs to stdout
@@ -7481,11 +7533,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
{
int type;
- if ((type=find_type(argument, &delay_key_write_typelib, 2)) <= 0)
- {
- fprintf(stderr,"Unknown delay_key_write type: %s\n",argument);
- exit(1);
- }
+ type= find_type_or_exit(argument, &delay_key_write_typelib, opt->name);
delay_key_write_options= (uint) type-1;
}
break;
@@ -7496,25 +7544,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_TX_ISOLATION:
{
int type;
- if ((type=find_type(argument, &tx_isolation_typelib, 2)) <= 0)
- {
- fprintf(stderr,"Unknown transaction isolation type: %s\n",argument);
- exit(1);
- }
+ type= find_type_or_exit(argument, &tx_isolation_typelib, opt->name);
global_system_variables.tx_isolation= (type-1);
break;
}
- case OPT_MERGE:
- case OPT_BDB:
- break;
- case OPT_NDBCLUSTER:
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- if (opt_ndbcluster)
- have_ndbcluster= SHOW_OPTION_YES;
- else
- have_ndbcluster= SHOW_OPTION_DISABLED;
-#endif
- break;
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
case OPT_NDB_MGMD:
case OPT_NDB_NODEID:
@@ -7541,16 +7574,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case OPT_NDB_DISTRIBUTION:
int id;
- if ((id= find_type(argument, &ndb_distribution_typelib, 2)) <= 0)
- {
- fprintf(stderr,
- "Unknown ndb distribution type: '%s' "
- "(should be '%s' or '%s')\n",
- argument,
- ndb_distribution_names[ND_KEYHASH],
- ndb_distribution_names[ND_LINHASH]);
- exit(1);
- }
+ id= find_type_or_exit(argument, &ndb_distribution_typelib, opt->name);
opt_ndb_distribution_id= (enum ndb_distribution)(id-1);
break;
case OPT_NDB_EXTRA_LOGGING:
@@ -7562,24 +7586,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
ndb_extra_logging= atoi(argument);
break;
#endif
- case OPT_INNODB:
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- if (opt_innodb)
- have_innodb= SHOW_OPTION_YES;
- else
- have_innodb= SHOW_OPTION_DISABLED;
-#endif
- break;
- case OPT_INNODB_DATA_FILE_PATH:
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- innobase_data_file_path= argument;
-#endif
- break;
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- case OPT_INNODB_LOG_ARCHIVE:
- innobase_log_archive= argument ? test(atoi(argument)) : 1;
- break;
-#endif /* WITH_INNOBASE_STORAGE_ENGINE */
case OPT_MYISAM_RECOVER:
{
if (!argument || !argument[0])
@@ -7590,12 +7596,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
{
myisam_recover_options_str=argument;
- if ((myisam_recover_options=
- find_bit_type(argument, &myisam_recover_typelib)) == ~(ulong) 0)
- {
- fprintf(stderr, "Unknown option to myisam-recover: %s\n",argument);
- exit(1);
- }
+ myisam_recover_options=
+ find_bit_type_or_exit(argument, &myisam_recover_typelib, opt->name);
}
ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
break;
@@ -7608,14 +7610,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
myisam_concurrent_insert= 0; /* --skip-concurrent-insert */
break;
case OPT_TC_HEURISTIC_RECOVER:
- {
- if ((tc_heuristic_recover=find_type(argument,
- &tc_heuristic_recover_typelib, 2)) <=0)
- {
- fprintf(stderr, "Unknown option to tc-heuristic-recover: %s\n",argument);
- exit(1);
- }
- }
+ tc_heuristic_recover= find_type_or_exit(argument,
+ &tc_heuristic_recover_typelib,
+ opt->name);
+ break;
case OPT_MYISAM_STATS_METHOD:
{
ulong method_conv;
@@ -7623,11 +7621,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
LINT_INIT(method_conv);
myisam_stats_method_str= argument;
- if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
- {
- fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument);
- exit(1);
- }
+ method= find_type_or_exit(argument, &myisam_stats_method_typelib,
+ opt->name);
switch (method-1) {
case 2:
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
@@ -7646,18 +7641,23 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_SQL_MODE:
{
sql_mode_str= argument;
- if ((global_system_variables.sql_mode=
- find_bit_type(argument, &sql_mode_typelib)) == ~(ulong) 0)
- {
- fprintf(stderr, "Unknown option to sql-mode: %s\n", argument);
- exit(1);
- }
+ global_system_variables.sql_mode=
+ find_bit_type_or_exit(argument, &sql_mode_typelib, opt->name);
global_system_variables.sql_mode= fix_sql_mode(global_system_variables.
sql_mode);
break;
}
+ case OPT_ONE_THREAD:
+ global_system_variables.thread_handling= 2;
+ break;
+ case OPT_THREAD_HANDLING:
+ {
+ global_system_variables.thread_handling=
+ find_type_or_exit(argument, &thread_handling_typelib, opt->name);
+ break;
+ }
case OPT_FT_BOOLEAN_SYNTAX:
- if (ft_boolean_check_syntax_string((byte*) argument))
+ if (ft_boolean_check_syntax_string((uchar*) argument))
{
fprintf(stderr, "Invalid ft-boolean-syntax string: %s\n", argument);
exit(1);
@@ -7678,7 +7678,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
/* Initiates DEBUG - but no debugging here ! */
-static gptr *
+static uchar* *
mysql_getopt_value(const char *keyname, uint key_length,
const struct my_option *option)
{
@@ -7693,13 +7693,13 @@ mysql_getopt_value(const char *keyname, uint key_length,
exit(1);
switch (option->id) {
case OPT_KEY_BUFFER_SIZE:
- return (gptr*) &key_cache->param_buff_size;
+ return (uchar**) &key_cache->param_buff_size;
case OPT_KEY_CACHE_BLOCK_SIZE:
- return (gptr*) &key_cache->param_block_size;
+ return (uchar**) &key_cache->param_block_size;
case OPT_KEY_CACHE_DIVISION_LIMIT:
- return (gptr*) &key_cache->param_division_limit;
+ return (uchar**) &key_cache->param_division_limit;
case OPT_KEY_CACHE_AGE_THRESHOLD:
- return (gptr*) &key_cache->param_age_threshold;
+ return (uchar**) &key_cache->param_age_threshold;
}
}
}
@@ -7716,7 +7716,7 @@ static void option_error_reporter(enum loglevel level, const char *format, ...)
}
-static void get_options(int argc,char **argv)
+static void get_options(int *argc,char **argv)
{
int ho_error;
@@ -7724,34 +7724,20 @@ static void get_options(int argc,char **argv)
strmake(def_ft_boolean_syntax, ft_boolean_syntax,
sizeof(ft_boolean_syntax)-1);
my_getopt_error_reporter= option_error_reporter;
- if ((ho_error= handle_options(&argc, &argv, my_long_options,
+
+ /* Skip unknown options so that they may be processed later by plugins */
+ my_getopt_skip_unknown= TRUE;
+
+ if ((ho_error= handle_options(argc, &argv, my_long_options,
get_one_option)))
exit(ho_error);
+ (*argc)++; /* add back one for the progname handle_options removes */
+ /* no need to do this for argv as we are discarding it. */
-#ifndef WITH_NDBCLUSTER_STORAGE_ENGINE
- if (opt_ndbcluster)
- sql_print_warning("this binary does not contain NDBCLUSTER storage engine");
-#endif
-#ifndef WITH_INNOBASE_STORAGE_ENGINE
- if (opt_innodb)
- sql_print_warning("this binary does not contain INNODB storage engine");
-#endif
if ((opt_log_slow_admin_statements || opt_log_queries_not_using_indexes) &&
!opt_slow_log)
sql_print_warning("options --log-slow-admin-statements and --log-queries-not-using-indexes have no effect if --log-slow-queries is not set");
- if (argc > 0)
- {
- fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv);
- /* FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code? */
- exit(1);
- }
-
- if (opt_help)
- {
- usage();
- exit(0);
- }
#if defined(HAVE_BROKEN_REALPATH)
my_use_symdir=0;
my_disable_symlinks=1;
@@ -7776,6 +7762,7 @@ static void get_options(int argc,char **argv)
if (mysqld_chroot)
set_root(mysqld_chroot);
#else
+ global_system_variables.thread_handling = SCHEDULER_NO_THREADS;
max_allowed_packet= global_system_variables.max_allowed_packet;
net_buffer_length= global_system_variables.net_buffer_length;
#endif
@@ -7806,6 +7793,17 @@ static void get_options(int argc,char **argv)
&global_system_variables.datetime_format))
exit(1);
+#ifdef EMBEDDED_LIBRARY
+ one_thread_scheduler(&thread_scheduler);
+#else
+ if (global_system_variables.thread_handling <=
+ SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ one_thread_per_connection_scheduler(&thread_scheduler);
+ else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)
+ one_thread_scheduler(&thread_scheduler);
+ else
+ pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */
+#endif
}
@@ -7853,7 +7851,7 @@ static char *get_relative_path(const char *path)
*/
bool
-fn_format_relative_to_data_home(my_string to, const char *name,
+fn_format_relative_to_data_home(char * to, const char *name,
const char *dir, const char *extension)
{
char tmp_path[FN_REFLEN];
@@ -7917,6 +7915,40 @@ static void fix_paths(void)
exit(1);
}
#endif /* HAVE_REPLICATION */
+ /*
+ Convert the secure-file-priv option to system format, allowing
+ a quick strcmp to check if read or write is in an allowed dir
+ */
+ if (opt_secure_file_priv)
+ {
+ convert_dirname(buff, opt_secure_file_priv, NullS);
+ my_free(opt_secure_file_priv, MYF(0));
+ opt_secure_file_priv= my_strdup(buff, MYF(MY_FAE));
+ }
+}
+
+
+static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
+ const char *option)
+{
+ ulong res;
+
+ const char **ptr;
+
+ if ((res= find_bit_type(x, bit_lib)) == ~(ulong) 0)
+ {
+ ptr= bit_lib->type_names;
+ if (!*x)
+ fprintf(stderr, "No option given to %s\n", option);
+ else
+ fprintf(stderr, "Wrong option to %s. Option(s) given: %s\n", option, x);
+ fprintf(stderr, "Alternatives are: '%s'", *ptr);
+ while (*++ptr)
+ fprintf(stderr, ",'%s'", *ptr);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ return res;
}
@@ -7937,7 +7969,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
found=0;
found_end= 0;
- pos=(my_string) x;
+ pos=(char *) x;
while (*pos == ' ') pos++;
found_end= *pos == 0;
while (!found_end)
@@ -8023,6 +8055,8 @@ static int test_if_case_insensitive(const char *dir_name)
/* Create file to store pid number */
+#ifndef EMBEDDED_LIBRARY
+
static void create_pid_file()
{
File file;
@@ -8032,7 +8066,7 @@ static void create_pid_file()
char buff[21], *end;
end= int10_to_str((long) getpid(), buff, 10);
*end++= '\n';
- if (!my_write(file, (byte*) buff, (uint) (end-buff), MYF(MY_WME | MY_NABP)))
+ if (!my_write(file, (uchar*) buff, (uint) (end-buff), MYF(MY_WME | MY_NABP)))
{
(void) my_close(file, MYF(0));
return;
@@ -8042,7 +8076,7 @@ static void create_pid_file()
sql_perror("Can't start server: can't create PID file");
exit(1);
}
-
+#endif /* EMBEDDED_LIBRARY */
/* Clear most status variables */
void refresh_status(THD *thd)
@@ -8056,12 +8090,7 @@ void refresh_status(THD *thd)
bzero((char*) &thd->status_var, sizeof(thd->status_var));
/* Reset some global variables */
- for (SHOW_VAR *ptr= status_vars; ptr->name; ptr++)
- {
- /* Note that SHOW_LONG_NOFLUSH variables are not reset */
- if (ptr->type == SHOW_LONG)
- *(ulong*) ptr->value= 0;
- }
+ reset_status_vars();
/* Reset the counters of all key caches (default and named). */
process_key_caches(reset_key_cache_counters);
@@ -8080,49 +8109,9 @@ void refresh_status(THD *thd)
/*****************************************************************************
- Instantiate have_xyx for missing storage engines
+ Instantiate variables for missing storage engines
+ This section should go away soon
*****************************************************************************/
-#undef have_innodb
-#undef have_ndbcluster
-#undef have_csv_db
-
-SHOW_COMP_OPTION have_innodb= SHOW_OPTION_NO;
-SHOW_COMP_OPTION have_ndbcluster= SHOW_OPTION_NO;
-SHOW_COMP_OPTION have_csv_db= SHOW_OPTION_NO;
-SHOW_COMP_OPTION have_partition_db= SHOW_OPTION_NO;
-
-#ifndef WITH_INNOBASE_STORAGE_ENGINE
-uint innobase_flush_log_at_trx_commit;
-ulong innobase_fast_shutdown;
-long innobase_mirrored_log_groups, innobase_log_files_in_group;
-longlong innobase_log_file_size;
-long innobase_log_buffer_size;
-longlong innobase_buffer_pool_size;
-long innobase_additional_mem_pool_size;
-long innobase_file_io_threads, innobase_lock_wait_timeout;
-long innobase_force_recovery;
-long innobase_open_files;
-char *innobase_data_home_dir, *innobase_data_file_path;
-char *innobase_log_group_home_dir, *innobase_log_arch_dir;
-char *innobase_unix_file_flush_method;
-my_bool innobase_log_archive,
- innobase_use_doublewrite,
- innobase_use_checksums,
- innobase_file_per_table,
- innobase_locks_unsafe_for_binlog;
-
-extern "C" {
-ulong srv_max_buf_pool_modified_pct;
-ulong srv_max_purge_lag;
-ulong srv_auto_extend_increment;
-ulong srv_n_spin_wait_rounds;
-ulong srv_n_free_tickets_to_enter;
-ulong srv_thread_sleep_delay;
-ulong srv_thread_concurrency;
-ulong srv_commit_concurrency;
-}
-
-#endif
#ifndef WITH_NDBCLUSTER_STORAGE_ENGINE
ulong ndb_cache_check_time;
@@ -8143,5 +8132,3 @@ template class I_List<NAMED_LIST>;
template class I_List<Statement>;
template class I_List_iterator<Statement>;
#endif
-
-
diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej
deleted file mode 100644
index 62f0357622d..00000000000
--- a/sql/mysqld.cc.rej
+++ /dev/null
@@ -1,17 +0,0 @@
-***************
-*** 5316,5322 ****
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \
- --skip-merge.",
-! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
---- 5336,5342 ----
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"merge", OPT_MERGE, "Enable Merge storage engine. Disable with \
- --skip-merge.",
-! (gptr*) &opt_merge, (gptr*) &opt_merge, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
diff --git a/sql/mysqld_suffix.h b/sql/mysqld_suffix.h
index 405c5d855b7..b348f272db1 100644
--- a/sql/mysqld_suffix.h
+++ b/sql/mysqld_suffix.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 6f8993f584d..ec12c4cabf3 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -48,9 +47,6 @@
#include <violite.h>
#include <signal.h>
#include <errno.h>
-#ifdef __WIN__
-#include <winsock.h>
-#endif
#ifdef __NETWARE__
#include <sys/select.h>
#endif
@@ -112,7 +108,7 @@ extern void query_cache_insert(NET *net, const char *packet, ulong length);
#define TEST_BLOCKING 8
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
-static my_bool net_write_buff(NET *net,const char *packet,ulong len);
+static my_bool net_write_buff(NET *net,const uchar *packet,ulong len);
/* Init with packet info */
@@ -121,7 +117,7 @@ my_bool my_net_init(NET *net, Vio* vio)
{
DBUG_ENTER("my_net_init");
my_net_local_init(net); /* Set some limits */
- if (!(net->buff=(uchar*) my_malloc((uint32) net->max_packet+
+ if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
DBUG_RETURN(1);
@@ -161,7 +157,7 @@ my_bool my_net_init(NET *net, Vio* vio)
void net_end(NET *net)
{
DBUG_ENTER("net_end");
- my_free((gptr) net->buff,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(net->buff,MYF(MY_ALLOW_ZERO_PTR));
net->buff=0;
DBUG_VOID_RETURN;
}
@@ -169,17 +165,17 @@ void net_end(NET *net)
/* Realloc the packet buffer */
-my_bool net_realloc(NET *net, ulong length)
+my_bool net_realloc(NET *net, size_t length)
{
uchar *buff;
- ulong pkt_length;
+ size_t pkt_length;
DBUG_ENTER("net_realloc");
- DBUG_PRINT("enter",("length: %lu", length));
+ DBUG_PRINT("enter",("length: %lu", (ulong) length));
if (length >= net->max_packet_size)
{
DBUG_PRINT("error", ("Packet too large. Max size: %lu",
- net->max_packet_size));
+ net->max_packet_size));
net->error= 1;
net->report_error= 1;
net->last_errno= ER_NET_PACKET_TOO_LARGE;
@@ -190,9 +186,9 @@ my_bool net_realloc(NET *net, ulong length)
We must allocate some extra bytes for the end 0 and to be able to
read big compressed blocks
*/
- if (!(buff=(uchar*) my_realloc((char*) net->buff, (uint32) pkt_length +
- NET_HEADER_SIZE + COMP_HEADER_SIZE,
- MYF(MY_WME))))
+ if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
+ NET_HEADER_SIZE + COMP_HEADER_SIZE,
+ MYF(MY_WME))))
{
net->error= 1;
net->report_error= 1;
@@ -200,7 +196,7 @@ my_bool net_realloc(NET *net, ulong length)
DBUG_RETURN(1);
}
net->buff=net->write_pos=buff;
- net->buff_end=buff+(net->max_packet=pkt_length);
+ net->buff_end=buff+(net->max_packet= (ulong) pkt_length);
DBUG_RETURN(0);
}
@@ -221,6 +217,8 @@ my_bool net_realloc(NET *net, ulong length)
-1 Don't know if data is ready or not
*/
+#if !defined(EMBEDDED_LIBRARY)
+
static int net_data_is_ready(my_socket sd)
{
#ifdef HAVE_POLL
@@ -255,9 +253,10 @@ static int net_data_is_ready(my_socket sd)
return 0;
else
return test(res ? FD_ISSET(sd, &sfds) : 0);
-#endif
+#endif /* HAVE_POLL */
}
+#endif /* EMBEDDED_LIBRARY */
/*
Remove unwanted characters from connection
@@ -283,22 +282,26 @@ static int net_data_is_ready(my_socket sd)
void net_clear(NET *net, my_bool clear_buffer)
{
- int count, ready;
+#if !defined(EMBEDDED_LIBRARY)
+ size_t count;
+ int ready;
+#endif
DBUG_ENTER("net_clear");
+
#if !defined(EMBEDDED_LIBRARY)
if (clear_buffer)
{
while ((ready= net_data_is_ready(net->vio->sd)) > 0)
{
/* The socket is ready */
- if ((count= vio_read(net->vio, (char*) (net->buff),
- (uint32) net->max_packet)) > 0)
+ if ((long) (count= vio_read(net->vio, net->buff,
+ (size_t) net->max_packet)) > 0)
{
- DBUG_PRINT("info",("skipped %d bytes from file: %s",
- count, vio_description(net->vio)));
-#ifdef EXTRA_DEBUG
- fprintf(stderr,"Error: net_clear() skipped %d bytes from file: %s\n",
- count, vio_description(net->vio));
+ DBUG_PRINT("info",("skipped %ld bytes from file: %s",
+ (long) count, vio_description(net->vio)));
+#if defined(EXTRA_DEBUG)
+ fprintf(stderr,"Note: net_clear() skipped %ld bytes from file: %s\n",
+ (long) count, vio_description(net->vio));
#endif
}
else
@@ -316,10 +319,10 @@ void net_clear(NET *net, my_bool clear_buffer)
my_bool old_mode;
if (!vio_blocking(net->vio, FALSE, &old_mode))
{
- while ((count= vio_read(net->vio, (char*) (net->buff),
- (uint32) net->max_packet)) > 0)
- DBUG_PRINT("info",("skipped %d bytes from file: %s",
- count, vio_description(net->vio)));
+ while ((long) (count= vio_read(net->vio, net->buff,
+ (size_t) net->max_packet)) > 0)
+ DBUG_PRINT("info",("skipped %ld bytes from file: %s",
+ (long) count, vio_description(net->vio)));
vio_blocking(net->vio, TRUE, &old_mode);
}
}
@@ -340,8 +343,8 @@ my_bool net_flush(NET *net)
DBUG_ENTER("net_flush");
if (net->buff != net->write_pos)
{
- error=test(net_real_write(net,(char*) net->buff,
- (ulong) (net->write_pos - net->buff)));
+ error=test(net_real_write(net, net->buff,
+ (size_t) (net->write_pos - net->buff)));
net->write_pos=net->buff;
}
/* Sync packet number if using compression */
@@ -365,7 +368,7 @@ my_bool net_flush(NET *net)
*/
my_bool
-my_net_write(NET *net,const char *packet,ulong len)
+my_net_write(NET *net,const uchar *packet,size_t len)
{
uchar buff[NET_HEADER_SIZE];
if (unlikely(!net->vio)) /* nowhere to write */
@@ -380,7 +383,7 @@ my_net_write(NET *net,const char *packet,ulong len)
const ulong z_size = MAX_PACKET_LENGTH;
int3store(buff, z_size);
buff[3]= (uchar) net->pkt_nr++;
- if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
+ if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
net_write_buff(net, packet, z_size))
return 1;
packet += z_size;
@@ -389,10 +392,10 @@ my_net_write(NET *net,const char *packet,ulong len)
/* Write last packet */
int3store(buff,len);
buff[3]= (uchar) net->pkt_nr++;
- if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
+ if (net_write_buff(net, buff, NET_HEADER_SIZE))
return 1;
#ifndef DEBUG_DATA_PACKETS
- DBUG_DUMP("packet_header",(char*) buff,NET_HEADER_SIZE);
+ DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
#endif
return test(net_write_buff(net,packet,len));
}
@@ -427,8 +430,8 @@ my_net_write(NET *net,const char *packet,ulong len)
my_bool
net_write_command(NET *net,uchar command,
- const char *header, ulong head_len,
- const char *packet, ulong len)
+ const uchar *header, size_t head_len,
+ const uchar *packet, size_t len)
{
ulong length=len+1+head_len; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
@@ -446,7 +449,7 @@ net_write_command(NET *net,uchar command,
{
int3store(buff, MAX_PACKET_LENGTH);
buff[3]= (uchar) net->pkt_nr++;
- if (net_write_buff(net,(char*) buff, header_size) ||
+ if (net_write_buff(net, buff, header_size) ||
net_write_buff(net, header, head_len) ||
net_write_buff(net, packet, len))
DBUG_RETURN(1);
@@ -460,9 +463,9 @@ net_write_command(NET *net,uchar command,
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- DBUG_RETURN(test(net_write_buff(net, (char*) buff, header_size) ||
- (head_len && net_write_buff(net, (char*) header, head_len)) ||
- net_write_buff(net, packet, len) || net_flush(net)));
+ DBUG_RETURN(test(net_write_buff(net, buff, header_size) ||
+ (head_len && net_write_buff(net, header, head_len)) ||
+ net_write_buff(net, packet, len) || net_flush(net)));
}
/*
@@ -495,7 +498,7 @@ net_write_command(NET *net,uchar command,
*/
static my_bool
-net_write_buff(NET *net,const char *packet,ulong len)
+net_write_buff(NET *net, const uchar *packet, ulong len)
{
ulong left_length;
if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
@@ -512,8 +515,8 @@ net_write_buff(NET *net,const char *packet,ulong len)
{
/* Fill up already used packet and write it */
memcpy((char*) net->write_pos,packet,left_length);
- if (net_real_write(net,(char*) net->buff,
- (ulong) (net->write_pos - net->buff) + left_length))
+ if (net_real_write(net, net->buff,
+ (size_t) (net->write_pos - net->buff) + left_length))
return 1;
net->write_pos= net->buff;
packet+= left_length;
@@ -550,10 +553,10 @@ net_write_buff(NET *net,const char *packet,ulong len)
*/
int
-net_real_write(NET *net,const char *packet,ulong len)
+net_real_write(NET *net,const uchar *packet, size_t len)
{
- long int length;
- char *pos,*end;
+ size_t length;
+ const uchar *pos,*end;
thr_alarm_t alarmed;
#ifndef NO_ALARM
ALARM alarm_buff;
@@ -563,7 +566,7 @@ net_real_write(NET *net,const char *packet,ulong len)
DBUG_ENTER("net_real_write");
#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
- query_cache_insert(net, packet, len);
+ query_cache_insert(net, (char*) packet, len);
#endif
if (net->error == 2)
@@ -573,11 +576,11 @@ net_real_write(NET *net,const char *packet,ulong len)
#ifdef HAVE_COMPRESS
if (net->compress)
{
- ulong complen;
+ size_t complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
- if (!(b=(uchar*) my_malloc((uint32) len + NET_HEADER_SIZE +
- COMP_HEADER_SIZE, MYF(MY_WME))))
+ if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
+ COMP_HEADER_SIZE, MYF(MY_WME))))
{
#ifdef MYSQL_SERVER
net->last_errno= ER_OUT_OF_RESOURCES;
@@ -590,34 +593,38 @@ net_real_write(NET *net,const char *packet,ulong len)
}
memcpy(b+header_length,packet,len);
- if (my_compress((byte*) b+header_length,&len,&complen))
+ if (my_compress(b+header_length, &len, &complen))
complen=0;
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
b[3]=(uchar) (net->compress_pkt_nr++);
len+= header_length;
- packet= (char*) b;
+ packet= b;
}
#endif /* HAVE_COMPRESS */
- /* DBUG_DUMP("net",packet,len); */
+#ifdef DEBUG_DATA_PACKETS
+ DBUG_DUMP("data", packet, len);
+#endif
+
#ifndef NO_ALARM
thr_alarm_init(&alarmed);
if (net_blocking)
thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
#else
alarmed=0;
- vio_timeout(net->vio, 1, net->write_timeout);
+ /* Write timeout is set in net_set_write_timeout */
#endif /* NO_ALARM */
- pos=(char*) packet; end=pos+len;
+ pos= packet;
+ end=pos+len;
while (pos != end)
{
- if ((long) (length=vio_write(net->vio,pos,(uint32) (end-pos))) <= 0)
+ if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
#if !defined(__WIN__)
- if ((interrupted || length==0) && !thr_alarm_in_use(&alarmed))
+ if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
{
if (!thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff))
{ /* Always true for client */
@@ -696,14 +703,14 @@ net_real_write(NET *net,const char *packet,ulong len)
#ifndef NO_ALARM
-static my_bool net_safe_read(NET *net, char *buff, uint32 length,
+static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
thr_alarm_t *alarmed)
{
uint retry_count=0;
while (length > 0)
{
- int tmp;
- if ((tmp=vio_read(net->vio,(char*) net->buff, length)) <= 0)
+ size_t tmp;
+ if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
if (!thr_got_alarm(alarmed) && interrupted)
@@ -714,6 +721,7 @@ static my_bool net_safe_read(NET *net, char *buff, uint32 length,
return 1;
}
length-= tmp;
+ buff+= tmp;
}
return 0;
}
@@ -754,15 +762,15 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
{
while (remain > 0)
{
- uint length= min(remain, net->max_packet);
- if (net_safe_read(net, (char*) net->buff, length, alarmed))
+ size_t length= min(remain, net->max_packet);
+ if (net_safe_read(net, net->buff, length, alarmed))
DBUG_RETURN(1);
update_statistics(thd_increment_bytes_received(length));
remain -= (uint32) length;
}
if (old != MAX_PACKET_LENGTH)
break;
- if (net_safe_read(net, (char*) net->buff, NET_HEADER_SIZE, alarmed))
+ if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
DBUG_RETURN(1);
old=remain= uint3korr(net->buff);
net->pkt_nr++;
@@ -779,10 +787,10 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
*/
static ulong
-my_real_read(NET *net, ulong *complen)
+my_real_read(NET *net, size_t *complen)
{
uchar *pos;
- long length;
+ size_t length;
uint i,retry_count=0;
ulong len=packet_error;
thr_alarm_t alarmed;
@@ -800,7 +808,7 @@ my_real_read(NET *net, ulong *complen)
if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
#else
- vio_timeout(net->vio, 0, net->read_timeout);
+ /* Read timeout is set in net_set_read_timeout */
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
@@ -809,12 +817,12 @@ my_real_read(NET *net, ulong *complen)
while (remain > 0)
{
/* First read is done with non blocking mode */
- if ((int) (length=vio_read(net->vio,(char*) pos,remain)) <= 0L)
+ if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
{
my_bool interrupted = vio_should_retry(net->vio);
- DBUG_PRINT("info",("vio_read returned %ld, errno: %d",
- length, vio_errno(net->vio)));
+ DBUG_PRINT("info",("vio_read returned %ld errno: %d",
+ (long) length, vio_errno(net->vio)));
#if !defined(__WIN__) || defined(MYSQL_SERVER)
/*
We got an error that there was no data on the socket. We now set up
@@ -870,7 +878,7 @@ my_real_read(NET *net, ulong *complen)
}
#endif
DBUG_PRINT("error",("Couldn't read packet: remain: %u errno: %d length: %ld",
- remain, vio_errno(net->vio), length));
+ remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2; /* Close socket */
net->report_error= 1;
@@ -881,13 +889,13 @@ my_real_read(NET *net, ulong *complen)
goto end;
}
remain -= (uint32) length;
- pos+= (ulong) length;
+ pos+= length;
update_statistics(thd_increment_bytes_received(length));
}
if (i == 0)
{ /* First parts is packet length */
ulong helping;
- DBUG_DUMP("packet_header",(char*) net->buff+net->where_b,
+ DBUG_DUMP("packet_header", net->buff+net->where_b,
NET_HEADER_SIZE);
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
{
@@ -898,9 +906,12 @@ my_real_read(NET *net, ulong *complen)
(int) net->buff[net->where_b + 3],
net->pkt_nr));
#ifdef EXTRA_DEBUG
+ fflush(stdout);
fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
(int) net->buff[net->where_b + 3],
(uint) (uchar) net->pkt_nr);
+ fflush(stderr);
+ DBUG_ASSERT(0);
#endif
}
len= packet_error;
@@ -955,7 +966,7 @@ end:
net->reading_or_writing=0;
#ifdef DEBUG_DATA_PACKETS
if (len != packet_error)
- DBUG_DUMP("data",(char*) net->buff+net->where_b, len);
+ DBUG_DUMP("data", net->buff+net->where_b, len);
#endif
return(len);
}
@@ -977,7 +988,7 @@ end:
ulong
my_net_read(NET *net)
{
- ulong len,complen;
+ size_t len, complen;
#ifdef HAVE_COMPRESS
if (!net->compress)
@@ -988,7 +999,7 @@ my_net_read(NET *net)
{
/* First packet of a multi-packet. Concatenate the packets */
ulong save_pos = net->where_b;
- ulong total_length=0;
+ size_t total_length= 0;
do
{
net->where_b += len;
@@ -1086,7 +1097,7 @@ my_net_read(NET *net)
net->where_b=buf_length;
if ((packet_len = my_real_read(net,&complen)) == packet_error)
return packet_error;
- if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
+ if (my_uncompress(net->buff + net->where_b, packet_len,
&complen))
{
net->error= 2; /* caller will close socket */
@@ -1096,7 +1107,7 @@ my_net_read(NET *net)
#endif
return packet_error;
}
- buf_length+=packet_len;
+ buf_length+= complen;
}
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
@@ -1111,3 +1122,26 @@ my_net_read(NET *net)
return len;
}
+
+void net_set_read_timeout(NET *net, uint timeout)
+{
+ DBUG_ENTER("net_set_read_timeout");
+ DBUG_PRINT("enter", ("timeout: %d", timeout));
+ net->read_timeout= timeout;
+#ifdef NO_ALARM
+ vio_timeout(net->vio, 0, timeout);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+void net_set_write_timeout(NET *net, uint timeout)
+{
+ DBUG_ENTER("net_set_write_timeout");
+ DBUG_PRINT("enter", ("timeout: %d", timeout));
+ net->write_timeout= timeout;
+#ifdef NO_ALARM
+ vio_timeout(net->vio, 1, timeout);
+#endif
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index fa575e73c39..4944c994d3d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -81,11 +80,11 @@
*/
#define double2rows(x) ((ha_rows)(x))
-static int sel_cmp(Field *f,char *a,char *b,uint8 a_flag,uint8 b_flag);
-
-static char is_null_string[2]= {1,0};
+static int sel_cmp(Field *f,uchar *a,uchar *b,uint8 a_flag,uint8 b_flag);
+static uchar is_null_string[2]= {1,0};
+class RANGE_OPT_PARAM;
/*
A construction block of the SEL_ARG-graph.
@@ -171,6 +170,89 @@ static char is_null_string[2]= {1,0};
- get_quick_select() - Walk the SEL_ARG, materialize the key intervals,
and create QUICK_RANGE_SELECT object that will
read records within these intervals.
+
+ 4. SPACE COMPLEXITY NOTES
+
+ SEL_ARG graph is a representation of an ordered disjoint sequence of
+ intervals over the ordered set of index tuple values.
+
+ For multi-part keys, one can construct a WHERE expression such that its
+ list of intervals will be of combinatorial size. Here is an example:
+
+ (keypart1 IN (1,2, ..., n1)) AND
+ (keypart2 IN (1,2, ..., n2)) AND
+ (keypart3 IN (1,2, ..., n3))
+
+ For this WHERE clause the list of intervals will have n1*n2*n3 intervals
+ of form
+
+ (keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i}
+
+ SEL_ARG graph structure aims to reduce the amount of required space by
+ "sharing" the elementary intervals when possible (the pic at the
+ beginning of this comment has examples of such sharing). The sharing may
+ prevent combinatorial blowup:
+
+ There are WHERE clauses that have combinatorial-size interval lists but
+ will be represented by a compact SEL_ARG graph.
+ Example:
+ (keypartN IN (1,2, ..., n1)) AND
+ ...
+ (keypart2 IN (1,2, ..., n2)) AND
+ (keypart1 IN (1,2, ..., n3))
+
+ but not in all cases:
+
+ - There are WHERE clauses that do have a compact SEL_ARG-graph
+ representation but get_mm_tree() and its callees will construct a
+ graph of combinatorial size.
+ Example:
+ (keypart1 IN (1,2, ..., n1)) AND
+ (keypart2 IN (1,2, ..., n2)) AND
+ ...
+ (keypartN IN (1,2, ..., n3))
+
+ - There are WHERE clauses for which the minimal possible SEL_ARG graph
+ representation will have combinatorial size.
+ Example:
+ By induction: Let's take any interval on some keypart in the middle:
+
+ kp15=c0
+
+ Then let's AND it with this interval 'structure' from preceding and
+ following keyparts:
+
+ (kp14=c1 AND kp16=c3) OR keypart14=c2) (*)
+
+ We will obtain this SEL_ARG graph:
+
+ kp14 $ kp15 $ kp16
+ $ $
+ +---------+ $ +---------+ $ +---------+
+ | kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 |
+ +---------+ $ +---------+ $ +---------+
+ | $ $
+ +---------+ $ +---------+ $
+ | kp14=c2 |--$-->| kp15=c0 | $
+ +---------+ $ +---------+ $
+ $ $
+
+ Note that we had to duplicate "kp15=c0" and there was no way to avoid
+ that.
+ The induction step: AND the obtained expression with another "wrapping"
+ expression like (*).
+ When the process ends because of the limit on max. number of keyparts
+ we'll have:
+
+ WHERE clause length is O(3*#max_keyparts)
+ SEL_ARG graph size is O(2^(#max_keyparts/2))
+
+ (it is also possible to construct a case where instead of 2 in 2^n we
+ have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31
+ nodes)
+
+ We avoid consuming too much memory by setting a limit on the number of
+ SEL_ARG object we can construct during one range analysis invocation.
*/
class SEL_ARG :public Sql_alloc
@@ -192,7 +274,7 @@ public:
ulong use_count;
Field *field;
- char *min_value,*max_value; // Pointer to range
+ uchar *min_value,*max_value; // Pointer to range
SEL_ARG *left,*right; /* R-B tree children */
SEL_ARG *next,*prev; /* Links for bi-directional interval list */
@@ -201,10 +283,12 @@ public:
enum leaf_color { BLACK,RED } color;
enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type;
+ enum { MAX_SEL_ARGS = 16000 };
+
SEL_ARG() {}
SEL_ARG(SEL_ARG &);
- SEL_ARG(Field *,const char *,const char *);
- SEL_ARG(Field *field, uint8 part, char *min_value, char *max_value,
+ SEL_ARG(Field *,const uchar *, const uchar *);
+ SEL_ARG(Field *field, uint8 part, uchar *min_value, uchar *max_value,
uint8 min_flag, uint8 max_flag, uint8 maybe_flag);
SEL_ARG(enum Type type_arg)
:min_flag(0),elements(1),use_count(1),left(0),next_key_part(0),
@@ -220,6 +304,8 @@ public:
}
inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; }
inline void maybe_smaller() { maybe_flag=1; }
+ /* Return true iff it's a single-point null interval */
+ inline bool is_null_interval() { return maybe_null && max_value[0] == 1; }
inline int cmp_min_to_min(SEL_ARG* arg)
{
return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag);
@@ -238,7 +324,7 @@ public:
}
SEL_ARG *clone_and(SEL_ARG* arg)
{ // Get overlapping range
- char *new_min,*new_max;
+ uchar *new_min,*new_max;
uint8 flag_min,flag_max;
if (cmp_min_to_min(arg) >= 0)
{
@@ -270,7 +356,7 @@ public:
return new SEL_ARG(field, part, min_value, arg->max_value,
min_flag, arg->max_flag, maybe_flag | arg->maybe_flag);
}
- SEL_ARG *clone(SEL_ARG *new_parent,SEL_ARG **next);
+ SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next);
bool copy_min(SEL_ARG* arg)
{ // Get overlapping range
@@ -311,7 +397,8 @@ public:
min_value=arg->max_value;
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN;
}
- void store_min(uint length,char **min_key,uint min_key_flag)
+ /* returns a number of keypart values (0 or 1) appended to the key buffer */
+ int store_min(uint length, uchar **min_key,uint min_key_flag)
{
if ((min_flag & GEOM_FLAG) ||
(!(min_flag & NO_MIN_RANGE) &&
@@ -325,12 +412,13 @@ public:
else
memcpy(*min_key,min_value,length);
(*min_key)+= length;
+ return 1;
}
+ return 0;
}
- void store(uint length,char **min_key,uint min_key_flag,
- char **max_key, uint max_key_flag)
+ /* returns a number of keypart values (0 or 1) appended to the key buffer */
+ int store_max(uint length, uchar **max_key, uint max_key_flag)
{
- store_min(length, min_key, min_key_flag);
if (!(max_flag & NO_MAX_RANGE) &&
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
{
@@ -342,33 +430,41 @@ public:
else
memcpy(*max_key,max_value,length);
(*max_key)+= length;
+ return 1;
}
+ return 0;
}
- void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
+ /* returns a number of keypart values appended to the key buffer */
+ int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= first();
- key_tree->store(key[key_tree->part].store_length,
- range_key,*range_key_flag,range_key,NO_MAX_RANGE);
+ uint res= key_tree->store_min(key[key_tree->part].store_length,
+ range_key, *range_key_flag);
*range_key_flag|= key_tree->min_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
- key_tree->next_key_part->store_min_key(key,range_key, range_key_flag);
+ res+= key_tree->next_key_part->store_min_key(key, range_key,
+ range_key_flag);
+ return res;
}
- void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
+ /* returns a number of keypart values appended to the key buffer */
+ int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= last();
- key_tree->store(key[key_tree->part].store_length,
- range_key, NO_MIN_RANGE, range_key,*range_key_flag);
+ uint res=key_tree->store_max(key[key_tree->part].store_length,
+ range_key, *range_key_flag);
(*range_key_flag)|= key_tree->max_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
- key_tree->next_key_part->store_max_key(key,range_key, range_key_flag);
+ res+= key_tree->next_key_part->store_max_key(key, range_key,
+ range_key_flag);
+ return res;
}
SEL_ARG *insert(SEL_ARG *key);
@@ -412,7 +508,6 @@ public:
{
return parent->left == this ? &parent->left : &parent->right;
}
- SEL_ARG *clone_tree();
/*
@@ -439,8 +534,8 @@ public:
*/
if (min_flag || max_flag)
return FALSE;
- byte *min_val= (byte *)min_value;
- byte *max_val= (byte *)max_value;
+ uchar *min_val= min_value;
+ uchar *max_val= max_value;
if (maybe_null)
{
@@ -455,6 +550,7 @@ public:
}
return !field->key_cmp(min_val, max_val);
}
+ SEL_ARG *clone_tree(RANGE_OPT_PARAM *param);
};
class SEL_IMERGE;
@@ -534,6 +630,8 @@ public:
using_real_indexes==TRUE
*/
uint real_keynr[MAX_KEY];
+ /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */
+ uint alloced_sel_args;
};
class PARAM : public RANGE_OPT_PARAM
@@ -543,8 +641,7 @@ public:
longlong baseflag;
uint max_key_part, range_count;
-
- char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
+ uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
bool quick; // Don't calulate possible keys
@@ -561,6 +658,7 @@ public:
bool is_ror_scan;
/* Number of ranges in the last checked tree->key */
uint n_ranges;
+ uint8 first_null_comp; /* first null component if any, 0 - otherwise */
};
class TABLE_READ_PLAN;
@@ -581,11 +679,11 @@ static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond);
static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
-static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree,
+static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree,
bool update_tbl_stats);
static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
- char *min_key,uint min_key_flag,
- char *max_key, uint max_key_flag);
+ uchar *min_key, uint min_key_flag, int,
+ uchar *max_key, uint max_key_flag, int);
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree,
@@ -607,9 +705,6 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double read_time);
static
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
-static int get_index_merge_params(PARAM *param, key_map& needed_reg,
- SEL_IMERGE *imerge, double *read_time,
- ha_rows* imerge_rows);
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
@@ -619,23 +714,23 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
static void print_ror_scans_arr(TABLE *table, const char *msg,
struct st_ror_scan_info **start,
struct st_ror_scan_info **end);
-static void print_rowid(byte* val, int len);
static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
#endif
static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2);
-static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2);
-static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag);
+static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2);
+static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2,
+ uint clone_flag);
static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1);
bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
- SEL_ARG *key_tree,char *min_key,uint min_key_flag,
- char *max_key,uint max_key_flag);
+ SEL_ARG *key_tree, uchar *min_key,uint min_key_flag,
+ uchar *max_key,uint max_key_flag);
static bool eq_tree(SEL_ARG* a,SEL_ARG *b);
static SEL_ARG null_element(SEL_ARG::IMPOSSIBLE);
-static bool null_part_in_key(KEY_PART *key_part, const char *key,
+static bool null_part_in_key(KEY_PART *key_part, const uchar *key,
uint length);
bool sel_trees_can_be_ored(SEL_TREE *tree1, SEL_TREE *tree2, RANGE_OPT_PARAM* param);
@@ -852,6 +947,7 @@ int imerge_list_or_tree(RANGE_OPT_PARAM *param,
return im1->is_empty();
}
+
/***************************************************************************
** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT
***************************************************************************/
@@ -889,7 +985,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
select->file= *head->sort.io_cache;
select->records=(ha_rows) (select->file.end_of_file/
head->file->ref_length);
- my_free((gptr) (head->sort.io_cache),MYF(0));
+ my_free(head->sort.io_cache, MYF(0));
head->sort.io_cache=0;
}
DBUG_RETURN(select);
@@ -931,7 +1027,7 @@ QUICK_SELECT_I::QUICK_SELECT_I()
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
bool no_alloc, MEM_ROOT *parent_alloc)
- :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),range(0)
+ :dont_free(0),error(0),free_file(0),in_range(0),cur_range(NULL),last_range(0)
{
my_bitmap_map *bitmap;
DBUG_ENTER("QUICK_RANGE_SELECT::QUICK_RANGE_SELECT");
@@ -1002,6 +1098,11 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
if (file)
{
range_end();
+ if (head->key_read)
+ {
+ head->key_read= 0;
+ file->extra(HA_EXTRA_NO_KEYREAD);
+ }
if (free_file)
{
DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file,
@@ -1010,10 +1111,6 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
file->close();
delete file;
}
- else
- {
- file->extra(HA_EXTRA_NO_KEYREAD);
- }
}
delete_dynamic(&ranges); /* ranges are allocated in alloc */
free_root(&alloc,MYF(0));
@@ -1094,8 +1191,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
else
bzero(&alloc, sizeof(MEM_ROOT));
- last_rowid= (byte*)alloc_root(parent_alloc? parent_alloc : &alloc,
- head->file->ref_length);
+ last_rowid= (uchar*) alloc_root(parent_alloc? parent_alloc : &alloc,
+ head->file->ref_length);
}
@@ -1195,7 +1292,11 @@ end:
org_file= head->file;
head->file= file;
/* We don't have to set 'head->keyread' here as the 'file' is unique */
- head->mark_columns_used_by_index(index);
+ if (!head->no_keyread)
+ {
+ head->key_read= 1;
+ head->mark_columns_used_by_index(index);
+ }
head->prepare_for_position();
head->file= org_file;
bitmap_copy(&column_bitmap, head->read_set);
@@ -1348,7 +1449,7 @@ int QUICK_ROR_UNION_SELECT::init()
DBUG_RETURN(1);
}
- if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length)))
+ if (!(cur_rowid= (uchar*) alloc_root(&alloc, 2*head->file->ref_length)))
DBUG_RETURN(1);
prev_rowid= cur_rowid + head->file->ref_length;
DBUG_RETURN(0);
@@ -1366,7 +1467,7 @@ int QUICK_ROR_UNION_SELECT::init()
val2 Second merged select
*/
-int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, byte *val1, byte *val2)
+int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, uchar *val1, uchar *val2)
{
QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg;
return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid,
@@ -1386,13 +1487,12 @@ int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, byte *val1, byte *val2)
int QUICK_ROR_UNION_SELECT::reset()
{
- QUICK_SELECT_I* quick;
+ QUICK_SELECT_I *quick;
int error;
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
have_prev_rowid= FALSE;
if (!scans_inited)
{
- QUICK_SELECT_I *quick;
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
@@ -1418,7 +1518,7 @@ int QUICK_ROR_UNION_SELECT::reset()
DBUG_RETURN(error);
}
quick->save_last_pos();
- queue_insert(&queue, (byte*)quick);
+ queue_insert(&queue, (uchar*)quick);
}
if (head->file->ha_rnd_init(1))
@@ -1451,7 +1551,8 @@ QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT()
QUICK_RANGE::QUICK_RANGE()
:min_key(0),max_key(0),min_length(0),max_length(0),
- flag(NO_MIN_RANGE | NO_MAX_RANGE)
+ flag(NO_MIN_RANGE | NO_MAX_RANGE),
+ min_keypart_map(0), max_keypart_map(0)
{}
SEL_ARG::SEL_ARG(SEL_ARG &arg) :Sql_alloc()
@@ -1478,16 +1579,18 @@ inline void SEL_ARG::make_root()
use_count=0; elements=1;
}
-SEL_ARG::SEL_ARG(Field *f,const char *min_value_arg,const char *max_value_arg)
+SEL_ARG::SEL_ARG(Field *f,const uchar *min_value_arg,
+ const uchar *max_value_arg)
:min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()),
- elements(1), use_count(1), field(f), min_value((char*) min_value_arg),
- max_value((char*) max_value_arg), next(0),prev(0),
+ elements(1), use_count(1), field(f), min_value((uchar*) min_value_arg),
+ max_value((uchar*) max_value_arg), next(0),prev(0),
next_key_part(0),color(BLACK),type(KEY_RANGE)
{
left=right= &null_element;
}
-SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_,
+SEL_ARG::SEL_ARG(Field *field_,uint8 part_,
+ uchar *min_value_, uchar *max_value_,
uint8 min_flag_,uint8 max_flag_,uint8 maybe_flag_)
:min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_),
part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1),
@@ -1497,12 +1600,18 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_,
left=right= &null_element;
}
-SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
+SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
+ SEL_ARG **next_arg)
{
SEL_ARG *tmp;
+
+ /* Bail out if we have already generated too many SEL_ARGs */
+ if (++param->alloced_sel_args > MAX_SEL_ARGS)
+ return 0;
+
if (type != KEY_RANGE)
{
- if (!(tmp= new SEL_ARG(type)))
+ if (!(tmp= new (param->mem_root) SEL_ARG(type)))
return 0; // out of memory
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
@@ -1510,20 +1619,21 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
}
else
{
- if (!(tmp= new SEL_ARG(field,part, min_value,max_value,
- min_flag, max_flag, maybe_flag)))
+ if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value,
+ min_flag, max_flag, maybe_flag)))
return 0; // OOM
tmp->parent=new_parent;
tmp->next_key_part=next_key_part;
if (left != &null_element)
- tmp->left=left->clone(tmp,next_arg);
+ if (!(tmp->left=left->clone(param, tmp, next_arg)))
+ return 0; // OOM
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
(*next_arg)= tmp;
if (right != &null_element)
- if (!(tmp->right= right->clone(tmp,next_arg)))
+ if (!(tmp->right= right->clone(param, tmp, next_arg)))
return 0; // OOM
}
increment_use_count(1);
@@ -1558,7 +1668,8 @@ SEL_ARG *SEL_ARG::last()
Returns -2 or 2 if the ranges where 'joined' like < 2 and >= 2
*/
-static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
+static int sel_cmp(Field *field, uchar *a, uchar *b, uint8 a_flag,
+ uint8 b_flag)
{
int cmp;
/* First check if there was a compare to a min or max element */
@@ -1582,7 +1693,7 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
goto end; // NULL where equal
a++; b++; // Skip NULL marker
}
- cmp=field->key_cmp((byte*) a,(byte*) b);
+ cmp=field->key_cmp(a , b);
if (cmp) return cmp < 0 ? -1 : 1; // The values differed
// Check if the compared equal arguments was defined with open/closed range
@@ -1601,11 +1712,12 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag)
}
-SEL_ARG *SEL_ARG::clone_tree()
+SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param)
{
SEL_ARG tmp_link,*next_arg,*root;
next_arg= &tmp_link;
- root= clone((SEL_ARG *) 0, &next_arg);
+ if (!(root= clone(param, (SEL_ARG *) 0, &next_arg)))
+ return 0;
next_arg->next=0; // Fix last link
tmp_link.next->prev=0; // Fix first link
if (root) // If not OOM
@@ -1860,7 +1972,7 @@ private:
KEY *index_info;
uint index;
uint key_infix_len;
- byte key_infix[MAX_KEY_LENGTH];
+ uchar key_infix[MAX_KEY_LENGTH];
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
uint param_idx; /* Index of used key in param->key. */
@@ -1873,7 +1985,7 @@ public:
uint group_prefix_len_arg, uint used_key_parts_arg,
uint group_key_parts_arg, KEY *index_info_arg,
uint index_arg, uint key_infix_len_arg,
- byte *key_infix_arg,
+ uchar *key_infix_arg,
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
uint param_idx_arg, ha_rows quick_prefix_records_arg)
: have_min(have_min_arg), have_max(have_max_arg),
@@ -2107,11 +2219,12 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.real_keynr[param.keys++]=idx;
}
param.key_parts_end=key_parts;
+ param.alloced_sel_args= 0;
/* Calculate cost of full index read for the shortest covering index */
- if (!head->used_keys.is_clear_all())
+ if (!head->covering_keys.is_clear_all())
{
- int key_for_use= find_shortest_key(head, &head->used_keys);
+ int key_for_use= find_shortest_key(head, &head->covering_keys);
double key_read_time= (get_index_only_read_time(&param, records,
key_for_use) +
(double) records / TIME_FOR_COMPARE);
@@ -2421,8 +2534,6 @@ static int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar,
static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar,
List<SEL_IMERGE> &merges);
static void mark_all_partitions_as_used(partition_info *part_info);
-static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* prune_par,
- uint32 num);
#ifndef DBUG_OFF
static void print_partitioning_index(KEY_PART *parts, KEY_PART *parts_end);
@@ -2501,6 +2612,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
range_par->using_real_indexes= FALSE;
range_par->remove_jump_scans= FALSE;
range_par->real_keynr[0]= 0;
+ range_par->alloced_sel_args= 0;
thd->no_errors=1; // Don't warn about NULL
thd->mem_root=&alloc;
@@ -2604,7 +2716,7 @@ end:
format.
*/
-void store_key_image_to_rec(Field *field, char *ptr, uint len)
+void store_key_image_to_rec(Field *field, uchar *ptr, uint len)
{
/* Do the same as print_key() does */
my_bitmap_map *old_map;
@@ -3132,7 +3244,7 @@ static bool fields_ok_for_partition_index(Field **pfield)
for (; (*pfield); pfield++)
{
enum_field_types ftype= (*pfield)->real_type();
- if (ftype == FIELD_TYPE_ENUM || ftype == FIELD_TYPE_GEOMETRY)
+ if (ftype == MYSQL_TYPE_ENUM || ftype == MYSQL_TYPE_GEOMETRY)
return FALSE;
}
return TRUE;
@@ -3231,7 +3343,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
key_part->store_length= (uint16) (*field)->pack_length();
if ((*field)->real_maybe_null())
key_part->store_length+= HA_KEY_NULL_LENGTH;
- if ((*field)->type() == FIELD_TYPE_BLOB ||
+ if ((*field)->type() == MYSQL_TYPE_BLOB ||
(*field)->real_type() == MYSQL_TYPE_VARCHAR)
key_part->store_length+= HA_KEY_BLOB_LENGTH;
@@ -3306,7 +3418,7 @@ static void dbug_print_segment_range(SEL_ARG *arg, KEY_PART *part)
DBUG_LOCK_FILE;
if (!(arg->min_flag & NO_MIN_RANGE))
{
- store_key_image_to_rec(part->field, (char*)(arg->min_value), part->length);
+ store_key_image_to_rec(part->field, arg->min_value, part->length);
dbug_print_field(part->field);
if (arg->min_flag & NEAR_MIN)
fputs(" < ", DBUG_FILE);
@@ -3322,7 +3434,7 @@ static void dbug_print_segment_range(SEL_ARG *arg, KEY_PART *part)
fputs(" < ", DBUG_FILE);
else
fputs(" <= ", DBUG_FILE);
- store_key_image_to_rec(part->field, (char*)(arg->max_value), part->length);
+ store_key_image_to_rec(part->field, arg->max_value, part->length);
dbug_print_field(part->field);
}
fputs("\n", DBUG_FILE);
@@ -4031,9 +4143,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
The calculation is conducted as follows:
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
- n_{k1} n_{k_2}
+ n_{k1} n_{k2}
--------- * --------- * .... (3)
- n_{k1-1} n_{k2_1}
+ n_{k1-1} n_{k2-1}
where k1,k2,... are key parts which fields were not yet marked as fixed
( this is result of application of option b) of the recursion step for
@@ -4041,9 +4153,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
Since it is reasonable to expect that most of the fields are not marked
as fixed, we calculate (3) as
- n_{i1} n_{i_2}
+ n_{i1} n_{i2}
(3) = n_{max_key_part} / ( --------- * --------- * .... )
- n_{i1-1} n_{i2_1}
+ n_{i1-1} n_{i2-1}
where i1,i2, .. are key parts that were already marked as fixed.
@@ -4052,7 +4164,6 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
RETURN
Selectivity of given ROR scan.
-
*/
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
@@ -4060,20 +4171,21 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
{
double selectivity_mult= 1.0;
KEY_PART_INFO *key_part= info->param->table->key_info[scan->keynr].key_part;
- byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */
- char *key_ptr= (char*) key_val;
+ uchar key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */
+ uchar *key_ptr= key_val;
SEL_ARG *sel_arg, *tuple_arg= NULL;
+ key_part_map keypart_map= 0;
bool cur_covered;
bool prev_covered= test(bitmap_is_set(&info->covered_fields,
key_part->fieldnr-1));
key_range min_range;
key_range max_range;
- min_range.key= (byte*) key_val;
+ min_range.key= key_val;
min_range.flag= HA_READ_KEY_EXACT;
- max_range.key= (byte*) key_val;
+ max_range.key= key_val;
max_range.flag= HA_READ_AFTER_KEY;
ha_rows prev_records= info->param->table->file->stats.records;
- DBUG_ENTER("ror_intersect_selectivity");
+ DBUG_ENTER("ror_scan_selectivity");
for (sel_arg= scan->sel_arg; sel_arg;
sel_arg= sel_arg->next_key_part)
@@ -4090,13 +4202,17 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
tuple_arg= scan->sel_arg;
/* Here we use the length of the first key part */
tuple_arg->store_min(key_part->store_length, &key_ptr, 0);
+ keypart_map= 1;
}
while (tuple_arg->next_key_part != sel_arg)
{
tuple_arg= tuple_arg->next_key_part;
- tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0);
+ tuple_arg->store_min(key_part[tuple_arg->part].store_length,
+ &key_ptr, 0);
+ keypart_map= (keypart_map << 1) | 1;
}
- min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
+ min_range.length= max_range.length= (size_t) (key_ptr - key_val);
+ min_range.keypart_map= max_range.keypart_map= keypart_map;
records= (info->param->table->file->
records_in_range(scan->keynr, &min_range, &max_range));
if (cur_covered)
@@ -4646,7 +4762,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
param->needed_reg->set_bit(keynr);
bool read_index_only= index_read_must_be_used ? TRUE :
- (bool) param->table->used_keys.is_set(keynr);
+ (bool) param->table->covering_keys.is_set(keynr);
found_records= check_quick_select(param, idx, *key, update_tbl_stats);
if (param->is_ror_scan)
@@ -4683,8 +4799,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
param->table->key_info[keynr].name, found_read_time,
read_time));
- if (read_time > found_read_time && found_records != HA_POS_ERROR
- /*|| read_time == DBL_MAX*/ )
+ if (read_time > found_read_time && found_records != HA_POS_ERROR)
{
read_time= found_read_time;
best_records= found_records;
@@ -4924,8 +5039,8 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
type. Tree won't be built for values with different result types,
so we check it here to avoid unnecessary work.
*/
- if (!func->array)
- break;
+ if (!func->arg_types_compatible)
+ break;
if (inv)
{
@@ -5012,7 +5127,8 @@ static SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, Item_func *cond_func,
for (uint idx= 0; idx < param->keys; idx++)
{
SEL_ARG *new_interval, *last_val;
- if (((new_interval= tree2->keys[idx])) &&
+ if (((new_interval= tree2->keys[idx])) &&
+ (tree->keys[idx]) &&
((last_val= tree->keys[idx]->last())))
{
new_interval->min_value= last_val->max_value;
@@ -5227,7 +5343,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
while ((item=li++))
{
SEL_TREE *new_tree=get_mm_tree(param,item);
- if (param->thd->is_fatal_error)
+ if (param->thd->is_fatal_error ||
+ param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS)
DBUG_RETURN(0); // out of memory
tree=tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
@@ -5305,12 +5422,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
*/
for (uint i= 1 ; i < cond_func->arg_count ; i++)
{
-
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
{
field_item= (Item_field*) (cond_func->arguments()[i]->real_item());
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
- field_item, (Item*) i, inv);
+ field_item, (Item*)(intptr)i, inv);
if (inv)
tree= !tree ? tmp : tree_or(param, tree, tmp);
else
@@ -5435,7 +5551,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
bool optimize_range;
SEL_ARG *tree= 0;
MEM_ROOT *alloc= param->mem_root;
- char *str;
+ uchar *str;
ulong orig_sql_mode;
int err;
DBUG_ENTER("get_mm_leaf");
@@ -5497,9 +5613,10 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
if (type == Item_func::LIKE_FUNC)
{
bool like_error;
- char buff1[MAX_FIELD_WIDTH],*min_str,*max_str;
+ char buff1[MAX_FIELD_WIDTH];
+ uchar *min_str,*max_str;
String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
- uint length,offset,min_length,max_length;
+ size_t length, offset, min_length, max_length;
uint field_length= field->pack_length()+maybe_null;
if (!optimize_range)
@@ -5546,7 +5663,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
field_length= length;
}
length+=offset;
- if (!(min_str= (char*) alloc_root(alloc, length*2)))
+ if (!(min_str= (uchar*) alloc_root(alloc, length*2)))
goto end;
max_str=min_str+length;
@@ -5559,7 +5676,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
((Item_func_like*)(param->cond))->escape,
wild_one, wild_many,
field_length,
- min_str+offset, max_str+offset,
+ (char*) min_str+offset, (char*) max_str+offset,
&min_length, &max_length);
if (like_error) // Can't optimize with LIKE
goto end;
@@ -5589,13 +5706,28 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
/* For comparison purposes allow invalid dates like 2000-01-32 */
orig_sql_mode= field->table->in_use->variables.sql_mode;
if (value->real_item()->type() == Item::STRING_ITEM &&
- (field->type() == FIELD_TYPE_DATE ||
- field->type() == FIELD_TYPE_DATETIME))
+ (field->type() == MYSQL_TYPE_DATE ||
+ field->type() == MYSQL_TYPE_DATETIME))
field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
err= value->save_in_field_no_warnings(field, 1);
if (err > 0 && field->cmp_type() != value->result_type())
{
- tree= 0;
+ if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) &&
+ value->result_type() == item_cmp_type(field->result_type(),
+ value->result_type()))
+
+ {
+ tree= new (alloc) SEL_ARG(field, 0, 0);
+ tree->type= SEL_ARG::IMPOSSIBLE;
+ }
+ else
+ {
+ /*
+ TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
+ for the cases like int_field > 999999999999999999999999 as well.
+ */
+ tree= 0;
+ }
goto end;
}
if (err < 0)
@@ -5606,12 +5738,13 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
goto end;
}
field->table->in_use->variables.sql_mode= orig_sql_mode;
- str= (char*) alloc_root(alloc, key_part->store_length+1);
+ str= (uchar*) alloc_root(alloc, key_part->store_length+1);
if (!str)
goto end;
if (maybe_null)
- *str= (char) field->is_real_null(); // Set to 1 if null
- field->get_key_image(str+maybe_null, key_part->length, key_part->image_type);
+ *str= (uchar) field->is_real_null(); // Set to 1 if null
+ field->get_key_image(str+maybe_null, key_part->length,
+ key_part->image_type);
if (!(tree= new (alloc) SEL_ARG(field, str, str)))
goto end; // out of memory
@@ -5789,9 +5922,9 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
tree1->type=SEL_TREE::KEY_SMALLER;
DBUG_RETURN(tree1);
}
-
key_map result_keys;
result_keys.clear_all();
+
/* Join the trees key per key */
SEL_ARG **key1,**key2,**end;
for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ;
@@ -5804,7 +5937,7 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
flag|=CLONE_KEY1_MAYBE;
if (*key2 && !(*key2)->simple_key())
flag|=CLONE_KEY2_MAYBE;
- *key1=key_and(*key1,*key2,flag);
+ *key1=key_and(param, *key1, *key2, flag);
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{
tree1->type= SEL_TREE::IMPOSSIBLE;
@@ -5812,8 +5945,8 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
}
result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG
- if (*key1)
- (*key1)->test_use_count(*key1);
+ if (*key1 && param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS)
+ (*key1)->test_use_count(*key1);
#endif
}
}
@@ -5965,13 +6098,14 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ;
key1 != end ; key1++,key2++)
{
- *key1=key_or(*key1,*key2);
+ *key1=key_or(param, *key1, *key2);
if (*key1)
{
result=tree1; // Added to tree1
result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG
- (*key1)->test_use_count(*key1);
+ if (param->alloced_sel_args < SEL_ARG::MAX_SEL_ARGS)
+ (*key1)->test_use_count(*key1);
#endif
}
}
@@ -6029,14 +6163,15 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
/* And key trees where key1->part < key2 -> part */
static SEL_ARG *
-and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
+and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2,
+ uint clone_flag)
{
SEL_ARG *next;
ulong use_count=key1->use_count;
if (key1->elements != 1)
{
- key2->use_count+=key1->elements-1;
+ key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p?
key2->increment_use_count((int) key1->elements-1);
}
if (key1->type == SEL_ARG::MAYBE_KEY)
@@ -6048,7 +6183,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
{
if (next->next_key_part)
{
- SEL_ARG *tmp=key_and(next->next_key_part,key2,clone_flag);
+ SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag);
if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE)
{
key1=key1->tree_delete(next);
@@ -6057,6 +6192,8 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
next->next_key_part=tmp;
if (use_count)
next->increment_use_count(use_count);
+ if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS)
+ break;
}
else
next->next_key_part=key2;
@@ -6073,8 +6210,10 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
SYNOPSIS
key_and()
- key1 First argument, root of its RB-tree
- key2 Second argument, root of its RB-tree
+ param Range analysis context (needed to track if we have allocated
+ too many SEL_ARGs)
+ key1 First argument, root of its RB-tree
+ key2 Second argument, root of its RB-tree
RETURN
RB-tree root of the resulting SEL_ARG graph.
@@ -6082,7 +6221,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
*/
static SEL_ARG *
-key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
+key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
{
if (!key1)
return key2;
@@ -6098,9 +6237,9 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
// key1->part < key2->part
key1->use_count--;
if (key1->use_count > 0)
- if (!(key1= key1->clone_tree()))
+ if (!(key1= key1->clone_tree(param)))
return 0; // OOM
- return and_all_keys(key1,key2,clone_flag);
+ return and_all_keys(param, key1, key2, clone_flag);
}
if (((clone_flag & CLONE_KEY2_MAYBE) &&
@@ -6118,14 +6257,14 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key1->use_count > 1)
{
key1->use_count--;
- if (!(key1=key1->clone_tree()))
+ if (!(key1=key1->clone_tree(param)))
return 0; // OOM
key1->use_count++;
}
if (key1->type == SEL_ARG::MAYBE_KEY)
{ // Both are maybe key
- key1->next_key_part=key_and(key1->next_key_part,key2->next_key_part,
- clone_flag);
+ key1->next_key_part=key_and(param, key1->next_key_part,
+ key2->next_key_part, clone_flag);
if (key1->next_key_part &&
key1->next_key_part->type == SEL_ARG::IMPOSSIBLE)
return key1;
@@ -6136,7 +6275,7 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
if (key2->next_key_part)
{
key1->use_count--; // Incremented in and_all_keys
- return and_all_keys(key1,key2,clone_flag);
+ return and_all_keys(param, key1, key2, clone_flag);
}
key2->use_count--; // Key2 doesn't have a tree
}
@@ -6172,7 +6311,8 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag)
}
else if (get_range(&e2,&e1,key2))
continue;
- SEL_ARG *next=key_and(e1->next_key_part,e2->next_key_part,clone_flag);
+ SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part,
+ clone_flag);
e1->increment_use_count(1);
e2->increment_use_count(1);
if (!next || next->type != SEL_ARG::IMPOSSIBLE)
@@ -6220,7 +6360,7 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1)
static SEL_ARG *
-key_or(SEL_ARG *key1,SEL_ARG *key2)
+key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
{
if (!key1)
{
@@ -6268,7 +6408,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{
swap_variables(SEL_ARG *,key1,key2);
}
- if (key1->use_count > 0 || !(key1=key1->clone_tree()))
+ if (key1->use_count > 0 || !(key1=key1->clone_tree(param)))
return 0; // OOM
}
@@ -6412,7 +6552,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
{ // tmp.min. <= x <= tmp.max
tmp->maybe_flag|= key.maybe_flag;
key.increment_use_count(key1->use_count+1);
- tmp->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
+ tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
if (!cmp) // Key2 is ready
break;
key.copy_max_to_min(tmp);
@@ -6443,7 +6583,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
tmp->increment_use_count(key1->use_count+1);
/* Increment key count as it may be used for next loop */
key.increment_use_count(1);
- new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
+ new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part);
key1=key1->insert(new_arg);
break;
}
@@ -7011,6 +7151,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
DBUG_ENTER("check_quick_select");
param->is_ror_scan= FALSE;
+ param->first_null_comp= 0;
if (!tree)
DBUG_RETURN(HA_POS_ERROR); // Can't use it
@@ -7041,7 +7182,9 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
}
param->n_ranges= 0;
- records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0);
+ records= check_quick_keys(param, idx, tree,
+ param->min_key, 0, -1,
+ param->max_key, 0, -1);
if (records != HA_POS_ERROR)
{
if (update_tbl_stats)
@@ -7104,13 +7247,15 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
*/
static ha_rows
-check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
- char *min_key,uint min_key_flag, char *max_key,
- uint max_key_flag)
+check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
+ uchar *min_key, uint min_key_flag, int min_keypart,
+ uchar *max_key, uint max_key_flag, int max_keypart)
{
ha_rows records=0, tmp;
uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length;
- char *tmp_min_key, *tmp_max_key;
+ uint tmp_min_keypart= min_keypart, tmp_max_keypart= max_keypart;
+ uchar *tmp_min_key, *tmp_max_key;
+ uint8 save_first_null_comp= param->first_null_comp;
param->max_key_part=max(param->max_key_part,key_tree->part);
if (key_tree->left != &null_element)
@@ -7122,18 +7267,21 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
- records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag,
- max_key,max_key_flag);
+ records=check_quick_keys(param, idx, key_tree->left,
+ min_key, min_key_flag, min_keypart,
+ max_key, max_key_flag, max_keypart);
if (records == HA_POS_ERROR) // Impossible
return records;
}
tmp_min_key= min_key;
tmp_max_key= max_key;
- key_tree->store(param->key[idx][key_tree->part].store_length,
- &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
- min_key_length= (uint) (tmp_min_key- param->min_key);
- max_key_length= (uint) (tmp_max_key- param->max_key);
+ tmp_min_keypart+= key_tree->store_min(param->key[idx][key_tree->part].store_length,
+ &tmp_min_key, min_key_flag);
+ tmp_max_keypart+= key_tree->store_max(param->key[idx][key_tree->part].store_length,
+ &tmp_max_key, max_key_flag);
+ min_key_length= (uint) (tmp_min_key - param->min_key);
+ max_key_length= (uint) (tmp_max_key - param->max_key);
if (param->is_ror_scan)
{
@@ -7148,17 +7296,21 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
param->is_ror_scan= FALSE;
}
+ if (!param->first_null_comp && key_tree->is_null_interval())
+ param->first_null_comp= key_tree->part+1;
+
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
if (min_key_length == max_key_length &&
- !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
+ !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag)
{
- tmp=check_quick_keys(param,idx,key_tree->next_key_part,
- tmp_min_key, min_key_flag | key_tree->min_flag,
- tmp_max_key, max_key_flag | key_tree->max_flag);
+ tmp=check_quick_keys(param,idx,key_tree->next_key_part, tmp_min_key,
+ min_key_flag | key_tree->min_flag, tmp_min_keypart,
+ tmp_max_key, max_key_flag | key_tree->max_flag,
+ tmp_max_keypart);
goto end; // Ugly, but efficient
}
else
@@ -7170,18 +7322,20 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
tmp_min_flag=key_tree->min_flag;
tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
+ tmp_min_keypart+=
key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key,
&tmp_min_flag);
if (!tmp_max_flag)
+ tmp_max_keypart+=
key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key,
&tmp_max_flag);
- min_key_length= (uint) (tmp_min_key- param->min_key);
- max_key_length= (uint) (tmp_max_key- param->max_key);
+ min_key_length= (uint) (tmp_min_key - param->min_key);
+ max_key_length= (uint) (tmp_max_key - param->max_key);
}
else
{
- tmp_min_flag=min_key_flag | key_tree->min_flag;
- tmp_max_flag=max_key_flag | key_tree->max_flag;
+ tmp_min_flag= min_key_flag | key_tree->min_flag;
+ tmp_max_flag= max_key_flag | key_tree->max_flag;
}
keynr=param->real_keynr[idx];
@@ -7189,9 +7343,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
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 | HA_END_SPACE_KEY)) ==
- HA_NOSAME &&
- min_key_length == max_key_length &&
- !memcmp(param->min_key,param->max_key,min_key_length))
+ HA_NOSAME && min_key_length == max_key_length &&
+ !memcmp(param->min_key, param->max_key, min_key_length) &&
+ !param->first_null_comp)
{
tmp=1; // Max one record
param->n_ranges++;
@@ -7210,7 +7364,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
first members of clustered primary key.
*/
if (!(min_key_length == max_key_length &&
- !memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
+ !memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag &&
is_key_scan_ror(param, keynr, key_tree->part + 1)))
param->is_ror_scan= FALSE;
@@ -7220,26 +7374,29 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
if (tmp_min_flag & GEOM_FLAG)
{
key_range min_range;
- min_range.key= (byte*) param->min_key;
+ min_range.key= param->min_key;
min_range.length= min_key_length;
+ min_range.keypart_map= make_keypart_map(tmp_min_keypart);
/* In this case tmp_min_flag contains the handler-read-function */
min_range.flag= (ha_rkey_function) (tmp_min_flag ^ GEOM_FLAG);
- tmp= param->table->file->records_in_range(keynr, &min_range,
- (key_range*) 0);
+ tmp= param->table->file->records_in_range(keynr,
+ &min_range, (key_range*) 0);
}
else
{
key_range min_range, max_range;
- min_range.key= (byte*) param->min_key;
+ min_range.key= param->min_key;
min_range.length= min_key_length;
min_range.flag= (tmp_min_flag & NEAR_MIN ? HA_READ_AFTER_KEY :
HA_READ_KEY_EXACT);
- max_range.key= (byte*) param->max_key;
+ min_range.keypart_map= make_keypart_map(tmp_min_keypart);
+ max_range.key= param->max_key;
max_range.length= max_key_length;
max_range.flag= (tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY);
+ max_range.keypart_map= make_keypart_map(tmp_max_keypart);
tmp=param->table->file->records_in_range(keynr,
(min_key_length ? &min_range :
(key_range*) 0),
@@ -7260,12 +7417,14 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
- tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag,
- max_key,max_key_flag);
+ tmp=check_quick_keys(param, idx, key_tree->right,
+ min_key, min_key_flag, min_keypart,
+ max_key, max_key_flag, max_keypart);
if (tmp == HA_POS_ERROR)
return tmp;
records+=tmp;
}
+ param->first_null_comp= save_first_null_comp;
return records;
}
@@ -7402,11 +7561,13 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree,
*/
bool
get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
- SEL_ARG *key_tree,char *min_key,uint min_key_flag,
- char *max_key, uint max_key_flag)
+ SEL_ARG *key_tree, uchar *min_key,uint min_key_flag,
+ uchar *max_key, uint max_key_flag)
{
QUICK_RANGE *range;
uint flag;
+ int min_part= key_tree->part-1, // # of keypart values in min_key buffer
+ max_part= key_tree->part-1; // # of keypart values in max_key buffer
if (key_tree->left != &null_element)
{
@@ -7414,17 +7575,19 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
min_key,min_key_flag, max_key, max_key_flag))
return 1;
}
- char *tmp_min_key=min_key,*tmp_max_key=max_key;
- key_tree->store(key[key_tree->part].store_length,
- &tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
+ uchar *tmp_min_key=min_key,*tmp_max_key=max_key;
+ min_part+= key_tree->store_min(key[key_tree->part].store_length,
+ &tmp_min_key,min_key_flag);
+ max_part+= key_tree->store_max(key[key_tree->part].store_length,
+ &tmp_max_key,max_key_flag);
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
- if (!((tmp_min_key - min_key) != (tmp_max_key - max_key) ||
- memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) ||
- key_tree->min_flag || key_tree->max_flag))
+ if ((tmp_min_key - min_key) == (tmp_max_key - max_key) &&
+ memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 &&
+ key_tree->min_flag==0 && key_tree->max_flag==0)
{
if (get_quick_keys(param,quick,key,key_tree->next_key_part,
tmp_min_key, min_key_flag | key_tree->min_flag,
@@ -7435,11 +7598,11 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
- key_tree->next_key_part->store_min_key(key, &tmp_min_key,
- &tmp_min_flag);
+ min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key,
+ &tmp_min_flag);
if (!tmp_max_flag)
- key_tree->next_key_part->store_max_key(key, &tmp_max_key,
- &tmp_max_flag);
+ max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key,
+ &tmp_max_flag);
flag=tmp_min_flag | tmp_max_flag;
}
}
@@ -7487,17 +7650,19 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
}
/* Get range for retrieving rows in QUICK_SELECT::get_next */
- if (!(range= new QUICK_RANGE((const char *) param->min_key,
+ if (!(range= new QUICK_RANGE(param->min_key,
(uint) (tmp_min_key - param->min_key),
- (const char *) param->max_key,
+ min_part >=0 ? make_keypart_map(min_part) : 0,
+ param->max_key,
(uint) (tmp_max_key - param->max_key),
+ max_part >=0 ? make_keypart_map(max_part) : 0,
flag)))
return 1; // out of memory
- set_if_bigger(quick->max_used_key_length,range->min_length);
- set_if_bigger(quick->max_used_key_length,range->max_length);
+ set_if_bigger(quick->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 (insert_dynamic(&quick->ranges, (gptr)&range))
+ if (insert_dynamic(&quick->ranges, (uchar*) &range))
return 1;
end:
@@ -7530,9 +7695,9 @@ bool QUICK_RANGE_SELECT::unique_key_range()
/* Returns TRUE if any part of the key is NULL */
-static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length)
+static bool null_part_in_key(KEY_PART *key_part, const uchar *key, uint length)
{
- for (const char *end=key+length ;
+ for (const uchar *end=key+length ;
key < end;
key+= key_part++->store_length)
{
@@ -7593,13 +7758,13 @@ bool QUICK_ROR_UNION_SELECT::is_keys_used(const MY_BITMAP *fields)
thd Thread handle
table Table to access
ref ref[_or_null] scan parameters
- records Estimate of number of records (needed only to construct
+ records Estimate of number of records (needed only to construct
quick select)
NOTES
This allocates things in a new memory root, as this may be called many
times during a query.
-
- RETURN
+
+ RETURN
Quick select that retrieves the same rows as passed ref scan
NULL on error.
*/
@@ -7635,8 +7800,10 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
!(range= new(alloc) QUICK_RANGE()))
goto err; // out of memory
- range->min_key=range->max_key=(char*) ref->key_buff;
- range->min_length=range->max_length=ref->key_length;
+ range->min_key= range->max_key= ref->key_buff;
+ range->min_length= range->max_length= ref->key_length;
+ range->min_keypart_map= range->max_keypart_map=
+ make_prev_keypart_map(ref->key_parts);
range->flag= ((ref->key_length == key_info->key_length &&
(key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME) ? EQ_RANGE : 0);
@@ -7649,12 +7816,12 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
{
key_part->part=part;
key_part->field= key_info->key_part[part].field;
- key_part->length= key_info->key_part[part].length;
+ key_part->length= key_info->key_part[part].length;
key_part->store_length= key_info->key_part[part].store_length;
key_part->null_bit= key_info->key_part[part].null_bit;
key_part->flag= (uint8) key_info->key_part[part].key_part_flag;
}
- if (insert_dynamic(&quick->ranges,(gptr)&range))
+ if (insert_dynamic(&quick->ranges,(uchar*)&range))
goto err;
/*
@@ -7668,14 +7835,14 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
QUICK_RANGE *null_range;
*ref->null_ref_key= 1; // Set null byte then create a range
- if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff,
- ref->key_length,
- (char*)ref->key_buff,
- ref->key_length,
- EQ_RANGE)))
+ if (!(null_range= new (alloc)
+ QUICK_RANGE(ref->key_buff, ref->key_length,
+ make_prev_keypart_map(ref->key_parts),
+ ref->key_buff, ref->key_length,
+ make_prev_keypart_map(ref->key_parts), EQ_RANGE)))
goto err;
*ref->null_ref_key= 0; // Clear null byte
- if (insert_dynamic(&quick->ranges,(gptr)&null_range))
+ if (insert_dynamic(&quick->ranges,(uchar*)&null_range))
goto err;
}
@@ -7930,7 +8097,7 @@ int QUICK_ROR_UNION_SELECT::get_next()
{
int error, dup_row;
QUICK_SELECT_I *quick;
- byte *tmp;
+ uchar *tmp;
DBUG_ENTER("QUICK_ROR_UNION_SELECT::get_next");
do
@@ -7980,10 +8147,10 @@ int QUICK_ROR_UNION_SELECT::get_next()
int QUICK_RANGE_SELECT::reset()
{
uint mrange_bufsiz;
- byte *mrange_buff;
+ uchar *mrange_buff;
DBUG_ENTER("QUICK_RANGE_SELECT::reset");
next=0;
- range= NULL;
+ last_range= NULL;
in_range= FALSE;
cur_range= (QUICK_RANGE**) ranges.buffer;
@@ -8023,8 +8190,9 @@ int QUICK_RANGE_SELECT::reset()
while (mrange_bufsiz &&
! my_multi_malloc(MYF(MY_WME),
- &multi_range_buff, sizeof(*multi_range_buff),
- &mrange_buff, mrange_bufsiz,
+ &multi_range_buff,
+ (uint) sizeof(*multi_range_buff),
+ &mrange_buff, (uint) mrange_bufsiz,
NullS))
{
/* Try to shrink the buffers until both are 0. */
@@ -8117,23 +8285,25 @@ int QUICK_RANGE_SELECT::get_next()
{
start_key= &mrange_slot->start_key;
end_key= &mrange_slot->end_key;
- range= *(cur_range++);
+ last_range= *(cur_range++);
- start_key->key= (const byte*) range->min_key;
- start_key->length= range->min_length;
- start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
- (range->flag & EQ_RANGE) ?
+ start_key->key= (const uchar*) last_range->min_key;
+ start_key->length= last_range->min_length;
+ start_key->flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+ (last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
- end_key->key= (const byte*) range->max_key;
- end_key->length= range->max_length;
+ start_key->keypart_map= last_range->min_keypart_map;
+ end_key->key= (const uchar*) last_range->max_key;
+ end_key->length= last_range->max_length;
/*
We use HA_READ_AFTER_KEY here because if we are reading on a key
prefix. We want to find all keys with this prefix.
*/
- end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+ end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
+ end_key->keypart_map= last_range->max_keypart_map;
- mrange_slot->range_flag= range->flag;
+ mrange_slot->range_flag= last_range->flag;
}
result= file->read_multi_range_first(&mrange, multi_range, count,
@@ -8181,7 +8351,9 @@ end:
other if some error occurred
*/
-int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
+int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length,
+ key_part_map keypart_map,
+ uchar *cur_prefix)
{
DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix");
@@ -8189,12 +8361,11 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
{
int result;
key_range start_key, end_key;
- if (range)
+ if (last_range)
{
/* Read the next record in the same range with prefix after cur_prefix. */
DBUG_ASSERT(cur_prefix != 0);
- result= file->index_read(record, cur_prefix, prefix_length,
- HA_READ_AFTER_KEY);
+ result= file->index_read(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY);
if (result || (file->compare_key(file->end_range) <= 0))
DBUG_RETURN(result);
}
@@ -8203,35 +8374,37 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
- range= 0;
+ last_range= 0;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
- range= *(cur_range++);
+ last_range= *(cur_range++);
- start_key.key= (const byte*) range->min_key;
- start_key.length= min(range->min_length, prefix_length);
- start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
- (range->flag & EQ_RANGE) ?
+ start_key.key= (const uchar*) last_range->min_key;
+ start_key.length= min(last_range->min_length, prefix_length);
+ start_key.keypart_map= last_range->min_keypart_map & keypart_map;
+ start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
+ (last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
- end_key.key= (const byte*) range->max_key;
- end_key.length= min(range->max_length, prefix_length);
+ end_key.key= (const uchar*) last_range->max_key;
+ end_key.length= min(last_range->max_length, prefix_length);
+ end_key.keypart_map= last_range->max_keypart_map & keypart_map;
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
*/
- end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
+ end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
- result= file->read_range_first(range->min_length ? &start_key : 0,
- range->max_length ? &end_key : 0,
- test(range->flag & EQ_RANGE),
+ result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0,
+ last_range->max_keypart_map ? &end_key : 0,
+ test(last_range->flag & EQ_RANGE),
sorted);
- if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
- range=0; // Stop searching
+ if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
+ last_range= 0; // Stop searching
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // No matching rows; go to next range
+ last_range= 0; // No matching rows; go to next range
}
}
@@ -8245,11 +8418,11 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
for (;;)
{
int result;
- if (range)
+ if (last_range)
{
// Already read through key
- result= file->index_next_same(record, (byte*) range->min_key,
- range->min_length);
+ result= file->index_next_same(record, last_range->min_key,
+ last_range->min_length);
if (result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
}
@@ -8258,18 +8431,17 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
if (count == 0)
{
/* Ranges have already been used up before. None is left for read. */
- range= 0;
+ last_range= 0;
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
- range= *(cur_range++);
+ last_range= *(cur_range++);
- result= file->index_read(record,
- (byte*) range->min_key,
- range->min_length,
- (ha_rkey_function)(range->flag ^ GEOM_FLAG));
+ result= file->index_read(record, last_range->min_key,
+ last_range->min_keypart_map,
+ (ha_rkey_function)(last_range->flag ^ GEOM_FLAG));
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // Not found, to next range
+ last_range= 0; // Not found, to next range
}
}
@@ -8294,7 +8466,7 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
bool QUICK_RANGE_SELECT::row_in_ranges()
{
- QUICK_RANGE *range;
+ QUICK_RANGE *res;
uint min= 0;
uint max= ranges.elements - 1;
uint mid= (max + min)/2;
@@ -8310,8 +8482,8 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
max= mid;
mid= (min + max) / 2;
}
- range= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid);
- return (!cmp_next(range) && !cmp_prev(range));
+ res= *(QUICK_RANGE**)dynamic_array_ptr(&ranges, mid);
+ return (!cmp_next(res) && !cmp_prev(res));
}
/*
@@ -8325,14 +8497,14 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
*/
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
- uint used_key_parts)
+ uint used_key_parts_arg)
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
{
QUICK_RANGE *r;
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
- QUICK_RANGE **last_range= pr + ranges.elements;
- for (; pr!=last_range; pr++)
+ QUICK_RANGE **end_range= pr + ranges.elements;
+ for (; pr!=end_range; pr++)
rev_ranges.push_front(*pr);
/* Remove EQ_RANGE flag for keys that are not using the full key */
@@ -8366,11 +8538,11 @@ int QUICK_SELECT_DESC::get_next()
for (;;)
{
int result;
- if (range)
+ if (last_range)
{ // Already read through key
- result = ((range->flag & EQ_RANGE)
- ? file->index_next_same(record, (byte*) range->min_key,
- range->min_length) :
+ result = ((last_range->flag & EQ_RANGE)
+ ? file->index_next_same(record, last_range->min_key,
+ last_range->min_length) :
file->index_prev(record));
if (!result)
{
@@ -8381,47 +8553,49 @@ int QUICK_SELECT_DESC::get_next()
DBUG_RETURN(result);
}
- if (!(range=rev_it++))
+ if (!(last_range= rev_it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
- if (range->flag & NO_MAX_RANGE) // Read last record
+ if (last_range->flag & NO_MAX_RANGE) // Read last record
{
int local_error;
if ((local_error=file->index_last(record)))
DBUG_RETURN(local_error); // Empty table
- if (cmp_prev(range) == 0)
+ if (cmp_prev(last_range) == 0)
DBUG_RETURN(0);
- range=0; // No matching records; go to next range
+ last_range= 0; // No match; go to next range
continue;
}
- if (range->flag & EQ_RANGE)
+ if (last_range->flag & EQ_RANGE)
{
- result = file->index_read(record, (byte*) range->max_key,
- range->max_length, HA_READ_KEY_EXACT);
+ result = file->index_read(record, last_range->max_key,
+ last_range->max_keypart_map, HA_READ_KEY_EXACT);
}
else
{
- DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
- result=file->index_read(record, (byte*) range->max_key,
- range->max_length,
- ((range->flag & NEAR_MAX) ?
- HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV));
+ DBUG_ASSERT(last_range->flag & NEAR_MAX ||
+ range_reads_after_key(last_range));
+ result=file->index_read(record, last_range->max_key,
+ last_range->max_keypart_map,
+ ((last_range->flag & NEAR_MAX) ?
+ HA_READ_BEFORE_KEY :
+ HA_READ_PREFIX_LAST_OR_PREV));
}
if (result)
{
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
- range=0; // Not found, to next range
+ last_range= 0; // Not found, to next range
continue;
}
- if (cmp_prev(range) == 0)
+ if (cmp_prev(last_range) == 0)
{
- if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
- range = 0; // Stop searching
+ if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
+ last_range= 0; // Stop searching
DBUG_RETURN(0); // Found key is in range
}
- range = 0; // To next range
+ last_range= 0; // To next range
}
}
@@ -8439,7 +8613,7 @@ int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
KEY_PART *key_part=key_parts;
uint store_length;
- for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
+ for (uchar *key=range_arg->max_key, *end=key+range_arg->max_length;
key < end;
key+= store_length, key_part++)
{
@@ -8458,7 +8632,7 @@ int QUICK_RANGE_SELECT::cmp_next(QUICK_RANGE *range_arg)
key++; // Skip null byte
store_length--;
}
- if ((cmp=key_part->field->key_cmp((byte*) key, key_part->length)) < 0)
+ if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
return 0;
if (cmp > 0)
return 1;
@@ -8477,7 +8651,7 @@ int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg)
if (range_arg->flag & NO_MIN_RANGE)
return 0; /* key can't be to small */
- cmp= key_cmp(key_part_info, (byte*) range_arg->min_key,
+ cmp= key_cmp(key_part_info, range_arg->min_key,
range_arg->min_length);
if (cmp > 0 || cmp == 0 && !(range_arg->flag & NEAR_MIN))
return 0;
@@ -8723,12 +8897,11 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
static inline uint get_field_keypart(KEY *index, Field *field);
static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree,
PARAM *param, uint *param_idx);
-static bool
-get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
+static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
KEY_PART_INFO *min_max_arg_part,
KEY_PART_INFO *last_part, THD *thd,
- byte *key_infix, uint *key_infix_len,
+ uchar *key_infix, uint *key_infix_len,
KEY_PART_INFO **first_non_infix_part);
static bool
check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
@@ -8885,7 +9058,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
uint index= 0; /* The id of the chosen index. */
uint group_key_parts= 0; // Number of index key parts in the group prefix.
uint used_key_parts= 0; /* Number of index key parts used for access. */
- byte key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/
+ uchar key_infix[MAX_KEY_LENGTH]; /* Constants from equality predicates.*/
uint key_infix_len= 0; /* Length of key_infix. */
TRP_GROUP_MIN_MAX *read_plan= NULL; /* The eventually constructed TRP. */
uint key_part_nr;
@@ -8900,7 +9073,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
if ((join->tables != 1) || /* The query must reference one table. */
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
(!join->select_distinct)) ||
- (thd->lex->select_lex.olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
+ (join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
DBUG_RETURN(NULL);
if (table->s->keys == 0) /* There are no indexes to use. */
DBUG_RETURN(NULL);
@@ -8924,7 +9097,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
else
DBUG_RETURN(NULL);
- Item *expr= min_max_item->args[0]; /* The argument of MIN/MAX. */
+ /* The argument of MIN/MAX. */
+ Item *expr= min_max_item->args[0]->real_item();
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */
{
if (! min_max_arg_item)
@@ -8988,7 +9162,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
cur_index_info++, cur_index++)
{
/* Check (B1) - if current index is covering. */
- if (!table->used_keys.is_set(cur_index))
+ if (!table->covering_keys.is_set(cur_index))
goto next_index;
/*
@@ -9122,7 +9296,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
NULL;
first_non_infix_part= min_max_arg_part ?
(min_max_arg_part < last_part) ?
- min_max_arg_part + 1 :
+ min_max_arg_part :
NULL :
NULL;
if (first_non_group_part &&
@@ -9168,7 +9342,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
/* Check if cur_part is referenced in the WHERE clause. */
if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
- (byte*) key_part_range))
+ (uchar*) key_part_range))
goto next_index;
}
}
@@ -9179,7 +9353,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (first_non_infix_part)
{
- for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++)
+ cur_part= first_non_infix_part +
+ (min_max_arg_part && (min_max_arg_part < last_part));
+ for (; cur_part != last_part; cur_part++)
{
if (bitmap_is_set(table->read_set, cur_part->field->field_index))
goto next_index;
@@ -9293,6 +9469,7 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
DBUG_ENTER("check_group_min_max_predicates");
DBUG_ASSERT(cond && min_max_arg_item);
+ cond= cond->real_item();
Item::Type cond_type= cond->type();
if (cond_type == Item::COND_ITEM) /* 'AND' or 'OR' */
{
@@ -9330,7 +9507,7 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item,
DBUG_PRINT("info", ("Analyzing: %s", pred->func_name()));
for (uint arg_idx= 0; arg_idx < pred->argument_count (); arg_idx++)
{
- cur_arg= arguments[arg_idx];
+ cur_arg= arguments[arg_idx]->real_item();
DBUG_PRINT("info", ("cur_arg: %s", cur_arg->full_name()));
if (cur_arg->type() == Item::FIELD_ITEM)
{
@@ -9435,7 +9612,7 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
KEY_PART_INFO *min_max_arg_part,
KEY_PART_INFO *last_part, THD *thd,
- byte *key_infix, uint *key_infix_len,
+ uchar *key_infix, uint *key_infix_len,
KEY_PART_INFO **first_non_infix_part)
{
SEL_ARG *cur_range;
@@ -9444,7 +9621,7 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *end_part= min_max_arg_part ? min_max_arg_part : last_part;
*key_infix_len= 0;
- byte *key_ptr= key_infix;
+ uchar *key_ptr= key_infix;
for (cur_part= first_non_group_part; cur_part != end_part; cur_part++)
{
/*
@@ -9725,7 +9902,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
RETURN
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
- NULL o/w.
+ NULL otherwise.
*/
QUICK_SELECT_I *
@@ -9738,10 +9915,10 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
param->thd->lex->current_select->join,
have_min, have_max, min_max_arg_part,
- group_prefix_len, used_key_parts,
- index_info, index, read_cost, records,
- key_infix_len, key_infix,
- parent_alloc);
+ group_prefix_len, group_key_parts,
+ used_key_parts, index_info, index,
+ read_cost, records, key_infix_len,
+ key_infix, parent_alloc);
if (!quick)
DBUG_RETURN(NULL);
@@ -9830,13 +10007,14 @@ QUICK_GROUP_MIN_MAX_SELECT::
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
bool have_max_arg,
KEY_PART_INFO *min_max_arg_part_arg,
- uint group_prefix_len_arg,
+ uint group_prefix_len_arg, uint group_key_parts_arg,
uint used_key_parts_arg, KEY *index_info_arg,
uint use_index, double read_cost_arg,
ha_rows records_arg, uint key_infix_len_arg,
- byte *key_infix_arg, MEM_ROOT *parent_alloc)
+ uchar *key_infix_arg, MEM_ROOT *parent_alloc)
:join(join_arg), index_info(index_info_arg),
- group_prefix_len(group_prefix_len_arg), have_min(have_min_arg),
+ group_prefix_len(group_prefix_len_arg),
+ group_key_parts(group_key_parts_arg), have_min(have_min_arg),
have_max(have_max_arg), seen_first_key(FALSE),
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
@@ -9850,6 +10028,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
read_time= read_cost_arg;
records= records_arg;
used_key_parts= used_key_parts_arg;
+ real_key_parts= used_key_parts_arg;
real_prefix_len= group_prefix_len + key_infix_len;
group_prefix= NULL;
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0;
@@ -9891,13 +10070,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::init()
if (group_prefix) /* Already initialized. */
return 0;
- if (!(last_prefix= (byte*) alloc_root(&alloc, group_prefix_len)))
+ if (!(last_prefix= (uchar*) alloc_root(&alloc, group_prefix_len)))
return 1;
/*
We may use group_prefix to store keys with all select fields, so allocate
enough space for it.
*/
- if (!(group_prefix= (byte*) alloc_root(&alloc,
+ if (!(group_prefix= (uchar*) alloc_root(&alloc,
real_prefix_len + min_max_arg_len)))
return 1;
@@ -9907,7 +10086,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::init()
The memory location pointed to by key_infix will be deleted soon, so
allocate a new buffer and copy the key_infix into it.
*/
- byte *tmp_key_infix= (byte*) alloc_root(&alloc, key_infix_len);
+ uchar *tmp_key_infix= (uchar*) alloc_root(&alloc, key_infix_len);
if (!tmp_key_infix)
return 1;
memcpy(tmp_key_infix, this->key_infix, key_infix_len);
@@ -10016,11 +10195,13 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range)
range_flag|= EQ_RANGE; /* equality condition */
}
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len,
+ make_keypart_map(sel_range->part),
sel_range->max_value, min_max_arg_len,
+ make_keypart_map(sel_range->part),
range_flag);
if (!range)
return TRUE;
- if (insert_dynamic(&min_max_ranges, (gptr)&range))
+ if (insert_dynamic(&min_max_ranges, (uchar*)&range))
return TRUE;
return FALSE;
}
@@ -10055,7 +10236,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::adjust_prefix_ranges ()
{
QUICK_RANGE *range;
- get_dynamic(arr, (gptr)&range, inx);
+ get_dynamic(arr, (uchar*)&range, inx);
range->flag &= ~(NEAR_MIN | NEAR_MAX);
}
}
@@ -10091,7 +10272,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
QUICK_RANGE *cur_range;
if (have_min)
{ /* Check if the right-most range has a lower boundary. */
- get_dynamic(&min_max_ranges, (gptr)&cur_range,
+ get_dynamic(&min_max_ranges, (uchar*)&cur_range,
min_max_ranges.elements - 1);
if (!(cur_range->flag & NO_MIN_RANGE))
{
@@ -10102,7 +10283,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_key_stat()
}
if (have_max)
{ /* Check if the left-most range has an upper boundary. */
- get_dynamic(&min_max_ranges, (gptr)&cur_range, 0);
+ get_dynamic(&min_max_ranges, (uchar*)&cur_range, 0);
if (!(cur_range->flag & NO_MAX_RANGE))
{
max_used_key_length+= min_max_arg_len;
@@ -10149,14 +10330,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset");
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
- result= file->ha_index_init(index, 1);
- result= file->index_last(record);
- if (result == HA_ERR_END_OF_FILE)
- DBUG_RETURN(0);
- if (result)
+ if ((result= file->ha_index_init(index,1)))
DBUG_RETURN(result);
if (quick_prefix_select && quick_prefix_select->reset())
DBUG_RETURN(1);
+ result= file->index_last(record);
+ if (result == HA_ERR_END_OF_FILE)
+ DBUG_RETURN(0);
/* Save the prefix of the last group. */
key_copy(last_prefix, record, index_info, group_prefix_len);
@@ -10205,7 +10385,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
#else
int result;
#endif
- int is_last_prefix;
+ int is_last_prefix= 0;
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::get_next");
@@ -10220,13 +10400,18 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
Check if this is the last group prefix. Notice that at this point
this->record contains the current prefix in record format.
*/
- is_last_prefix= key_cmp(index_info->key_part, last_prefix,
- group_prefix_len);
- DBUG_ASSERT(is_last_prefix <= 0);
- if (result == HA_ERR_KEY_NOT_FOUND)
- continue;
- if (result)
+ if (!result)
+ {
+ is_last_prefix= key_cmp(index_info->key_part, last_prefix,
+ group_prefix_len);
+ DBUG_ASSERT(is_last_prefix <= 0);
+ }
+ else
+ {
+ if (result == HA_ERR_KEY_NOT_FOUND)
+ continue;
break;
+ }
if (have_min)
{
@@ -10251,7 +10436,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
first sub-group with the extended prefix.
*/
if (!have_min && !have_max && key_infix_len > 0)
- result= file->index_read(record, group_prefix, real_prefix_len,
+ result= file->index_read(record, group_prefix,
+ make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT);
result= have_min ? min_res : have_max ? max_res : result;
@@ -10314,7 +10500,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Apply the constant equality conditions to the non-group select fields */
if (key_infix_len > 0)
{
- if ((result= file->index_read(record, group_prefix, real_prefix_len,
+ if ((result= file->index_read(record, group_prefix,
+ make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT)))
DBUG_RETURN(result);
}
@@ -10331,7 +10518,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Find the first subsequent record without NULL in the MIN/MAX field. */
key_copy(tmp_record, record, index_info, 0);
result= file->index_read(record, tmp_record,
- real_prefix_len + min_max_arg_len,
+ make_keypart_map(real_key_parts),
HA_READ_AFTER_KEY);
/*
Check if the new record belongs to the current group by comparing its
@@ -10387,7 +10574,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
if (min_max_ranges.elements > 0)
result= next_max_in_range();
else
- result= file->index_read(record, group_prefix, real_prefix_len,
+ result= file->index_read(record, group_prefix,
+ make_prev_keypart_map(real_key_parts),
HA_READ_PREFIX_LAST);
DBUG_RETURN(result);
}
@@ -10421,9 +10609,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
if (quick_prefix_select)
{
- byte *cur_prefix= seen_first_key ? group_prefix : NULL;
+ uchar *cur_prefix= seen_first_key ? group_prefix : NULL;
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len,
- cur_prefix)))
+ make_prev_keypart_map(group_key_parts), cur_prefix)))
DBUG_RETURN(result);
seen_first_key= TRUE;
}
@@ -10439,7 +10627,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
else
{
/* Load the first key in this group into record. */
- result= file->index_read(record, group_prefix, group_prefix_len,
+ result= file->index_read(record, group_prefix,
+ make_prev_keypart_map(group_key_parts),
HA_READ_AFTER_KEY);
if (result)
DBUG_RETURN(result);
@@ -10481,7 +10670,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
{
ha_rkey_function find_flag;
- uint search_prefix_len;
+ key_part_map keypart_map;
QUICK_RANGE *cur_range;
bool found_null= FALSE;
int result= HA_ERR_KEY_NOT_FOUND;
@@ -10490,35 +10679,34 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
for (uint range_idx= 0; range_idx < min_max_ranges.elements; range_idx++)
{ /* Search from the left-most range to the right. */
- get_dynamic(&min_max_ranges, (gptr)&cur_range, range_idx);
+ get_dynamic(&min_max_ranges, (uchar*)&cur_range, range_idx);
/*
If the current value for the min/max argument is bigger than the right
boundary of cur_range, there is no need to check this range.
*/
if (range_idx != 0 && !(cur_range->flag & NO_MAX_RANGE) &&
- (key_cmp(min_max_arg_part, (const byte*) cur_range->max_key,
+ (key_cmp(min_max_arg_part, (const uchar*) cur_range->max_key,
min_max_arg_len) == 1))
continue;
if (cur_range->flag & NO_MIN_RANGE)
{
+ keypart_map= make_prev_keypart_map(real_key_parts);
find_flag= HA_READ_KEY_EXACT;
- search_prefix_len= real_prefix_len;
}
else
{
/* Extend the search key with the lower boundary for this range. */
memcpy(group_prefix + real_prefix_len, cur_range->min_key,
cur_range->min_length);
- search_prefix_len= real_prefix_len + min_max_arg_len;
+ keypart_map= make_keypart_map(real_key_parts);
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
}
- result= file->index_read(record, group_prefix, search_prefix_len,
- find_flag);
+ result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
@@ -10559,7 +10747,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
if ( !(cur_range->flag & NO_MAX_RANGE) )
{
/* Compose the MAX key for the range. */
- byte *max_key= (byte*) my_alloca(real_prefix_len + min_max_arg_len);
+ uchar *max_key= (uchar*) my_alloca(real_prefix_len + min_max_arg_len);
memcpy(max_key, group_prefix, real_prefix_len);
memcpy(max_key + real_prefix_len, cur_range->max_key,
cur_range->max_length);
@@ -10615,7 +10803,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
{
ha_rkey_function find_flag;
- uint search_prefix_len;
+ key_part_map keypart_map;
QUICK_RANGE *cur_range;
int result;
@@ -10623,7 +10811,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
for (uint range_idx= min_max_ranges.elements; range_idx > 0; range_idx--)
{ /* Search from the right-most range to the left. */
- get_dynamic(&min_max_ranges, (gptr)&cur_range, range_idx - 1);
+ get_dynamic(&min_max_ranges, (uchar*)&cur_range, range_idx - 1);
/*
If the current value for the min/max argument is smaller than the left
@@ -10631,28 +10819,27 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
*/
if (range_idx != min_max_ranges.elements &&
!(cur_range->flag & NO_MIN_RANGE) &&
- (key_cmp(min_max_arg_part, (const byte*) cur_range->min_key,
+ (key_cmp(min_max_arg_part, (const uchar*) cur_range->min_key,
min_max_arg_len) == -1))
continue;
if (cur_range->flag & NO_MAX_RANGE)
{
+ keypart_map= make_prev_keypart_map(real_key_parts);
find_flag= HA_READ_PREFIX_LAST;
- search_prefix_len= real_prefix_len;
}
else
{
/* Extend the search key with the upper boundary for this range. */
memcpy(group_prefix + real_prefix_len, cur_range->max_key,
cur_range->max_length);
- search_prefix_len= real_prefix_len + min_max_arg_len;
+ keypart_map= make_keypart_map(real_key_parts);
find_flag= (cur_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
}
- result= file->index_read(record, group_prefix, search_prefix_len,
- find_flag);
+ result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{
@@ -10678,7 +10865,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
if ( !(cur_range->flag & NO_MIN_RANGE) )
{
/* Compose the MIN key for the range. */
- byte *min_key= (byte*) my_alloca(real_prefix_len + min_max_arg_len);
+ uchar *min_key= (uchar*) my_alloca(real_prefix_len + min_max_arg_len);
memcpy(min_key, group_prefix, real_prefix_len);
memcpy(min_key + real_prefix_len, cur_range->min_key,
cur_range->min_length);
@@ -10849,10 +11036,10 @@ static void print_ror_scans_arr(TABLE *table, const char *msg,
*****************************************************************************/
static void
-print_key(KEY_PART *key_part,const char *key,uint used_length)
+print_key(KEY_PART *key_part, const uchar *key, uint used_length)
{
char buff[1024];
- const char *key_end= key+used_length;
+ const uchar *key_end= key+used_length;
String tmp(buff,sizeof(buff),&my_charset_bin);
uint store_length;
TABLE *table= key_part->field->table;
@@ -10875,7 +11062,7 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
key++; // Skip null byte
store_length--;
}
- field->set_key_image((char*) key, key_part->length);
+ field->set_key_image(key, key_part->length);
if (field->type() == MYSQL_TYPE_BIT)
(void) field->val_int_as_str(&tmp, 1);
else
@@ -10913,23 +11100,9 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
}
-static void print_rowid(byte* val, int len)
-{
- byte *pb;
- DBUG_LOCK_FILE;
- fputc('\"', DBUG_FILE);
- for (pb= val; pb!= val + len; ++pb)
- fprintf(DBUG_FILE, "%c", *pb);
- fprintf(DBUG_FILE, "\", hex: ");
-
- for (pb= val; pb!= val + len; ++pb)
- fprintf(DBUG_FILE, "%x ", *pb);
- fputc('\n', DBUG_FILE);
- DBUG_UNLOCK_FILE;
-}
-
void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
{
+ /* purecov: begin inspected */
fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n",
indent, "", head->key_info[index].name, max_used_key_length);
@@ -10937,14 +11110,14 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
{
QUICK_RANGE *range;
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
- QUICK_RANGE **last_range= pr + ranges.elements;
- for (; pr!=last_range; ++pr)
+ QUICK_RANGE **end_range= pr + ranges.elements;
+ for (; pr != end_range; ++pr)
{
fprintf(DBUG_FILE, "%*s", indent + 2, "");
range= *pr;
if (!(range->flag & NO_MIN_RANGE))
{
- print_key(key_parts,range->min_key,range->min_length);
+ print_key(key_parts, range->min_key, range->min_length);
if (range->flag & NEAR_MIN)
fputs(" < ",DBUG_FILE);
else
@@ -10958,11 +11131,12 @@ void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
fputs(" < ",DBUG_FILE);
else
fputs(" <= ",DBUG_FILE);
- print_key(key_parts,range->max_key,range->max_length);
+ print_key(key_parts, range->max_key, range->max_length);
}
fputs("\n",DBUG_FILE);
}
}
+ /* purecov: end */
}
void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 170766c7c10..dd219129167 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,20 +35,26 @@ typedef struct st_key_part {
class QUICK_RANGE :public Sql_alloc {
public:
- char *min_key,*max_key;
+ uchar *min_key,*max_key;
uint16 min_length,max_length,flag;
+ key_part_map min_keypart_map, // bitmap of used keyparts in min_key
+ max_keypart_map; // bitmap of used keyparts in max_key
#ifdef HAVE_purify
uint16 dummy; /* Avoid warnings on 'flag' */
#endif
QUICK_RANGE(); /* Full range */
- QUICK_RANGE(const char *min_key_arg,uint min_length_arg,
- const char *max_key_arg,uint max_length_arg,
+ QUICK_RANGE(const uchar *min_key_arg, uint min_length_arg,
+ key_part_map min_keypart_map_arg,
+ const uchar *max_key_arg, uint max_length_arg,
+ key_part_map max_keypart_map_arg,
uint flag_arg)
- : min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
- max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
+ : min_key((uchar*) sql_memdup(min_key_arg,min_length_arg+1)),
+ max_key((uchar*) sql_memdup(max_key_arg,max_length_arg+1)),
min_length((uint16) min_length_arg),
max_length((uint16) max_length_arg),
- flag((uint16) flag_arg)
+ flag((uint16) flag_arg),
+ min_keypart_map(min_keypart_map_arg),
+ max_keypart_map(max_keypart_map_arg)
{
#ifdef HAVE_purify
dummy=0;
@@ -61,11 +66,11 @@ class QUICK_RANGE :public Sql_alloc {
/*
Quick select interface.
This class is a parent for all QUICK_*_SELECT and FT_SELECT classes.
-
+
The usage scenario is as follows:
1. Create quick select
quick= new QUICK_XXX_SELECT(...);
-
+
2. Perform lightweight initialization. This can be done in 2 ways:
2.a: Regular initialization
if (quick->init())
@@ -76,29 +81,29 @@ class QUICK_RANGE :public Sql_alloc {
2.b: Special initialization for quick selects merged by QUICK_ROR_*_SELECT
if (quick->init_ror_merged_scan())
delete quick;
-
+
3. Perform zero, one, or more scans.
while (...)
{
// initialize quick select for scan. This may allocate
- // buffers and/or prefetch rows.
+ // buffers and/or prefetch rows.
if (quick->reset())
{
//the only valid action after failed reset() call is delete
delete quick;
//abort query
}
-
+
// perform the scan
do
{
res= quick->get_next();
} while (res && ...)
}
-
+
4. Delete the select:
delete quick;
-
+
*/
class QUICK_SELECT_I
@@ -124,6 +129,8 @@ public:
Max. number of (first) key parts this quick select uses for retrieval.
eg. for "(key1p1=c1 AND key1p2=c2) OR key1p1=c2" used_key_parts == 2.
Applicable if index!= MAX_KEY.
+
+ For QUICK_GROUP_MIN_MAX_SELECT it includes MIN/MAX argument keyparts.
*/
uint used_key_parts;
@@ -234,12 +241,12 @@ public:
rowid of last row retrieved by this quick select. This is used only when
doing ROR-index_merge selects
*/
- byte *last_rowid;
+ uchar *last_rowid;
/*
Table record buffer used by this quick select.
*/
- byte *record;
+ uchar *record;
#ifndef DBUG_OFF
/*
Print quick select information to DBUG_FILE. Caller is responsible
@@ -289,8 +296,8 @@ protected:
friend bool get_quick_keys(PARAM *param,
QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,
- char *min_key, uint min_key_flag,
- char *max_key, uint max_key_flag);
+ uchar *min_key, uint min_key_flag,
+ uchar *max_key, uint max_key_flag);
friend QUICK_RANGE_SELECT *get_quick_select(PARAM*,uint idx,
SEL_ARG *key_tree,
MEM_ROOT *alloc);
@@ -302,7 +309,7 @@ protected:
DYNAMIC_ARRAY ranges; /* ordered array of range ptrs */
QUICK_RANGE **cur_range; /* current element in ranges */
- QUICK_RANGE *range;
+ QUICK_RANGE *last_range;
KEY_PART *key_parts;
KEY_PART_INFO *key_part_info;
int cmp_next(QUICK_RANGE *range);
@@ -319,7 +326,8 @@ public:
int reset(void);
int get_next();
void range_end();
- int get_next_prefix(uint prefix_length, byte *cur_prefix);
+ int get_next_prefix(uint prefix_length, key_part_map keypart_map,
+ uchar *cur_prefix);
bool reverse_sorted() { return 0; }
bool unique_key_range();
int init_ror_merged_scan(bool reuse_handler);
@@ -553,12 +561,12 @@ public:
MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
THD *thd; /* current thread */
- byte *cur_rowid; /* buffer used in get_next() */
- byte *prev_rowid; /* rowid of last row returned by get_next() */
+ uchar *cur_rowid; /* buffer used in get_next() */
+ uchar *prev_rowid; /* rowid of last row returned by get_next() */
bool have_prev_rowid; /* true if prev_rowid has valid data */
uint rowid_length; /* table rowid length */
private:
- static int queue_cmp(void *arg, byte *val1, byte *val2);
+ static int queue_cmp(void *arg, uchar *val1, uchar *val2);
bool scans_inited;
};
@@ -602,21 +610,23 @@ private:
handler *file; /* The handler used to get data. */
JOIN *join; /* Descriptor of the current query */
KEY *index_info; /* The index chosen for data access */
- byte *record; /* Buffer where the next record is returned. */
- byte *tmp_record; /* Temporary storage for next_min(), next_max(). */
- byte *group_prefix; /* Key prefix consisting of the GROUP fields. */
+ uchar *record; /* Buffer where the next record is returned. */
+ uchar *tmp_record; /* Temporary storage for next_min(), next_max(). */
+ uchar *group_prefix; /* Key prefix consisting of the GROUP fields. */
uint group_prefix_len; /* Length of the group prefix. */
- byte *last_prefix; /* Prefix of the last group for detecting EOF. */
+ uint group_key_parts; /* A number of keyparts in the group prefix */
+ uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
bool seen_first_key; /* Denotes whether the first key was retrieved.*/
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
/* of all MIN/MAX functions. */
uint min_max_arg_len; /* The length of the MIN/MAX argument field */
- byte *key_infix; /* Infix of constants from equality predicates. */
+ uchar *key_infix; /* Infix of constants from equality predicates. */
uint key_infix_len;
DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
uint real_prefix_len; /* Length of key prefix extended with key_infix. */
+ uint real_key_parts; /* A number of keyparts in the above value. */
List<Item_sum> *min_functions;
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
@@ -639,10 +649,11 @@ private:
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
bool have_max, KEY_PART_INFO *min_max_arg_part,
- uint group_prefix_len, uint used_key_parts,
- KEY *index_info, uint use_index, double read_cost,
- ha_rows records, uint key_infix_len,
- byte *key_infix, MEM_ROOT *parent_alloc);
+ uint group_prefix_len, uint group_key_parts,
+ uint used_key_parts, KEY *index_info, uint
+ use_index, double read_cost, ha_rows records, uint
+ key_infix_len, uchar *key_infix, MEM_ROOT
+ *parent_alloc);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();
@@ -725,7 +736,7 @@ uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
-void store_key_image_to_rec(Field *field, char *ptr, uint len);
+void store_key_image_to_rec(Field *field, uchar *ptr, uint len);
#endif
#endif
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index cb8b53ac6a7..8851401d21f 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -98,9 +97,9 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables)
GROUP BY part.
RETURN VALUES
- 0 No errors
- 1 if all items were resolved
- -1 on impossible conditions
+ 0 no errors
+ 1 if all items were resolved
+ HA_ERR_KEY_NOT_FOUND on impossible conditions
OR an error number from my_base.h HA_ERR_... if a deadlock or a lock
wait timeout happens, for example
*/
@@ -223,7 +222,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Item *expr=item_sum->args[0];
if (expr->real_item()->type() == Item::FIELD_ITEM)
{
- byte key_buff[MAX_KEY_LENGTH];
+ uchar key_buff[MAX_KEY_LENGTH];
TABLE_REF ref;
uint range_fl, prefix_len;
@@ -250,12 +249,69 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (!ref.key_length)
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);
+ else
+ {
+ /*
+ Use index to replace MIN/MAX functions with their values
+ according to the following rules:
+
+ 1) Insert the minimum non-null values where the WHERE clause still
+ matches, or
+ 2) a NULL value if there are only NULL values for key_part_k.
+ 3) Fail, producing a row of nulls
+
+ Implementation: Read the smallest value using the search key. If
+ the interval is open, read the next value after the search
+ key. If read fails, and we're looking for a MIN() value for a
+ nullable column, test if there is an exact match for the key.
+ */
+ if (!(range_fl & NEAR_MIN))
+ /*
+ Closed interval: Either The MIN argument is non-nullable, or
+ we have a >= predicate for the MIN argument.
+ */
+ error= table->file->index_read(table->record[0], ref.key_buff,
+ make_prev_keypart_map(ref.key_parts),
+ HA_READ_KEY_OR_NEXT);
+ else
+ {
+ /*
+ Open interval: There are two cases:
+ 1) We have only MIN() and the argument column is nullable, or
+ 2) there is a > predicate on it, nullability is irrelevant.
+ We need to scan the next bigger record first.
+ */
+ error= table->file->index_read(table->record[0], ref.key_buff,
+ make_prev_keypart_map(ref.key_parts),
+ HA_READ_AFTER_KEY);
+ /*
+ If the found record is outside the group formed by the search
+ prefix, or there is no such record at all, check if all
+ records in that group have NULL in the MIN argument
+ column. If that is the case return that NULL.
+
+ Check if case 1 from above holds. If it does, we should read
+ the skipped tuple.
+ */
+ if (ref.key_buff[prefix_len] == 1 &&
+ /*
+ Last keypart (i.e. the argument to MIN) is set to NULL by
+ find_key_for_maxmin only if all other keyparts are bound
+ to constants in a conjunction of equalities. Hence, we
+ can detect this by checking only if the last keypart is
+ NULL.
+ */
+ (error == HA_ERR_KEY_NOT_FOUND ||
+ key_cmp_if_same(table, ref.key_buff, ref.key, prefix_len)))
+ {
+ DBUG_ASSERT(item_field->field->real_maybe_null());
+ error= table->file->index_read(table->record[0], ref.key_buff,
+ make_prev_keypart_map(ref.key_parts),
+ HA_READ_KEY_EXACT);
+ }
+ }
+ }
+ /* Verify that the read tuple indeed matches the search key */
if (!error && reckey_in_range(0, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
@@ -268,7 +324,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return -1; // No rows matching WHERE
+ return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
return(error);
@@ -310,7 +366,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Item *expr=item_sum->args[0];
if (expr->real_item()->type() == Item::FIELD_ITEM)
{
- byte key_buff[MAX_KEY_LENGTH];
+ uchar key_buff[MAX_KEY_LENGTH];
TABLE_REF ref;
uint range_fl, prefix_len;
@@ -339,11 +395,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= table->file->index_last(table->record[0]);
else
error= table->file->index_read(table->record[0], key_buff,
- ref.key_length,
+ make_prev_keypart_map(ref.key_parts),
range_fl & NEAR_MAX ?
HA_READ_BEFORE_KEY :
HA_READ_PREFIX_LAST_OR_PREV);
- if (!error && reckey_in_range(1, &ref, item_field->field,
+ 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)
@@ -355,7 +411,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return -1; // No rows matching WHERE
+ return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
return(error);
@@ -604,17 +660,15 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
less_fl= 1-less_fl; // Convert '<' -> '>' (etc)
/* Check if field is part of the tested partial key */
- byte *key_ptr= ref->key_buff;
+ uchar *key_ptr= ref->key_buff;
KEY_PART_INFO *part;
- for (part= keyinfo->key_part;
- ;
- key_ptr+= part++->store_length)
+ for (part= keyinfo->key_part; ; key_ptr+= part++->store_length)
{
if (part > field_part)
return 0; // Field is beyond the tested parts
if (part->field->eq(((Item_field*) args[0])->field))
- break; // Found a part od the key for the field
+ break; // Found a part of the key for the field
}
bool is_field_part= part == field_part;
@@ -626,8 +680,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
{
uint length= (key_ptr-ref->key_buff)+part->store_length;
if (ref->key_length < length)
+ {
/* Ultimately ref->key_length will contain the length of the search key */
ref->key_length= length;
+ ref->key_parts= (part - keyinfo->key_part) + 1;
+ }
if (!*prefix_len && part+1 == field_part)
*prefix_len= length;
if (is_field_part && eq_type)
@@ -652,15 +709,15 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
if (is_null)
{
part->field->set_null();
- *key_ptr= (byte) 1;
+ *key_ptr= (uchar) 1;
}
else
{
store_val_in_field(part->field, args[between && max_fl ? 2 : 1],
CHECK_FIELD_IGNORE);
if (part->null_bit)
- *key_ptr++= (byte) test(part->field->is_null());
- part->field->get_key_image((char*) key_ptr, part->length, Field::itRAW);
+ *key_ptr++= (uchar) test(part->field->is_null());
+ part->field->get_key_image(key_ptr, part->length, Field::itRAW);
}
if (is_field_part)
{
@@ -774,6 +831,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
{
ref->key= idx;
ref->key_length= 0;
+ ref->key_parts= 0;
key_part_map key_part_used= 0;
*range_fl= NO_MIN_RANGE | NO_MAX_RANGE;
if (matching_cond(max_fl, ref, keyinfo, part, cond,
@@ -783,14 +841,26 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
if (!max_fl && key_part_used == key_part_to_use && part->null_bit)
{
/*
- SELECT MIN(key_part2) FROM t1 WHERE key_part1=const
- If key_part2 may be NULL, then we want to find the first row
- that is not null
+ The query is on this form:
+
+ SELECT MIN(key_part_k)
+ FROM t1
+ WHERE key_part_1 = const and ... and key_part_k-1 = const
+
+ If key_part_k is nullable, we want to find the first matching row
+ where key_part_k is not null. The key buffer is now {const, ...,
+ NULL}. This will be passed to the handler along with a flag
+ indicating open interval. If a tuple is read that does not match
+ these search criteria, an attempt will be made to read an exact
+ match for the key buffer.
*/
+ /* Set the first byte of key_part_k to 1, that means NULL */
ref->key_buff[ref->key_length]= 1;
ref->key_length+= part->store_length;
+ ref->key_parts++;
+ DBUG_ASSERT(ref->key_parts == jdx+1);
*range_fl&= ~NO_MIN_RANGE;
- *range_fl|= NEAR_MIN; // > NULL
+ *range_fl|= NEAR_MIN; // Open interval
}
/*
The following test is false when the key in the key tree is
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 0a2d4012af4..5ea49396cb4 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -50,27 +49,27 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
*/
switch(*ptr) {
case '\\': // escape character
- if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\\")))
+ if (my_b_append(file, (const uchar *)STRING_WITH_LEN("\\\\")))
return TRUE;
break;
case '\n': // parameter value delimiter
- if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\n")))
+ if (my_b_append(file, (const uchar *)STRING_WITH_LEN("\\n")))
return TRUE;
break;
case '\0': // problem for some string processing utilities
- if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\0")))
+ if (my_b_append(file, (const uchar *)STRING_WITH_LEN("\\0")))
return TRUE;
break;
case 26: // problem for windows utilities (Ctrl-Z)
- if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\z")))
+ if (my_b_append(file, (const uchar *)STRING_WITH_LEN("\\z")))
return TRUE;
break;
case '\'': // list of string delimiter
- if (my_b_append(file, (const byte *)STRING_WITH_LEN("\\\'")))
+ if (my_b_append(file, (const uchar *)STRING_WITH_LEN("\\\'")))
return TRUE;
break;
default:
- if (my_b_append(file, (const byte *)ptr, 1))
+ if (my_b_append(file, (const uchar *)ptr, 1))
return TRUE;
}
}
@@ -94,7 +93,7 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
*/
static my_bool
-write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
+write_parameter(IO_CACHE *file, uchar* base, File_option *parameter,
ulonglong *old_version)
{
char num_buf[20]; // buffer for numeric operations
@@ -106,7 +105,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
case FILE_OPTIONS_STRING:
{
LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset);
- if (my_b_append(file, (const byte *)val_s->str, val_s->length))
+ if (my_b_append(file, (const uchar *)val_s->str, val_s->length))
DBUG_RETURN(TRUE);
break;
}
@@ -119,7 +118,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
case FILE_OPTIONS_ULONGLONG:
{
num.set(*((ulonglong *)(base + parameter->offset)), &my_charset_bin);
- if (my_b_append(file, (const byte *)num.ptr(), num.length()))
+ if (my_b_append(file, (const uchar *)num.ptr(), num.length()))
DBUG_RETURN(TRUE);
break;
}
@@ -128,7 +127,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
ulonglong *val_i= (ulonglong *)(base + parameter->offset);
*old_version= (*val_i)++;
num.set(*val_i, &my_charset_bin);
- if (my_b_append(file, (const byte *)num.ptr(), num.length()))
+ if (my_b_append(file, (const uchar *)num.ptr(), num.length()))
DBUG_RETURN(TRUE);
break;
}
@@ -141,7 +140,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH,
tm);
val_s->length= PARSE_FILE_TIMESTAMPLENGTH;
- if (my_b_append(file, (const byte *)val_s->str,
+ if (my_b_append(file, (const uchar *)val_s->str,
PARSE_FILE_TIMESTAMPLENGTH))
DBUG_RETURN(TRUE);
break;
@@ -155,10 +154,10 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
while ((str= it++))
{
// We need ' ' after string to detect list continuation
- if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) ||
- my_b_append(file, (const byte *)STRING_WITH_LEN("\'")) ||
+ if ((!first && my_b_append(file, (const uchar *)STRING_WITH_LEN(" "))) ||
+ my_b_append(file, (const uchar *)STRING_WITH_LEN("\'")) ||
write_escaped_string(file, str) ||
- my_b_append(file, (const byte *)STRING_WITH_LEN("\'")))
+ my_b_append(file, (const uchar *)STRING_WITH_LEN("\'")))
{
DBUG_RETURN(TRUE);
}
@@ -176,8 +175,8 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
{
num.set(*val, &my_charset_bin);
// We need ' ' after string to detect list continuation
- if ((!first && my_b_append(file, (const byte *)STRING_WITH_LEN(" "))) ||
- my_b_append(file, (const byte *)num.ptr(), num.length()))
+ if ((!first && my_b_append(file, (const uchar *)STRING_WITH_LEN(" "))) ||
+ my_b_append(file, (const uchar *)num.ptr(), num.length()))
{
DBUG_RETURN(TRUE);
}
@@ -213,7 +212,7 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
my_bool
sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
const LEX_STRING *type,
- gptr base, File_option *parameters,
+ uchar* base, File_option *parameters,
uint max_versions)
{
File handler;
@@ -229,7 +228,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
if (dir)
{
- fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
+ fn_format(path, file_name->str, dir->str, "", MY_UNPACK_FILENAME);
path_end= strlen(path);
}
else
@@ -255,19 +254,19 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
goto err_w_file;
// write header (file signature)
- if (my_b_append(&file, (const byte *)STRING_WITH_LEN("TYPE=")) ||
- my_b_append(&file, (const byte *)type->str, type->length) ||
- my_b_append(&file, (const byte *)STRING_WITH_LEN("\n")))
+ if (my_b_append(&file, (const uchar *)STRING_WITH_LEN("TYPE=")) ||
+ my_b_append(&file, (const uchar *)type->str, type->length) ||
+ my_b_append(&file, (const uchar *)STRING_WITH_LEN("\n")))
goto err_w_file;
// write parameters to temporary file
for (param= parameters; param->name.str; param++)
{
- if (my_b_append(&file, (const byte *)param->name.str,
+ if (my_b_append(&file, (const uchar *)param->name.str,
param->name.length) ||
- my_b_append(&file, (const byte *)STRING_WITH_LEN("=")) ||
+ my_b_append(&file, (const uchar *)STRING_WITH_LEN("=")) ||
write_parameter(&file, base, param, &old_version) ||
- my_b_append(&file, (const byte *)STRING_WITH_LEN("\n")))
+ my_b_append(&file, (const uchar *)STRING_WITH_LEN("\n")))
goto err_w_cache;
}
@@ -424,7 +423,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
bool bad_format_errors)
{
MY_STAT stat_info;
- uint len;
+ size_t len;
char *end, *sign;
File_parser *parser;
File file;
@@ -446,7 +445,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
- if (!(parser->buff= alloc_root(mem_root, stat_info.st_size+1)))
+ if (!(parser->buff= (char*) alloc_root(mem_root, stat_info.st_size+1)))
{
DBUG_RETURN(0);
}
@@ -456,7 +455,7 @@ sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
- if ((len= my_read(file, (byte *)parser->buff,
+ if ((len= my_read(file, (uchar *)parser->buff,
stat_info.st_size, MYF(MY_WME))) ==
MY_FILE_ERROR)
{
@@ -534,11 +533,8 @@ parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
str->length= eol - ptr;
- if (!(str->str= alloc_root(mem_root, str->length+1)))
+ if (!(str->str= strmake_root(mem_root, ptr, str->length)))
return 0;
-
- memcpy(str->str, ptr, str->length);
- str->str[str->length]= '\0'; // just for safety
return eol+1;
}
@@ -624,7 +620,7 @@ parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
char *eol= strchr(ptr, '\n');
if (eol == 0 || eol >= end ||
- !(str->str= alloc_root(mem_root, (eol - ptr) + 1)) ||
+ !(str->str= (char*) alloc_root(mem_root, (eol - ptr) + 1)) ||
read_escaped_string(ptr, eol, str))
return 0;
@@ -669,7 +665,7 @@ parse_quoted_escaped_string(char *ptr, char *end,
// process string
if (eol >= end ||
- !(str->str= alloc_root(mem_root, result_len + 1)) ||
+ !(str->str= (char*) alloc_root(mem_root, result_len + 1)) ||
read_escaped_string(ptr, eol, str))
return 0;
@@ -692,7 +688,7 @@ parse_quoted_escaped_string(char *ptr, char *end,
*/
bool get_file_options_ulllist(char *&ptr, char *end, char *line,
- gptr base, File_option *parameter,
+ uchar* base, File_option *parameter,
MEM_ROOT *mem_root)
{
List<ulonglong> *nlist= (List<ulonglong>*)(base + parameter->offset);
@@ -734,14 +730,18 @@ nlist_err:
/*
parse parameters
-
+
SYNOPSIS
File_parser::parse()
base base address for parameter writing (structure like
TABLE)
mem_root MEM_ROOT for parameters allocation
parameters parameters description
- required number of required parameters in above list
+ required number of parameters in the above list. If the file
+ contains more parameters than "required", they will
+ be ignored. If the file contains less parameters
+ then "required", non-existing parameters will
+ remain their values.
hook hook called for unknown keys
hook_data some data specific for the hook
@@ -751,7 +751,7 @@ nlist_err:
*/
my_bool
-File_parser::parse(gptr base, MEM_ROOT *mem_root,
+File_parser::parse(uchar* base, MEM_ROOT *mem_root,
struct File_option *parameters, uint required,
Unknown_key_hook *hook)
{
@@ -924,6 +924,13 @@ list_err:
}
}
}
+
+ /*
+ NOTE: if we read less than "required" parameters, it is still Ok.
+ Probably, we've just read the file of the previous version, which
+ contains less parameters.
+ */
+
DBUG_RETURN(FALSE);
}
@@ -953,7 +960,7 @@ list_err:
bool
File_parser_dummy_hook::process_unknown_string(char *&unknown_key,
- gptr base, MEM_ROOT *mem_root,
+ uchar* base, MEM_ROOT *mem_root,
char *end)
{
DBUG_ENTER("file_parser_dummy_hook::process_unknown_string");
diff --git a/sql/parse_file.h b/sql/parse_file.h
index 0a02bf7eb75..91700959681 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -51,7 +50,7 @@ class Unknown_key_hook
public:
Unknown_key_hook() {} /* Remove gcc warning */
virtual ~Unknown_key_hook() {} /* Remove gcc warning */
- virtual bool process_unknown_string(char *&unknown_key, gptr base,
+ virtual bool process_unknown_string(char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end)= 0;
};
@@ -62,14 +61,14 @@ class File_parser_dummy_hook: public Unknown_key_hook
{
public:
File_parser_dummy_hook() {} /* Remove gcc warning */
- virtual bool process_unknown_string(char *&unknown_key, gptr base,
+ virtual bool process_unknown_string(char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end);
};
extern File_parser_dummy_hook file_parser_dummy_hook;
bool get_file_options_ulllist(char *&ptr, char *end, char *line,
- gptr base, File_option *parameter,
+ uchar* base, File_option *parameter,
MEM_ROOT *mem_root);
char *
@@ -82,7 +81,7 @@ File_parser *sql_parse_prepare(const LEX_STRING *file_name,
my_bool
sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
const LEX_STRING *type,
- gptr base, File_option *parameters, uint versions);
+ uchar* base, File_option *parameters, uint versions);
my_bool rename_in_schema_file(const char *schema, const char *old_name,
const char *new_name, ulonglong revision,
uint num_view_backups);
@@ -98,7 +97,7 @@ public:
my_bool ok() { return content_ok; }
LEX_STRING *type() { return &file_type; }
- my_bool parse(gptr base, MEM_ROOT *mem_root,
+ my_bool parse(uchar* base, MEM_ROOT *mem_root,
struct File_option *parameters, uint required,
Unknown_key_hook *hook);
diff --git a/sql/partition_element.h b/sql/partition_element.h
index 1e2769bc21a..905bc38165b 100644
--- a/sql/partition_element.h
+++ b/sql/partition_element.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000,200666666 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/**
* An enum and a struct to handle partitioning and subpartitioning.
@@ -85,9 +84,9 @@ public:
partition_element(partition_element *part_elem)
: part_max_rows(part_elem->part_max_rows),
part_min_rows(part_elem->part_min_rows),
- partition_name(NULL),
+ range_value(0), partition_name(NULL),
tablespace_name(part_elem->tablespace_name),
- range_value(0), part_comment(part_elem->part_comment),
+ part_comment(part_elem->part_comment),
data_file_name(part_elem->data_file_name),
index_file_name(part_elem->index_file_name),
engine_type(part_elem->engine_type),
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 9d5b6d0494a..23bc3c96e8f 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -91,10 +90,11 @@ partition_info *partition_info::get_clone()
#define MAX_PART_NAME_SIZE 8
-char *partition_info::create_default_partition_names(uint part_no, uint no_parts,
+char *partition_info::create_default_partition_names(uint part_no,
+ uint no_parts,
uint start_no)
{
- char *ptr= sql_calloc(no_parts*MAX_PART_NAME_SIZE);
+ char *ptr= (char*) sql_calloc(no_parts*MAX_PART_NAME_SIZE);
char *move_ptr= ptr;
uint i= 0;
DBUG_ENTER("create_default_partition_names");
@@ -130,7 +130,7 @@ char *partition_info::create_subpartition_name(uint subpart_no,
const char *part_name)
{
uint size_alloc= strlen(part_name) + MAX_PART_NAME_SIZE;
- char *ptr= sql_calloc(size_alloc);
+ char *ptr= (char*) sql_calloc(size_alloc);
DBUG_ENTER("create_subpartition_name");
if (likely(ptr != NULL))
@@ -188,8 +188,14 @@ bool partition_info::set_up_default_partitions(handler *file,
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
goto end;
}
- if (no_parts == 0)
- no_parts= file->get_default_no_partitions(info);
+
+ if ((no_parts == 0) &&
+ ((no_parts= file->get_default_no_partitions(info)) == 0))
+ {
+ my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
+ goto end;
+ }
+
if (unlikely(no_parts > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
@@ -754,7 +760,11 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
}
if (unlikely(set_up_defaults_for_partitioning(file, info, (uint)0)))
goto end;
- tot_partitions= get_tot_partitions();
+ if (!(tot_partitions= get_tot_partitions()))
+ {
+ my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
+ goto end;
+ }
if (unlikely(tot_partitions > MAX_PARTITIONS))
{
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
@@ -777,6 +787,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
partition_element *part_elem= part_it++;
if (part_elem->engine_type == NULL)
part_elem->engine_type= default_engine_type;
+ if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
+ part_elem->data_file_name= part_elem->index_file_name= 0;
if (!is_sub_partitioned())
{
if (check_table_name(part_elem->partition_name,
@@ -850,15 +862,27 @@ void partition_info::print_no_partition_found(TABLE *table)
{
char buf[100];
char *buf_ptr= (char*)&buf;
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ TABLE_LIST table_list;
+
+ bzero(&table_list, sizeof(table_list));
+ table_list.db= table->s->db.str;
+ table_list.table_name= table->s->table_name.str;
- if (part_expr->null_value)
- buf_ptr= (char*)"NULL";
+ if (check_single_table_access(current_thd,
+ SELECT_ACL, &table_list, TRUE))
+ my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
+ ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0));
else
- longlong2str(err_value, buf,
- part_expr->unsigned_flag ? 10 : -10);
- my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
- dbug_tmp_restore_column_map(table->read_set, old_map);
+ {
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+ if (part_expr->null_value)
+ buf_ptr= (char*)"NULL";
+ else
+ longlong2str(err_value, buf,
+ part_expr->unsigned_flag ? 10 : -10);
+ my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+ }
}
/*
Set up buffers and arrays for fields requiring preparation
@@ -879,7 +903,7 @@ void partition_info::print_no_partition_found(TABLE *table)
bool partition_info::set_up_charset_field_preps()
{
Field *field, **ptr;
- char **char_ptrs;
+ uchar **char_ptrs;
unsigned i;
bool found;
size_t size;
@@ -904,14 +928,14 @@ bool partition_info::set_up_charset_field_preps()
}
}
size= tot_part_fields * sizeof(char*);
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
part_field_buffers= char_ptrs;
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
restore_part_field_ptrs= char_ptrs;
size= (tot_part_fields + 1) * sizeof(Field*);
- if (!(char_ptrs= (char**)sql_alloc(size)))
+ if (!(char_ptrs= (uchar**)sql_alloc(size)))
goto error;
part_charset_field_array= (Field**)char_ptrs;
ptr= part_field_array;
@@ -920,10 +944,9 @@ bool partition_info::set_up_charset_field_preps()
{
if (field_is_partition_charset(field))
{
- char *field_buf;
- CHARSET_INFO *cs= ((Field_str*)field)->charset();
+ uchar *field_buf;
size= field->pack_length();
- if (!(field_buf= sql_calloc(size)))
+ if (!(field_buf= (uchar*) sql_calloc(size)))
goto error;
part_charset_field_array[i]= field;
part_field_buffers[i++]= field_buf;
@@ -942,14 +965,14 @@ bool partition_info::set_up_charset_field_preps()
tot_subpart_fields++;
}
size= tot_subpart_fields * sizeof(char*);
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**) sql_calloc(size)))
goto error;
subpart_field_buffers= char_ptrs;
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**) sql_calloc(size)))
goto error;
restore_subpart_field_ptrs= char_ptrs;
size= (tot_subpart_fields + 1) * sizeof(Field*);
- if (!(char_ptrs= (char**)sql_alloc(size)))
+ if (!(char_ptrs= (uchar**) sql_alloc(size)))
goto error;
subpart_charset_field_array= (Field**)char_ptrs;
i= 0;
@@ -957,7 +980,7 @@ bool partition_info::set_up_charset_field_preps()
{
unsigned j= 0;
CHARSET_INFO *cs;
- char *field_buf;
+ uchar *field_buf;
LINT_INIT(field_buf);
if (!field_is_partition_charset(field))
@@ -973,12 +996,12 @@ bool partition_info::set_up_charset_field_preps()
if (!found)
{
tot_fields++;
- if (!(field_buf= sql_calloc(size)))
+ if (!(field_buf= (uchar*) sql_calloc(size)))
goto error;
}
subpart_field_buffers[i++]= field_buf;
}
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**) sql_calloc(size)))
goto error;
restore_subpart_field_ptrs= char_ptrs;
}
@@ -987,14 +1010,14 @@ bool partition_info::set_up_charset_field_preps()
uint j,k,l;
size= tot_fields*sizeof(char**);
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
full_part_field_buffers= char_ptrs;
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
restore_full_part_field_ptrs= char_ptrs;
size= (tot_fields + 1) * sizeof(char**);
- if (!(char_ptrs= (char**)sql_calloc(size)))
+ if (!(char_ptrs= (uchar**)sql_calloc(size)))
goto error;
full_part_charset_field_array= (Field**)char_ptrs;
for (i= 0; i < tot_part_fields; i++)
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 09d827d44c4..ce2f2a7b358 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000,2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
@@ -88,12 +87,12 @@ public:
partition functions we must allocate field buffers for the field of
the fields in the partition function.
*/
- char **part_field_buffers;
- char **subpart_field_buffers;
- char **full_part_field_buffers;
- char **restore_part_field_ptrs;
- char **restore_subpart_field_ptrs;
- char **restore_full_part_field_ptrs;
+ uchar **part_field_buffers;
+ uchar **subpart_field_buffers;
+ uchar **full_part_field_buffers;
+ uchar **restore_part_field_ptrs;
+ uchar **restore_subpart_field_ptrs;
+ uchar **restore_full_part_field_ptrs;
Item *part_expr;
Item *subpart_expr;
@@ -157,7 +156,7 @@ public:
char *part_func_string;
char *subpart_func_string;
- uchar *part_state;
+ const char *part_state;
partition_element *curr_part_elem;
partition_element *current_partition;
diff --git a/sql/password.c b/sql/password.c
index c6d904bc45b..1ff67888ea4 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -473,7 +472,7 @@ scramble(char *to, const char *message, const char *password)
*/
my_bool
-check_scramble(const char *scramble, const char *message,
+check_scramble(const char *scramble_arg, const char *message,
const uint8 *hash_stage2)
{
SHA1_CONTEXT sha1_context;
@@ -486,7 +485,7 @@ check_scramble(const char *scramble, const char *message,
mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
mysql_sha1_result(&sha1_context, buf);
/* encrypt scramble */
- my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH);
+ my_crypt((char *) buf, buf, (const uchar *) scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
mysql_sha1_reset(&sha1_context);
mysql_sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
@@ -496,7 +495,8 @@ check_scramble(const char *scramble, const char *message,
/*
- Convert scrambled password from asciiz hex string to binary form.
+ Convert scrambled password from asciiz hex string to binary form.
+
SYNOPSIS
get_salt_from_password()
res OUT buf to hold password. Must be at least SHA1_HASH_SIZE
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 554e2cd0565..bbfabc46608 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2002, 2004-2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/procedure.h b/sql/procedure.h
index 5c8a3387eec..6a731766046 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 6fe4e34d5a9..2ed241c4c98 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,13 +27,15 @@
#include <stdarg.h>
static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
-static void write_eof_packet(THD *thd, NET *net);
void net_send_error_packet(THD *thd, uint sql_errno, const char *err);
+#ifndef EMBEDDED_LIBRARY
+static void write_eof_packet(THD *thd, NET *net);
+#endif
#ifndef EMBEDDED_LIBRARY
-bool Protocol::net_store_data(const char *from, uint length)
+bool Protocol::net_store_data(const uchar *from, size_t length)
#else
-bool Protocol_prep::net_store_data(const char *from, uint length)
+bool Protocol_binary::net_store_data(const uchar *from, size_t length)
#endif
{
ulong packet_length=packet->length();
@@ -45,10 +46,9 @@ bool Protocol_prep::net_store_data(const char *from, uint length)
if (packet_length+9+length > packet->alloced_length() &&
packet->realloc(packet_length+9+length))
return 1;
- char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
- length);
+ uchar *to= net_store_length((uchar*) packet->ptr()+packet_length, length);
memcpy(to,from,length);
- packet->length((uint) (to+length-packet->ptr()));
+ packet->length((uint) (to+length-(uchar*) packet->ptr()));
return 0;
}
@@ -226,7 +226,7 @@ net_printf_error(THD *thd, uint errcode, ...)
memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
}
}
- VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
+ VOID(net_real_write(net, net->buff, length+head_length+1+offset));
#else
net->last_errno= errcode;
strmake(net->last_error, text_pos, length);
@@ -270,7 +270,7 @@ void
send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
{
NET *net= &thd->net;
- char buff[MYSQL_ERRMSG_SIZE+10],*pos;
+ uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
DBUG_ENTER("send_ok");
if (net->no_send_ok || !net->vio) // hack for re-parsing queries
@@ -306,8 +306,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
pos+=2;
}
if (message)
- pos=net_store_data((char*) pos, message, strlen(message));
- VOID(my_net_write(net,buff,(uint) (pos-buff)));
+ pos= net_store_data(pos, (uchar*) message, strlen(message));
+ VOID(my_net_write(net, buff, (size_t) (pos-buff)));
VOID(net_flush(net));
/* We can't anymore send an error to the client */
thd->net.report_error= 0;
@@ -317,7 +317,7 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
DBUG_VOID_RETURN;
}
-static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
+static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */
/*
Send eof (= end of result set) to the client
@@ -382,7 +382,7 @@ static void write_eof_packet(THD *thd, NET *net)
if (thd->is_fatal_error)
thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
int2store(buff+3, thd->server_status);
- VOID(my_net_write(net, (char*) buff, 5));
+ VOID(my_net_write(net, buff, 5));
}
else
VOID(my_net_write(net, eof_buff, 1));
@@ -410,7 +410,7 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
{
NET *net= &thd->net;
uint length;
- char buff[MYSQL_ERRMSG_SIZE+2], *pos;
+ uchar buff[MYSQL_ERRMSG_SIZE+2], *pos;
DBUG_ENTER("send_error_packet");
@@ -432,17 +432,19 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
{
/* The first # is to make the protocol backward compatible */
buff[2]= '#';
- pos= strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
+ pos= (uchar*) strmov((char*) buff+3, mysql_errno_to_sqlstate(sql_errno));
}
- length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
- err=buff;
+ length= (uint) (strmake((char*) pos, err, MYSQL_ERRMSG_SIZE-1) -
+ (char*) buff);
+ err= (char*) buff;
}
else
{
length=(uint) strlen(err);
set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
}
- VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length));
+ VOID(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) err,
+ length));
DBUG_VOID_RETURN;
}
@@ -458,17 +460,16 @@ void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
ulonglong for bigger numbers.
*/
-static char *net_store_length_fast(char *pkg, uint length)
+static uchar *net_store_length_fast(uchar *packet, uint length)
{
- uchar *packet=(uchar*) pkg;
if (length < 251)
{
*packet=(uchar) length;
- return (char*) packet+1;
+ return packet+1;
}
*packet++=252;
int2store(packet,(uint) length);
- return (char*) packet+2;
+ return packet+2;
}
@@ -479,14 +480,14 @@ static char *net_store_length_fast(char *pkg, uint length)
/* The following will only be used for short strings < 65K */
-char *net_store_data(char *to,const char *from, uint length)
+uchar *net_store_data(uchar *to, const uchar *from, size_t length)
{
to=net_store_length_fast(to,length);
memcpy(to,from,length);
return to+length;
}
-char *net_store_data(char *to,int32 from)
+uchar *net_store_data(uchar *to,int32 from)
{
char buff[20];
uint length=(uint) (int10_to_str(from,buff,10)-buff);
@@ -495,7 +496,7 @@ char *net_store_data(char *to,int32 from)
return to+length;
}
-char *net_store_data(char *to,longlong from)
+uchar *net_store_data(uchar *to,longlong from)
{
char buff[22];
uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
@@ -554,17 +555,17 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
{
List_iterator_fast<Item> it(*list);
Item *item;
- char buff[80];
+ uchar buff[80];
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- Protocol_simple prot(thd);
+ Protocol_text prot(thd);
String *local_packet= prot.storage_packet();
CHARSET_INFO *thd_charset= thd->variables.character_set_results;
DBUG_ENTER("send_fields");
if (flags & SEND_NUM_ROWS)
{ // Packet with number of elements
- char *pos=net_store_length(buff, list->elements);
- (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
+ uchar *pos= net_store_length(buff, list->elements);
+ (void) my_net_write(&thd->net, buff, (size_t) (pos-buff));
}
#ifndef DBUG_OFF
@@ -697,7 +698,8 @@ err:
bool Protocol::write()
{
DBUG_ENTER("Protocol::write");
- DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length()));
+ DBUG_RETURN(my_net_write(&thd->net, (uchar*) packet->ptr(),
+ packet->length()));
}
#endif /* EMBEDDED_LIBRARY */
@@ -759,7 +761,7 @@ bool Protocol::store(I_List<i_string>* str_list)
****************************************************************************/
#ifndef EMBEDDED_LIBRARY
-void Protocol_simple::prepare_for_resend()
+void Protocol_text::prepare_for_resend()
{
packet->length(0);
#ifndef DBUG_OFF
@@ -767,7 +769,7 @@ void Protocol_simple::prepare_for_resend()
#endif
}
-bool Protocol_simple::store_null()
+bool Protocol_text::store_null()
{
#ifndef DBUG_OFF
field_pos++;
@@ -784,7 +786,7 @@ bool Protocol_simple::store_null()
and store in network buffer.
*/
-bool Protocol::store_string_aux(const char *from, uint length,
+bool Protocol::store_string_aux(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
/* 'tocs' is set 0 when client issues SET character_set_results=NULL */
@@ -793,15 +795,15 @@ bool Protocol::store_string_aux(const char *from, uint length,
tocs != &my_charset_bin)
{
uint dummy_errors;
- return convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
- net_store_data(convert->ptr(), convert->length());
+ return (convert->copy(from, length, fromcs, tocs, &dummy_errors) ||
+ net_store_data((uchar*) convert->ptr(), convert->length()));
}
- return net_store_data(from, length);
+ return net_store_data((uchar*) from, length);
}
-bool Protocol_simple::store(const char *from, uint length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
+bool Protocol_text::store(const char *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -816,8 +818,8 @@ bool Protocol_simple::store(const char *from, uint length,
}
-bool Protocol_simple::store(const char *from, uint length,
- CHARSET_INFO *fromcs)
+bool Protocol_text::store(const char *from, size_t length,
+ CHARSET_INFO *fromcs)
{
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
#ifndef DBUG_OFF
@@ -833,19 +835,19 @@ bool Protocol_simple::store(const char *from, uint length,
}
-bool Protocol_simple::store_tiny(longlong from)
+bool Protocol_text::store_tiny(longlong from)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
field_pos++;
#endif
char buff[20];
- return net_store_data((char*) buff,
- (uint) (int10_to_str((int) from,buff, -10)-buff));
+ return net_store_data((uchar*) buff,
+ (size_t) (int10_to_str((int) from, buff, -10) - buff));
}
-bool Protocol_simple::store_short(longlong from)
+bool Protocol_text::store_short(longlong from)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -854,12 +856,13 @@ bool Protocol_simple::store_short(longlong from)
field_pos++;
#endif
char buff[20];
- return net_store_data((char*) buff,
- (uint) (int10_to_str((int) from,buff, -10)-buff));
+ return net_store_data((uchar*) buff,
+ (size_t) (int10_to_str((int) from, buff, -10) -
+ buff));
}
-bool Protocol_simple::store_long(longlong from)
+bool Protocol_text::store_long(longlong from)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -868,12 +871,13 @@ bool Protocol_simple::store_long(longlong from)
field_pos++;
#endif
char buff[20];
- return net_store_data((char*) buff,
- (uint) (int10_to_str((long int)from,buff, (from <0)?-10:10)-buff));
+ return net_store_data((uchar*) buff,
+ (size_t) (int10_to_str((long int)from, buff,
+ (from <0)?-10:10)-buff));
}
-bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
+bool Protocol_text::store_longlong(longlong from, bool unsigned_flag)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -881,14 +885,14 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
field_pos++;
#endif
char buff[22];
- return net_store_data((char*) buff,
- (uint) (longlong10_to_str(from,buff,
- unsigned_flag ? 10 : -10)-
- buff));
+ return net_store_data((uchar*) buff,
+ (size_t) (longlong10_to_str(from,buff,
+ unsigned_flag ? 10 : -10)-
+ buff));
}
-bool Protocol_simple::store_decimal(const my_decimal *d)
+bool Protocol_text::store_decimal(const my_decimal *d)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -898,11 +902,11 @@ bool Protocol_simple::store_decimal(const my_decimal *d)
char buff[DECIMAL_MAX_STR_LENGTH];
String str(buff, sizeof(buff), &my_charset_bin);
(void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
- return net_store_data(str.ptr(), str.length());
+ return net_store_data((uchar*) str.ptr(), str.length());
}
-bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
+bool Protocol_text::store(float from, uint32 decimals, String *buffer)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -910,11 +914,11 @@ bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
field_pos++;
#endif
buffer->set_real((double) from, decimals, thd->charset());
- return net_store_data((char*) buffer->ptr(), buffer->length());
+ return net_store_data((uchar*) buffer->ptr(), buffer->length());
}
-bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
+bool Protocol_text::store(double from, uint32 decimals, String *buffer)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -922,11 +926,11 @@ bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
field_pos++;
#endif
buffer->set_real(from, decimals, thd->charset());
- return net_store_data((char*) buffer->ptr(), buffer->length());
+ return net_store_data((uchar*) buffer->ptr(), buffer->length());
}
-bool Protocol_simple::store(Field *field)
+bool Protocol_text::store(Field *field)
{
if (field->is_null())
return store_null();
@@ -936,15 +940,15 @@ bool Protocol_simple::store(Field *field)
char buff[MAX_FIELD_WIDTH];
String str(buff,sizeof(buff), &my_charset_bin);
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
+#ifndef DBUG_OFF
TABLE *table= field->table;
-#ifdef DBUG_OFF
my_bitmap_map *old_map= 0;
if (table->file)
old_map= dbug_tmp_use_all_columns(table, table->read_set);
#endif
field->val_str(&str);
-#ifdef DBUG_OFF
+#ifndef DBUG_OFF
if (old_map)
dbug_tmp_restore_column_map(table->read_set, old_map);
#endif
@@ -960,7 +964,7 @@ bool Protocol_simple::store(Field *field)
*/
-bool Protocol_simple::store(TIME *tm)
+bool Protocol_text::store(MYSQL_TIME *tm)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -978,12 +982,13 @@ bool Protocol_simple::store(TIME *tm)
(int) tm->minute,
(int) tm->second));
if (tm->second_part)
- length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
- return net_store_data((char*) buff, length);
+ length+= my_sprintf(buff+length,(buff+length, ".%06d",
+ (int)tm->second_part));
+ return net_store_data((uchar*) buff, length);
}
-bool Protocol_simple::store_date(TIME *tm)
+bool Protocol_text::store_date(MYSQL_TIME *tm)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -991,8 +996,8 @@ bool Protocol_simple::store_date(TIME *tm)
field_pos++;
#endif
char buff[MAX_DATE_STRING_REP_LENGTH];
- int length= my_date_to_str(tm, buff);
- return net_store_data(buff, (uint) length);
+ size_t length= my_date_to_str(tm, buff);
+ return net_store_data((uchar*) buff, length);
}
@@ -1002,7 +1007,7 @@ bool Protocol_simple::store_date(TIME *tm)
we support 0-6 decimals for time.
*/
-bool Protocol_simple::store_time(TIME *tm)
+bool Protocol_text::store_time(MYSQL_TIME *tm)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -1019,7 +1024,7 @@ bool Protocol_simple::store_time(TIME *tm)
(int) tm->second));
if (tm->second_part)
length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
- return net_store_data((char*) buff, length);
+ return net_store_data((uchar*) buff, length);
}
@@ -1042,7 +1047,7 @@ bool Protocol_simple::store_time(TIME *tm)
[..]..[[length]data] data
****************************************************************************/
-bool Protocol_prep::prepare_for_send(List<Item> *item_list)
+bool Protocol_binary::prepare_for_send(List<Item> *item_list)
{
Protocol::prepare_for_send(item_list);
bit_fields= (field_count+9)/8;
@@ -1053,29 +1058,30 @@ bool Protocol_prep::prepare_for_send(List<Item> *item_list)
}
-void Protocol_prep::prepare_for_resend()
+void Protocol_binary::prepare_for_resend()
{
packet->length(bit_fields+1);
- bzero((char*) packet->ptr(), 1+bit_fields);
+ bzero((uchar*) packet->ptr(), 1+bit_fields);
field_pos=0;
}
-bool Protocol_prep::store(const char *from, uint length, CHARSET_INFO *fromcs)
+bool Protocol_binary::store(const char *from, size_t length,
+ CHARSET_INFO *fromcs)
{
CHARSET_INFO *tocs= thd->variables.character_set_results;
field_pos++;
return store_string_aux(from, length, fromcs, tocs);
}
-bool Protocol_prep::store(const char *from,uint length,
- CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
+bool Protocol_binary::store(const char *from, size_t length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
field_pos++;
return store_string_aux(from, length, fromcs, tocs);
}
-bool Protocol_prep::store_null()
+bool Protocol_binary::store_null()
{
uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
/* Room for this as it's allocated in prepare_for_send */
@@ -1086,7 +1092,7 @@ bool Protocol_prep::store_null()
}
-bool Protocol_prep::store_tiny(longlong from)
+bool Protocol_binary::store_tiny(longlong from)
{
char buff[1];
field_pos++;
@@ -1095,7 +1101,7 @@ bool Protocol_prep::store_tiny(longlong from)
}
-bool Protocol_prep::store_short(longlong from)
+bool Protocol_binary::store_short(longlong from)
{
field_pos++;
char *to= packet->prep_append(2, PACKET_BUFFER_EXTRA_ALLOC);
@@ -1106,7 +1112,7 @@ bool Protocol_prep::store_short(longlong from)
}
-bool Protocol_prep::store_long(longlong from)
+bool Protocol_binary::store_long(longlong from)
{
field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
@@ -1117,7 +1123,7 @@ bool Protocol_prep::store_long(longlong from)
}
-bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
+bool Protocol_binary::store_longlong(longlong from, bool unsigned_flag)
{
field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
@@ -1127,7 +1133,7 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
return 0;
}
-bool Protocol_prep::store_decimal(const my_decimal *d)
+bool Protocol_binary::store_decimal(const my_decimal *d)
{
#ifndef DBUG_OFF
DBUG_ASSERT(field_types == 0 ||
@@ -1140,7 +1146,7 @@ bool Protocol_prep::store_decimal(const my_decimal *d)
return store(str.ptr(), str.length(), str.charset());
}
-bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
+bool Protocol_binary::store(float from, uint32 decimals, String *buffer)
{
field_pos++;
char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC);
@@ -1151,7 +1157,7 @@ bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
}
-bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
+bool Protocol_binary::store(double from, uint32 decimals, String *buffer)
{
field_pos++;
char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC);
@@ -1162,7 +1168,7 @@ bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
}
-bool Protocol_prep::store(Field *field)
+bool Protocol_binary::store(Field *field)
{
/*
We should not increment field_pos here as send_binary() will call another
@@ -1174,7 +1180,7 @@ bool Protocol_prep::store(Field *field)
}
-bool Protocol_prep::store(TIME *tm)
+bool Protocol_binary::store(MYSQL_TIME *tm)
{
char buff[12],*pos;
uint length;
@@ -1200,15 +1206,15 @@ bool Protocol_prep::store(TIME *tm)
return packet->append(buff, length+1, PACKET_BUFFER_EXTRA_ALLOC);
}
-bool Protocol_prep::store_date(TIME *tm)
+bool Protocol_binary::store_date(MYSQL_TIME *tm)
{
tm->hour= tm->minute= tm->second=0;
tm->second_part= 0;
- return Protocol_prep::store(tm);
+ return Protocol_binary::store(tm);
}
-bool Protocol_prep::store_time(TIME *tm)
+bool Protocol_binary::store_time(MYSQL_TIME *tm)
{
char buff[13], *pos;
uint length;
diff --git a/sql/protocol.h b/sql/protocol.h
index 7e2bc1516ec..46a2b6d36b6 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2002-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,14 +35,14 @@ protected:
#endif
uint field_count;
#ifndef EMBEDDED_LIBRARY
- bool net_store_data(const char *from, uint length);
+ bool net_store_data(const uchar *from, size_t length);
#else
- virtual bool net_store_data(const char *from, uint length);
+ virtual bool net_store_data(const uchar *from, size_t length);
char **next_field;
MYSQL_FIELD *next_mysql_field;
MEM_ROOT *alloc;
#endif
- bool store_string_aux(const char *from, uint length,
+ bool store_string_aux(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
public:
Protocol() {}
@@ -59,6 +58,8 @@ public:
String *storage_packet() { return packet; }
inline void free() { packet->free(); }
virtual bool write();
+ inline bool store(int from)
+ { return store_long((longlong) from); }
inline bool store(uint32 from)
{ return store_long((longlong) from); }
inline bool store(longlong from)
@@ -82,14 +83,14 @@ public:
virtual bool store_long(longlong from)=0;
virtual bool store_longlong(longlong from, bool unsigned_flag)=0;
virtual bool store_decimal(const my_decimal *)=0;
- virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0;
- virtual bool store(const char *from, uint length,
+ virtual bool store(const char *from, size_t length, CHARSET_INFO *cs)=0;
+ virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
virtual bool store(float from, uint32 decimals, String *buffer)=0;
virtual bool store(double from, uint32 decimals, String *buffer)=0;
- virtual bool store(TIME *time)=0;
- virtual bool store_date(TIME *time)=0;
- virtual bool store_time(TIME *time)=0;
+ virtual bool store(MYSQL_TIME *time)=0;
+ virtual bool store_date(MYSQL_TIME *time)=0;
+ virtual bool store_time(MYSQL_TIME *time)=0;
virtual bool store(Field *field)=0;
#ifdef EMBEDDED_LIBRARY
int begin_dataset();
@@ -97,16 +98,25 @@ public:
#else
void remove_last_row() {}
#endif
+ enum enum_protocol_type
+ {
+ PROTOCOL_TEXT= 0, PROTOCOL_BINARY= 1
+ /*
+ before adding here or change the values, consider that it is cast to a
+ bit in sql_cache.cc.
+ */
+ };
+ virtual enum enum_protocol_type type()= 0;
};
/* Class used for the old (MySQL 4.0 protocol) */
-class Protocol_simple :public Protocol
+class Protocol_text :public Protocol
{
public:
- Protocol_simple() {}
- Protocol_simple(THD *thd_arg) :Protocol(thd_arg) {}
+ Protocol_text() {}
+ Protocol_text(THD *thd_arg) :Protocol(thd_arg) {}
virtual void prepare_for_resend();
virtual bool store_null();
virtual bool store_tiny(longlong from);
@@ -114,33 +124,34 @@ public:
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
virtual bool store_decimal(const my_decimal *);
- virtual bool store(const char *from, uint length, CHARSET_INFO *cs);
- virtual bool store(const char *from, uint length,
+ virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
+ virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual bool store(TIME *time);
- virtual bool store_date(TIME *time);
- virtual bool store_time(TIME *time);
+ virtual bool store(MYSQL_TIME *time);
+ virtual bool store_date(MYSQL_TIME *time);
+ virtual bool store_time(MYSQL_TIME *time);
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
#ifdef EMBEDDED_LIBRARY
void remove_last_row();
#endif
+ virtual enum enum_protocol_type type() { return PROTOCOL_TEXT; };
};
-class Protocol_prep :public Protocol
+class Protocol_binary :public Protocol
{
private:
uint bit_fields;
public:
- Protocol_prep() {}
- Protocol_prep(THD *thd_arg) :Protocol(thd_arg) {}
+ Protocol_binary() {}
+ Protocol_binary(THD *thd_arg) :Protocol(thd_arg) {}
virtual bool prepare_for_send(List<Item> *item_list);
virtual void prepare_for_resend();
#ifdef EMBEDDED_LIBRARY
virtual bool write();
- bool net_store_data(const char *from, uint length);
+ bool net_store_data(const uchar *from, size_t length);
#endif
virtual bool store_null();
virtual bool store_tiny(longlong from);
@@ -148,15 +159,16 @@ public:
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
virtual bool store_decimal(const my_decimal *);
- virtual bool store(const char *from,uint length, CHARSET_INFO *cs);
- virtual bool store(const char *from, uint length,
+ virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
+ virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
- virtual bool store(TIME *time);
- virtual bool store_date(TIME *time);
- virtual bool store_time(TIME *time);
+ virtual bool store(MYSQL_TIME *time);
+ virtual bool store_date(MYSQL_TIME *time);
+ virtual bool store_time(MYSQL_TIME *time);
virtual bool store(float nr, uint32 decimals, String *buffer);
virtual bool store(double from, uint32 decimals, String *buffer);
virtual bool store(Field *field);
+ virtual enum enum_protocol_type type() { return PROTOCOL_BINARY; };
};
void send_warning(THD *thd, uint sql_errno, const char *err=0);
@@ -166,7 +178,7 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
void send_eof(THD *thd);
bool send_old_password_request(THD *thd);
-char *net_store_data(char *to,const char *from, uint length);
-char *net_store_data(char *to,int32 from);
-char *net_store_data(char *to,longlong from);
+uchar *net_store_data(uchar *to,const uchar *from, size_t length);
+uchar *net_store_data(uchar *to,int32 from);
+uchar *net_store_data(uchar *to,longlong from);
diff --git a/sql/records.cc b/sql/records.cc
index f8b6a7d1df9..81c26da4b4d 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -151,7 +150,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->file= table->file;
info->forms= &info->table; /* Only one table */
- if (table->s->tmp_table == TMP_TABLE && !table->sort.addon_field)
+ if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
+ !table->sort.addon_field)
VOID(table->file->extra(HA_EXTRA_MMAP));
if (table->sort.addon_field)
@@ -432,7 +432,7 @@ static int rr_unpack_from_tempfile(READ_RECORD *info)
static int rr_from_pointers(READ_RECORD *info)
{
int tmp;
- byte *cache_pos;
+ uchar *cache_pos;
for (;;)
{
@@ -502,7 +502,7 @@ static int init_rr_cache(THD *thd, READ_RECORD *info)
// We have to allocate one more byte to use uint3korr (see comments for it)
if (info->cache_records <= 2 ||
- !(info->cache=(byte*) my_malloc_lock(rec_cache_size+info->cache_records*
+ !(info->cache=(uchar*) my_malloc_lock(rec_cache_size+info->cache_records*
info->struct_length+1,
MYF(0))))
DBUG_RETURN(1);
@@ -523,7 +523,7 @@ static int rr_from_cache(READ_RECORD *info)
ulong length;
my_off_t rest_of_file;
int16 error;
- byte *position,*ref_position,*record_pos;
+ uchar *position,*ref_position,*record_pos;
ulong record;
for (;;)
@@ -560,7 +560,7 @@ static int rr_from_cache(READ_RECORD *info)
ref_position=info->read_positions;
for (i=0 ; i < length ; i++,position+=info->ref_length)
{
- memcpy(ref_position,position,(size_s) info->ref_length);
+ memcpy(ref_position,position,(size_t) info->ref_length);
ref_position+=MAX_REFLENGTH;
int3store(ref_position,(long) i);
ref_position+=3;
@@ -570,7 +570,7 @@ static int rr_from_cache(READ_RECORD *info)
position=info->read_positions;
for (i=0 ; i < length ; i++)
{
- memcpy(info->ref_pos,position,(size_s) info->ref_length);
+ memcpy(info->ref_pos,position,(size_t) info->ref_length);
position+=MAX_REFLENGTH;
record=uint3korr(position);
position+=3;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 762fcfb7a6a..8bab1ff1ca3 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
+/* Copyright (C) 2001-2006 MySQL AB & Sasha
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +19,7 @@
#include "repl_failsafe.h"
#include "sql_repl.h"
#include "slave.h"
+#include "rpl_mi.h"
#include "rpl_filter.h"
#include "log_event.h"
#include <mysql.h>
@@ -58,6 +58,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
functions like register_slave()) are working.
*/
+#if NOT_USED
static int init_failsafe_rpl_thread(THD* thd)
{
DBUG_ENTER("init_failsafe_rpl_thread");
@@ -73,23 +74,19 @@ static int init_failsafe_rpl_thread(THD* thd)
thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet;
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id = thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
if (init_thr_lock() || thd->store_globals())
{
+ /* purecov: begin inspected */
close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
+ one_thread_per_connection_end(thd,0);
DBUG_RETURN(-1);
+ /* purecov: end */
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
thd->mem_root->free= thd->mem_root->used= 0;
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options|= OPTION_BIG_SELECTS;
@@ -99,7 +96,7 @@ static int init_failsafe_rpl_thread(THD* thd)
thd->set_time();
DBUG_RETURN(0);
}
-
+#endif
void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
{
@@ -137,9 +134,9 @@ void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
SLAVE_INFO* old_si;
if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
- (byte*)&thd->server_id, 4)) &&
+ (uchar*)&thd->server_id, 4)) &&
(!only_mine || old_si->thd == thd))
- hash_delete(&slave_list, (byte*)old_si);
+ hash_delete(&slave_list, (uchar*)old_si);
if (need_mutex)
pthread_mutex_unlock(&LOCK_slave_list);
@@ -183,12 +180,12 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
pthread_mutex_lock(&LOCK_slave_list);
unregister_slave(thd,0,0);
- res= my_hash_insert(&slave_list, (byte*) si);
+ res= my_hash_insert(&slave_list, (uchar*) si);
pthread_mutex_unlock(&LOCK_slave_list);
return res;
err:
- my_free((gptr) si, MYF(MY_WME));
+ my_free(si, MYF(MY_WME));
my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave",
MYF(0));
err2:
@@ -196,7 +193,7 @@ err2:
}
extern "C" uint32
-*slave_list_key(SLAVE_INFO* si, uint* len,
+*slave_list_key(SLAVE_INFO* si, size_t *len,
my_bool not_used __attribute__((unused)))
{
*len = 4;
@@ -205,7 +202,7 @@ extern "C" uint32
extern "C" void slave_info_free(void *s)
{
- my_free((gptr) s, MYF(MY_WME));
+ my_free(s, MYF(MY_WME));
}
void init_slave_list()
@@ -530,11 +527,11 @@ HOSTS";
while ((row= mysql_fetch_row(res)))
{
- uint32 server_id;
+ uint32 log_server_id;
SLAVE_INFO* si, *old_si;
- server_id = atoi(row[0]);
+ log_server_id = atoi(row[0]);
if ((old_si= (SLAVE_INFO*)hash_search(&slave_list,
- (byte*)&server_id,4)))
+ (uchar*)&log_server_id,4)))
si = old_si;
else
{
@@ -544,8 +541,8 @@ HOSTS";
pthread_mutex_unlock(&LOCK_slave_list);
goto err;
}
- si->server_id = server_id;
- my_hash_insert(&slave_list, (byte*)si);
+ si->server_id = log_server_id;
+ my_hash_insert(&slave_list, (uchar*)si);
}
strmake(si->host, row[1], sizeof(si->host)-1);
si->port = atoi(row[port_ind]);
@@ -573,12 +570,14 @@ err:
}
+#if NOT_USED
int find_recovery_captain(THD* thd, MYSQL* mysql)
{
return 0;
}
+#endif
-
+#if NOT_USED
pthread_handler_t handle_failsafe_rpl(void *arg)
{
DBUG_ENTER("handle_failsafe_rpl");
@@ -626,7 +625,7 @@ err:
pthread_exit(0);
DBUG_RETURN(0);
}
-
+#endif
bool show_slave_hosts(THD* thd)
{
@@ -694,12 +693,16 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
#ifdef HAVE_OPENSSL
if (mi->ssl)
+ {
mysql_ssl_set(mysql,
mi->ssl_key[0]?mi->ssl_key:0,
mi->ssl_cert[0]?mi->ssl_cert:0,
mi->ssl_ca[0]?mi->ssl_ca:0,
mi->ssl_capath[0]?mi->ssl_capath:0,
mi->ssl_cipher[0]?mi->ssl_cipher:0);
+ mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ &mi->ssl_verify_server_cert);
+ }
#endif
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
@@ -916,14 +919,14 @@ bool load_master_data(THD* thd)
setting active_mi, because init_master_info() sets active_mi with
defaults.
*/
- int error;
+ int error_2;
if (init_master_info(active_mi, master_info_file, relay_log_info_file,
0, (SLAVE_IO | SLAVE_SQL)))
my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
strmake(active_mi->master_log_name, row[0],
sizeof(active_mi->master_log_name));
- active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error);
+ active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error_2);
/* at least in recent versions, the condition below should be false */
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
index 19849e63af9..561db00d841 100644
--- a/sql/repl_failsafe.h
+++ b/sql/repl_failsafe.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
+/* Copyright (C) 2001-2005 MySQL AB & Sasha
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/rpl_constants.h b/sql/rpl_constants.h
new file mode 100644
index 00000000000..426e80a328d
--- /dev/null
+++ b/sql/rpl_constants.h
@@ -0,0 +1,18 @@
+#ifndef RPL_CONSTANTS_H
+#define RPL_CONSTANTS_H
+
+/**
+ Enumeration of the incidents that can occur for the server.
+ */
+enum Incident {
+ /** No incident */
+ INCIDENT_NONE,
+
+ /** There are possibly lost events in the replication stream */
+ INCIDENT_LOST_EVENTS,
+
+ /** Shall be last event of the enumeration */
+ INCIDENT_COUNT
+};
+
+#endif /* RPL_CONSTANTS_H */
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index c01b5189887..bb5db0106eb 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -104,12 +103,12 @@ Rpl_filter::tables_ok(const char* db, TABLE_LIST* tables)
len= (uint) (strmov(end, tables->table_name) - hash_key);
if (do_table_inited) // if there are any do's
{
- if (hash_search(&do_table, (byte*) hash_key, len))
+ if (hash_search(&do_table, (uchar*) hash_key, len))
DBUG_RETURN(1);
}
if (ignore_table_inited) // if there are any ignores
{
- if (hash_search(&ignore_table, (byte*) hash_key, len))
+ if (hash_search(&ignore_table, (uchar*) hash_key, len))
DBUG_RETURN(0);
}
if (wild_do_table_inited &&
@@ -320,7 +319,7 @@ Rpl_filter::add_table_rule(HASH* h, const char* table_spec)
e->key_len= len;
memcpy(e->db, table_spec, len);
- return my_hash_insert(h, (byte*)e);
+ return my_hash_insert(h, (uchar*)e);
}
@@ -341,7 +340,7 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
e->tbl_name= e->db + (dot - table_spec) + 1;
e->key_len= len;
memcpy(e->db, table_spec, len);
- insert_dynamic(a, (gptr)&e);
+ insert_dynamic(a, (uchar*)&e);
return 0;
}
@@ -364,13 +363,13 @@ Rpl_filter::add_ignore_db(const char* table_spec)
}
-static byte* get_table_key(const byte* a, uint* len,
+static uchar* get_table_key(const uchar* a, size_t *len,
my_bool __attribute__((unused)))
{
TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
*len= e->key_len;
- return (byte*)e->db;
+ return (uchar*)e->db;
}
@@ -378,7 +377,7 @@ static void free_table_ent(void* a)
{
TABLE_RULE_ENT *e= (TABLE_RULE_ENT *) a;
- my_free((gptr) e, MYF(0));
+ my_free((uchar*) e, MYF(0));
}
@@ -409,7 +408,7 @@ Rpl_filter::find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
for (i= 0; i < a->elements; i++)
{
TABLE_RULE_ENT* e ;
- get_dynamic(a, (gptr)&e, i);
+ get_dynamic(a, (uchar*)&e, i);
if (!my_wildcmp(system_charset_info, key, key_end,
(const char*)e->db,
(const char*)(e->db + e->key_len),
@@ -428,7 +427,7 @@ Rpl_filter::free_string_array(DYNAMIC_ARRAY *a)
for (i= 0; i < a->elements; i++)
{
char* p;
- get_dynamic(a, (gptr) &p, i);
+ get_dynamic(a, (uchar*) &p, i);
my_free(p, MYF(MY_WME));
}
delete_dynamic(a);
@@ -475,7 +474,7 @@ Rpl_filter::table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a,
for (uint i= 0; i < a->elements; i++)
{
TABLE_RULE_ENT* e;
- get_dynamic(a, (gptr)&e, i);
+ get_dynamic(a, (uchar*)&e, i);
if (s->length())
s->append(',');
s->append(e->db,e->key_len);
@@ -513,7 +512,7 @@ Rpl_filter::get_wild_ignore_table(String* str)
const char*
-Rpl_filter::get_rewrite_db(const char* db, uint *new_len)
+Rpl_filter::get_rewrite_db(const char* db, size_t *new_len)
{
if (rewrite_db.is_empty() || !db)
return db;
diff --git a/sql/rpl_filter.h b/sql/rpl_filter.h
index 718fd401c56..ff7e4081bb1 100644
--- a/sql/rpl_filter.h
+++ b/sql/rpl_filter.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -70,7 +69,7 @@ public:
void get_wild_do_table(String* str);
void get_wild_ignore_table(String* str);
- const char* get_rewrite_db(const char* db, uint *new_len);
+ const char* get_rewrite_db(const char* db, size_t *new_len);
I_List<i_string>* get_do_db();
I_List<i_string>* get_ignore_db();
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index eba6d24d557..aa3020c42be 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -1,10 +1,8 @@
-/*
- Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "mysql_priv.h"
#include "rpl_injector.h"
@@ -77,9 +75,11 @@ int injector::transaction::use_table(server_id_type sid, table tbl)
if ((error= check_state(TABLE_STATE)))
DBUG_RETURN(error);
+ server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
error= m_thd->binlog_write_table_map(tbl.get_table(),
tbl.is_transactional());
+ m_thd->set_server_id(save_id);
DBUG_RETURN(error);
}
@@ -93,9 +93,11 @@ int injector::transaction::write_row (server_id_type sid, table tbl,
if (int error= check_state(ROW_STATE))
DBUG_RETURN(error);
+ server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
m_thd->binlog_write_row(tbl.get_table(), tbl.is_transactional(),
cols, colcnt, record);
+ m_thd->set_server_id(save_id);
DBUG_RETURN(0);
}
@@ -109,9 +111,11 @@ int injector::transaction::delete_row(server_id_type sid, table tbl,
if (int error= check_state(ROW_STATE))
DBUG_RETURN(error);
+ server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
m_thd->binlog_delete_row(tbl.get_table(), tbl.is_transactional(),
cols, colcnt, record);
+ m_thd->set_server_id(save_id);
DBUG_RETURN(0);
}
@@ -125,9 +129,11 @@ int injector::transaction::update_row(server_id_type sid, table tbl,
if (int error= check_state(ROW_STATE))
DBUG_RETURN(error);
+ server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
m_thd->binlog_update_row(tbl.get_table(), tbl.is_transactional(),
cols, colcnt, before, after);
+ m_thd->set_server_id(save_id);
DBUG_RETURN(0);
}
@@ -190,3 +196,21 @@ void injector::new_trans(THD *thd, injector::transaction *ptr)
DBUG_VOID_RETURN;
}
+
+int injector::record_incident(THD *thd, Incident incident)
+{
+ Incident_log_event ev(thd, incident);
+ if (int error= mysql_bin_log.write(&ev))
+ return error;
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
+ return 0;
+}
+
+int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message)
+{
+ Incident_log_event ev(thd, incident, message);
+ if (int error= mysql_bin_log.write(&ev))
+ return error;
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
+ return 0;
+}
diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h
index a3dce2184d7..4ece092c5b8 100644
--- a/sql/rpl_injector.h
+++ b/sql/rpl_injector.h
@@ -1,10 +1,8 @@
-/*
- Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,16 +11,17 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef INJECTOR_H
#define INJECTOR_H
/* Pull in 'byte', 'my_off_t', and 'uint32' */
#include <my_global.h>
-
#include <my_bitmap.h>
+#include "rpl_constants.h"
+
/* Forward declarations */
class handler;
class MYSQL_BIN_LOG;
@@ -75,7 +74,7 @@ public:
friend class injector;
public:
/* Convenience definitions */
- typedef byte* record_type;
+ typedef uchar* record_type;
typedef uint32 server_id_type;
/*
@@ -286,12 +285,14 @@ public:
*/
int check_state(enum_state const target_state)
{
+#ifndef DBUG_OFF
static char const *state_name[] = {
"START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT"
};
DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT);
DBUG_PRINT("info", ("In state %s", state_name[m_state]));
+#endif
if (m_state <= target_state && target_state <= m_state + 1 &&
m_state < STATE_COUNT)
@@ -322,6 +323,9 @@ public:
transaction new_trans(THD *);
void new_trans(THD *, transaction *);
+ int record_incident(THD*, Incident incident);
+ int record_incident(THD*, Incident incident, LEX_STRING const message);
+
private:
explicit injector();
~injector() { } /* Nothing needs to be done */
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index d23d57c7eb7..f506a3c319d 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -31,12 +30,13 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
MASTER_INFO::MASTER_INFO()
:Slave_reporting_capability("I/O"),
ssl(0), fd(-1), io_thd(0), inited(0),
- abort_slave(0),slave_running(0), slave_run_id(0)
+ abort_slave(0),slave_running(0),
+ ssl_verify_server_cert(0), slave_run_id(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
ssl_cipher[0]= 0; ssl_key[0]= 0;
-
+
bzero((char*) &file, sizeof(file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
@@ -82,12 +82,21 @@ void init_master_info_with_options(MASTER_INFO* mi)
strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
if (master_ssl_key)
strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
+ /* Intentionally init ssl_verify_server_cert to 0, no option available */
+ mi->ssl_verify_server_cert= 0;
DBUG_VOID_RETURN;
}
-#define LINES_IN_MASTER_INFO_WITH_SSL 14
+enum {
+ LINES_IN_MASTER_INFO_WITH_SSL= 14,
+
+ /* 5.1.16 added value of master_ssl_verify_server_cert */
+ LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
+ /* Number of lines currently used when saving master info file */
+ LINES_IN_MASTER_INFO= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT
+};
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
@@ -186,7 +195,8 @@ file '%s')", fname);
}
mi->fd = fd;
- int port, connect_retry, master_log_pos, ssl= 0, lines;
+ int port, connect_retry, master_log_pos, lines;
+ int ssl= 0, ssl_verify_server_cert= 0;
char *first_non_digit;
/*
@@ -197,7 +207,8 @@ file '%s')", fname);
file since versions before 4.1.x could generate files with more
lines than needed.
If first line doesn't contain a number or contain number less than
- 14 then such file is treated like file from pre 4.1.1 version.
+ LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
+ from pre 4.1.1 version.
There is no ambiguity when reading an old master.info, as before
4.1.1, the first line contained the binlog's name, which is either
empty or has an extension (contains a '.'), so can't be confused
@@ -221,7 +232,8 @@ file '%s')", fname);
if (mi->master_log_name[0]!='\0' &&
*first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
- { // Seems to be new format
+ {
+ /* Seems to be new format => read master log name from next line */
if (init_strvar_from_file(mi->master_log_name,
sizeof(mi->master_log_name), &mi->file, ""))
goto errwithmsg;
@@ -247,19 +259,31 @@ file '%s')", fname);
slave will try connect to master, so in this case warning
is printed.
*/
- if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
- (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
- init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
- &mi->file, master_ssl_ca) ||
- init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
- &mi->file, master_ssl_capath) ||
- init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
- &mi->file, master_ssl_cert) ||
- init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
- &mi->file, master_ssl_cipher) ||
- init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
- &mi->file, master_ssl_key)))
- goto errwithmsg;
+ if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
+ {
+ if (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
+ init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
+ &mi->file, master_ssl_ca) ||
+ init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
+ &mi->file, master_ssl_capath) ||
+ init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
+ &mi->file, master_ssl_cert) ||
+ init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
+ &mi->file, master_ssl_cipher) ||
+ init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
+ &mi->file, master_ssl_key))
+ goto errwithmsg;
+
+ /*
+ Starting from 5.1.16 ssl_verify_server_cert might be
+ in the file
+ */
+ if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
+ init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0))
+ goto errwithmsg;
+
+ }
+
#ifndef HAVE_OPENSSL
if (ssl)
sql_print_warning("SSL information in the master info file "
@@ -275,6 +299,7 @@ file '%s')", fname);
mi->port= (uint) port;
mi->connect_retry= (uint) connect_retry;
mi->ssl= (my_bool) ssl;
+ mi->ssl_verify_server_cert= ssl_verify_server_cert;
}
DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
mi->master_log_name,
@@ -317,6 +342,7 @@ int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
{
IO_CACHE* file = &mi->file;
char lbuf[22];
+
DBUG_ENTER("flush_master_info");
DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
@@ -354,13 +380,14 @@ int flush_master_info(MASTER_INFO* mi, bool flush_relay_log_cache)
*/
my_b_seek(file, 0L);
- my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
- LINES_IN_MASTER_INFO_WITH_SSL,
+ my_b_printf(file,
+ "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n",
+ LINES_IN_MASTER_INFO,
mi->master_log_name, llstr(mi->master_log_pos, lbuf),
mi->host, mi->user,
mi->password, mi->port, mi->connect_retry,
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
- mi->ssl_cipher, mi->ssl_key);
+ mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert);
DBUG_RETURN(-flush_io_cache(file));
}
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index aac1072402f..054356935de 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +19,8 @@
#ifdef HAVE_REPLICATION
#include "rpl_reporting.h"
+#include "rpl_rli.h"
+
/*****************************************************************************
@@ -68,6 +69,7 @@ class MASTER_INFO : public Slave_reporting_capability
my_bool ssl; // enables use of SSL connection if true
char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
+ my_bool ssl_verify_server_cert;
my_off_t master_log_pos;
File fd; // we keep the file open, so we need to remember the file pointer
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
new file mode 100644
index 00000000000..45edb42374b
--- /dev/null
+++ b/sql/rpl_record.cc
@@ -0,0 +1,280 @@
+/* Copyright 2007 MySQL AB. All rights reserved.
+
+ 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; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+#include "rpl_record.h"
+#include "slave.h" // Need to pull in slave_print_msg
+
+/**
+ Pack a record of data for a table into a format suitable for
+ transfer via the binary log.
+
+ The format for a row in transfer with N fields is the following:
+
+ ceil(N/8) null bytes:
+ One null bit for every column *regardless of whether it can be
+ null or not*. This simplifies the decoding. Observe that the
+ number of null bits is equal to the number of set bits in the
+ @c cols bitmap. The number of null bytes is the smallest number
+ of bytes necessary to store the null bits.
+
+ Padding bits are 1.
+
+ N packets:
+ Each field is stored in packed format.
+
+
+ @param table Table describing the format of the record
+
+ @param cols Bitmap with a set bit for each column that should
+ be stored in the row
+
+ @param row_data Pointer to memory where row will be written
+
+ @param record Pointer to record that should be packed. It is
+ assumed that the pointer refers to either @c
+ record[0] or @c record[1], but no such check is
+ made since the code does not rely on that.
+
+ @return The number of bytes written at @c row_data.
+ */
+#if !defined(MYSQL_CLIENT)
+size_t
+pack_row(TABLE *table, MY_BITMAP const* cols,
+ uchar *row_data, const uchar *record)
+{
+ Field **p_field= table->field, *field;
+ int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
+ uchar *pack_ptr = row_data + null_byte_count;
+ uchar *null_ptr = row_data;
+ my_ptrdiff_t const rec_offset= record - table->record[0];
+ my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+
+ /*
+ We write the null bits and the packed records using one pass
+ through all the fields. The null bytes are written little-endian,
+ i.e., the first fields are in the first byte.
+ */
+ unsigned int null_bits= (1U << 8) - 1;
+ // Mask to mask out the correct but among the null bits
+ unsigned int null_mask= 1U;
+ for ( ; (field= *p_field) ; p_field++)
+ {
+ DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
+ null_mask, null_ptr, row_data, null_byte_count));
+ if (bitmap_is_set(cols, p_field - table->field))
+ {
+ my_ptrdiff_t offset;
+ if (field->is_null(rec_offset))
+ {
+ offset= def_offset;
+ null_bits |= null_mask;
+ }
+ else
+ {
+ offset= rec_offset;
+ null_bits &= ~null_mask;
+
+ /*
+ We only store the data of the field if it is non-null
+ */
+ pack_ptr= field->pack(pack_ptr, field->ptr + offset);
+ }
+
+ null_mask <<= 1;
+ if ((null_mask & 0xFF) == 0)
+ {
+ DBUG_ASSERT(null_ptr < row_data + null_byte_count);
+ null_mask = 1U;
+ *null_ptr++ = null_bits;
+ null_bits= (1U << 8) - 1;
+ }
+ }
+ }
+
+ /*
+ Write the last (partial) byte, if there is one
+ */
+ if ((null_mask & 0xFF) > 1)
+ {
+ DBUG_ASSERT(null_ptr < row_data + null_byte_count);
+ *null_ptr++ = null_bits;
+ }
+
+ /*
+ The null pointer should now point to the first byte of the
+ packed data. If it doesn't, something is very wrong.
+ */
+ DBUG_ASSERT(null_ptr == row_data + null_byte_count);
+
+ return static_cast<size_t>(pack_ptr - row_data);
+}
+#endif
+
+
+/**
+ Unpack a row into @c table->record[0].
+
+ The function will always unpack into the @c table->record[0]
+ record. This is because there are too many dependencies on where
+ the various member functions of Field and subclasses expect to
+ write.
+
+ The row is assumed to only consist of the fields for which the
+ bitset represented by @c arr and @c bits; the other parts of the
+ record are left alone.
+
+ At most @c colcnt columns are read: if the table is larger than
+ that, the remaining fields are not filled in.
+
+ @param rli Relay log info
+ @param table Table to unpack into
+ @param colcnt Number of columns to read from record
+ @param row Packed row data
+ @param cols Pointer to columns data to fill in
+ @param row_end Pointer to variable that will hold the value of the
+ one-after-end position for the row
+ @param master_reclength
+ Pointer to variable that will be set to the length of the
+ record on the master side
+ @param rw_set Pointer to bitmap that holds either the read_set or the
+ write_set of the table
+
+
+ @retval 0 No error
+
+ @retval ER_NO_DEFAULT_FOR_FIELD
+ Returned if one of the fields existing on the slave but not on the
+ master does not have a default value (and isn't nullable)
+
+ */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int
+unpack_row(RELAY_LOG_INFO const *rli,
+ TABLE *table, uint const colcnt,
+ uchar const *const row_data, MY_BITMAP const *cols,
+ uchar const **const row_end, ulong *const master_reclength,
+ MY_BITMAP* const rw_set, Log_event_type const event_type)
+{
+ DBUG_ENTER("unpack_row");
+ DBUG_ASSERT(row_data);
+ size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
+ int error= 0;
+
+ uchar const *null_ptr= row_data;
+ uchar const *pack_ptr= row_data + master_null_byte_count;
+
+ bitmap_clear_all(rw_set);
+
+ empty_record(table);
+
+ Field **const begin_ptr = table->field;
+ Field **field_ptr;
+ Field **const end_ptr= begin_ptr + colcnt;
+
+ DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
+
+ // Mask to mask out the correct bit among the null bits
+ unsigned int null_mask= 1U;
+ // The "current" null bits
+ unsigned int null_bits= *null_ptr++;
+ for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
+ {
+ Field *const f= *field_ptr;
+
+ /*
+ No need to bother about columns that does not exist: they have
+ gotten default values when being emptied above.
+ */
+ if (bitmap_is_set(cols, field_ptr - begin_ptr))
+ {
+ if ((null_mask & 0xFF) == 0)
+ {
+ DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
+ null_mask= 1U;
+ null_bits= *null_ptr++;
+ }
+
+ DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
+
+ /* Field...::unpack() cannot return 0 */
+ DBUG_ASSERT(pack_ptr != NULL);
+
+ if ((null_bits & null_mask) && f->maybe_null())
+ f->set_null();
+ else
+ {
+ f->set_notnull();
+
+ /*
+ We only unpack the field if it was non-null
+ */
+ pack_ptr= f->unpack(f->ptr, pack_ptr);
+ }
+
+ bitmap_set_bit(rw_set, f->field_index);
+ null_mask <<= 1;
+ }
+ }
+
+ /*
+ We should now have read all the null bytes, otherwise something is
+ really wrong.
+ */
+ DBUG_ASSERT(null_ptr == row_data + master_null_byte_count);
+
+ *row_end = pack_ptr;
+ if (master_reclength)
+ {
+ if (*field_ptr)
+ *master_reclength = (*field_ptr)->ptr - table->record[0];
+ else
+ *master_reclength = table->s->reclength;
+ }
+
+ /*
+ Set properties for remaining columns, if there are any. We let the
+ corresponding bit in the write_set be set, to write the value if
+ it was not there already. We iterate over all remaining columns,
+ even if there were an error, to get as many error messages as
+ possible. We are still able to return a pointer to the next row,
+ so redo that.
+
+ This generation of error messages is only relevant when inserting
+ new rows.
+ */
+ for ( ; *field_ptr ; ++field_ptr)
+ {
+ uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
+ Field *const f= *field_ptr;
+
+ if (event_type == WRITE_ROWS_EVENT &&
+ ((*field_ptr)->flags & mask) == mask)
+ {
+ slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD,
+ "Field `%s` of table `%s`.`%s` "
+ "has no default value and cannot be NULL",
+ (*field_ptr)->field_name, table->s->db.str,
+ table->s->table_name.str);
+ error = ER_NO_DEFAULT_FOR_FIELD;
+ }
+ else
+ f->set_default();
+ }
+
+ DBUG_RETURN(error);
+}
+
+#endif // HAVE_REPLICATION
diff --git a/sql/rpl_record.h b/sql/rpl_record.h
new file mode 100644
index 00000000000..12c2f1fc713
--- /dev/null
+++ b/sql/rpl_record.h
@@ -0,0 +1,33 @@
+/* Copyright 2007 MySQL AB. All rights reserved.
+
+ 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; version 2 of the License.
+
+ 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 RPL_RECORD_H
+#define RPL_RECORD_H
+
+#if !defined(MYSQL_CLIENT)
+size_t pack_row(TABLE* table, MY_BITMAP const* cols,
+ uchar *row_data, const uchar *data);
+#endif
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int unpack_row(RELAY_LOG_INFO const *rli,
+ TABLE *table, uint const colcnt,
+ uchar const *const row_data, MY_BITMAP const *cols,
+ uchar const **const row_end, ulong *const master_reclength,
+ MY_BITMAP* const rw_set,
+ Log_event_type const event_type);
+#endif
+
+#endif
diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc
new file mode 100644
index 00000000000..b6f170082fe
--- /dev/null
+++ b/sql/rpl_record_old.cc
@@ -0,0 +1,173 @@
+
+#include "mysql_priv.h"
+#include "rpl_record_old.h"
+
+size_t
+pack_row_old(TABLE *table, MY_BITMAP const* cols,
+ uchar *row_data, const uchar *record)
+{
+ Field **p_field= table->field, *field;
+ int n_null_bytes= table->s->null_bytes;
+ uchar *ptr;
+ uint i;
+ my_ptrdiff_t const rec_offset= record - table->record[0];
+ my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+ memcpy(row_data, record, n_null_bytes);
+ ptr= row_data+n_null_bytes;
+
+ for (i= 0 ; (field= *p_field) ; i++, p_field++)
+ {
+ if (bitmap_is_set(cols,i))
+ {
+ my_ptrdiff_t const offset=
+ field->is_null(rec_offset) ? def_offset : rec_offset;
+ field->move_field_offset(offset);
+ ptr= field->pack(ptr, field->ptr);
+ field->move_field_offset(-offset);
+ }
+ }
+ return (static_cast<size_t>(ptr - row_data));
+}
+
+
+/*
+ Unpack a row into a record.
+
+ SYNOPSIS
+ unpack_row()
+ rli Relay log info
+ table Table to unpack into
+ colcnt Number of columns to read from record
+ record Record where the data should be unpacked
+ row Packed row data
+ cols Pointer to columns data to fill in
+ row_end Pointer to variable that will hold the value of the
+ one-after-end position for the row
+ master_reclength
+ Pointer to variable that will be set to the length of the
+ record on the master side
+ rw_set Pointer to bitmap that holds either the read_set or the
+ write_set of the table
+
+ DESCRIPTION
+
+ The row is assumed to only consist of the fields for which the
+ bitset represented by 'arr' and 'bits'; the other parts of the
+ record are left alone.
+
+ At most 'colcnt' columns are read: if the table is larger than
+ that, the remaining fields are not filled in.
+
+ RETURN VALUE
+
+ Error code, or zero if no error. The following error codes can
+ be returned:
+
+ ER_NO_DEFAULT_FOR_FIELD
+ Returned if one of the fields existing on the slave but not on
+ the master does not have a default value (and isn't nullable)
+ */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int
+unpack_row_old(RELAY_LOG_INFO *rli,
+ TABLE *table, uint const colcnt, uchar *record,
+ uchar const *row, MY_BITMAP const *cols,
+ uchar const **row_end, ulong *master_reclength,
+ MY_BITMAP* const rw_set, Log_event_type const event_type)
+{
+ DBUG_ASSERT(record && row);
+ my_ptrdiff_t const offset= record - (uchar*) table->record[0];
+ size_t master_null_bytes= table->s->null_bytes;
+
+ if (colcnt != table->s->fields)
+ {
+ Field **fptr= &table->field[colcnt-1];
+ do
+ master_null_bytes= (*fptr)->last_null_byte();
+ while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF &&
+ fptr-- > table->field);
+
+ /*
+ If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time,
+ there were no nullable fields nor BIT fields at all in the
+ columns that are common to the master and the slave. In that
+ case, there is only one null byte holding the X bit.
+
+ OBSERVE! There might still be nullable columns following the
+ common columns, so table->s->null_bytes might be greater than 1.
+ */
+ if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF)
+ master_null_bytes= 1;
+ }
+
+ DBUG_ASSERT(master_null_bytes <= table->s->null_bytes);
+ memcpy(record, row, master_null_bytes); // [1]
+ int error= 0;
+
+ bitmap_set_all(rw_set);
+
+ Field **const begin_ptr = table->field;
+ Field **field_ptr;
+ uchar const *ptr= row + master_null_bytes;
+ Field **const end_ptr= begin_ptr + colcnt;
+ for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
+ {
+ Field *const f= *field_ptr;
+
+ if (bitmap_is_set(cols, field_ptr - begin_ptr))
+ {
+ f->move_field_offset(offset);
+ ptr= f->unpack(f->ptr, ptr);
+ f->move_field_offset(-offset);
+ /* Field...::unpack() cannot return 0 */
+ DBUG_ASSERT(ptr != NULL);
+ }
+ else
+ bitmap_clear_bit(rw_set, field_ptr - begin_ptr);
+ }
+
+ *row_end = ptr;
+ if (master_reclength)
+ {
+ if (*field_ptr)
+ *master_reclength = (*field_ptr)->ptr - table->record[0];
+ else
+ *master_reclength = table->s->reclength;
+ }
+
+ /*
+ Set properties for remaining columns, if there are any. We let the
+ corresponding bit in the write_set be set, to write the value if
+ it was not there already. We iterate over all remaining columns,
+ even if there were an error, to get as many error messages as
+ possible. We are still able to return a pointer to the next row,
+ so redo that.
+
+ This generation of error messages is only relevant when inserting
+ new rows.
+ */
+ for ( ; *field_ptr ; ++field_ptr)
+ {
+ uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
+
+ DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x",
+ (*field_ptr)->flags, mask,
+ (*field_ptr)->flags & mask));
+
+ if (event_type == WRITE_ROWS_EVENT &&
+ ((*field_ptr)->flags & mask) == mask)
+ {
+ slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD,
+ "Field `%s` of table `%s`.`%s` "
+ "has no default value and cannot be NULL",
+ (*field_ptr)->field_name, table->s->db.str,
+ table->s->table_name.str);
+ error = ER_NO_DEFAULT_FOR_FIELD;
+ }
+ else
+ (*field_ptr)->set_default();
+ }
+
+ return error;
+}
+#endif
diff --git a/sql/rpl_record_old.h b/sql/rpl_record_old.h
new file mode 100644
index 00000000000..6af61141d47
--- /dev/null
+++ b/sql/rpl_record_old.h
@@ -0,0 +1,32 @@
+/* Copyright 2007 MySQL AB. All rights reserved.
+
+ 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; version 2 of the License.
+
+ 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 RPL_RECORD_OLD_H
+#define RPL_RECORD_OLD_H
+
+#ifndef MYSQL_CLIENT
+size_t pack_row_old(TABLE *table, MY_BITMAP const* cols,
+ uchar *row_data, const uchar *record);
+
+#ifdef HAVE_REPLICATION
+int unpack_row_old(RELAY_LOG_INFO *rli,
+ TABLE *table, uint const colcnt, uchar *record,
+ uchar const *row, MY_BITMAP const *cols,
+ uchar const **row_end, ulong *master_reclength,
+ MY_BITMAP* const rw_set,
+ Log_event_type const event_type);
+#endif
+#endif
+#endif
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 104a2747eb4..41df3f63825 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,9 +15,11 @@
#include "mysql_priv.h"
+#include "rpl_mi.h"
#include "rpl_rli.h"
#include <my_dir.h> // For MY_STAT
#include "sql_repl.h" // For check_binlog_magic
+#include "rpl_utility.h"
static int count_relay_log_space(RELAY_LOG_INFO* rli);
@@ -30,14 +31,15 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
st_relay_log_info::st_relay_log_info()
:Slave_reporting_capability("SQL"),
- no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
+ no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
+ info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_thd(0),
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0),
tables_to_lock(0), tables_to_lock_count(0),
- unsafe_to_stop_at(0)
+ last_event_start_time(0), m_flags(0)
{
DBUG_ENTER("st_relay_log_info::st_relay_log_info");
@@ -959,7 +961,7 @@ err:
strtol() conversions needed for log names comparison. We don't need to
compare them each time this function is called, we only need to do this
when current log name changes. If we have UNTIL_MASTER_POS condition we
- need to do this only after Rotate_log_event::exec_event() (which is
+ need to do this only after Rotate_log_event::do_apply_event() (which is
rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS
condition then we should invalidate cached comarison value after
inc_group_relay_log_pos() which called for each group of events (so we
@@ -992,6 +994,22 @@ bool st_relay_log_info::is_until_satisfied()
log_pos= group_relay_log_pos;
}
+#ifndef DBUG_OFF
+ {
+ char buf[32];
+ DBUG_PRINT("info", ("group_master_log_name='%s', group_master_log_pos=%s",
+ group_master_log_name, llstr(group_master_log_pos, buf)));
+ DBUG_PRINT("info", ("group_relay_log_name='%s', group_relay_log_pos=%s",
+ group_relay_log_name, llstr(group_relay_log_pos, buf)));
+ DBUG_PRINT("info", ("(%s) log_name='%s', log_pos=%s",
+ until_condition == UNTIL_MASTER_POS ? "master" : "relay",
+ log_name, llstr(log_pos, buf)));
+ DBUG_PRINT("info", ("(%s) until_log_name='%s', until_log_pos=%s",
+ until_condition == UNTIL_MASTER_POS ? "master" : "relay",
+ until_log_name, llstr(until_log_pos, buf)));
+ }
+#endif
+
if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
{
/*
@@ -1047,28 +1065,64 @@ void st_relay_log_info::cached_charset_invalidate()
}
-bool st_relay_log_info::cached_charset_compare(char *charset)
+bool st_relay_log_info::cached_charset_compare(char *charset) const
{
DBUG_ENTER("st_relay_log_info::cached_charset_compare");
- if (bcmp(cached_charset, charset, sizeof(cached_charset)))
+ if (bcmp((uchar*) cached_charset, (uchar*) charset,
+ sizeof(cached_charset)))
{
- memcpy(cached_charset, charset, sizeof(cached_charset));
+ memcpy(const_cast<char*>(cached_charset), charset, sizeof(cached_charset));
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
-void st_relay_log_info::transaction_end(THD* thd)
+void st_relay_log_info::stmt_done(my_off_t event_master_log_pos,
+ time_t event_creation_time)
{
- DBUG_ENTER("st_relay_log_info::transaction_end");
+ clear_flag(IN_STMT);
/*
- Nothing to do here right now.
- */
-
- DBUG_VOID_RETURN;
+ If in a transaction, and if the slave supports transactions, just
+ inc_event_relay_log_pos(). We only have to check for OPTION_BEGIN
+ (not OPTION_NOT_AUTOCOMMIT) as transactions are logged with
+ BEGIN/COMMIT, not with SET AUTOCOMMIT= .
+
+ CAUTION: opt_using_transactions means innodb || bdb ; suppose the
+ master supports InnoDB and BDB, but the slave supports only BDB,
+ problems will arise: - suppose an InnoDB table is created on the
+ master, - 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 using opt_using_transactions instead of a finer
+ "does the slave support _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.
+ */
+ if ((sql_thd->options & OPTION_BEGIN) && opt_using_transactions)
+ inc_event_relay_log_pos();
+ else
+ {
+ inc_group_relay_log_pos(event_master_log_pos);
+ flush_relay_log_info(this);
+ /*
+ Note that Rotate_log_event::do_apply_event() does not call this
+ function, so there is no chance that a fake rotate event resets
+ last_master_timestamp. Note that we update without mutex
+ (probably ok - except in some very rare cases, only consequence
+ is that value may take some time to display in
+ Seconds_Behind_Master - not critical).
+ */
+ last_master_timestamp= event_creation_time;
+ }
}
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -1078,12 +1132,12 @@ void st_relay_log_info::cleanup_context(THD *thd, bool error)
DBUG_ASSERT(sql_thd == thd);
/*
- 1) Instances of Table_map_log_event, if ::exec_event() was called on them,
+ 1) Instances of Table_map_log_event, if ::do_apply_event() was called on them,
may have opened tables, which we cannot be sure have been closed (because
maybe the Rows_log_event have not been found or will not be, because slave
SQL thread is stopping, or relay log has a missing tail etc). So we close
all thread's tables. And so the table mappings have to be cancelled.
- 2) Rows_log_event::exec_event() may even have started statements or
+ 2) Rows_log_event::do_apply_event() may even have started statements or
transactions on them, which we need to rollback in case of error.
3) If finding a Format_description_log_event after a BEGIN, we also need
to rollback before continuing with the next events.
@@ -1097,7 +1151,27 @@ void st_relay_log_info::cleanup_context(THD *thd, bool error)
m_table_map.clear_tables();
close_thread_tables(thd);
clear_tables_to_lock();
- unsafe_to_stop_at= 0;
+ clear_flag(IN_STMT);
+ last_event_start_time= 0;
DBUG_VOID_RETURN;
}
+
+void st_relay_log_info::clear_tables_to_lock()
+{
+ while (tables_to_lock)
+ {
+ uchar* to_free= reinterpret_cast<uchar*>(tables_to_lock);
+ if (tables_to_lock->m_tabledef_valid)
+ {
+ tables_to_lock->m_tabledef.table_def::~table_def();
+ tables_to_lock->m_tabledef_valid= FALSE;
+ }
+ tables_to_lock=
+ static_cast<RPL_TABLE_LIST*>(tables_to_lock->next_global);
+ tables_to_lock_count--;
+ my_free(to_free, MYF(MY_WME));
+ }
+ DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
+}
+
#endif
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 2761f3f5db7..b4c6a4bf7c5 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,6 +21,9 @@
#include "rpl_tblmap.h"
#include "rpl_reporting.h"
+struct RPL_TABLE_LIST;
+
+
/****************************************************************************
Replication SQL Thread
@@ -50,6 +52,17 @@
typedef struct st_relay_log_info : public Slave_reporting_capability
{
+ /**
+ Flags for the state of the replication.
+ */
+ enum enum_state_flag {
+ /** The replication thread is inside a statement */
+ IN_STMT,
+
+ /** Flag counter. Should always be last */
+ STATE_FLAGS_COUNT
+ };
+
/*
If flag set, then rli does not store its state in any info file.
This is the case only when we execute BINLOG SQL commands inside
@@ -57,7 +70,16 @@ typedef struct st_relay_log_info : public Slave_reporting_capability
*/
bool no_storage;
- /* The following variables can only be read when protect by data lock */
+ /*
+ If true, events with the same server id should be replicated. This
+ field is set on creation of a relay log info structure by copying
+ the value of ::replicate_same_server_id and can be overridden if
+ necessary. For example of when this is done, check sql_binlog.cc,
+ where the BINLOG statement can be used to execute "raw" events.
+ */
+ bool replicate_same_server_id;
+
+ /*** The following variables can only be read when protect by data lock ****/
/*
info_fd - file descriptor of the info file. set only during
@@ -163,7 +185,7 @@ typedef struct st_relay_log_info : public Slave_reporting_capability
ulonglong future_group_master_log_pos;
#endif
- time_t last_master_timestamp;
+ time_t last_master_timestamp;
void clear_until_condition();
@@ -277,7 +299,7 @@ typedef struct st_relay_log_info : public Slave_reporting_capability
group_relay_log_pos);
}
- TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */
+ RPL_TABLE_LIST *tables_to_lock; /* RBR: Tables to lock */
uint tables_to_lock_count; /* RBR: Count of tables to lock */
table_mapping m_table_map; /* RBR: Mapping table-id to table */
@@ -288,23 +310,79 @@ typedef struct st_relay_log_info : public Slave_reporting_capability
When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
*/
void cached_charset_invalidate();
- bool cached_charset_compare(char *charset);
-
- void transaction_end(THD*);
+ bool cached_charset_compare(char *charset) const;
void cleanup_context(THD *, bool);
- void clear_tables_to_lock() {
- while (tables_to_lock)
- {
- char *to_free= reinterpret_cast<gptr>(tables_to_lock);
- tables_to_lock= tables_to_lock->next_global;
- tables_to_lock_count--;
- my_free(to_free, MYF(MY_WME));
- }
- DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
+ void clear_tables_to_lock();
+
+ /*
+ Used by row-based replication to detect that it should not stop at
+ this event, but give it a chance to send more events. The time
+ where the last event inside a group started is stored here. If the
+ variable is zero, we are not in a group (but may be in a
+ transaction).
+ */
+ time_t last_event_start_time;
+
+ /**
+ Helper function to do after statement completion.
+
+ This function is called from an event to complete the group by
+ either stepping the group position, if the "statement" is not
+ inside a transaction; or increase the event position, if the
+ "statement" is inside a transaction.
+
+ @param event_log_pos
+ Master log position of the event. The position is recorded in the
+ relay log info and used to produce information for <code>SHOW
+ SLAVE STATUS</code>.
+
+ @param event_creation_time
+ Timestamp for the creation of the event on the master side. The
+ time stamp is recorded in the relay log info and used to compute
+ the <code>Seconds_behind_master</code> field.
+ */
+ void stmt_done(my_off_t event_log_pos,
+ time_t event_creation_time);
+
+
+ /**
+ Set the value of a replication state flag.
+
+ @param flag Flag to set
+ */
+ void set_flag(enum_state_flag flag)
+ {
+ m_flags |= (1UL << flag);
+ }
+
+ /**
+ Clear the value of a replication state flag.
+
+ @param flag Flag to clear
+ */
+ void clear_flag(enum_state_flag flag)
+ {
+ m_flags &= ~(1UL << flag);
+ }
+
+ /**
+ Is the replication inside a group?
+
+ Replication is inside a group if either:
+ - The OPTION_BEGIN flag is set, meaning we're inside a transaction
+ - The RLI_IN_STMT flag is set, meaning we're inside a statement
+
+ @retval true Replication thread is currently inside a group
+ @retval false Replication thread is currently not inside a group
+ */
+ bool is_in_group() const {
+ return (sql_thd->options & OPTION_BEGIN) ||
+ (m_flags & (1UL << IN_STMT));
}
- time_t unsafe_to_stop_at;
+private:
+ uint32 m_flags;
} RELAY_LOG_INFO;
diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc
index 97f0066233c..6c8b494dfa9 100644
--- a/sql/rpl_tblmap.cc
+++ b/sql/rpl_tblmap.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -105,11 +104,11 @@ int table_mapping::set_table(ulong table_id, TABLE* table)
m_free= m_free->next;
}
else
- hash_delete(&m_table_ids,(byte *)e);
+ hash_delete(&m_table_ids,(uchar *)e);
e->table_id= table_id;
e->table= table;
- my_hash_insert(&m_table_ids,(byte *)e);
+ my_hash_insert(&m_table_ids,(uchar *)e);
DBUG_PRINT("info", ("tid %lu -> table 0x%lx (%s)",
table_id, (long) e->table,
@@ -122,7 +121,7 @@ int table_mapping::remove_table(ulong table_id)
entry *e= find_entry(table_id);
if (e)
{
- hash_delete(&m_table_ids,(byte *)e);
+ hash_delete(&m_table_ids,(uchar *)e);
/* we add this entry to the chain of free (free for use) entries */
e->next= m_free;
m_free= e;
diff --git a/sql/rpl_tblmap.h b/sql/rpl_tblmap.h
index 23864bd329e..446833d5ed6 100644
--- a/sql/rpl_tblmap.h
+++ b/sql/rpl_tblmap.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -86,7 +85,7 @@ private:
entry *find_entry(ulong table_id)
{
return (entry *)hash_search(&m_table_ids,
- (byte*)&table_id,
+ (uchar*)&table_id,
sizeof(table_id));
}
int expand();
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 3241dd6edc0..e56cb4f2730 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -1,9 +1,8 @@
-/* Copyright 2006 MySQL AB. All rights reserved.
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,13 +11,13 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "rpl_utility.h"
uint32
field_length_from_packed(enum_field_types const field_type,
- byte const *const data)
+ uchar const *const data)
{
uint32 length;
@@ -109,7 +108,7 @@ field_length_from_packed(enum_field_types const field_type,
*/
int
-table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table)
+table_def::compatible_with(RELAY_LOG_INFO const *rli_arg, TABLE *table)
const
{
/*
@@ -117,6 +116,7 @@ table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table)
*/
uint const cols_to_check= min(table->s->fields, size());
int error= 0;
+ RELAY_LOG_INFO const *rli= const_cast<RELAY_LOG_INFO*>(rli_arg);
TABLE_SHARE const *const tsh= table->s;
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index df0b0cd2ee1..2ce8def4577 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -1,9 +1,8 @@
-/* Copyright 2006 MySQL AB. All rights reserved.
+/* Copyright (C) 2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef RPL_UTILITY_H
#define RPL_UTILITY_H
@@ -23,104 +22,116 @@
#include "mysql_priv.h"
+struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
+
uint32
-field_length_from_packed(enum_field_types const field_type,
- byte const *const data);
+field_length_from_packed(enum_field_types field_type, uchar const *data);
-/*
+/**
A table definition from the master.
- RESPONSIBILITIES
-
+ The responsibilities of this class is:
- Extract and decode table definition data from the table map event
- Check if table definition in table map is compatible with table
definition on slave
- DESCRIPTION
-
- Currently, the only field type data available is an array of the
- type operators that are present in the table map event.
+ Currently, the only field type data available is an array of the
+ type operators that are present in the table map event.
- TODO
-
- Add type operands to this structure to allow detection of
- difference between, e.g., BIT(5) and BIT(10).
+ @todo Add type operands to this structure to allow detection of
+ difference between, e.g., BIT(5) and BIT(10).
*/
class table_def
{
public:
- /*
+ /**
Convenience declaration of the type of the field type data in a
table map event.
*/
typedef unsigned char field_type;
- /*
+ /**
Constructor.
- SYNOPSIS
- table_def()
- types Array of types
- size Number of elements in array 'types'
+ @param types Array of types
+ @param size Number of elements in array 'types'
*/
- table_def(field_type *types, my_size_t size)
- : m_type(types), m_size(size)
+ table_def(field_type *types, ulong size)
+ : m_size(size), m_type(new unsigned char [size])
{
+ if (m_type)
+ memcpy(m_type, types, size);
+ else
+ m_size= 0;
}
- /*
- Return the number of fields there is type data for.
+ ~table_def() {
+ if (m_type)
+ delete [] m_type;
+#ifndef DBUG_OFF
+ m_type= 0;
+ m_size= 0;
+#endif
+ }
- SYNOPSIS
- size()
+ /**
+ Return the number of fields there is type data for.
- RETURN VALUE
- The number of fields that there is type data for.
+ @return The number of fields that there is type data for.
*/
- my_size_t size() const { return m_size; }
+ ulong size() const { return m_size; }
+
/*
Return a representation of the type data for one field.
- SYNOPSIS
- type()
- i Field index to return data for
+ @param index Field index to return data for
- RETURN VALUE
-
- Will return a representation of the type data for field
- 'i'. Currently, only the type identifier is returned.
+ @return Will return a representation of the type data for field
+ <code>index</code>. Currently, only the type identifier is
+ returned.
*/
- field_type type(my_ptrdiff_t i) const { return m_type[i]; }
+ field_type type(ulong index) const
+ {
+ DBUG_ASSERT(index < m_size);
+ return m_type[index];
+ }
- /*
+ /**
Decide if the table definition is compatible with a table.
- SYNOPSIS
- compatible_with()
- rli Pointer to relay log info
- table Pointer to table to compare with.
-
- DESCRIPTION
-
- Compare the definition with a table to see if it is compatible
- with it. A table definition is compatible with a table if:
+ Compare the definition with a table to see if it is compatible
+ with it.
+ A table definition is compatible with a table if:
- the columns types of the table definition is a (not
necessarily proper) prefix of the column type of the table, or
-
- the other way around
- RETURN VALUE
- 1 if the table definition is not compatible with 'table'
- 0 if the table definition is compatible with 'table'
+ @param rli Pointer to relay log info
+ @param table Pointer to table to compare with.
+
+ @retval 1 if the table definition is not compatible with @c table
+ @retval 0 if the table definition is compatible with @c table
*/
- int compatible_with(RELAY_LOG_INFO *rli, TABLE *table) const;
+ int compatible_with(RELAY_LOG_INFO const *rli, TABLE *table) const;
private:
- my_size_t m_size; // Number of elements in the types array
+ ulong m_size; // Number of elements in the types array
field_type *m_type; // Array of type descriptors
};
+/**
+ Extend the normal table list with a few new fields needed by the
+ slave thread, but nowhere else.
+ */
+struct RPL_TABLE_LIST
+ : public st_table_list
+{
+ bool m_tabledef_valid;
+ table_def m_tabledef;
+};
+
#endif /* RPL_UTILITY_H */
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
new file mode 100644
index 00000000000..b05bdf4756f
--- /dev/null
+++ b/sql/scheduler.cc
@@ -0,0 +1,88 @@
+/* Copyright (C) 2007 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; version 2 of the License.
+
+ 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 */
+
+/*
+ Implementation for the thread scheduler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma implementation
+#endif
+
+#include <mysql_priv.h>
+
+/*
+ 'Dummy' functions to be used when we don't need any handling for a scheduler
+ event
+ */
+
+static bool init_dummy(void) {return 0;}
+static void post_kill_dummy(THD* thd) {}
+static void end_dummy(void) {}
+static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; }
+
+/*
+ Initialize default scheduler with dummy functions so that setup functions
+ only need to declare those that are relvant for their usage
+*/
+
+scheduler_functions::scheduler_functions()
+ :init(init_dummy),
+ init_new_connection_thread(init_new_connection_handler_thread),
+ add_connection(0), // Must be defined
+ post_kill_notification(post_kill_dummy),
+ end_thread(end_thread_dummy), end(end_dummy)
+{}
+
+
+/*
+ End connection, in case when we are using 'no-threads'
+*/
+
+static bool no_threads_end(THD *thd, bool put_in_cache)
+{
+ unlink_thd(thd);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ return 1; // Abort handle_one_connection
+}
+
+
+/*
+ Initailize scheduler for --thread-handling=no-threads
+*/
+
+void one_thread_scheduler(scheduler_functions* func)
+{
+ func->max_threads= 1;
+#ifndef EMBEDDED_LIBRARY
+ func->add_connection= handle_connection_in_main_thread;
+#endif
+ func->init_new_connection_thread= init_dummy;
+ func->end_thread= no_threads_end;
+}
+
+
+/*
+ Initialize scheduler for --thread-handling=one-thread-per-connection
+*/
+
+#ifndef EMBEDDED_LIBRARY
+void one_thread_per_connection_scheduler(scheduler_functions* func)
+{
+ func->max_threads= max_connections;
+ func->add_connection= create_thread_to_handle_connection;
+ func->end_thread= one_thread_per_connection_end;
+}
+#endif /* EMBEDDED_LIBRARY */
diff --git a/sql/scheduler.h b/sql/scheduler.h
new file mode 100644
index 00000000000..8351cefda4c
--- /dev/null
+++ b/sql/scheduler.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007 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; version 2 of the License.
+
+ 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 */
+
+/*
+ Classes for the thread scheduler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface
+#endif
+
+class THD;
+
+/* Functions used when manipulating threads */
+
+class scheduler_functions
+{
+public:
+ uint max_threads;
+ bool (*init)(void);
+ bool (*init_new_connection_thread)(void);
+ void (*add_connection)(THD *thd);
+ void (*post_kill_notification)(THD *thd);
+ bool (*end_thread)(THD *thd, bool cache_thread);
+ void (*end)(void);
+ scheduler_functions();
+};
+
+enum scheduler_types
+{
+ SCHEDULER_ONE_THREAD_PER_CONNECTION=1,
+ SCHEDULER_NO_THREADS,
+ SCHEDULER_POOL_OF_THREADS
+};
+
+void one_thread_per_connection_scheduler(scheduler_functions* func);
+void one_thread_scheduler(scheduler_functions* func);
+
+enum pool_command_op
+{
+ NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
+};
+
+#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */
+#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A)
+
+class thd_scheduler
+{};
diff --git a/sql/set_var.cc b/sql/set_var.cc
index bc7bbbf8037..e794f708bad 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,8 +27,6 @@
of it in the my_option structure list in mysqld.cc
- Don't forget to initialize new fields in global_system_variables and
max_system_variables!
- - If the variable should show up in 'show variables' add it to the
- init_vars[] struct in this file
NOTES:
- Be careful with var->save_result: sys_var::check() only updates
@@ -52,6 +49,7 @@
#include "mysql_priv.h"
#include <mysql.h>
#include "slave.h"
+#include "rpl_mi.h"
#include <my_getopt.h>
#include <thr_alarm.h>
#include <myisam.h>
@@ -59,50 +57,24 @@
#include "events.h"
-/* WITH_INNOBASE_STORAGE_ENGINE */
-extern uint innobase_flush_log_at_trx_commit;
-extern ulong innobase_fast_shutdown;
-extern long innobase_mirrored_log_groups, innobase_log_files_in_group;
-extern longlong innobase_log_file_size;
-extern long innobase_log_buffer_size;
-extern longlong innobase_buffer_pool_size;
-extern long innobase_additional_mem_pool_size;
-extern long innobase_file_io_threads, innobase_lock_wait_timeout;
-extern long innobase_force_recovery;
-extern long innobase_open_files;
-extern char *innobase_data_home_dir, *innobase_data_file_path;
-extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
-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_doublewrite,
- innobase_use_checksums,
- innobase_file_per_table,
- innobase_locks_unsafe_for_binlog;
-
-extern "C" {
-extern ulong srv_max_buf_pool_modified_pct;
-extern ulong srv_max_purge_lag;
-extern ulong srv_auto_extend_increment;
-extern ulong srv_n_spin_wait_rounds;
-extern ulong srv_n_free_tickets_to_enter;
-extern ulong srv_thread_sleep_delay;
-extern ulong srv_thread_concurrency;
-extern ulong srv_commit_concurrency;
-extern ulong srv_flush_log_at_trx_commit;
-}
-
/* WITH_NDBCLUSTER_STORAGE_ENGINE */
+#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
extern ulong ndb_cache_check_time;
+extern char opt_ndb_constrbuf[];
extern ulong ndb_extra_logging;
+#endif
+
#ifdef HAVE_NDB_BINLOG
extern ulong ndb_report_thresh_binlog_epoch_slip;
extern ulong ndb_report_thresh_binlog_mem_usage;
#endif
+extern CHARSET_INFO *character_set_filesystem;
+static DYNAMIC_ARRAY fixed_show_vars;
static HASH system_variable_hash;
+
const char *bool_type_names[]= { "OFF", "ON", NullS };
TYPELIB bool_typelib=
{
@@ -116,9 +88,6 @@ TYPELIB delay_key_write_typelib=
delay_key_write_type_names, NULL
};
-static int sys_check_charset(THD *thd, set_var *var);
-static bool sys_update_charset(THD *thd, set_var *var);
-static void sys_set_default_charset(THD *thd, enum_var_type type);
static int sys_check_ftb_syntax(THD *thd, set_var *var);
static bool sys_update_ftb_syntax(THD *thd, set_var * var);
static void sys_default_ftb_syntax(THD *thd, enum_var_type type);
@@ -153,9 +122,9 @@ static void fix_trans_mem_root(THD *thd, enum_var_type type);
static void fix_server_id(THD *thd, enum_var_type type);
static KEY_CACHE *create_key_cache(const char *name, uint length);
void fix_sql_mode_var(THD *thd, enum_var_type type);
-static byte *get_error_count(THD *thd);
-static byte *get_warning_count(THD *thd);
-static byte *get_tmpdir(THD *thd);
+static uchar *get_error_count(THD *thd);
+static uchar *get_warning_count(THD *thd);
+static uchar *get_tmpdir(THD *thd);
static int sys_check_log_path(THD *thd, set_var *var);
static bool sys_update_general_log_path(THD *thd, set_var * var);
static void sys_default_general_log_path(THD *thd, enum_var_type type);
@@ -172,862 +141,570 @@ static void sys_default_slow_log_path(THD *thd, enum_var_type type);
it in the constructor (see sys_var class for details).
*/
-sys_var *sys_var::first= NULL;
-uint sys_var::sys_vars= 0;
+static sys_var_chain vars = { NULL, NULL };
-sys_var_thd_ulong sys_auto_increment_increment("auto_increment_increment",
+static sys_var_thd_ulong sys_auto_increment_increment(&vars, "auto_increment_increment",
&SV::auto_increment_increment);
-sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset",
+static sys_var_thd_ulong sys_auto_increment_offset(&vars, "auto_increment_offset",
&SV::auto_increment_offset);
-sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges",
+static sys_var_bool_ptr sys_automatic_sp_privileges(&vars, "automatic_sp_privileges",
&sp_automatic_privileges);
-sys_var_const_str sys_basedir("basedir", mysql_home);
-sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
+static sys_var_const_str sys_basedir(&vars, "basedir", mysql_home);
+static sys_var_long_ptr sys_binlog_cache_size(&vars, "binlog_cache_size",
&binlog_cache_size);
-sys_var_thd_binlog_format sys_binlog_format("binlog_format",
+static sys_var_thd_binlog_format sys_binlog_format(&vars, "binlog_format",
&SV::binlog_format);
-sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size",
+static sys_var_thd_ulong sys_bulk_insert_buff_size(&vars, "bulk_insert_buffer_size",
&SV::bulk_insert_buff_size);
-sys_var_character_set_server sys_character_set_server("character_set_server");
-sys_var_const_str sys_charset_system("character_set_system",
+static sys_var_character_set_sv sys_character_set_server(&vars, "character_set_server",
+ &SV::collation_server,
+ &default_charset_info);
+sys_var_const_str sys_charset_system(&vars, "character_set_system",
(char *)my_charset_utf8_general_ci.name);
-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_character_set_filesystem sys_character_set_filesystem("character_set_filesystem");
-sys_var_thd_ulong sys_completion_type("completion_type",
+static sys_var_character_set_database sys_character_set_database(&vars, "character_set_database");
+static sys_var_character_set_sv sys_character_set_client(&vars, "character_set_client",
+ &SV::character_set_client,
+ &default_charset_info);
+static sys_var_character_set_sv sys_character_set_connection(&vars, "character_set_connection",
+ &SV::collation_connection,
+ &default_charset_info);
+static sys_var_character_set_sv sys_character_set_results(&vars, "character_set_results",
+ &SV::character_set_results,
+ &default_charset_info, true);
+static sys_var_character_set_sv sys_character_set_filesystem(&vars, "character_set_filesystem",
+ &SV::character_set_filesystem,
+ &character_set_filesystem);
+static sys_var_thd_ulong sys_completion_type(&vars, "completion_type",
&SV::completion_type,
check_completion_type,
fix_completion_type);
-sys_var_collation_connection sys_collation_connection("collation_connection");
-sys_var_collation_database sys_collation_database("collation_database");
-sys_var_collation_server sys_collation_server("collation_server");
-sys_var_long_ptr sys_concurrent_insert("concurrent_insert",
+static sys_var_collation_sv sys_collation_connection(&vars, "collation_connection",
+ &SV::collation_connection,
+ &default_charset_info);
+static sys_var_collation_sv sys_collation_database(&vars, "collation_database",
+ &SV::collation_database,
+ &default_charset_info);
+static sys_var_collation_sv sys_collation_server(&vars, "collation_server",
+ &SV::collation_server,
+ &default_charset_info);
+static sys_var_long_ptr sys_concurrent_insert(&vars, "concurrent_insert",
&myisam_concurrent_insert);
-sys_var_long_ptr sys_connect_timeout("connect_timeout",
+static sys_var_long_ptr sys_connect_timeout(&vars, "connect_timeout",
&connect_timeout);
-sys_var_const_str sys_datadir("datadir", mysql_real_data_home);
+static sys_var_const_str sys_datadir(&vars, "datadir", mysql_real_data_home);
#ifndef DBUG_OFF
-sys_var_thd_dbug sys_dbug("debug");
+static sys_var_thd_dbug sys_dbug(&vars, "debug");
#endif
-sys_var_enum sys_delay_key_write("delay_key_write",
+static sys_var_enum sys_delay_key_write(&vars, "delay_key_write",
&delay_key_write_options,
&delay_key_write_typelib,
fix_delay_key_write);
-sys_var_long_ptr sys_delayed_insert_limit("delayed_insert_limit",
+static sys_var_long_ptr sys_delayed_insert_limit(&vars, "delayed_insert_limit",
&delayed_insert_limit);
-sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
+static sys_var_long_ptr sys_delayed_insert_timeout(&vars, "delayed_insert_timeout",
&delayed_insert_timeout);
-sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
+static sys_var_long_ptr sys_delayed_queue_size(&vars, "delayed_queue_size",
&delayed_queue_size);
-sys_var_event_scheduler sys_event_scheduler("event_scheduler");
-sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
+static sys_var_event_scheduler sys_event_scheduler(&vars, "event_scheduler");
+static sys_var_long_ptr sys_expire_logs_days(&vars, "expire_logs_days",
&expire_logs_days);
-sys_var_bool_ptr sys_flush("flush", &myisam_flush);
-sys_var_long_ptr sys_flush_time("flush_time", &flush_time);
-sys_var_str sys_ft_boolean_syntax("ft_boolean_syntax",
+static sys_var_bool_ptr sys_flush(&vars, "flush", &myisam_flush);
+static sys_var_long_ptr sys_flush_time(&vars, "flush_time", &flush_time);
+static sys_var_str sys_ft_boolean_syntax(&vars, "ft_boolean_syntax",
sys_check_ftb_syntax,
sys_update_ftb_syntax,
sys_default_ftb_syntax,
ft_boolean_syntax);
-sys_var_str sys_init_connect("init_connect", 0,
+sys_var_str sys_init_connect(&vars, "init_connect", 0,
sys_update_init_connect,
sys_default_init_connect,0);
-sys_var_str sys_init_slave("init_slave", 0,
+sys_var_str sys_init_slave(&vars, "init_slave", 0,
sys_update_init_slave,
sys_default_init_slave,0);
-sys_var_thd_ulong sys_interactive_timeout("interactive_timeout",
+static sys_var_thd_ulong sys_interactive_timeout(&vars, "interactive_timeout",
&SV::net_interactive_timeout);
-sys_var_thd_ulong sys_join_buffer_size("join_buffer_size",
+static sys_var_thd_ulong sys_join_buffer_size(&vars, "join_buffer_size",
&SV::join_buff_size);
-sys_var_key_buffer_size sys_key_buffer_size("key_buffer_size");
-sys_var_key_cache_long sys_key_cache_block_size("key_cache_block_size",
+static sys_var_key_buffer_size sys_key_buffer_size(&vars, "key_buffer_size");
+static sys_var_key_cache_long sys_key_cache_block_size(&vars, "key_cache_block_size",
offsetof(KEY_CACHE,
param_block_size));
-sys_var_key_cache_long sys_key_cache_division_limit("key_cache_division_limit",
+static sys_var_key_cache_long sys_key_cache_division_limit(&vars, "key_cache_division_limit",
offsetof(KEY_CACHE,
param_division_limit));
-sys_var_key_cache_long sys_key_cache_age_threshold("key_cache_age_threshold",
+static sys_var_key_cache_long sys_key_cache_age_threshold(&vars, "key_cache_age_threshold",
offsetof(KEY_CACHE,
param_age_threshold));
-sys_var_bool_ptr sys_local_infile("local_infile",
+static sys_var_bool_ptr sys_local_infile(&vars, "local_infile",
&opt_local_infile);
-sys_var_trust_routine_creators
-sys_trust_routine_creators("log_bin_trust_routine_creators",
+static sys_var_trust_routine_creators
+sys_trust_routine_creators(&vars, "log_bin_trust_routine_creators",
&trust_function_creators);
-sys_var_bool_ptr
-sys_trust_function_creators("log_bin_trust_function_creators",
+static sys_var_bool_ptr
+sys_trust_function_creators(&vars, "log_bin_trust_function_creators",
&trust_function_creators);
-sys_var_bool_ptr
- sys_log_queries_not_using_indexes("log_queries_not_using_indexes",
+static sys_var_bool_ptr
+ sys_log_queries_not_using_indexes(&vars, "log_queries_not_using_indexes",
&opt_log_queries_not_using_indexes);
-sys_var_thd_ulong sys_log_warnings("log_warnings", &SV::log_warnings);
-sys_var_thd_ulong sys_long_query_time("long_query_time",
+static sys_var_thd_ulong sys_log_warnings(&vars, "log_warnings", &SV::log_warnings);
+static sys_var_thd_ulong sys_long_query_time(&vars, "long_query_time",
&SV::long_query_time);
-sys_var_thd_bool sys_low_priority_updates("low_priority_updates",
+static sys_var_thd_bool sys_low_priority_updates(&vars, "low_priority_updates",
&SV::low_priority_updates,
fix_low_priority_updates);
#ifndef TO_BE_DELETED /* Alias for the low_priority_updates */
-sys_var_thd_bool sys_sql_low_priority_updates("sql_low_priority_updates",
+static sys_var_thd_bool sys_sql_low_priority_updates(&vars, "sql_low_priority_updates",
&SV::low_priority_updates,
fix_low_priority_updates);
#endif
-sys_var_thd_ulong sys_max_allowed_packet("max_allowed_packet",
+static sys_var_thd_ulong sys_max_allowed_packet(&vars, "max_allowed_packet",
&SV::max_allowed_packet);
-sys_var_long_ptr sys_max_binlog_cache_size("max_binlog_cache_size",
+static sys_var_long_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size",
&max_binlog_cache_size);
-sys_var_long_ptr sys_max_binlog_size("max_binlog_size",
+static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size",
&max_binlog_size,
fix_max_binlog_size);
-sys_var_long_ptr sys_max_connections("max_connections",
+static sys_var_long_ptr sys_max_connections(&vars, "max_connections",
&max_connections,
fix_max_connections);
-sys_var_long_ptr sys_max_connect_errors("max_connect_errors",
+static sys_var_long_ptr sys_max_connect_errors(&vars, "max_connect_errors",
&max_connect_errors);
-sys_var_thd_ulong sys_max_insert_delayed_threads("max_insert_delayed_threads",
+static sys_var_thd_ulong sys_max_insert_delayed_threads(&vars, "max_insert_delayed_threads",
&SV::max_insert_delayed_threads,
check_max_delayed_threads,
fix_max_connections);
-sys_var_thd_ulong sys_max_delayed_threads("max_delayed_threads",
+static sys_var_thd_ulong sys_max_delayed_threads(&vars, "max_delayed_threads",
&SV::max_insert_delayed_threads,
check_max_delayed_threads,
fix_max_connections);
-sys_var_thd_ulong sys_max_error_count("max_error_count",
+static sys_var_thd_ulong sys_max_error_count(&vars, "max_error_count",
&SV::max_error_count);
-sys_var_thd_ulonglong sys_max_heap_table_size("max_heap_table_size",
+static sys_var_thd_ulonglong sys_max_heap_table_size(&vars, "max_heap_table_size",
&SV::max_heap_table_size);
-sys_var_thd_ulong sys_pseudo_thread_id("pseudo_thread_id",
+static sys_var_thd_ulong sys_pseudo_thread_id(&vars, "pseudo_thread_id",
&SV::pseudo_thread_id,
check_pseudo_thread_id, 0);
-sys_var_thd_ha_rows sys_max_join_size("max_join_size",
+static sys_var_thd_ha_rows sys_max_join_size(&vars, "max_join_size",
&SV::max_join_size,
fix_max_join_size);
-sys_var_thd_ulong sys_max_seeks_for_key("max_seeks_for_key",
+static sys_var_thd_ulong sys_max_seeks_for_key(&vars, "max_seeks_for_key",
&SV::max_seeks_for_key);
-sys_var_thd_ulong sys_max_length_for_sort_data("max_length_for_sort_data",
+static sys_var_thd_ulong sys_max_length_for_sort_data(&vars, "max_length_for_sort_data",
&SV::max_length_for_sort_data);
#ifndef TO_BE_DELETED /* Alias for max_join_size */
-sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size",
+static sys_var_thd_ha_rows sys_sql_max_join_size(&vars, "sql_max_join_size",
&SV::max_join_size,
fix_max_join_size);
#endif
static sys_var_long_ptr_global
-sys_max_prepared_stmt_count("max_prepared_stmt_count",
+sys_max_prepared_stmt_count(&vars, "max_prepared_stmt_count",
&max_prepared_stmt_count,
&LOCK_prepared_stmt_count);
-sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size",
+static sys_var_long_ptr sys_max_relay_log_size(&vars, "max_relay_log_size",
&max_relay_log_size,
fix_max_relay_log_size);
-sys_var_thd_ulong sys_max_sort_length("max_sort_length",
+static sys_var_thd_ulong sys_max_sort_length(&vars, "max_sort_length",
&SV::max_sort_length);
-sys_var_thd_ulong sys_max_sp_recursion_depth("max_sp_recursion_depth",
+static sys_var_thd_ulong sys_max_sp_recursion_depth(&vars, "max_sp_recursion_depth",
&SV::max_sp_recursion_depth);
-sys_var_max_user_conn sys_max_user_connections("max_user_connections");
-sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables",
+static sys_var_max_user_conn sys_max_user_connections(&vars, "max_user_connections");
+static sys_var_thd_ulong sys_max_tmp_tables(&vars, "max_tmp_tables",
&SV::max_tmp_tables);
-sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count",
+static sys_var_long_ptr sys_max_write_lock_count(&vars, "max_write_lock_count",
&max_write_lock_count);
-sys_var_thd_ulong sys_multi_range_count("multi_range_count",
+static sys_var_thd_ulong sys_multi_range_count(&vars, "multi_range_count",
&SV::multi_range_count);
-sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size",
+static sys_var_long_ptr sys_myisam_data_pointer_size(&vars, "myisam_data_pointer_size",
&myisam_data_pointer_size);
-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_bool_ptr sys_myisam_use_mmap("myisam_use_mmap",
+static sys_var_thd_ulonglong sys_myisam_max_sort_file_size(&vars, "myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1);
+static sys_var_thd_ulong sys_myisam_repair_threads(&vars, "myisam_repair_threads", &SV::myisam_repair_threads);
+static sys_var_thd_ulong sys_myisam_sort_buffer_size(&vars, "myisam_sort_buffer_size", &SV::myisam_sort_buff_size);
+static sys_var_bool_ptr sys_myisam_use_mmap(&vars, "myisam_use_mmap",
&opt_myisam_use_mmap);
-sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method",
+static sys_var_thd_enum sys_myisam_stats_method(&vars, "myisam_stats_method",
&SV::myisam_stats_method,
&myisam_stats_method_typelib,
NULL);
-sys_var_thd_ulong sys_net_buffer_length("net_buffer_length",
+static sys_var_thd_ulong sys_net_buffer_length(&vars, "net_buffer_length",
&SV::net_buffer_length);
-sys_var_thd_ulong sys_net_read_timeout("net_read_timeout",
+static sys_var_thd_ulong sys_net_read_timeout(&vars, "net_read_timeout",
&SV::net_read_timeout,
0, fix_net_read_timeout);
-sys_var_thd_ulong sys_net_write_timeout("net_write_timeout",
+static sys_var_thd_ulong sys_net_write_timeout(&vars, "net_write_timeout",
&SV::net_write_timeout,
0, fix_net_write_timeout);
-sys_var_thd_ulong sys_net_retry_count("net_retry_count",
+static sys_var_thd_ulong sys_net_retry_count(&vars, "net_retry_count",
&SV::net_retry_count,
0, fix_net_retry_count);
-sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
-sys_var_thd_bool sys_old_alter_table("old_alter_table",
- &SV::old_alter_table);
-sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
-sys_var_thd_ulong sys_optimizer_prune_level("optimizer_prune_level",
+static sys_var_thd_bool sys_new_mode(&vars, "new", &SV::new_mode);
+static sys_var_bool_ptr_readonly sys_old_mode(&vars, "old",
+ &global_system_variables.old_mode);
+/* these two cannot be static */
+sys_var_thd_bool sys_old_alter_table(&vars, "old_alter_table",
+ &SV::old_alter_table);
+sys_var_thd_bool sys_old_passwords(&vars, "old_passwords", &SV::old_passwords);
+static sys_var_thd_ulong sys_optimizer_prune_level(&vars, "optimizer_prune_level",
&SV::optimizer_prune_level);
-sys_var_thd_ulong sys_optimizer_search_depth("optimizer_search_depth",
+static sys_var_thd_ulong sys_optimizer_search_depth(&vars, "optimizer_search_depth",
&SV::optimizer_search_depth);
-sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
+static sys_var_thd_ulong sys_preload_buff_size(&vars, "preload_buffer_size",
&SV::preload_buff_size);
-sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
+static sys_var_thd_ulong sys_read_buff_size(&vars, "read_buffer_size",
&SV::read_buff_size);
-sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
-sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
+static sys_var_opt_readonly sys_readonly(&vars, "read_only", &opt_readonly);
+static sys_var_thd_ulong sys_read_rnd_buff_size(&vars, "read_rnd_buffer_size",
&SV::read_rnd_buff_size);
-sys_var_thd_ulong sys_div_precincrement("div_precision_increment",
+static sys_var_thd_ulong sys_div_precincrement(&vars, "div_precision_increment",
&SV::div_precincrement);
-#ifdef HAVE_REPLICATION
-sys_var_bool_ptr sys_relay_log_purge("relay_log_purge",
- &relay_log_purge);
-#endif
-sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank",
+static sys_var_long_ptr sys_rpl_recovery_rank(&vars, "rpl_recovery_rank",
&rpl_recovery_rank);
-sys_var_long_ptr sys_query_cache_size("query_cache_size",
+static sys_var_long_ptr sys_query_cache_size(&vars, "query_cache_size",
&query_cache_size,
fix_query_cache_size);
-sys_var_thd_ulong sys_range_alloc_block_size("range_alloc_block_size",
+static sys_var_thd_ulong sys_range_alloc_block_size(&vars, "range_alloc_block_size",
&SV::range_alloc_block_size);
-sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size",
+static sys_var_thd_ulong sys_query_alloc_block_size(&vars, "query_alloc_block_size",
&SV::query_alloc_block_size,
0, fix_thd_mem_root);
-sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size",
+static sys_var_thd_ulong sys_query_prealloc_size(&vars, "query_prealloc_size",
&SV::query_prealloc_size,
0, fix_thd_mem_root);
-sys_var_readonly sys_tmpdir("tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
-sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size",
+static sys_var_readonly sys_tmpdir(&vars, "tmpdir", OPT_GLOBAL, SHOW_CHAR, get_tmpdir);
+static sys_var_thd_ulong sys_trans_alloc_block_size(&vars, "transaction_alloc_block_size",
&SV::trans_alloc_block_size,
0, fix_trans_mem_root);
-sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size",
+static sys_var_thd_ulong sys_trans_prealloc_size(&vars, "transaction_prealloc_size",
&SV::trans_prealloc_size,
0, fix_trans_mem_root);
+sys_var_thd_enum sys_thread_handling(&vars, "thread_handling",
+ &SV::thread_handling,
+ &thread_handling_typelib,
+ NULL);
#ifdef HAVE_QUERY_CACHE
-sys_var_long_ptr sys_query_cache_limit("query_cache_limit",
+static sys_var_long_ptr sys_query_cache_limit(&vars, "query_cache_limit",
&query_cache.query_cache_limit);
-sys_var_long_ptr sys_query_cache_min_res_unit("query_cache_min_res_unit",
+static sys_var_long_ptr sys_query_cache_min_res_unit(&vars, "query_cache_min_res_unit",
&query_cache_min_res_unit,
fix_query_cache_min_res_unit);
-sys_var_thd_enum sys_query_cache_type("query_cache_type",
+static sys_var_thd_enum sys_query_cache_type(&vars, "query_cache_type",
&SV::query_cache_type,
&query_cache_type_typelib);
-sys_var_thd_bool
-sys_query_cache_wlock_invalidate("query_cache_wlock_invalidate",
+static sys_var_thd_bool
+sys_query_cache_wlock_invalidate(&vars, "query_cache_wlock_invalidate",
&SV::query_cache_wlock_invalidate);
#endif /* HAVE_QUERY_CACHE */
-sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth);
-sys_var_long_ptr sys_server_id("server_id", &server_id, fix_server_id);
-sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
+static sys_var_bool_ptr sys_secure_auth(&vars, "secure_auth", &opt_secure_auth);
+static sys_var_const_str_ptr sys_secure_file_priv(&vars, "secure_file_priv",
+ &opt_secure_file_priv);
+static sys_var_long_ptr sys_server_id(&vars, "server_id", &server_id, fix_server_id);
+static sys_var_bool_ptr sys_slave_compressed_protocol(&vars, "slave_compressed_protocol",
&opt_slave_compressed_protocol);
-#ifdef HAVE_REPLICATION
-sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
- &slave_net_timeout);
-sys_var_long_ptr sys_slave_trans_retries("slave_transaction_retries",
- &slave_trans_retries);
-#endif
-sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
+static sys_var_long_ptr sys_slow_launch_time(&vars, "slow_launch_time",
&slow_launch_time);
-sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
+static sys_var_thd_ulong sys_sort_buffer(&vars, "sort_buffer_size",
&SV::sortbuff_size);
-sys_var_thd_sql_mode sys_sql_mode("sql_mode",
+static sys_var_thd_sql_mode sys_sql_mode(&vars, "sql_mode",
&SV::sql_mode);
#ifdef HAVE_OPENSSL
extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher,
*opt_ssl_key;
-sys_var_const_str_ptr sys_ssl_ca("ssl_ca", &opt_ssl_ca);
-sys_var_const_str_ptr sys_ssl_capath("ssl_capath", &opt_ssl_capath);
-sys_var_const_str_ptr sys_ssl_cert("ssl_cert", &opt_ssl_cert);
-sys_var_const_str_ptr sys_ssl_cipher("ssl_cipher", &opt_ssl_cipher);
-sys_var_const_str_ptr sys_ssl_key("ssl_key", &opt_ssl_key);
+static sys_var_const_str_ptr sys_ssl_ca(&vars, "ssl_ca", &opt_ssl_ca);
+static sys_var_const_str_ptr sys_ssl_capath(&vars, "ssl_capath", &opt_ssl_capath);
+static sys_var_const_str_ptr sys_ssl_cert(&vars, "ssl_cert", &opt_ssl_cert);
+static sys_var_const_str_ptr sys_ssl_cipher(&vars, "ssl_cipher", &opt_ssl_cipher);
+static sys_var_const_str_ptr sys_ssl_key(&vars, "ssl_key", &opt_ssl_key);
#else
-sys_var_const_str sys_ssl_ca("ssl_ca", NULL);
-sys_var_const_str sys_ssl_capath("ssl_capath", NULL);
-sys_var_const_str sys_ssl_cert("ssl_cert", NULL);
-sys_var_const_str sys_ssl_cipher("ssl_cipher", NULL);
-sys_var_const_str sys_ssl_key("ssl_key", NULL);
+static sys_var_const_str sys_ssl_ca(&vars, "ssl_ca", NULL);
+static sys_var_const_str sys_ssl_capath(&vars, "ssl_capath", NULL);
+static sys_var_const_str sys_ssl_cert(&vars, "ssl_cert", NULL);
+static sys_var_const_str sys_ssl_cipher(&vars, "ssl_cipher", NULL);
+static sys_var_const_str sys_ssl_key(&vars, "ssl_key", NULL);
#endif
-sys_var_thd_enum
-sys_updatable_views_with_limit("updatable_views_with_limit",
+static sys_var_thd_enum
+sys_updatable_views_with_limit(&vars, "updatable_views_with_limit",
&SV::updatable_views_with_limit,
&updatable_views_with_limit_typelib);
-sys_var_thd_table_type sys_table_type("table_type",
- &SV::table_type);
-sys_var_thd_storage_engine sys_storage_engine("storage_engine",
- &SV::table_type);
-#ifdef HAVE_REPLICATION
-sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period);
-#endif
-sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm);
-sys_var_const_str sys_system_time_zone("system_time_zone",
+static sys_var_thd_table_type sys_table_type(&vars, "table_type",
+ &SV::table_plugin);
+static sys_var_thd_storage_engine sys_storage_engine(&vars, "storage_engine",
+ &SV::table_plugin);
+static sys_var_bool_ptr sys_sync_frm(&vars, "sync_frm", &opt_sync_frm);
+static sys_var_const_str sys_system_time_zone(&vars, "system_time_zone",
system_time_zone);
-sys_var_long_ptr sys_table_def_size("table_definition_cache",
+static sys_var_long_ptr sys_table_def_size(&vars, "table_definition_cache",
&table_def_size);
-sys_var_long_ptr sys_table_cache_size("table_open_cache",
+static sys_var_long_ptr sys_table_cache_size(&vars, "table_open_cache",
&table_cache_size);
-sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout",
+static sys_var_long_ptr sys_table_lock_wait_timeout(&vars, "table_lock_wait_timeout",
&table_lock_wait_timeout);
-sys_var_long_ptr sys_thread_cache_size("thread_cache_size",
+static sys_var_long_ptr sys_thread_cache_size(&vars, "thread_cache_size",
&thread_cache_size);
-sys_var_thd_enum sys_tx_isolation("tx_isolation",
+#if HAVE_POOL_OF_THREADS == 1
+sys_var_long_ptr sys_thread_pool_size(&vars, "thread_pool_size",
+ &thread_pool_size);
+#endif
+static sys_var_thd_enum sys_tx_isolation(&vars, "tx_isolation",
&SV::tx_isolation,
&tx_isolation_typelib,
fix_tx_isolation,
check_tx_isolation);
-sys_var_thd_ulonglong sys_tmp_table_size("tmp_table_size",
+static sys_var_thd_ulonglong sys_tmp_table_size(&vars, "tmp_table_size",
&SV::tmp_table_size);
-sys_var_bool_ptr sys_timed_mutexes("timed_mutexes",
+static sys_var_bool_ptr sys_timed_mutexes(&vars, "timed_mutexes",
&timed_mutexes);
-sys_var_const_str sys_version("version", server_version);
-sys_var_const_str sys_version_comment("version_comment",
+static sys_var_const_str sys_version(&vars, "version", server_version);
+static sys_var_const_str sys_version_comment(&vars, "version_comment",
MYSQL_COMPILATION_COMMENT);
-sys_var_const_str sys_version_compile_machine("version_compile_machine",
+static sys_var_const_str sys_version_compile_machine(&vars, "version_compile_machine",
MACHINE_TYPE);
-sys_var_const_str sys_version_compile_os("version_compile_os",
+static sys_var_const_str sys_version_compile_os(&vars, "version_compile_os",
SYSTEM_TYPE);
-sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
+static sys_var_thd_ulong sys_net_wait_timeout(&vars, "wait_timeout",
&SV::net_wait_timeout);
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
-sys_var_long_ptr sys_innodb_fast_shutdown("innodb_fast_shutdown",
- &innobase_fast_shutdown);
-sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct",
- &srv_max_buf_pool_modified_pct);
-sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag",
- &srv_max_purge_lag);
-sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
- &SV::innodb_table_locks);
-sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa",
- &SV::innodb_support_xa);
-sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment",
- &srv_auto_extend_increment);
-sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops",
- &srv_n_spin_wait_rounds);
-sys_var_long_ptr sys_innodb_concurrency_tickets("innodb_concurrency_tickets",
- &srv_n_free_tickets_to_enter);
-sys_var_long_ptr sys_innodb_thread_sleep_delay("innodb_thread_sleep_delay",
- &srv_thread_sleep_delay);
-sys_var_long_ptr sys_innodb_thread_concurrency("innodb_thread_concurrency",
- &srv_thread_concurrency);
-sys_var_long_ptr sys_innodb_commit_concurrency("innodb_commit_concurrency",
- &srv_commit_concurrency);
-sys_var_long_ptr sys_innodb_flush_log_at_trx_commit(
- "innodb_flush_log_at_trx_commit",
- &srv_flush_log_at_trx_commit);
-#endif
+
/* Condition pushdown to storage engine */
-sys_var_thd_bool
-sys_engine_condition_pushdown("engine_condition_pushdown",
+static sys_var_thd_bool
+sys_engine_condition_pushdown(&vars, "engine_condition_pushdown",
&SV::engine_condition_pushdown);
+#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
/* ndb thread specific variable settings */
-sys_var_thd_ulong
-sys_ndb_autoincrement_prefetch_sz("ndb_autoincrement_prefetch_sz",
+static sys_var_thd_ulong
+sys_ndb_autoincrement_prefetch_sz(&vars, "ndb_autoincrement_prefetch_sz",
&SV::ndb_autoincrement_prefetch_sz);
-sys_var_thd_bool
-sys_ndb_force_send("ndb_force_send", &SV::ndb_force_send);
+static sys_var_thd_bool
+sys_ndb_force_send(&vars, "ndb_force_send", &SV::ndb_force_send);
#ifdef HAVE_NDB_BINLOG
-sys_var_long_ptr
-sys_ndb_report_thresh_binlog_epoch_slip("ndb_report_thresh_binlog_epoch_slip",
+static sys_var_long_ptr
+sys_ndb_report_thresh_binlog_epoch_slip(&vars, "ndb_report_thresh_binlog_epoch_slip",
&ndb_report_thresh_binlog_epoch_slip);
-sys_var_long_ptr
-sys_ndb_report_thresh_binlog_mem_usage("ndb_report_thresh_binlog_mem_usage",
+static sys_var_long_ptr
+sys_ndb_report_thresh_binlog_mem_usage(&vars, "ndb_report_thresh_binlog_mem_usage",
&ndb_report_thresh_binlog_mem_usage);
#endif
-sys_var_thd_bool
-sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count);
-sys_var_thd_bool
-sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions);
-sys_var_long_ptr
-sys_ndb_cache_check_time("ndb_cache_check_time", &ndb_cache_check_time);
-sys_var_thd_bool
-sys_ndb_index_stat_enable("ndb_index_stat_enable",
+static sys_var_thd_bool
+sys_ndb_use_exact_count(&vars, "ndb_use_exact_count", &SV::ndb_use_exact_count);
+static sys_var_thd_bool
+sys_ndb_use_transactions(&vars, "ndb_use_transactions", &SV::ndb_use_transactions);
+static sys_var_long_ptr
+sys_ndb_cache_check_time(&vars, "ndb_cache_check_time", &ndb_cache_check_time);
+static sys_var_const_str
+sys_ndb_connectstring(&vars, "ndb_connectstring", opt_ndb_constrbuf);
+static sys_var_thd_bool
+sys_ndb_index_stat_enable(&vars, "ndb_index_stat_enable",
&SV::ndb_index_stat_enable);
-sys_var_thd_ulong
-sys_ndb_index_stat_cache_entries("ndb_index_stat_cache_entries",
+static sys_var_thd_ulong
+sys_ndb_index_stat_cache_entries(&vars, "ndb_index_stat_cache_entries",
&SV::ndb_index_stat_cache_entries);
-sys_var_thd_ulong
-sys_ndb_index_stat_update_freq("ndb_index_stat_update_freq",
+static sys_var_thd_ulong
+sys_ndb_index_stat_update_freq(&vars, "ndb_index_stat_update_freq",
&SV::ndb_index_stat_update_freq);
-sys_var_long_ptr
-sys_ndb_extra_logging("ndb_extra_logging", &ndb_extra_logging);
-sys_var_thd_bool
-sys_ndb_use_copying_alter_table("ndb_use_copying_alter_table", &SV::ndb_use_copying_alter_table);
+static sys_var_long_ptr
+sys_ndb_extra_logging(&vars, "ndb_extra_logging", &ndb_extra_logging);
+static sys_var_thd_bool
+sys_ndb_use_copying_alter_table(&vars, "ndb_use_copying_alter_table", &SV::ndb_use_copying_alter_table);
+#endif //WITH_NDBCLUSTER_STORAGE_ENGINE
/* Time/date/datetime formats */
-sys_var_thd_date_time_format sys_time_format("time_format",
+static sys_var_thd_date_time_format sys_time_format(&vars, "time_format",
&SV::time_format,
MYSQL_TIMESTAMP_TIME);
-sys_var_thd_date_time_format sys_date_format("date_format",
+static sys_var_thd_date_time_format sys_date_format(&vars, "date_format",
&SV::date_format,
MYSQL_TIMESTAMP_DATE);
-sys_var_thd_date_time_format sys_datetime_format("datetime_format",
+static sys_var_thd_date_time_format sys_datetime_format(&vars, "datetime_format",
&SV::datetime_format,
MYSQL_TIMESTAMP_DATETIME);
/* Variables that are bits in THD */
-sys_var_thd_bit sys_autocommit("autocommit", 0,
+sys_var_thd_bit sys_autocommit(&vars, "autocommit", 0,
set_option_autocommit,
OPTION_NOT_AUTOCOMMIT,
1);
-static sys_var_thd_bit sys_big_tables("big_tables", 0,
+static sys_var_thd_bit sys_big_tables(&vars, "big_tables", 0,
set_option_bit,
OPTION_BIG_TABLES);
#ifndef TO_BE_DELETED /* Alias for big_tables */
-static sys_var_thd_bit sys_sql_big_tables("sql_big_tables", 0,
+static sys_var_thd_bit sys_sql_big_tables(&vars, "sql_big_tables", 0,
set_option_bit,
OPTION_BIG_TABLES);
#endif
-static sys_var_thd_bit sys_big_selects("sql_big_selects", 0,
+static sys_var_thd_bit sys_big_selects(&vars, "sql_big_selects", 0,
set_option_bit,
OPTION_BIG_SELECTS);
-static sys_var_thd_bit sys_log_off("sql_log_off",
+static sys_var_thd_bit sys_log_off(&vars, "sql_log_off",
check_log_update,
set_option_bit,
OPTION_LOG_OFF);
-static sys_var_thd_bit sys_log_update("sql_log_update",
+static sys_var_thd_bit sys_log_update(&vars, "sql_log_update",
check_log_update,
set_log_update,
OPTION_BIN_LOG);
-static sys_var_thd_bit sys_log_binlog("sql_log_bin",
+static sys_var_thd_bit sys_log_binlog(&vars, "sql_log_bin",
check_log_update,
set_option_bit,
OPTION_BIN_LOG);
-static sys_var_thd_bit sys_sql_warnings("sql_warnings", 0,
+static sys_var_thd_bit sys_sql_warnings(&vars, "sql_warnings", 0,
set_option_bit,
OPTION_WARNINGS);
-static sys_var_thd_bit sys_sql_notes("sql_notes", 0,
+static sys_var_thd_bit sys_sql_notes(&vars, "sql_notes", 0,
set_option_bit,
OPTION_SQL_NOTES);
-static sys_var_thd_bit sys_auto_is_null("sql_auto_is_null", 0,
+static sys_var_thd_bit sys_auto_is_null(&vars, "sql_auto_is_null", 0,
set_option_bit,
OPTION_AUTO_IS_NULL);
-static sys_var_thd_bit sys_safe_updates("sql_safe_updates", 0,
+static sys_var_thd_bit sys_safe_updates(&vars, "sql_safe_updates", 0,
set_option_bit,
OPTION_SAFE_UPDATES);
-static sys_var_thd_bit sys_buffer_results("sql_buffer_result", 0,
+static sys_var_thd_bit sys_buffer_results(&vars, "sql_buffer_result", 0,
set_option_bit,
OPTION_BUFFER_RESULT);
-static sys_var_thd_bit sys_quote_show_create("sql_quote_show_create", 0,
+static sys_var_thd_bit sys_quote_show_create(&vars, "sql_quote_show_create", 0,
set_option_bit,
OPTION_QUOTE_SHOW_CREATE);
-static sys_var_thd_bit sys_foreign_key_checks("foreign_key_checks", 0,
+static sys_var_thd_bit sys_foreign_key_checks(&vars, "foreign_key_checks", 0,
set_option_bit,
OPTION_NO_FOREIGN_KEY_CHECKS,
1);
-static sys_var_thd_bit sys_unique_checks("unique_checks", 0,
+static sys_var_thd_bit sys_unique_checks(&vars, "unique_checks", 0,
set_option_bit,
OPTION_RELAXED_UNIQUE_CHECKS,
1);
/* Local state variables */
-static sys_var_thd_ha_rows sys_select_limit("sql_select_limit",
+static sys_var_thd_ha_rows sys_select_limit(&vars, "sql_select_limit",
&SV::select_limit);
-static sys_var_timestamp sys_timestamp("timestamp");
-static sys_var_last_insert_id sys_last_insert_id("last_insert_id");
-static sys_var_last_insert_id sys_identity("identity");
+static sys_var_timestamp sys_timestamp(&vars, "timestamp");
+static sys_var_last_insert_id sys_last_insert_id(&vars, "last_insert_id");
+static sys_var_last_insert_id sys_identity(&vars, "identity");
-static sys_var_thd_lc_time_names sys_lc_time_names("lc_time_names");
+static sys_var_thd_lc_time_names sys_lc_time_names(&vars, "lc_time_names");
-static sys_var_insert_id sys_insert_id("insert_id");
-static sys_var_readonly sys_error_count("error_count",
+static sys_var_insert_id sys_insert_id(&vars, "insert_id");
+static sys_var_readonly sys_error_count(&vars, "error_count",
OPT_SESSION,
SHOW_LONG,
get_error_count);
-static sys_var_readonly sys_warning_count("warning_count",
+static sys_var_readonly sys_warning_count(&vars, "warning_count",
OPT_SESSION,
SHOW_LONG,
get_warning_count);
/* alias for last_insert_id() to be compatible with Sybase */
-#ifdef HAVE_REPLICATION
-static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter");
-#endif
-static sys_var_rand_seed1 sys_rand_seed1("rand_seed1");
-static sys_var_rand_seed2 sys_rand_seed2("rand_seed2");
+static sys_var_rand_seed1 sys_rand_seed1(&vars, "rand_seed1");
+static sys_var_rand_seed2 sys_rand_seed2(&vars, "rand_seed2");
-static sys_var_thd_ulong sys_default_week_format("default_week_format",
+static sys_var_thd_ulong sys_default_week_format(&vars, "default_week_format",
&SV::default_week_format);
-sys_var_thd_ulong sys_group_concat_max_len("group_concat_max_len",
+sys_var_thd_ulong sys_group_concat_max_len(&vars, "group_concat_max_len",
&SV::group_concat_max_len);
-sys_var_thd_time_zone sys_time_zone("time_zone");
+sys_var_thd_time_zone sys_time_zone(&vars, "time_zone");
+
+/* Global read-only variable containing hostname */
+static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname);
/* Read only variables */
-sys_var_have_variable sys_have_compress("have_compress", &have_compress);
-sys_var_have_variable sys_have_crypt("have_crypt", &have_crypt);
-sys_var_have_variable sys_have_csv_db("have_csv", &have_csv_db);
-sys_var_have_variable sys_have_dlopen("have_dynamic_loading", &have_dlopen);
-sys_var_have_variable sys_have_geometry("have_geometry", &have_geometry);
-sys_var_have_variable sys_have_innodb("have_innodb", &have_innodb);
-sys_var_have_variable sys_have_ndbcluster("have_ndbcluster", &have_ndbcluster);
-sys_var_have_variable sys_have_openssl("have_openssl", &have_openssl);
-sys_var_have_variable sys_have_partition_db("have_partitioning",
- &have_partition_db);
-sys_var_have_variable sys_have_query_cache("have_query_cache",
+static sys_var_have_variable sys_have_compress(&vars, "have_compress", &have_compress);
+static sys_var_have_variable sys_have_crypt(&vars, "have_crypt", &have_crypt);
+static sys_var_have_plugin sys_have_csv(&vars, "have_csv", C_STRING_WITH_LEN("csv"), MYSQL_STORAGE_ENGINE_PLUGIN);
+static sys_var_have_variable sys_have_dlopen(&vars, "have_dynamic_loading", &have_dlopen);
+static sys_var_have_variable sys_have_geometry(&vars, "have_geometry", &have_geometry);
+static sys_var_have_plugin sys_have_innodb(&vars, "have_innodb", C_STRING_WITH_LEN("innodb"), MYSQL_STORAGE_ENGINE_PLUGIN);
+static sys_var_have_plugin sys_have_ndbcluster(&vars, "have_ndbcluster", C_STRING_WITH_LEN("ndbcluster"), MYSQL_STORAGE_ENGINE_PLUGIN);
+static sys_var_have_variable sys_have_openssl(&vars, "have_openssl", &have_ssl);
+static sys_var_have_variable sys_have_ssl(&vars, "have_ssl", &have_ssl);
+static sys_var_have_plugin sys_have_partition_db(&vars, "have_partitioning", C_STRING_WITH_LEN("partition"), MYSQL_STORAGE_ENGINE_PLUGIN);
+static sys_var_have_variable sys_have_query_cache(&vars, "have_query_cache",
&have_query_cache);
-sys_var_have_variable sys_have_rtree_keys("have_rtree_keys", &have_rtree_keys);
-sys_var_have_variable sys_have_symlink("have_symlink", &have_symlink);
+static sys_var_have_variable sys_have_rtree_keys(&vars, "have_rtree_keys", &have_rtree_keys);
+static sys_var_have_variable sys_have_symlink(&vars, "have_symlink", &have_symlink);
/* Global read-only variable describing server license */
-sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE));
-
+static sys_var_const_str sys_license(&vars, "license", STRINGIFY_ARG(LICENSE));
/* Global variables which enable|disable logging */
-sys_var_log_state sys_var_general_log("general_log", &opt_log,
+static sys_var_log_state sys_var_general_log(&vars, "general_log", &opt_log,
QUERY_LOG_GENERAL);
-sys_var_log_state sys_var_slow_query_log("slow_query_log", &opt_slow_log,
+static sys_var_log_state sys_var_slow_query_log(&vars, "slow_query_log", &opt_slow_log,
QUERY_LOG_SLOW);
-sys_var_str sys_var_general_log_path("general_log_file", sys_check_log_path,
+sys_var_str sys_var_general_log_path(&vars, "general_log_file", sys_check_log_path,
sys_update_general_log_path,
sys_default_general_log_path,
opt_logname);
-sys_var_str sys_var_slow_log_path("slow_query_log_file", sys_check_log_path,
+sys_var_str sys_var_slow_log_path(&vars, "slow_query_log_file", sys_check_log_path,
sys_update_slow_log_path,
sys_default_slow_log_path,
opt_slow_logname);
-sys_var_log_output sys_var_log_output_state("log_output", &log_output_options,
+static sys_var_log_output sys_var_log_output_state(&vars, "log_output", &log_output_options,
&log_output_typelib, 0);
-#ifdef HAVE_REPLICATION
-static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff)
-{
- var->type=SHOW_CHAR;
- var->value= buff;
- if (!use_slave_mask || bitmap_is_clear_all(&slave_error_mask))
- {
- var->value= const_cast<char *>("OFF");
- }
- else if (bitmap_is_set_all(&slave_error_mask))
- {
- var->value= const_cast<char *>("ALL");
- }
- else
- {
- /* 10 is enough assuming errors are max 4 digits */
- int i;
- var->value= buff;
- for (i= 1;
- i < MAX_SLAVE_ERROR &&
- (buff - var->value) < SHOW_VAR_FUNC_BUFF_SIZE;
- i++)
- {
- if (bitmap_is_set(&slave_error_mask, i))
- {
- buff= int10_to_str(i, buff, 10);
- *buff++= ',';
- }
- }
- if (var->value != buff)
- buff--; // Remove last ','
- if (i < MAX_SLAVE_ERROR)
- buff= strmov(buff, "..."); // Couldn't show all errors
- *buff=0;
- }
- return 0;
-}
-#endif /* HAVE_REPLICATION */
/*
- Variables shown by SHOW VARIABLES in alphabetical order
+ Additional variables (not derived from sys_var class, not accessible as
+ @@varname in SELECT or SET). Sorted in alphabetical order to facilitate
+ maintenance - SHOW VARIABLES will sort its output.
+ TODO: remove this list completely
*/
-SHOW_VAR init_vars[]= {
- {"auto_increment_increment", (char*) &sys_auto_increment_increment, SHOW_SYS},
- {"auto_increment_offset", (char*) &sys_auto_increment_offset, SHOW_SYS},
- {sys_automatic_sp_privileges.name,(char*) &sys_automatic_sp_privileges, SHOW_SYS},
+#define FIXED_VARS_SIZE (sizeof(fixed_vars) / sizeof(SHOW_VAR))
+static SHOW_VAR fixed_vars[]= {
{"back_log", (char*) &back_log, SHOW_LONG},
- {sys_basedir.name, (char*) &sys_basedir, SHOW_SYS},
- {sys_binlog_cache_size.name,(char*) &sys_binlog_cache_size, SHOW_SYS},
- {sys_binlog_format.name, (char*) &sys_binlog_format, SHOW_SYS},
- {sys_bulk_insert_buff_size.name,(char*) &sys_bulk_insert_buff_size,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_database.name, (char*) &sys_character_set_database,SHOW_SYS},
- {sys_character_set_filesystem.name,(char*) &sys_character_set_filesystem, SHOW_SYS},
- {sys_character_set_results.name,(char*) &sys_character_set_results, SHOW_SYS},
- {sys_character_set_server.name, (char*) &sys_character_set_server,SHOW_SYS},
- {sys_charset_system.name, (char*) &sys_charset_system, SHOW_SYS},
{"character_sets_dir", mysql_charsets_dir, SHOW_CHAR},
- {sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
- {sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS},
- {sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS},
- {sys_completion_type.name, (char*) &sys_completion_type, SHOW_SYS},
- {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
- {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
- {sys_datadir.name, (char*) &sys_datadir, SHOW_SYS},
- {sys_date_format.name, (char*) &sys_date_format, SHOW_SYS},
- {sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS},
-#ifndef DBUG_OFF
- {sys_dbug.name, (char*) &sys_dbug, SHOW_SYS},
-#endif
- {sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS},
- {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS},
- {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS},
- {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS},
- {sys_delayed_queue_size.name,(char*) &sys_delayed_queue_size, SHOW_SYS},
- {sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
- {sys_engine_condition_pushdown.name,
- (char*) &sys_engine_condition_pushdown, SHOW_SYS},
- {sys_event_scheduler.name, (char*) &sys_event_scheduler, SHOW_SYS},
- {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
- {sys_flush.name, (char*) &sys_flush, SHOW_SYS},
- {sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS},
- {sys_ft_boolean_syntax.name,(char*) &ft_boolean_syntax, SHOW_CHAR},
{"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG},
{"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG},
{"ft_query_expansion_limit",(char*) &ft_query_expansion_limit, SHOW_LONG},
{"ft_stopword_file", (char*) &ft_stopword_file, SHOW_CHAR_PTR},
- {sys_var_general_log.name, (char*) &opt_log, SHOW_MY_BOOL},
- {sys_var_general_log_path.name, (char*) &sys_var_general_log_path, SHOW_SYS},
- {sys_group_concat_max_len.name, (char*) &sys_group_concat_max_len, SHOW_SYS},
- {sys_have_compress.name, (char*) &have_compress, SHOW_HAVE},
- {sys_have_crypt.name, (char*) &have_crypt, SHOW_HAVE},
- {sys_have_csv_db.name, (char*) &have_csv_db, SHOW_HAVE},
- {sys_have_dlopen.name, (char*) &have_dlopen, SHOW_HAVE},
- {sys_have_geometry.name, (char*) &have_geometry, SHOW_HAVE},
- {sys_have_innodb.name, (char*) &have_innodb, SHOW_HAVE},
- {sys_have_ndbcluster.name, (char*) &have_ndbcluster, SHOW_HAVE},
- {sys_have_openssl.name, (char*) &have_openssl, SHOW_HAVE},
- {sys_have_partition_db.name,(char*) &have_partition_db, SHOW_HAVE},
- {sys_have_query_cache.name, (char*) &have_query_cache, SHOW_HAVE},
- {sys_have_rtree_keys.name, (char*) &have_rtree_keys, SHOW_HAVE},
- {sys_have_symlink.name, (char*) &have_symlink, SHOW_HAVE},
- {"init_connect", (char*) &sys_init_connect, SHOW_SYS},
{"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
- {"init_slave", (char*) &sys_init_slave, SHOW_SYS},
-#ifdef WITH_INNOBASE_STORAGE_ENGINE
- {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
- {sys_innodb_autoextend_increment.name, (char*) &sys_innodb_autoextend_increment, SHOW_SYS},
- {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONGLONG },
- {"innodb_checksums", (char*) &innobase_use_checksums, SHOW_MY_BOOL},
- {sys_innodb_commit_concurrency.name, (char*) &sys_innodb_commit_concurrency, SHOW_SYS},
- {sys_innodb_concurrency_tickets.name, (char*) &sys_innodb_concurrency_tickets, SHOW_SYS},
- {"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
- {"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
- {"innodb_doublewrite", (char*) &innobase_use_doublewrite, SHOW_MY_BOOL},
- {sys_innodb_fast_shutdown.name,(char*) &sys_innodb_fast_shutdown, SHOW_SYS},
- {"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
- {"innodb_file_per_table", (char*) &innobase_file_per_table, SHOW_MY_BOOL},
- {"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR},
- {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
- {"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG },
- {"innodb_locks_unsafe_for_binlog", (char*) &innobase_locks_unsafe_for_binlog, SHOW_MY_BOOL},
- {"innodb_log_arch_dir", (char*) &innobase_log_arch_dir, SHOW_CHAR_PTR},
- {"innodb_log_archive", (char*) &innobase_log_archive, SHOW_MY_BOOL},
- {"innodb_log_buffer_size", (char*) &innobase_log_buffer_size, SHOW_LONG },
- {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONGLONG},
- {"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},
- {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS},
- {sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS},
- {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG},
- {"innodb_open_files", (char*) &innobase_open_files, SHOW_LONG },
- {sys_innodb_support_xa.name, (char*) &sys_innodb_support_xa, SHOW_SYS},
- {sys_innodb_sync_spin_loops.name, (char*) &sys_innodb_sync_spin_loops, SHOW_SYS},
- {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
- {sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS},
- {sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS},
- {sys_innodb_flush_log_at_trx_commit.name, (char*) &sys_innodb_flush_log_at_trx_commit, 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},
- {sys_key_buffer_size.name, (char*) &sys_key_buffer_size, SHOW_SYS},
- {sys_key_cache_age_threshold.name, (char*) &sys_key_cache_age_threshold,
- SHOW_SYS},
- {sys_key_cache_block_size.name, (char*) &sys_key_cache_block_size,
- SHOW_SYS},
- {sys_key_cache_division_limit.name, (char*) &sys_key_cache_division_limit,
- SHOW_SYS},
{"language", language, SHOW_CHAR},
{"large_files_support", (char*) &opt_large_files, SHOW_BOOL},
{"large_page_size", (char*) &opt_large_page_size, SHOW_INT},
{"large_pages", (char*) &opt_large_pages, SHOW_MY_BOOL},
- {sys_lc_time_names.name, (char*) &sys_lc_time_names, SHOW_SYS},
- {sys_license.name, (char*) &sys_license, SHOW_SYS},
- {sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS},
#ifdef HAVE_MLOCKALL
- {"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL},
+ {"locked_in_memory", (char*) &locked_in_memory, SHOW_MY_BOOL},
#endif
- {"log", (char*) &opt_log, SHOW_BOOL},
+ {"log", (char*) &opt_log, SHOW_MY_BOOL},
{"log_bin", (char*) &opt_bin_log, SHOW_BOOL},
- {sys_trust_function_creators.name,(char*) &sys_trust_function_creators, SHOW_SYS},
{"log_error", (char*) log_error_file, SHOW_CHAR},
- {sys_var_log_output_state.name, (char*) &sys_var_log_output_state, SHOW_SYS},
- {sys_log_queries_not_using_indexes.name,
- (char*) &sys_log_queries_not_using_indexes, SHOW_SYS},
-#ifdef HAVE_REPLICATION
- {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL},
-#endif
- {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL},
- {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS},
- {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS},
- {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS},
+ {"log_slow_queries", (char*) &opt_slow_log, SHOW_MY_BOOL},
{"lower_case_file_system", (char*) &lower_case_file_system, SHOW_MY_BOOL},
{"lower_case_table_names", (char*) &lower_case_table_names, SHOW_INT},
- {sys_max_allowed_packet.name,(char*) &sys_max_allowed_packet, SHOW_SYS},
- {sys_max_binlog_cache_size.name,(char*) &sys_max_binlog_cache_size, SHOW_SYS},
- {sys_max_binlog_size.name, (char*) &sys_max_binlog_size, SHOW_SYS},
- {sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS},
- {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS},
- {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS},
- {sys_max_error_count.name, (char*) &sys_max_error_count, SHOW_SYS},
- {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS},
- {sys_max_insert_delayed_threads.name,
- (char*) &sys_max_insert_delayed_threads, SHOW_SYS},
- {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
- {sys_max_length_for_sort_data.name, (char*) &sys_max_length_for_sort_data,
- SHOW_SYS},
- {sys_max_prepared_stmt_count.name, (char*) &sys_max_prepared_stmt_count,
- SHOW_SYS},
- {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS},
- {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS},
- {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
- {sys_max_sp_recursion_depth.name,
- (char*) &sys_max_sp_recursion_depth, SHOW_SYS},
- {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS},
- {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
- {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS},
- {sys_multi_range_count.name, (char*) &sys_multi_range_count, SHOW_SYS},
- {sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS},
- {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size,
- SHOW_SYS},
{"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR},
- {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads,
- SHOW_SYS},
- {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS},
-
- {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS},
- {sys_myisam_use_mmap.name, (char*) &sys_myisam_use_mmap, SHOW_SYS},
-
#ifdef __NT__
{"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL},
#endif
- {sys_ndb_autoincrement_prefetch_sz.name,
- (char*) &sys_ndb_autoincrement_prefetch_sz, SHOW_SYS},
- {sys_ndb_cache_check_time.name,(char*) &sys_ndb_cache_check_time, SHOW_SYS},
- {sys_ndb_extra_logging.name,(char*) &sys_ndb_extra_logging, SHOW_SYS},
- {sys_ndb_force_send.name, (char*) &sys_ndb_force_send, SHOW_SYS},
- {sys_ndb_index_stat_cache_entries.name, (char*) &sys_ndb_index_stat_cache_entries, SHOW_SYS},
- {sys_ndb_index_stat_enable.name, (char*) &sys_ndb_index_stat_enable, SHOW_SYS},
- {sys_ndb_index_stat_update_freq.name, (char*) &sys_ndb_index_stat_update_freq, SHOW_SYS},
-#ifdef HAVE_NDB_BINLOG
- {sys_ndb_report_thresh_binlog_epoch_slip.name,
- (char*) &sys_ndb_report_thresh_binlog_epoch_slip, SHOW_SYS},
- {sys_ndb_report_thresh_binlog_mem_usage.name,
- (char*) &sys_ndb_report_thresh_binlog_mem_usage, SHOW_SYS},
-#endif
- {sys_ndb_use_copying_alter_table.name,
- (char*) &sys_ndb_use_copying_alter_table, SHOW_SYS},
- {sys_ndb_use_exact_count.name,(char*) &sys_ndb_use_exact_count, SHOW_SYS},
- {sys_ndb_use_transactions.name,(char*) &sys_ndb_use_transactions, SHOW_SYS},
- {sys_net_buffer_length.name,(char*) &sys_net_buffer_length, SHOW_SYS},
- {sys_net_read_timeout.name, (char*) &sys_net_read_timeout, SHOW_SYS},
- {sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS},
- {sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS},
- {sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS},
- {sys_old_alter_table.name, (char*) &sys_old_alter_table, SHOW_SYS},
- {sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS},
{"open_files_limit", (char*) &open_files_limit, SHOW_LONG},
- {sys_optimizer_prune_level.name, (char*) &sys_optimizer_prune_level,
- SHOW_SYS},
- {sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth,
- SHOW_SYS},
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
{"plugin_dir", (char*) opt_plugin_dir, SHOW_CHAR},
- {"port", (char*) &mysqld_port, SHOW_INT},
- {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
+ {"port", (char*) &mysqld_port, SHOW_INT},
{"protocol_version", (char*) &protocol_version, SHOW_INT},
- {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size,
- SHOW_SYS},
-#ifdef HAVE_QUERY_CACHE
- {sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS},
- {sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit,
- SHOW_SYS},
- {sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS},
- {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS},
- {sys_query_cache_wlock_invalidate.name,
- (char *) &sys_query_cache_wlock_invalidate, SHOW_SYS},
-#endif /* HAVE_QUERY_CACHE */
- {sys_query_prealloc_size.name, (char*) &sys_query_prealloc_size, SHOW_SYS},
- {sys_range_alloc_block_size.name, (char*) &sys_range_alloc_block_size,
- SHOW_SYS},
- {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
- {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
- {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
-#ifdef HAVE_REPLICATION
- {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
- {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG},
-#endif
- {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
- {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS},
#ifdef HAVE_SMEM
{"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL},
{"shared_memory_base_name", (char*) &shared_memory_base_name, SHOW_CHAR_PTR},
#endif
- {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS},
{"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},
-#ifdef HAVE_REPLICATION
- {sys_slave_compressed_protocol.name,
- (char*) &sys_slave_compressed_protocol, SHOW_SYS},
- {"slave_load_tmpdir", (char*) &slave_load_tmpdir, SHOW_CHAR_PTR},
- {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
- {"slave_skip_errors", (char*) &show_slave_skip_errors, SHOW_FUNC},
- {sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS},
-#endif
- {sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
- {sys_var_slow_query_log.name, (char*) &opt_slow_log, SHOW_MY_BOOL},
- {sys_var_slow_log_path.name, (char*) &sys_var_slow_log_path, SHOW_SYS},
#ifdef HAVE_SYS_UN_H
- {"socket", (char*) &mysqld_unix_port, SHOW_CHAR_PTR},
-#endif
- {sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS},
- {sys_big_selects.name, (char*) &sys_big_selects, SHOW_SYS},
- {sys_sql_mode.name, (char*) &sys_sql_mode, SHOW_SYS},
- {"sql_notes", (char*) &sys_sql_notes, SHOW_SYS},
- {"sql_warnings", (char*) &sys_sql_warnings, SHOW_SYS},
- {sys_ssl_ca.name, (char*) &sys_ssl_ca, SHOW_SYS},
- {sys_ssl_capath.name, (char*) &sys_ssl_capath, SHOW_SYS},
- {sys_ssl_cert.name, (char*) &sys_ssl_cert, SHOW_SYS},
- {sys_ssl_cipher.name, (char*) &sys_ssl_cipher, SHOW_SYS},
- {sys_ssl_key.name, (char*) &sys_ssl_key, SHOW_SYS},
- {sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS},
-#ifdef HAVE_REPLICATION
- {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS},
-#endif
- {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS},
-#ifdef HAVE_TZNAME
- {"system_time_zone", system_time_zone, SHOW_CHAR},
+ {"socket", (char*) &mysqld_unix_port, SHOW_CHAR_PTR},
#endif
{"table_definition_cache", (char*) &table_def_size, SHOW_LONG},
{"table_lock_wait_timeout", (char*) &table_lock_wait_timeout, SHOW_LONG },
- {"table_open_cache", (char*) &table_cache_size, SHOW_LONG},
- {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS},
- {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS},
#ifdef HAVE_THR_SETCONCURRENCY
{"thread_concurrency", (char*) &concurrency, SHOW_LONG},
#endif
{"thread_stack", (char*) &thread_stack, SHOW_LONG},
- {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS},
- {"time_zone", (char*) &sys_time_zone, SHOW_SYS},
- {sys_timed_mutexes.name, (char*) &sys_timed_mutexes, SHOW_SYS},
- {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS},
- {sys_tmpdir.name, (char*) &sys_tmpdir, SHOW_SYS},
- {sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size,
- SHOW_SYS},
- {sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS},
- {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS},
- {sys_updatable_views_with_limit.name,
- (char*) &sys_updatable_views_with_limit,SHOW_SYS},
- {sys_version.name, (char*) &sys_version, SHOW_SYS},
- {sys_version_comment.name, (char*) &sys_version_comment, SHOW_SYS},
- {sys_version_compile_machine.name, (char*) &sys_version_compile_machine,
- SHOW_SYS},
- {sys_version_compile_os.name, (char*) &sys_version_compile_os, SHOW_SYS},
- {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS},
- {NullS, NullS, SHOW_LONG}
};
@@ -1111,7 +788,7 @@ static void sys_default_init_slave(THD* thd, enum_var_type type)
static int sys_check_ftb_syntax(THD *thd, set_var *var)
{
if (thd->security_ctx->master_access & SUPER_ACL)
- return (ft_boolean_check_syntax_string((byte*)
+ return (ft_boolean_check_syntax_string((uchar*)
var->value->str_value.c_ptr()) ?
-1 : 0);
else
@@ -1125,6 +802,11 @@ static bool sys_update_ftb_syntax(THD *thd, set_var * var)
{
strmake(ft_boolean_syntax, var->value->str_value.c_ptr(),
sizeof(ft_boolean_syntax)-1);
+
+#ifdef HAVE_QUERY_CACHE
+ query_cache.flush();
+#endif /* HAVE_QUERY_CACHE */
+
return 0;
}
@@ -1142,7 +824,11 @@ static void sys_default_ftb_syntax(THD *thd, enum_var_type type)
static void fix_low_priority_updates(THD *thd, enum_var_type type)
{
- if (type != OPT_GLOBAL)
+ if (type == OPT_GLOBAL)
+ thr_upgraded_concurrent_insert_lock=
+ (global_system_variables.low_priority_updates ?
+ TL_WRITE_LOW_PRIORITY : TL_WRITE);
+ else
thd->update_lock_default= (thd->variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY : TL_WRITE);
}
@@ -1220,14 +906,14 @@ static int check_completion_type(THD *thd, set_var *var)
static void fix_net_read_timeout(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
- thd->net.read_timeout=thd->variables.net_read_timeout;
+ net_set_read_timeout(&thd->net, thd->variables.net_read_timeout);
}
static void fix_net_write_timeout(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
- thd->net.write_timeout=thd->variables.net_write_timeout;
+ net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
}
static void fix_net_retry_count(THD *thd, enum_var_type type)
@@ -1251,12 +937,19 @@ static void fix_net_retry_count(THD *thd __attribute__((unused)),
static void fix_query_cache_size(THD *thd, enum_var_type type)
{
#ifdef HAVE_QUERY_CACHE
- ulong requested= query_cache_size;
- query_cache.resize(query_cache_size);
- if (requested != query_cache_size)
+ ulong new_cache_size= query_cache.resize(query_cache_size);
+
+ /*
+ Note: query_cache_size is a global variable reflecting the
+ requested cache size. See also query_cache_size_arg
+ */
+
+ if (query_cache_size != new_cache_size)
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_QC_RESIZE, ER(ER_WARN_QC_RESIZE),
- requested, query_cache_size);
+ query_cache_size, new_cache_size);
+
+ query_cache_size= new_cache_size;
#endif
}
@@ -1322,7 +1015,8 @@ bool sys_var_thd_binlog_format::is_readonly() const
/*
Cluster does not support changing the binlog format on the fly yet.
*/
- if (opt_bin_log && (have_ndbcluster == SHOW_OPTION_YES))
+ LEX_STRING ndb_name= {(char*)STRING_WITH_LEN("ndbcluster")};
+ if (opt_bin_log && plugin_is_ready(&ndb_name, MYSQL_STORAGE_ENGINE_PLUGIN))
{
my_error(ER_NDB_CANT_SWITCH_BINLOG_FORMAT, MYF(0));
return 1;
@@ -1413,9 +1107,9 @@ static void fix_server_id(THD *thd, enum_var_type type)
sys_var_long_ptr::
-sys_var_long_ptr(const char *name_arg, ulong *value_ptr,
+sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_arg,
sys_after_update_func after_update_arg)
- :sys_var_long_ptr_global(name_arg, value_ptr,
+ :sys_var_long_ptr_global(chain, name_arg, value_ptr_arg,
&LOCK_global_system_variables, after_update_arg)
{}
@@ -1489,9 +1183,9 @@ bool sys_var_enum::update(THD *thd, set_var *var)
}
-byte *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+uchar *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
- return (byte*) enum_names->type_names[*value];
+ return (uchar*) enum_names->type_names[*value];
}
bool sys_var_thd_ulong::check(THD *thd, set_var *var)
@@ -1536,12 +1230,12 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type == OPT_GLOBAL)
- return (byte*) &(global_system_variables.*offset);
- return (byte*) &(thd->variables.*offset);
+ return (uchar*) &(global_system_variables.*offset);
+ return (uchar*) &(thd->variables.*offset);
}
@@ -1582,12 +1276,12 @@ void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type == OPT_GLOBAL)
- return (byte*) &(global_system_variables.*offset);
- return (byte*) &(thd->variables.*offset);
+ return (uchar*) &(global_system_variables.*offset);
+ return (uchar*) &(thd->variables.*offset);
}
bool sys_var_thd_ulonglong::update(THD *thd, set_var *var)
@@ -1625,12 +1319,12 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_ulonglong::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_ulonglong::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type == OPT_GLOBAL)
- return (byte*) &(global_system_variables.*offset);
- return (byte*) &(thd->variables.*offset);
+ return (uchar*) &(global_system_variables.*offset);
+ return (uchar*) &(thd->variables.*offset);
}
@@ -1653,16 +1347,16 @@ void sys_var_thd_bool::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type == OPT_GLOBAL)
- return (byte*) &(global_system_variables.*offset);
- return (byte*) &(thd->variables.*offset);
+ return (uchar*) &(global_system_variables.*offset);
+ return (uchar*) &(thd->variables.*offset);
}
-bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names)
+bool sys_var::check_enum(THD *thd, set_var *var, const TYPELIB *enum_names)
{
char buff[STRING_BUFFER_USUAL_SIZE];
const char *value;
@@ -1765,7 +1459,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
/* As there was no local variable, return the global value */
var_type= OPT_GLOBAL;
}
- switch (type()) {
+ switch (show_type()) {
case SHOW_INT:
{
uint value;
@@ -1799,7 +1493,13 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
return new Item_int((longlong) value);
}
case SHOW_MY_BOOL:
- return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1);
+ {
+ int32 value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(my_bool*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_int(value,1);
+ }
case SHOW_CHAR:
{
Item *tmp;
@@ -1842,13 +1542,13 @@ void sys_var_thd_enum::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
ulong tmp= ((type == OPT_GLOBAL) ?
global_system_variables.*offset :
thd->variables.*offset);
- return (byte*) enum_names->type_names[tmp];
+ return (uchar*) enum_names->type_names[tmp];
}
bool sys_var_thd_bit::check(THD *thd, set_var *var)
@@ -1864,7 +1564,7 @@ bool sys_var_thd_bit::update(THD *thd, set_var *var)
}
-byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
/*
@@ -1873,7 +1573,7 @@ byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type,
*/
thd->sys_var_tmp.my_bool_value= ((thd->options & bit_flag) ?
!reverse : reverse);
- return (byte*) &thd->sys_var_tmp.my_bool_value;
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
}
@@ -1884,7 +1584,7 @@ void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type,
{
DATE_TIME_FORMAT *old;
DBUG_ENTER("sys_var_date_time_format::update2");
- DBUG_DUMP("positions",(char*) new_value->positions,
+ DBUG_DUMP("positions", (uchar*) new_value->positions,
sizeof(new_value->positions));
if (type == OPT_GLOBAL)
@@ -1964,7 +1664,7 @@ void sys_var_thd_date_time_format::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type == OPT_GLOBAL)
@@ -1977,9 +1677,9 @@ byte *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type,
*/
res= thd->strmake((global_system_variables.*offset)->format.str,
(global_system_variables.*offset)->format.length);
- return (byte*) res;
+ return (uchar*) res;
}
- return (byte*) (thd->variables.*offset)->format.str;
+ return (uchar*) (thd->variables.*offset)->format.str;
}
@@ -2100,130 +1800,33 @@ bool sys_var_character_set::update(THD *thd, set_var *var)
}
-byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_character_set::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
CHARSET_INFO *cs= ci_ptr(thd,type)[0];
- return cs ? (byte*) cs->csname : (byte*) NULL;
-}
-
-
-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_connection= default_charset_info;
- else
- {
- thd->variables.collation_connection= global_system_variables.collation_connection;
- thd->update_charset();
- }
-}
-
-
-CHARSET_INFO ** sys_var_character_set_client::ci_ptr(THD *thd,
- enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- return &global_system_variables.character_set_client;
- else
- return &thd->variables.character_set_client;
-}
-
-
-void sys_var_character_set_client::set_default(THD *thd, enum_var_type type)
-{
- 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);
- thd->update_charset();
- }
-}
-
-
-CHARSET_INFO **
-sys_var_character_set_filesystem::ci_ptr(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- return &global_system_variables.character_set_filesystem;
- else
- return &thd->variables.character_set_filesystem;
-}
-
-
-extern CHARSET_INFO *character_set_filesystem;
-
-void
-sys_var_character_set_filesystem::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.character_set_filesystem= character_set_filesystem;
- else
- {
- thd->variables.character_set_filesystem= (global_system_variables.
- character_set_filesystem);
- thd->update_charset();
- }
+ return cs ? (uchar*) cs->csname : (uchar*) NULL;
}
-CHARSET_INFO **
-sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type)
+void sys_var_character_set_sv::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- return &global_system_variables.character_set_results;
+ global_system_variables.*offset= *global_default;
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.character_set_results= default_charset_info;
- else
- {
- thd->variables.character_set_results= (global_system_variables.
- character_set_results);
- thd->update_charset();
- }
+ {
+ thd->variables.*offset= global_system_variables.*offset;
+ thd->update_charset();
+ }
}
-
-
-CHARSET_INFO **
-sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type)
+CHARSET_INFO **sys_var_character_set_sv::ci_ptr(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- return &global_system_variables.collation_server;
+ return &(global_system_variables.*offset);
else
- return &thd->variables.collation_server;
+ return &(thd->variables.*offset);
}
-void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.collation_server= default_charset_info;
- else
- {
- thd->variables.collation_server= global_system_variables.collation_server;
- thd->update_charset();
- }
-}
-
CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
enum_var_type type)
{
@@ -2246,110 +1849,37 @@ void sys_var_character_set_database::set_default(THD *thd, enum_var_type type)
}
-bool sys_var_collation_connection::update(THD *thd, set_var *var)
+bool sys_var_collation_sv::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
- global_system_variables.collation_connection= var->save_result.charset;
+ global_system_variables.*offset= var->save_result.charset;
else
{
- thd->variables.collation_connection= var->save_result.charset;
+ thd->variables.*offset= var->save_result.charset;
thd->update_charset();
}
return 0;
}
-byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
- global_system_variables.collation_connection :
- thd->variables.collation_connection);
- return cs ? (byte*) cs->name : (byte*) "NULL";
-}
-
-
-void sys_var_collation_connection::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.collation_connection= default_charset_info;
- else
- {
- thd->variables.collation_connection= (global_system_variables.
- collation_connection);
- thd->update_charset();
- }
-}
-
-bool sys_var_collation_database::update(THD *thd, set_var *var)
+void sys_var_collation_sv::set_default(THD *thd, enum_var_type type)
{
- if (var->type == OPT_GLOBAL)
- global_system_variables.collation_database= var->save_result.charset;
+ if (type == OPT_GLOBAL)
+ global_system_variables.*offset= *global_default;
else
{
- thd->variables.collation_database= var->save_result.charset;
+ thd->variables.*offset= global_system_variables.*offset;
thd->update_charset();
}
- return 0;
}
-byte *sys_var_collation_database::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
- global_system_variables.collation_database :
- thd->variables.collation_database);
- return cs ? (byte*) cs->name : (byte*) "NULL";
-}
-
-
-void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.collation_database= default_charset_info;
- else
- {
- thd->variables.collation_database= (global_system_variables.
- collation_database);
- thd->update_charset();
- }
-}
-
-
-bool sys_var_collation_server::update(THD *thd, set_var *var)
-{
- if (var->type == OPT_GLOBAL)
- global_system_variables.collation_server= var->save_result.charset;
- else
- {
- thd->variables.collation_server= var->save_result.charset;
- thd->update_charset();
- }
- return 0;
-}
-
-
-byte *sys_var_collation_server::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+uchar *sys_var_collation_sv::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
{
CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
- global_system_variables.collation_server :
- thd->variables.collation_server);
- return cs ? (byte*) cs->name : (byte*) "NULL";
-}
-
-
-void sys_var_collation_server::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.collation_server= default_charset_info;
- else
- {
- thd->variables.collation_server= (global_system_variables.
- collation_server);
- thd->update_charset();
- }
+ global_system_variables.*offset : thd->variables.*offset);
+ return cs ? (uchar*) cs->name : (uchar*) "NULL";
}
@@ -2367,13 +1897,13 @@ KEY_CACHE *get_key_cache(LEX_STRING *cache_name)
}
-byte *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
KEY_CACHE *key_cache= get_key_cache(base);
if (!key_cache)
key_cache= &zero_key_cache;
- return (byte*) key_cache + offset ;
+ return (uchar*) key_cache + offset ;
}
@@ -2559,11 +2089,12 @@ static int sys_check_log_path(THD *thd, set_var *var)
}
else
{
+ size_t path_length;
/*
Check if directory exists and
we have permission to create file & write to file
*/
- (void) dirname_part(path, var_path);
+ (void) dirname_part(path, var_path, &path_length);
if (my_access(path, (F_OK|W_OK)))
return -1;
}
@@ -2589,7 +2120,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
file_log= logger.get_log_file_handler();
break;
default:
- DBUG_ASSERT(0);
+ assert(0); // Impossible
}
if (!old_value)
@@ -2616,7 +2147,7 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
{
switch (log_type) {
case QUERY_LOG_SLOW:
- file_log->open_slow_log(sys_var_general_log_path.value);
+ file_log->open_slow_log(sys_var_slow_log_path.value);
break;
case QUERY_LOG_GENERAL:
file_log->open_query_log(sys_var_general_log_path.value);
@@ -2689,7 +2220,7 @@ void sys_var_log_output::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_log_output::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_log_output::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
char buff[256];
@@ -2710,7 +2241,7 @@ byte *sys_var_log_output::value_ptr(THD *thd, enum_var_type type,
if ((length= tmp.length()))
length--;
- return (byte*) thd->strmake(tmp.ptr(), length);
+ return (uchar*) thd->strmake(tmp.ptr(), length);
}
@@ -2729,8 +2260,8 @@ int set_var_collation_client::update(THD *thd)
thd->variables.character_set_results= character_set_results;
thd->variables.collation_connection= collation_connection;
thd->update_charset();
- thd->protocol_simple.init(thd);
- thd->protocol_prep.init(thd);
+ thd->protocol_text.init(thd);
+ thd->protocol_binary.init(thd);
return 0;
}
@@ -2749,11 +2280,11 @@ void sys_var_timestamp::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
thd->sys_var_tmp.long_value= (long) thd->start_time;
- return (byte*) &thd->sys_var_tmp.long_value;
+ return (uchar*) &thd->sys_var_tmp.long_value;
}
@@ -2765,7 +2296,7 @@ bool sys_var_last_insert_id::update(THD *thd, set_var *var)
}
-byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
/*
@@ -2774,7 +2305,7 @@ byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type,
*/
thd->sys_var_tmp.ulonglong_value=
thd->read_first_successful_insert_id_in_prev_stmt();
- return (byte*) &thd->sys_var_tmp.ulonglong_value;
+ return (uchar*) &thd->sys_var_tmp.ulonglong_value;
}
@@ -2785,61 +2316,15 @@ bool sys_var_insert_id::update(THD *thd, set_var *var)
}
-byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
thd->sys_var_tmp.ulonglong_value=
thd->auto_inc_intervals_forced.minimum();
- return (byte*) &thd->sys_var_tmp.ulonglong_value;
-}
-
-
-#ifdef HAVE_REPLICATION
-bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
-{
- int result= 0;
- pthread_mutex_lock(&LOCK_active_mi);
- pthread_mutex_lock(&active_mi->rli.run_lock);
- if (active_mi->rli.slave_running)
- {
- my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
- result=1;
- }
- pthread_mutex_unlock(&active_mi->rli.run_lock);
- pthread_mutex_unlock(&LOCK_active_mi);
- var->save_result.ulong_value= (ulong) var->value->val_int();
- return result;
-}
-
-
-bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
-{
- pthread_mutex_lock(&LOCK_active_mi);
- pthread_mutex_lock(&active_mi->rli.run_lock);
- /*
- The following test should normally never be true as we test this
- in the check function; To be safe against multiple
- SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
- */
- if (!active_mi->rli.slave_running)
- {
- pthread_mutex_lock(&active_mi->rli.data_lock);
- active_mi->rli.slave_skip_counter= var->save_result.ulong_value;
- pthread_mutex_unlock(&active_mi->rli.data_lock);
- }
- pthread_mutex_unlock(&active_mi->rli.run_lock);
- pthread_mutex_unlock(&LOCK_active_mi);
- return 0;
+ return (uchar*) &thd->sys_var_tmp.ulonglong_value;
}
-bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
-{
- sync_binlog_period= (ulong) var->save_result.ulonglong_value;
- return 0;
-}
-#endif /* HAVE_REPLICATION */
-
bool sys_var_rand_seed1::update(THD *thd, set_var *var)
{
thd->rand.seed1= (ulong) var->save_result.ulonglong_value;
@@ -2859,8 +2344,7 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
String str(buff, sizeof(buff), &my_charset_latin1);
String *res= var->value->val_str(&str);
- if (!(var->save_result.time_zone=
- my_tz_find(res, thd->lex->time_zone_tables_used)))
+ if (!(var->save_result.time_zone= my_tz_find(thd, res)))
{
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
return 1;
@@ -2884,7 +2368,7 @@ bool sys_var_thd_time_zone::update(THD *thd, set_var *var)
}
-byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
/*
@@ -2892,7 +2376,7 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
time zone name is guaranteed to be zero ended.
*/
if (type == OPT_GLOBAL)
- return (byte *)(global_system_variables.time_zone->get_name()->ptr());
+ return (uchar *)(global_system_variables.time_zone->get_name()->ptr());
else
{
/*
@@ -2904,7 +2388,7 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
(binlog code stores session value only).
*/
thd->time_zone_used= 1;
- return (byte *)(thd->variables.time_zone->get_name()->ptr());
+ return (uchar *)(thd->variables.time_zone->get_name()->ptr());
}
}
@@ -2921,8 +2405,7 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
We are guaranteed to find this time zone since its existence
is checked during start-up.
*/
- global_system_variables.time_zone=
- my_tz_find(&str, thd->lex->time_zone_tables_used);
+ global_system_variables.time_zone= my_tz_find(thd, &str);
}
else
global_system_variables.time_zone= my_tz_SYSTEM;
@@ -2967,13 +2450,13 @@ void sys_var_max_user_conn::set_default(THD *thd, enum_var_type type)
}
-byte *sys_var_max_user_conn::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_max_user_conn::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
if (type != OPT_GLOBAL &&
thd->user_connect && thd->user_connect->user_resources.user_conn)
- return (byte*) &(thd->user_connect->user_resources.user_conn);
- return (byte*) &(max_user_connections);
+ return (uchar*) &(thd->user_connect->user_resources.user_conn);
+ return (uchar*) &(max_user_connections);
}
@@ -3016,21 +2499,29 @@ bool sys_var_thd_lc_time_names::check(THD *thd, set_var *var)
bool sys_var_thd_lc_time_names::update(THD *thd, set_var *var)
{
- thd->variables.lc_time_names= var->save_result.locale_value;
+ if (var->type == OPT_GLOBAL)
+ global_system_variables.lc_time_names= var->save_result.locale_value;
+ else
+ thd->variables.lc_time_names= var->save_result.locale_value;
return 0;
}
-byte *sys_var_thd_lc_time_names::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_lc_time_names::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
- return (byte *)(thd->variables.lc_time_names->name);
+ return type == OPT_GLOBAL ?
+ (uchar *) global_system_variables.lc_time_names->name :
+ (uchar *) thd->variables.lc_time_names->name;
}
void sys_var_thd_lc_time_names::set_default(THD *thd, enum_var_type type)
{
- thd->variables.lc_time_names = &my_locale_en_US;
+ if (type == OPT_GLOBAL)
+ global_system_variables.lc_time_names= my_default_lc_time_names;
+ else
+ thd->variables.lc_time_names= global_system_variables.lc_time_names;
}
/*
@@ -3064,16 +2555,15 @@ static bool set_option_autocommit(THD *thd, set_var *var)
if ((org_options & OPTION_NOT_AUTOCOMMIT))
{
/* We changed to auto_commit mode */
- thd->options&= ~(ulonglong) (OPTION_BEGIN |
- OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
if (ha_commit(thd))
return 1;
}
else
{
- thd->options&= ~(ulonglong) (OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
}
}
@@ -3131,20 +2621,20 @@ static int check_pseudo_thread_id(THD *thd, set_var *var)
#endif
}
-static byte *get_warning_count(THD *thd)
+static uchar *get_warning_count(THD *thd)
{
thd->sys_var_tmp.long_value=
(thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
- return (byte*) &thd->sys_var_tmp.long_value;
+ return (uchar*) &thd->sys_var_tmp.long_value;
}
-static byte *get_error_count(THD *thd)
+static uchar *get_error_count(THD *thd)
{
thd->sys_var_tmp.long_value=
thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
- return (byte*) &thd->sys_var_tmp.long_value;
+ return (uchar*) &thd->sys_var_tmp.long_value;
}
@@ -3165,11 +2655,11 @@ static byte *get_error_count(THD *thd)
RETURN VALUES
ptr pointer to NUL-terminated string
*/
-static byte *get_tmpdir(THD *thd)
+static uchar *get_tmpdir(THD *thd)
{
if (opt_mysql_tmpdir)
- return (byte *)opt_mysql_tmpdir;
- return (byte*)mysql_tmpdir;
+ return (uchar *)opt_mysql_tmpdir;
+ return (uchar*)mysql_tmpdir;
}
/****************************************************************************
@@ -3215,31 +2705,161 @@ static struct my_option *find_option(struct my_option *opt, const char *name)
Return variable name and length for hashing of variables
*/
-static byte *get_sys_var_length(const sys_var *var, uint *length,
- my_bool first)
+static uchar *get_sys_var_length(const sys_var *var, size_t *length,
+ my_bool first)
{
*length= var->name_length;
- return (byte*) var->name;
+ return (uchar*) var->name;
}
/*
- Initialises sys variables and put them in system_variable_hash
+ Add variables to the dynamic hash of system variables
+
+ SYNOPSIS
+ mysql_add_sys_var_chain()
+ first Pointer to first system variable to add
+ long_opt (optional)command line arguments may be tied for limit checks.
+
+ RETURN VALUES
+ 0 SUCCESS
+ otherwise FAILURE
*/
-void set_var_init()
+int mysql_add_sys_var_chain(sys_var *first, struct my_option *long_options)
{
sys_var *var;
-
- hash_init(&system_variable_hash, system_charset_info, sys_var::sys_vars, 0,
- 0, (hash_get_key) get_sys_var_length, 0, 0);
- for (var= sys_var::first; var; var= var->next)
+
+ /* A write lock should be held on LOCK_system_variables_hash */
+
+ for (var= first; var; var= var->next)
{
var->name_length= strlen(var->name);
- var->option_limits= find_option(my_long_options, var->name);
- my_hash_insert(&system_variable_hash, (byte*) var);
+ /* this fails if there is a conflicting variable name. see HASH_UNIQUE */
+ if (my_hash_insert(&system_variable_hash, (uchar*) var))
+ goto error;
+ if (long_options)
+ var->option_limits= find_option(long_options, var->name);
}
+ return 0;
+
+error:
+ for (; first != var; first= first->next)
+ hash_delete(&system_variable_hash, (uchar*) first);
+ return 1;
+}
+
+
+/*
+ Remove variables to the dynamic hash of system variables
+
+ SYNOPSIS
+ mysql_del_sys_var_chain()
+ first Pointer to first system variable to remove
+
+ RETURN VALUES
+ 0 SUCCESS
+ otherwise FAILURE
+*/
+
+int mysql_del_sys_var_chain(sys_var *first)
+{
+ int result= 0;
+
+ /* A write lock should be held on LOCK_system_variables_hash */
+
+ for (sys_var *var= first; var; var= var->next)
+ result|= hash_delete(&system_variable_hash, (uchar*) var);
+
+ return result;
+}
+
+
+static int show_cmp(SHOW_VAR *a, SHOW_VAR *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+
+/*
+ Constructs an array of system variables for display to the user.
+
+ SYNOPSIS
+ enumerate_sys_vars()
+ thd current thread
+ sorted If TRUE, the system variables should be sorted
+
+ RETURN VALUES
+ pointer Array of SHOW_VAR elements for display
+ NULL FAILURE
+*/
+
+SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted)
+{
+ int count= system_variable_hash.records, i;
+ int fixed_count= fixed_show_vars.elements;
+ int size= sizeof(SHOW_VAR) * (count + fixed_count + 1);
+ SHOW_VAR *result= (SHOW_VAR*) thd->alloc(size);
+
+ if (result)
+ {
+ SHOW_VAR *show= result + fixed_count;
+ memcpy(result, fixed_show_vars.buffer, fixed_count * sizeof(SHOW_VAR));
+
+ for (i= 0; i < count; i++)
+ {
+ sys_var *var= (sys_var*) hash_element(&system_variable_hash, i);
+ show->name= var->name;
+ show->value= (char*) var;
+ show->type= SHOW_SYS;
+ show++;
+ }
+
+ /* sort into order */
+ if (sorted)
+ qsort(result, count + fixed_count, sizeof(SHOW_VAR), (qsort_cmp)show_cmp);
+
+ /* make last element empty */
+ bzero(show, sizeof(SHOW_VAR));
+ }
+ return result;
+}
+
+
+/*
+ Initialize the system variables
+
+ SYNOPSIS
+ set_var_init()
+
+ RETURN VALUES
+ 0 SUCCESS
+ otherwise FAILURE
+*/
+
+int set_var_init()
+{
+ uint count= 0;
+ DBUG_ENTER("set_var_init");
+
+ for (sys_var *var=vars.first; var; var= var->next, count++);
+
+ if (my_init_dynamic_array(&fixed_show_vars, sizeof(SHOW_VAR),
+ FIXED_VARS_SIZE + 64, 64))
+ goto error;
+
+ fixed_show_vars.elements= FIXED_VARS_SIZE;
+ memcpy(fixed_show_vars.buffer, fixed_vars, sizeof(fixed_vars));
+
+ if (hash_init(&system_variable_hash, system_charset_info, count, 0,
+ 0, (hash_get_key) get_sys_var_length, 0, HASH_UNIQUE))
+ goto error;
+
+ vars.last->next= NULL;
+ if (mysql_add_sys_var_chain(vars.first, my_long_options))
+ goto error;
+
/*
Special cases
Needed because MySQL can't find the limits for a variable it it has
@@ -3247,12 +2867,40 @@ void set_var_init()
As these variables are deprecated, this code will disappear soon...
*/
sys_sql_max_join_size.option_limits= sys_max_join_size.option_limits;
+
+ DBUG_RETURN(0);
+
+error:
+ fprintf(stderr, "failed to initialize system variables");
+ DBUG_RETURN(1);
}
void set_var_free()
{
hash_free(&system_variable_hash);
+ delete_dynamic(&fixed_show_vars);
+}
+
+
+/*
+ Add elements to the dynamic list of read-only system variables.
+
+ SYNOPSIS
+ mysql_append_static_vars()
+ show_vars Pointer to start of array
+ count Number of elements
+
+ RETURN VALUES
+ 0 SUCCESS
+ otherwise FAILURE
+*/
+int mysql_append_static_vars(const SHOW_VAR *show_vars, uint count)
+{
+ for (; count > 0; count--, show_vars++)
+ if (insert_dynamic(&fixed_show_vars, (uchar*) show_vars))
+ return 1;
+ return 0;
}
@@ -3260,7 +2908,7 @@ void set_var_free()
Find a user set-table variable
SYNOPSIS
- find_sys_var()
+ intern_find_sys_var()
str Name of system variable to find
length Length of variable. zero means that we should use strlen()
on the variable
@@ -3270,14 +2918,19 @@ void set_var_free()
0 Unknown variable (error message is given)
*/
-sys_var *find_sys_var(const char *str, uint length)
+sys_var *intern_find_sys_var(const char *str, uint length, bool no_error)
{
- sys_var *var= (sys_var*) hash_search(&system_variable_hash,
- (byte*) str,
- length ? length :
- strlen(str));
- if (!var)
+ sys_var *var;
+
+ /*
+ This function is only called from the sql_plugin.cc.
+ A lock on LOCK_system_variable_hash should be held
+ */
+ var= (sys_var*) hash_search(&system_variable_hash,
+ (uchar*) str, length ? length : strlen(str));
+ if (!(var || no_error))
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
+
return var;
}
@@ -3543,14 +3196,16 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
const char *value;
String str(buff, sizeof(buff), &my_charset_latin1), *res;
+ var->save_result.plugin= NULL;
if (var->value->result_type() == STRING_RESULT)
{
LEX_STRING name;
- handlerton *db_type;
+ handlerton *hton;
if (!(res=var->value->val_str(&str)) ||
!(name.str= (char *)res->ptr()) || !(name.length= res->length()) ||
- !(var->save_result.hton= db_type= ha_resolve_by_name(thd, &name)) ||
- ha_checktype(thd, ha_legacy_type(db_type), 1, 0) != db_type)
+ !(var->save_result.plugin= ha_resolve_by_name(thd, &name)) ||
+ !(hton= plugin_data(var->save_result.plugin, handlerton *)) ||
+ ha_checktype(thd, ha_legacy_type(hton), 1, 0) != hton)
{
value= res ? res->c_ptr() : "NULL";
goto err;
@@ -3565,31 +3220,55 @@ err:
}
-byte *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
- handlerton *val;
- val= (type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset;
- return (byte *) hton2plugin[val->slot]->name.str;
+ uchar* result;
+ handlerton *hton;
+ LEX_STRING *name;
+ plugin_ref plugin= thd->variables.*offset;
+ if (type == OPT_GLOBAL)
+ plugin= my_plugin_lock(thd, &(global_system_variables.*offset));
+ hton= plugin_data(plugin, handlerton*);
+ name= &hton2plugin[hton->slot]->name;
+ result= (uchar *) thd->strmake(name->str, name->length);
+ if (type == OPT_GLOBAL)
+ plugin_unlock(thd, plugin);
+ return result;
}
void sys_var_thd_storage_engine::set_default(THD *thd, enum_var_type type)
{
+ plugin_ref old_value, new_value, *value;
if (type == OPT_GLOBAL)
- global_system_variables.*offset= myisam_hton;
+ {
+ value= &(global_system_variables.*offset);
+ new_value= ha_lock_engine(NULL, myisam_hton);
+ }
else
- thd->variables.*offset= global_system_variables.*offset;
+ {
+ value= &(thd->variables.*offset);
+ new_value= my_plugin_lock(NULL, &(global_system_variables.*offset));
+ }
+ DBUG_ASSERT(new_value);
+ old_value= *value;
+ *value= new_value;
+ plugin_unlock(NULL, old_value);
}
bool sys_var_thd_storage_engine::update(THD *thd, set_var *var)
{
- handlerton **value= &(global_system_variables.*offset);
- if (var->type != OPT_GLOBAL)
- value= &(thd->variables.*offset);
- *value= var->save_result.hton;
+ plugin_ref *value= &(global_system_variables.*offset), old_value;
+ if (var->type != OPT_GLOBAL)
+ value= &(thd->variables.*offset);
+ old_value= *value;
+ if (old_value != var->save_result.plugin)
+ {
+ *value= my_plugin_lock(NULL, &var->save_result.plugin);
+ plugin_unlock(NULL, old_value);
+ }
return 0;
}
@@ -3621,21 +3300,18 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var)
SYNOPSIS
thd in thread handler
val in sql_mode value
- len out pointer on length of string
-
- RETURN
- pointer to string with sql_mode representation
+ rep out pointer pointer to string with sql_mode representation
*/
-byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd,
- ulong val,
- ulong *len)
+bool
+sys_var_thd_sql_mode::
+symbolic_mode_representation(THD *thd, ulonglong val, LEX_STRING *rep)
{
- char buff[256];
+ char buff[STRING_BUFFER_USUAL_SIZE*8];
String tmp(buff, sizeof(buff), &my_charset_latin1);
- ulong length;
tmp.length(0);
+
for (uint i= 0; val; val>>= 1, i++)
{
if (val & 1)
@@ -3646,20 +3322,25 @@ byte *sys_var_thd_sql_mode::symbolic_mode_representation(THD *thd,
}
}
- if ((length= tmp.length()))
- length--;
- *len= length;
- return (byte*) thd->strmake(tmp.ptr(), length);
+ if (tmp.length())
+ tmp.length(tmp.length() - 1); /* trim the trailing comma */
+
+ rep->str= thd->strmake(tmp.ptr(), tmp.length());
+
+ rep->length= rep->str ? tmp.length() : 0;
+
+ return rep->length != tmp.length();
}
-byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
+ LEX_STRING sql_mode;
ulonglong val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
thd->variables.*offset);
- ulong length_unused;
- return symbolic_mode_representation(thd, val, &length_unused);
+ (void) symbolic_mode_representation(thd, val, &sql_mode);
+ return (uchar *) sql_mode.str;
}
@@ -3750,7 +3431,7 @@ ulong fix_sql_mode(ulong sql_mode)
Named list handling
****************************************************************************/
-gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
+uchar* find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
NAMED_LIST **found)
{
I_List_iterator<NAMED_LIST> it(*list);
@@ -3769,7 +3450,7 @@ gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char *name, gptr))
+ void (*free_element)(const char *name, uchar*))
{
NAMED_LIST *element;
DBUG_ENTER("delete_elements");
@@ -3793,7 +3474,7 @@ static KEY_CACHE *create_key_cache(const char *name, uint length)
if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
MYF(MY_ZEROFILL | MY_WME))))
{
- if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache))
+ if (!new NAMED_LIST(&key_caches, name, length, (uchar*) key_cache))
{
my_free((char*) key_cache, MYF(0));
key_cache= 0;
@@ -3869,6 +3550,70 @@ bool sys_var_trust_routine_creators::update(THD *thd, set_var *var)
return sys_var_bool_ptr::update(thd, var);
}
+bool sys_var_opt_readonly::update(THD *thd, set_var *var)
+{
+ bool result;
+
+ DBUG_ENTER("sys_var_opt_readonly::update");
+
+ /* Prevent self dead-lock */
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
+ DBUG_RETURN(true);
+ }
+
+ if (thd->global_read_lock)
+ {
+ /*
+ This connection already holds the global read lock.
+ This can be the case with:
+ - FLUSH TABLES WITH READ LOCK
+ - SET GLOBAL READ_ONLY = 1
+ */
+ result= sys_var_bool_ptr::update(thd, var);
+ DBUG_RETURN(result);
+ }
+
+ /*
+ Perform a 'FLUSH TABLES WITH READ LOCK'.
+ This is a 3 step process:
+ - [1] lock_global_read_lock()
+ - [2] close_cached_tables()
+ - [3] make_global_read_lock_block_commit()
+ [1] prevents new connections from obtaining tables locked for write.
+ [2] waits until all existing connections close their tables.
+ [3] prevents transactions from being committed.
+ */
+
+ if (lock_global_read_lock(thd))
+ DBUG_RETURN(true);
+
+ /*
+ This call will be blocked by any connection holding a READ or WRITE lock.
+ Ideally, we want to wait only for pending WRITE locks, but since:
+ con 1> LOCK TABLE T FOR READ;
+ con 2> LOCK TABLE T FOR WRITE; (blocked by con 1)
+ con 3> SET GLOBAL READ ONLY=1; (blocked by con 2)
+ can cause to wait on a read lock, it's required for the client application
+ to unlock everything, and acceptable for the server to wait on all locks.
+ */
+ if (result= close_cached_tables(thd, true, NULL, false))
+ goto end_with_read_lock;
+
+ if (result= make_global_read_lock_block_commit(thd))
+ goto end_with_read_lock;
+
+ /* Change the opt_readonly system variable, safe because the lock is held */
+ result= sys_var_bool_ptr::update(thd, var);
+
+end_with_read_lock:
+ /* Release the lock */
+ unlock_global_read_lock(thd);
+ DBUG_RETURN(result);
+}
+
+
/* even session variable here requires SUPER, because of -#o,file */
bool sys_var_thd_dbug::check(THD *thd, set_var *var)
{
@@ -3888,14 +3633,14 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var)
}
-byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
+uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
{
char buf[256];
if (type == OPT_GLOBAL)
DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
else
DBUG_EXPLAIN(buf, sizeof(buf));
- return (byte*) thd->strdup(buf);
+ return (uchar*) thd->strdup(buf);
}
@@ -3926,43 +3671,22 @@ sys_var_event_scheduler::update(THD *thd, set_var *var)
int res;
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_scheduler::update");
- if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
- {
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED");
- DBUG_RETURN(TRUE);
- }
-
DBUG_PRINT("info", ("new_value: %d", (int) var->save_result.ulong_value));
- Item_result var_type= var->value->result_type();
+ enum Events::enum_opt_event_scheduler
+ new_state=
+ (enum Events::enum_opt_event_scheduler) var->save_result.ulong_value;
- if (var->save_result.ulong_value == Events::EVENTS_ON)
- res= Events::get_instance()->start_execution_of_events();
- else if (var->save_result.ulong_value == Events::EVENTS_OFF)
- res= Events::get_instance()->stop_execution_of_events();
- else
- {
- DBUG_ASSERT(0);
- }
- if (res)
- my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
+ res= Events::switch_event_scheduler_state(new_state);
DBUG_RETURN((bool) res);
}
-byte *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
+uchar *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
- int state;
- if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
- state= Events::EVENTS_DISABLED; // This should be DISABLED
- else if (Events::get_instance()->is_execution_of_events_started())
- state= Events::EVENTS_ON; // This should be ON
- else
- state= Events::EVENTS_OFF; // This should be OFF
-
- return (byte*) Events::opt_typelib.type_names[state];
+ return (uchar *) Events::get_opt_event_scheduler_str();
}
diff --git a/sql/set_var.h b/sql/set_var.h
index 8f319b1790d..a998dc93b84 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2002-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,6 +26,7 @@
class sys_var;
class set_var;
+class sys_var_pluginvar; /* opaque */
typedef struct system_variables SV;
typedef struct my_locale_st MY_LOCALE;
@@ -36,13 +36,17 @@ typedef int (*sys_check_func)(THD *, set_var *);
typedef bool (*sys_update_func)(THD *, set_var *);
typedef void (*sys_after_update_func)(THD *,enum_var_type);
typedef void (*sys_set_default_func)(THD *, enum_var_type);
-typedef byte *(*sys_value_ptr_func)(THD *thd);
+typedef uchar *(*sys_value_ptr_func)(THD *thd);
+
+struct sys_var_chain
+{
+ sys_var *first;
+ sys_var *last;
+};
class sys_var
{
public:
- static sys_var *first;
- static uint sys_vars;
sys_var *next;
struct my_option *option_limits; /* Updated by by set_var_init() */
uint name_length; /* Updated by by set_var_init() */
@@ -53,21 +57,23 @@ public:
sys_var(const char *name_arg,sys_after_update_func func= NULL)
:name(name_arg), after_update(func)
, no_support_one_shot(1)
- { add_sys_var(); }
+ {}
virtual ~sys_var() {}
- void add_sys_var()
+ void chain_sys_var(sys_var_chain *chain_arg)
{
- next= first;
- first= this;
- sys_vars++;
+ if (chain_arg->last)
+ chain_arg->last->next= this;
+ else
+ chain_arg->first= this;
+ chain_arg->last= this;
}
virtual bool check(THD *thd, set_var *var);
- bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names);
+ bool check_enum(THD *thd, set_var *var, const TYPELIB *enum_names);
bool check_set(THD *thd, set_var *var, TYPELIB *enum_names);
virtual bool update(THD *thd, set_var *var)=0;
- virtual void set_default(THD *thd, enum_var_type type) {}
- virtual SHOW_TYPE type() { return SHOW_UNDEF; }
- virtual byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ virtual void set_default(THD *thd_arg, enum_var_type type) {}
+ virtual SHOW_TYPE show_type() { return SHOW_UNDEF; }
+ virtual uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{ return 0; }
virtual bool check_type(enum_var_type type)
{ return type != OPT_GLOBAL; } /* Error if not GLOBAL */
@@ -78,6 +84,7 @@ public:
Item *item(THD *thd, enum_var_type type, LEX_STRING *base);
virtual bool is_struct() { return 0; }
virtual bool is_readonly() const { return 0; }
+ virtual sys_var_pluginvar *cast_pluginvar() { return 0; }
};
@@ -106,16 +113,18 @@ class sys_var_long_ptr_global: public sys_var_global
{
public:
ulong *value;
- sys_var_long_ptr_global(const char *name_arg, ulong *value_ptr,
+ sys_var_long_ptr_global(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_arg,
pthread_mutex_t *guard_arg,
sys_after_update_func after_update_arg= NULL)
- :sys_var_global(name_arg, after_update_arg, guard_arg), value(value_ptr) {}
+ :sys_var_global(name_arg, after_update_arg, guard_arg),
+ value(value_ptr_arg)
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (byte*) value; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ { return (uchar*) value; }
};
@@ -126,7 +135,7 @@ public:
class sys_var_long_ptr :public sys_var_long_ptr_global
{
public:
- sys_var_long_ptr(const char *name_arg, ulong *value_ptr,
+ sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr,
sys_after_update_func after_update_arg= NULL);
};
@@ -135,16 +144,18 @@ class sys_var_ulonglong_ptr :public sys_var
{
public:
ulonglong *value;
- sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr)
- :sys_var(name_arg),value(value_ptr) {}
- sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr,
+ sys_var_ulonglong_ptr(sys_var_chain *chain, const char *name_arg, ulonglong *value_ptr_arg)
+ :sys_var(name_arg),value(value_ptr_arg)
+ { chain_sys_var(chain); }
+ sys_var_ulonglong_ptr(sys_var_chain *chain, const char *name_arg, ulonglong *value_ptr_arg,
sys_after_update_func func)
- :sys_var(name_arg,func), value(value_ptr) {}
+ :sys_var(name_arg,func), value(value_ptr_arg)
+ { chain_sys_var(chain); }
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, LEX_STRING *base)
- { return (byte*) value; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ { return (uchar*) value; }
};
@@ -152,22 +163,33 @@ class sys_var_bool_ptr :public sys_var
{
public:
my_bool *value;
- sys_var_bool_ptr(const char *name_arg, my_bool *value_arg)
+ sys_var_bool_ptr(sys_var_chain *chain, const char *name_arg, my_bool *value_arg)
:sys_var(name_arg),value(value_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
return check_enum(thd, var, &bool_typelib);
}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (byte*) value; }
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ { return (uchar*) value; }
bool check_update_type(Item_result type) { return 0; }
};
+class sys_var_bool_ptr_readonly :public sys_var_bool_ptr
+{
+public:
+ sys_var_bool_ptr_readonly(sys_var_chain *chain, const char *name_arg,
+ my_bool *value_arg)
+ :sys_var_bool_ptr(chain, name_arg, value_arg)
+ {}
+ bool is_readonly() const { return 1; }
+};
+
+
class sys_var_str :public sys_var
{
public:
@@ -176,14 +198,14 @@ public:
sys_check_func check_func;
sys_update_func update_func;
sys_set_default_func set_default_func;
- sys_var_str(const char *name_arg,
+ sys_var_str(sys_var_chain *chain, const char *name_arg,
sys_check_func check_func_arg,
sys_update_func update_func_arg,
sys_set_default_func set_default_func_arg,
char *value_arg)
:sys_var(name_arg), value(value_arg), check_func(check_func_arg),
update_func(update_func_arg),set_default_func(set_default_func_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var)
{
@@ -193,9 +215,9 @@ public:
{
(*set_default_func)(thd, type);
}
- SHOW_TYPE type() { return SHOW_CHAR; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
- { return (byte*) value; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ { return (uchar*) value; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
@@ -208,9 +230,9 @@ class sys_var_const_str :public sys_var
{
public:
char *value; // Pointer to const value
- sys_var_const_str(const char *name_arg, const char *value_arg)
+ sys_var_const_str(sys_var_chain *chain, const char *name_arg, const char *value_arg)
:sys_var(name_arg),value((char*) value_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
return 1;
@@ -219,10 +241,10 @@ public:
{
return 1;
}
- SHOW_TYPE type() { return SHOW_CHAR; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
- return (byte*) value;
+ return (uchar*) value;
}
bool check_update_type(Item_result type)
{
@@ -237,9 +259,9 @@ class sys_var_const_str_ptr :public sys_var
{
public:
char **value; // Pointer to const value
- sys_var_const_str_ptr(const char *name_arg, char **value_arg)
+ sys_var_const_str_ptr(sys_var_chain *chain, const char *name_arg, char **value_arg)
:sys_var(name_arg),value(value_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
return 1;
@@ -248,10 +270,10 @@ public:
{
return 1;
}
- SHOW_TYPE type() { return SHOW_CHAR; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
- return (byte*) *value;
+ return (uchar*) *value;
}
bool check_update_type(Item_result type)
{
@@ -267,17 +289,17 @@ class sys_var_enum :public sys_var
uint *value;
TYPELIB *enum_names;
public:
- sys_var_enum(const char *name_arg, uint *value_arg,
+ sys_var_enum(sys_var_chain *chain, const char *name_arg, uint *value_arg,
TYPELIB *typelib, sys_after_update_func func)
:sys_var(name_arg,func), value(value_arg), enum_names(typelib)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
return check_enum(thd, var, enum_names);
}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
};
@@ -285,7 +307,8 @@ public:
class sys_var_thd :public sys_var
{
public:
- sys_var_thd(const char *name_arg, sys_after_update_func func= NULL)
+ sys_var_thd(const char *name_arg,
+ sys_after_update_func func= NULL)
:sys_var(name_arg,func)
{}
bool check_type(enum_var_type type) { return 0; }
@@ -301,18 +324,18 @@ class sys_var_thd_ulong :public sys_var_thd
sys_check_func check_func;
public:
ulong SV::*offset;
- sys_var_thd_ulong(const char *name_arg, ulong SV::*offset_arg)
+ sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg)
:sys_var_thd(name_arg), check_func(0), offset(offset_arg)
- {}
- sys_var_thd_ulong(const char *name_arg, ulong SV::*offset_arg,
+ { chain_sys_var(chain); }
+ sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg,
sys_check_func c_func, sys_after_update_func au_func)
:sys_var_thd(name_arg,au_func), check_func(c_func), offset(offset_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_LONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_LONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -320,17 +343,19 @@ class sys_var_thd_ha_rows :public sys_var_thd
{
public:
ha_rows SV::*offset;
- sys_var_thd_ha_rows(const char *name_arg, ha_rows SV::*offset_arg)
+ sys_var_thd_ha_rows(sys_var_chain *chain, const char *name_arg,
+ ha_rows SV::*offset_arg)
:sys_var_thd(name_arg), offset(offset_arg)
- {}
- sys_var_thd_ha_rows(const char *name_arg, ha_rows SV::*offset_arg,
+ { chain_sys_var(chain); }
+ sys_var_thd_ha_rows(sys_var_chain *chain, const char *name_arg,
+ ha_rows SV::*offset_arg,
sys_after_update_func func)
:sys_var_thd(name_arg,func), offset(offset_arg)
- {}
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_HA_ROWS; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_HA_ROWS; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -339,18 +364,20 @@ 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_ulonglong(sys_var_chain *chain, 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,
+ { chain_sys_var(chain); }
+ sys_var_thd_ulonglong(sys_var_chain *chain, const char *name_arg,
+ ulonglong SV::*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)
- {}
+ { chain_sys_var(chain); }
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, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_default(enum_var_type type)
{
return type == OPT_GLOBAL && !option_limits;
@@ -366,17 +393,17 @@ class sys_var_thd_bool :public sys_var_thd
{
public:
my_bool SV::*offset;
- sys_var_thd_bool(const char *name_arg, my_bool SV::*offset_arg)
+ sys_var_thd_bool(sys_var_chain *chain, const char *name_arg, my_bool SV::*offset_arg)
:sys_var_thd(name_arg), offset(offset_arg)
- {}
- sys_var_thd_bool(const char *name_arg, my_bool SV::*offset_arg,
+ { chain_sys_var(chain); }
+ sys_var_thd_bool(sys_var_chain *chain, const char *name_arg, my_bool SV::*offset_arg,
sys_after_update_func func)
:sys_var_thd(name_arg,func), offset(offset_arg)
- {}
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check(THD *thd, set_var *var)
{
return check_enum(thd, var, &bool_typelib);
@@ -392,23 +419,23 @@ protected:
TYPELIB *enum_names;
sys_check_func check_func;
public:
- sys_var_thd_enum(const char *name_arg, ulong SV::*offset_arg,
+ sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg,
TYPELIB *typelib)
:sys_var_thd(name_arg), offset(offset_arg), enum_names(typelib),
check_func(0)
- {}
- sys_var_thd_enum(const char *name_arg, ulong SV::*offset_arg,
+ { chain_sys_var(chain); }
+ sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg,
TYPELIB *typelib,
sys_after_update_func func)
:sys_var_thd(name_arg,func), offset(offset_arg), enum_names(typelib),
check_func(0)
- {}
- sys_var_thd_enum(const char *name_arg, ulong SV::*offset_arg,
+ { chain_sys_var(chain); }
+ sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg,
TYPELIB *typelib, sys_after_update_func func,
sys_check_func check)
:sys_var_thd(name_arg,func), offset(offset_arg), enum_names(typelib),
check_func(check)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
int ret= 0;
@@ -418,8 +445,8 @@ public:
}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_CHAR; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
};
@@ -429,8 +456,9 @@ extern void fix_sql_mode_var(THD *thd, enum_var_type type);
class sys_var_thd_sql_mode :public sys_var_thd_enum
{
public:
- sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg)
- :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib,
+ sys_var_thd_sql_mode(sys_var_chain *chain, const char *name_arg,
+ ulong SV::*offset_arg)
+ :sys_var_thd_enum(chain, name_arg, offset_arg, &sql_mode_typelib,
fix_sql_mode_var)
{}
bool check(THD *thd, set_var *var)
@@ -438,36 +466,38 @@ public:
return check_set(thd, var, enum_names);
}
void set_default(THD *thd, enum_var_type type);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- static byte *symbolic_mode_representation(THD *thd, ulong sql_mode,
- ulong *length);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ static bool symbolic_mode_representation(THD *thd, ulonglong sql_mode,
+ LEX_STRING *rep);
};
class sys_var_thd_storage_engine :public sys_var_thd
{
protected:
- handlerton *SV::*offset;
+ plugin_ref SV::*offset;
public:
- sys_var_thd_storage_engine(const char *name_arg, handlerton *SV::*offset_arg)
+ sys_var_thd_storage_engine(sys_var_chain *chain, const char *name_arg,
+ plugin_ref SV::*offset_arg)
:sys_var_thd(name_arg), offset(offset_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
-SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
}
void set_default(THD *thd, enum_var_type type);
bool update(THD *thd, set_var *var);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
class sys_var_thd_table_type :public sys_var_thd_storage_engine
{
public:
- sys_var_thd_table_type(const char *name_arg, handlerton *SV::*offset_arg)
- :sys_var_thd_storage_engine(name_arg, offset_arg)
+ sys_var_thd_table_type(sys_var_chain *chain, const char *name_arg,
+ plugin_ref SV::*offset_arg)
+ :sys_var_thd_storage_engine(chain, name_arg, offset_arg)
{}
void warn_deprecated(THD *thd);
void set_default(THD *thd, enum_var_type type);
@@ -479,32 +509,34 @@ class sys_var_thd_bit :public sys_var_thd
sys_check_func check_func;
sys_update_func update_func;
public:
- ulong bit_flag;
+ ulonglong bit_flag;
bool reverse;
- sys_var_thd_bit(const char *name_arg,
+ sys_var_thd_bit(sys_var_chain *chain, const char *name_arg,
sys_check_func c_func, sys_update_func u_func,
- ulong bit, bool reverse_arg=0)
+ ulonglong bit, bool reverse_arg=0)
:sys_var_thd(name_arg), check_func(c_func), update_func(u_func),
bit_flag(bit), reverse(reverse_arg)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
bool check_update_type(Item_result type) { return 0; }
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_MY_BOOL; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
class sys_var_thd_dbug :public sys_var_thd
{
public:
- sys_var_thd_dbug(const char *name_arg) :sys_var_thd(name_arg) {}
+ sys_var_thd_dbug(sys_var_chain *chain, const char *name_arg)
+ :sys_var_thd(name_arg)
+ { chain_sys_var(chain); }
bool check_update_type(Item_result type) { return type != STRING_RESULT; }
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type) { DBUG_POP(); }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b);
};
@@ -514,65 +546,50 @@ public:
class sys_var_timestamp :public sys_var
{
public:
- sys_var_timestamp(const char *name_arg) :sys_var(name_arg) {}
+ sys_var_timestamp(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
bool check_default(enum_var_type type) { return 0; }
- SHOW_TYPE type() { return SHOW_LONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_LONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
class sys_var_last_insert_id :public sys_var
{
public:
- sys_var_last_insert_id(const char *name_arg) :sys_var(name_arg) {}
+ sys_var_last_insert_id(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_LONGLONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
class sys_var_insert_id :public sys_var
{
public:
- sys_var_insert_id(const char *name_arg) :sys_var(name_arg) {}
+ sys_var_insert_id(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
- SHOW_TYPE type() { return SHOW_LONGLONG; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
-#ifdef HAVE_REPLICATION
-class sys_var_slave_skip_counter :public sys_var
-{
-public:
- sys_var_slave_skip_counter(const char *name_arg) :sys_var(name_arg) {}
- bool check(THD *thd, set_var *var);
- bool update(THD *thd, set_var *var);
- bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
- /*
- We can't retrieve the value of this, so we don't have to define
- type() or value_ptr()
- */
-};
-
-class sys_var_sync_binlog_period :public sys_var_long_ptr
-{
-public:
- sys_var_sync_binlog_period(const char *name_arg, ulong *value_ptr)
- :sys_var_long_ptr(name_arg,value_ptr) {}
- bool update(THD *thd, set_var *var);
-};
-#endif
-
class sys_var_rand_seed1 :public sys_var
{
public:
- sys_var_rand_seed1(const char *name_arg) :sys_var(name_arg) {}
+ sys_var_rand_seed1(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
};
@@ -580,7 +597,9 @@ public:
class sys_var_rand_seed2 :public sys_var
{
public:
- sys_var_rand_seed2(const char *name_arg) :sys_var(name_arg) {}
+ sys_var_rand_seed2(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var);
bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
};
@@ -589,12 +608,13 @@ public:
class sys_var_collation :public sys_var_thd
{
public:
- sys_var_collation(const char *name_arg) :sys_var_thd(name_arg)
+ sys_var_collation(const char *name_arg)
+ :sys_var_thd(name_arg)
{
no_support_one_shot= 0;
}
bool check(THD *thd, set_var *var);
-SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
@@ -607,10 +627,9 @@ class sys_var_character_set :public sys_var_thd
{
public:
bool nullable;
- sys_var_character_set(const char *name_arg) :
- sys_var_thd(name_arg)
+ sys_var_character_set(const char *name_arg, bool is_nullable= 0) :
+ sys_var_thd(name_arg), nullable(is_nullable)
{
- nullable= 0;
/*
In fact only almost all variables derived from sys_var_character_set
support ONE_SHOT; character_set_results doesn't. But that's good enough.
@@ -618,98 +637,61 @@ public:
no_support_one_shot= 0;
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
}
bool check_default(enum_var_type type) { return 0; }
bool update(THD *thd, set_var *var);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
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_character_set_filesystem :public sys_var_character_set
-{
-public:
- sys_var_character_set_filesystem(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_client :public sys_var_character_set
+class sys_var_character_set_sv :public sys_var_character_set
{
+ CHARSET_INFO *SV::*offset;
+ CHARSET_INFO **global_default;
public:
- sys_var_character_set_client(const char *name_arg) :
- sys_var_character_set(name_arg) {}
+ sys_var_character_set_sv(sys_var_chain *chain, const char *name_arg,
+ CHARSET_INFO *SV::*offset_arg,
+ CHARSET_INFO **global_default_arg,
+ bool is_nullable= 0)
+ : sys_var_character_set(name_arg, is_nullable),
+ offset(offset_arg), global_default(global_default_arg)
+ { chain_sys_var(chain); }
void set_default(THD *thd, enum_var_type type);
CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
};
-class sys_var_character_set_results :public sys_var_character_set
-{
-public:
- 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) {}
+ sys_var_character_set_database(sys_var_chain *chain, const char *name_arg) :
+ sys_var_character_set(name_arg)
+ { chain_sys_var(chain); }
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, LEX_STRING *base);
-};
-
-class sys_var_collation_server :public sys_var_collation
-{
-public:
- sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
- bool update(THD *thd, set_var *var);
- void set_default(THD *thd, enum_var_type type);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
-};
-
-class sys_var_collation_database :public sys_var_collation
+class sys_var_collation_sv :public sys_var_collation
{
+ CHARSET_INFO *SV::*offset;
+ CHARSET_INFO **global_default;
public:
- sys_var_collation_database(const char *name_arg) :sys_var_collation(name_arg) {}
+ sys_var_collation_sv(sys_var_chain *chain, const char *name_arg,
+ CHARSET_INFO *SV::*offset_arg,
+ CHARSET_INFO **global_default_arg)
+ :sys_var_collation(name_arg),
+ offset(offset_arg), global_default(global_default_arg)
+ {
+ chain_sys_var(chain);
+ }
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
@@ -718,10 +700,11 @@ class sys_var_key_cache_param :public sys_var
protected:
size_t offset;
public:
- sys_var_key_cache_param(const char *name_arg, size_t offset_arg)
+ sys_var_key_cache_param(sys_var_chain *chain, const char *name_arg,
+ size_t offset_arg)
:sys_var(name_arg), offset(offset_arg)
- {}
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ { chain_sys_var(chain); }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_default(enum_var_type type) { return 1; }
bool is_struct() { return 1; }
};
@@ -730,22 +713,23 @@ public:
class sys_var_key_buffer_size :public sys_var_key_cache_param
{
public:
- sys_var_key_buffer_size(const char *name_arg)
- :sys_var_key_cache_param(name_arg, offsetof(KEY_CACHE, param_buff_size))
+ sys_var_key_buffer_size(sys_var_chain *chain, const char *name_arg)
+ :sys_var_key_cache_param(chain, name_arg,
+ offsetof(KEY_CACHE, param_buff_size))
{}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_LONGLONG; }
+ SHOW_TYPE show_type() { return SHOW_LONGLONG; }
};
class sys_var_key_cache_long :public sys_var_key_cache_param
{
public:
- sys_var_key_cache_long(const char *name_arg, size_t offset_arg)
- :sys_var_key_cache_param(name_arg, offset_arg)
+ sys_var_key_cache_long(sys_var_chain *chain, const char *name_arg, size_t offset_arg)
+ :sys_var_key_cache_param(chain, name_arg, offset_arg)
{}
bool update(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_LONG; }
+ SHOW_TYPE show_type() { return SHOW_LONG; }
};
@@ -754,13 +738,13 @@ class sys_var_thd_date_time_format :public sys_var_thd
DATE_TIME_FORMAT *SV::*offset;
timestamp_type date_time_type;
public:
- sys_var_thd_date_time_format(const char *name_arg,
+ sys_var_thd_date_time_format(sys_var_chain *chain, const char *name_arg,
DATE_TIME_FORMAT *SV::*offset_arg,
timestamp_type date_time_type_arg)
:sys_var_thd(name_arg), offset(offset_arg),
date_time_type(date_time_type_arg)
- {}
- SHOW_TYPE type() { return SHOW_CHAR; }
+ { chain_sys_var(chain); }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
@@ -769,7 +753,7 @@ public:
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
void set_default(THD *thd, enum_var_type type);
};
@@ -778,8 +762,9 @@ class sys_var_log_state :public sys_var_bool_ptr
{
uint log_type;
public:
- sys_var_log_state(const char *name_arg, my_bool *value_arg, uint log_type_arg)
- :sys_var_bool_ptr(name_arg, value_arg), log_type(log_type_arg) {}
+ sys_var_log_state(sys_var_chain *chain, const char *name_arg, my_bool *value_arg,
+ uint log_type_arg)
+ :sys_var_bool_ptr(chain, name_arg, value_arg), log_type(log_type_arg) {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
};
@@ -790,19 +775,19 @@ class sys_var_log_output :public sys_var
ulong *value;
TYPELIB *enum_names;
public:
- sys_var_log_output(const char *name_arg, ulong *value_arg,
+ sys_var_log_output(sys_var_chain *chain, const char *name_arg, ulong *value_arg,
TYPELIB *typelib, sys_after_update_func func)
:sys_var(name_arg,func), value(value_arg), enum_names(typelib)
- {}
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var)
{
return check_set(thd, var, enum_names);
}
bool update(THD *thd, set_var *var);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
bool check_update_type(Item_result type) { return 0; }
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
};
@@ -812,67 +797,99 @@ class sys_var_readonly: public sys_var
{
public:
enum_var_type var_type;
- SHOW_TYPE show_type;
+ SHOW_TYPE show_type_value;
sys_value_ptr_func value_ptr_func;
- sys_var_readonly(const char *name_arg, enum_var_type type,
+ sys_var_readonly(sys_var_chain *chain, const char *name_arg, enum_var_type type,
SHOW_TYPE show_type_arg,
sys_value_ptr_func value_ptr_func_arg)
:sys_var(name_arg), var_type(type),
- show_type(show_type_arg), value_ptr_func(value_ptr_func_arg)
- {}
+ show_type_value(show_type_arg), value_ptr_func(value_ptr_func_arg)
+ { chain_sys_var(chain); }
bool update(THD *thd, set_var *var) { return 1; }
bool check_default(enum_var_type type) { return 1; }
bool check_type(enum_var_type type) { return type != var_type; }
bool check_update_type(Item_result type) { return 1; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
return (*value_ptr_func)(thd);
}
- SHOW_TYPE type() { return show_type; }
+ SHOW_TYPE show_type() { return show_type_value; }
bool is_readonly() const { return 1; }
};
-class sys_var_have_variable: public sys_var
+class sys_var_have_option: public sys_var
{
- SHOW_COMP_OPTION *have_variable;
-
+protected:
+ virtual SHOW_COMP_OPTION get_option() = 0;
public:
- sys_var_have_variable(const char *variable_name,
- SHOW_COMP_OPTION *have_variable_arg):
- sys_var(variable_name),
- have_variable(have_variable_arg)
- { }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+ sys_var_have_option(sys_var_chain *chain, const char *variable_name):
+ sys_var(variable_name)
+ { chain_sys_var(chain); }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
{
- return (byte*) show_comp_option_name[*have_variable];
+ return (uchar*) show_comp_option_name[get_option()];
}
bool update(THD *thd, set_var *var) { return 1; }
bool check_default(enum_var_type type) { return 1; }
bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
bool check_update_type(Item_result type) { return 1; }
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool is_readonly() const { return 1; }
};
+class sys_var_have_variable: public sys_var_have_option
+{
+ SHOW_COMP_OPTION *have_variable;
+
+public:
+ sys_var_have_variable(sys_var_chain *chain, const char *variable_name,
+ SHOW_COMP_OPTION *have_variable_arg):
+ sys_var_have_option(chain, variable_name),
+ have_variable(have_variable_arg)
+ { }
+ SHOW_COMP_OPTION get_option() { return *have_variable; }
+};
+
+
+class sys_var_have_plugin: public sys_var_have_option
+{
+ const char *plugin_name_str;
+ const uint plugin_name_len;
+ const int plugin_type;
+
+public:
+ sys_var_have_plugin(sys_var_chain *chain, const char *variable_name,
+ const char *plugin_name_str_arg, uint plugin_name_len_arg,
+ int plugin_type_arg):
+ sys_var_have_option(chain, variable_name),
+ plugin_name_str(plugin_name_str_arg), plugin_name_len(plugin_name_len_arg),
+ plugin_type(plugin_type_arg)
+ { }
+ /* the following method is declared in sql_plugin.cc */
+ SHOW_COMP_OPTION get_option();
+};
+
+
class sys_var_thd_time_zone :public sys_var_thd
{
public:
- sys_var_thd_time_zone(const char *name_arg):
+ sys_var_thd_time_zone(sys_var_chain *chain, const char *name_arg):
sys_var_thd(name_arg)
{
no_support_one_shot= 0;
+ chain_sys_var(chain);
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_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);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
virtual void set_default(THD *thd, enum_var_type type);
};
@@ -880,8 +897,9 @@ public:
class sys_var_max_user_conn : public sys_var_thd
{
public:
- sys_var_max_user_conn(const char *name_arg):
- sys_var_thd(name_arg) {}
+ sys_var_max_user_conn(sys_var_chain *chain, const char *name_arg):
+ sys_var_thd(name_arg)
+ { chain_sys_var(chain); }
bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
bool check_default(enum_var_type type)
@@ -889,41 +907,58 @@ public:
return type != OPT_GLOBAL || !option_limits;
}
void set_default(THD *thd, enum_var_type type);
- SHOW_TYPE type() { return SHOW_INT; }
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_INT; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
class sys_var_trust_routine_creators :public sys_var_bool_ptr
{
/* We need a derived class only to have a warn_deprecated() */
public:
- sys_var_trust_routine_creators(const char *name_arg, my_bool *value_arg) :
- sys_var_bool_ptr(name_arg, value_arg) {};
+ sys_var_trust_routine_creators(sys_var_chain *chain,
+ const char *name_arg, my_bool *value_arg) :
+ sys_var_bool_ptr(chain, name_arg, value_arg) {};
void warn_deprecated(THD *thd);
void set_default(THD *thd, enum_var_type type);
bool update(THD *thd, set_var *var);
};
+/**
+ Handler for setting the system variable --read-only.
+*/
+
+class sys_var_opt_readonly :public sys_var_bool_ptr
+{
+public:
+ sys_var_opt_readonly(sys_var_chain *chain, const char *name_arg,
+ my_bool *value_arg) :
+ sys_var_bool_ptr(chain, name_arg, value_arg) {};
+ ~sys_var_opt_readonly() {};
+ bool update(THD *thd, set_var *var);
+};
+
+
class sys_var_thd_lc_time_names :public sys_var_thd
{
public:
- sys_var_thd_lc_time_names(const char *name_arg):
- sys_var_thd(name_arg)
+ sys_var_thd_lc_time_names(sys_var_chain *chain, const char *name_arg):
+ sys_var_thd(name_arg)
{
#if MYSQL_VERSION_ID < 50000
no_support_one_shot= 0;
#endif
+ chain_sys_var(chain);
}
bool check(THD *thd, set_var *var);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return ((type != STRING_RESULT) && (type != INT_RESULT));
}
bool check_default(enum_var_type type) { return 0; }
bool update(THD *thd, set_var *var);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
virtual void set_default(THD *thd, enum_var_type type);
};
@@ -932,11 +967,11 @@ class sys_var_event_scheduler :public sys_var_long_ptr
{
/* We need a derived class only to have a warn_deprecated() */
public:
- sys_var_event_scheduler(const char *name_arg) :
- sys_var_long_ptr(name_arg, NULL, NULL) {};
+ sys_var_event_scheduler(sys_var_chain *chain, const char *name_arg) :
+ sys_var_long_ptr(chain, name_arg, NULL, NULL) {};
bool update(THD *thd, set_var *var);
- byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
- SHOW_TYPE type() { return SHOW_CHAR; }
+ uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ SHOW_TYPE show_type() { return SHOW_CHAR; }
bool check(THD *thd, set_var *var);
bool check_update_type(Item_result type)
{
@@ -949,8 +984,9 @@ extern void fix_binlog_format_after_update(THD *thd, enum_var_type type);
class sys_var_thd_binlog_format :public sys_var_thd_enum
{
public:
- sys_var_thd_binlog_format(const char *name_arg, ulong SV::*offset_arg)
- :sys_var_thd_enum(name_arg, offset_arg,
+ sys_var_thd_binlog_format(sys_var_chain *chain, const char *name_arg,
+ ulong SV::*offset_arg)
+ :sys_var_thd_enum(chain, name_arg, offset_arg,
&binlog_format_typelib
, fix_binlog_format_after_update
)
@@ -988,15 +1024,15 @@ public:
CHARSET_INFO *charset;
ulong ulong_value;
ulonglong ulonglong_value;
- handlerton *hton;
+ plugin_ref plugin;
DATE_TIME_FORMAT *date_time_format;
Time_zone *time_zone;
MY_LOCALE *locale_value;
} save_result;
LEX_STRING base; /* for structs */
- set_var(enum_var_type type_arg, sys_var *var_arg, const LEX_STRING *base_name_arg,
- Item *value_arg)
+ set_var(enum_var_type type_arg, sys_var *var_arg,
+ const LEX_STRING *base_name_arg, Item *value_arg)
:var(var_arg), type(type_arg), base(*base_name_arg)
{
/*
@@ -1077,10 +1113,10 @@ class NAMED_LIST :public ilink
const char *name;
uint name_length;
public:
- gptr data;
+ uchar* data;
NAMED_LIST(I_List<NAMED_LIST> *links, const char *name_arg,
- uint name_length_arg, gptr data_arg)
+ uint name_length_arg, uchar* data_arg)
:name_length(name_length_arg), data(data_arg)
{
name= my_strndup(name_arg, name_length, MYF(MY_WME));
@@ -1092,12 +1128,12 @@ public:
}
~NAMED_LIST()
{
- my_free((char*) name, MYF(0));
+ my_free((uchar*) name, MYF(0));
}
friend bool process_key_caches(int (* func) (const char *name,
KEY_CACHE *));
friend void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char*, gptr));
+ void (*free_element)(const char*, uchar*));
};
/* updated in sql_acl.cc */
@@ -1117,9 +1153,13 @@ struct sys_var_with_base
Prototypes for helper functions
*/
-void set_var_init();
+int set_var_init();
void set_var_free();
-sys_var *find_sys_var(const char *str, uint length=0);
+int mysql_append_static_vars(const SHOW_VAR *show_vars, uint count);
+SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted);
+int mysql_add_sys_var_chain(sys_var *chain, struct my_option *long_options);
+int mysql_del_sys_var_chain(sys_var *chain);
+sys_var *find_sys_var(THD *thd, const char *str, uint length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list);
bool not_all_support_one_shot(List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
@@ -1130,7 +1170,7 @@ extern sys_var_str sys_init_slave;
extern sys_var_thd_time_zone sys_time_zone;
extern sys_var_thd_bit sys_autocommit;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
-gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
+uchar* find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
NAMED_LIST **found);
extern sys_var_str sys_var_general_log_path, sys_var_slow_log_path;
@@ -1141,4 +1181,4 @@ KEY_CACHE *get_or_create_key_cache(const char *name, uint length);
void free_key_cache(const char *name, KEY_CACHE *key_cache);
bool process_key_caches(int (* func) (const char *name, KEY_CACHE *));
void delete_elements(I_List<NAMED_LIST> *list,
- void (*free_element)(const char*, gptr));
+ void (*free_element)(const char*, uchar*));
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index 6d905ba35dc..68b393e619f 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -2,8 +2,7 @@
#
# 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.
+# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml
index 3f1a25072b7..80b844e2f19 100644
--- a/sql/share/charsets/Index.xml
+++ b/sql/share/charsets/Index.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/armscii8.xml b/sql/share/charsets/armscii8.xml
index d0ab428345f..714e57bb12e 100644
--- a/sql/share/charsets/armscii8.xml
+++ b/sql/share/charsets/armscii8.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml
index 3813bd42601..97006c53680 100644
--- a/sql/share/charsets/ascii.xml
+++ b/sql/share/charsets/ascii.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp1250.xml b/sql/share/charsets/cp1250.xml
index b83d0faeca8..bd0d7d3f3c0 100644
--- a/sql/share/charsets/cp1250.xml
+++ b/sql/share/charsets/cp1250.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp1251.xml b/sql/share/charsets/cp1251.xml
index 7f94788c0d0..b80db9f8ec0 100644
--- a/sql/share/charsets/cp1251.xml
+++ b/sql/share/charsets/cp1251.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml
index 69eb6a68238..64cb253145c 100644
--- a/sql/share/charsets/cp1256.xml
+++ b/sql/share/charsets/cp1256.xml
@@ -9,8 +9,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml
index 93a1bd47a77..0c2688c264e 100644
--- a/sql/share/charsets/cp1257.xml
+++ b/sql/share/charsets/cp1257.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp850.xml b/sql/share/charsets/cp850.xml
index 79497aa17f1..4076a5f6a56 100644
--- a/sql/share/charsets/cp850.xml
+++ b/sql/share/charsets/cp850.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp852.xml b/sql/share/charsets/cp852.xml
index 73a81e54b02..25b622d2a4b 100644
--- a/sql/share/charsets/cp852.xml
+++ b/sql/share/charsets/cp852.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml
index 1a72b396c7c..fa2e1865de6 100644
--- a/sql/share/charsets/cp866.xml
+++ b/sql/share/charsets/cp866.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/dec8.xml b/sql/share/charsets/dec8.xml
index 2cb28cb0f4f..2cd52de464a 100644
--- a/sql/share/charsets/dec8.xml
+++ b/sql/share/charsets/dec8.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml
index c09aa078fb7..5e3816975d6 100644
--- a/sql/share/charsets/geostd8.xml
+++ b/sql/share/charsets/geostd8.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/greek.xml b/sql/share/charsets/greek.xml
index 1cfe6b49610..000019a8ce0 100644
--- a/sql/share/charsets/greek.xml
+++ b/sql/share/charsets/greek.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml
index 5bcf222a728..20d68487301 100644
--- a/sql/share/charsets/hebrew.xml
+++ b/sql/share/charsets/hebrew.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -40,7 +39,7 @@
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
- 02 02 02 02 02 02 02 02 02 02 02 00 00 00 00 00
+ 02 02 02 02 02 02 02 02 02 02 02 00 00 20 20 00
</map>
</ctype>
@@ -106,7 +105,7 @@
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2017
05D0 05D1 05D2 05D3 05D4 05D5 05D6 05D7 05D8 05D9 05DA 05DB 05DC 05DD 05DE 05DF
-05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 0000 0000 0000
+05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 200E 200F 0000
</map>
</unicode>
diff --git a/sql/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml
index 35224f8c544..3ab383ef386 100644
--- a/sql/share/charsets/hp8.xml
+++ b/sql/share/charsets/hp8.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml
index 6332891ef23..7335a0f428d 100644
--- a/sql/share/charsets/keybcs2.xml
+++ b/sql/share/charsets/keybcs2.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml
index 033597e9bfc..2d8473f6440 100644
--- a/sql/share/charsets/koi8r.xml
+++ b/sql/share/charsets/koi8r.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/koi8u.xml b/sql/share/charsets/koi8u.xml
index 4f5fa35af3d..16177627ffe 100644
--- a/sql/share/charsets/koi8u.xml
+++ b/sql/share/charsets/koi8u.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml
index 5814a17b0e1..88ceff440d5 100644
--- a/sql/share/charsets/latin1.xml
+++ b/sql/share/charsets/latin1.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml
index 7f00148a1df..6b887b927a4 100644
--- a/sql/share/charsets/latin2.xml
+++ b/sql/share/charsets/latin2.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml
index 5004f045889..9c23200a46d 100644
--- a/sql/share/charsets/latin5.xml
+++ b/sql/share/charsets/latin5.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml
index dd87a1a2d89..02d3ff8b17e 100644
--- a/sql/share/charsets/latin7.xml
+++ b/sql/share/charsets/latin7.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/macce.xml b/sql/share/charsets/macce.xml
index 61f6d79b34f..21e303609cf 100644
--- a/sql/share/charsets/macce.xml
+++ b/sql/share/charsets/macce.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/macroman.xml b/sql/share/charsets/macroman.xml
index 36c8e8cf13a..2b43fe73b07 100644
--- a/sql/share/charsets/macroman.xml
+++ b/sql/share/charsets/macroman.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/charsets/swe7.xml b/sql/share/charsets/swe7.xml
index 2b8ff4edcce..17fa6b7d9bc 100644
--- a/sql/share/charsets/swe7.xml
+++ b/sql/share/charsets/swe7.xml
@@ -7,8 +7,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 48f2ecdee89..b5bfe8a691c 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -51,204 +51,204 @@ ER_YES
spa "SI"
ukr "ôáë"
ER_CANT_CREATE_FILE
- cze "Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)"
- dan "Kan ikke oprette filen '%-.64s' (Fejlkode: %d)"
- nla "Kan file '%-.64s' niet aanmaken (Errcode: %d)"
+ cze "Nemohu vytvo-Bøit soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke oprette filen '%-.200s' (Fejlkode: %d)"
+ nla "Kan file '%-.200s' niet aanmaken (Errcode: %d)"
eng "Can't create file '%-.200s' (errno: %d)"
- est "Ei suuda luua faili '%-.64s' (veakood: %d)"
- fre "Ne peut créer le fichier '%-.64s' (Errcode: %d)"
- ger "Kann Datei '%-.64s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.64s' file nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare il file '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
- kor "È­ÀÏ '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette fila '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette fila '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)"
- por "Não pode criar o arquivo '%-.64s' (erro no. %d)"
- rum "Nu pot sa creez fisierul '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram file '%-.64s' (errno: %d)"
- slo "Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)"
- spa "No puedo crear archivo '%-.64s' (Error: %d)"
- swe "Kan inte skapa filen '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ est "Ei suuda luua faili '%-.200s' (veakood: %d)"
+ fre "Ne peut créer le fichier '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.200s' file nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
+ kor "È­ÀÏ '%-.200s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette fila '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette fila '%-.200s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ pliku '%-.200s' (Kod b³êdu: %d)"
+ por "Não pode criar o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa creez fisierul '%-.200s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram file '%-.200s' (errno: %d)"
+ slo "Nemô¾em vytvori» súbor '%-.200s' (chybový kód: %d)"
+ spa "No puedo crear archivo '%-.200s' (Error: %d)"
+ swe "Kan inte skapa filen '%-.200s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_CREATE_TABLE
- cze "Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)"
- dan "Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)"
- nla "Kan tabel '%-.64s' niet aanmaken (Errcode: %d)"
- eng "Can't create table '%-.64s' (errno: %d)"
- jps "'%-.64s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda luua tabelit '%-.64s' (veakood: %d)"
- fre "Ne peut créer la table '%-.64s' (Errcode: %d)"
- ger "Kann Tabelle '%-.64s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.64s' tabla nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare la tabella '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)"
- kor "Å×À̺í '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)"
- por "Não pode criar a tabela '%-.64s' (erro no. %d)"
- rum "Nu pot sa creez tabla '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram tabelu '%-.64s' (errno: %d)"
- slo "Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)"
- spa "No puedo crear tabla '%-.64s' (Error: %d)"
- swe "Kan inte skapa tabellen '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Nemohu vytvo-Bøit tabulku '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke oprette tabellen '%-.200s' (Fejlkode: %d)"
+ nla "Kan tabel '%-.200s' niet aanmaken (Errcode: %d)"
+ eng "Can't create table '%-.200s' (errno: %d)"
+ jps "'%-.200s' ƒe[ƒuƒ‹‚ªì‚ê‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda luua tabelit '%-.200s' (veakood: %d)"
+ fre "Ne peut créer la table '%-.200s' (Errcode: %d)"
+ ger "Kann Tabelle '%-.200s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.200s' tabla nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare la tabella '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Æ¡¼¥Ö¥ë¤¬ºî¤ì¤Þ¤»¤ó.(errno: %d)"
+ kor "Å×À̺í '%-.200s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette tabellen '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette tabellen '%-.200s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ tabeli '%-.200s' (Kod b³êdu: %d)"
+ por "Não pode criar a tabela '%-.200s' (erro no. %d)"
+ rum "Nu pot sa creez tabla '%-.200s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram tabelu '%-.200s' (errno: %d)"
+ slo "Nemô¾em vytvori» tabuµku '%-.200s' (chybový kód: %d)"
+ spa "No puedo crear tabla '%-.200s' (Error: %d)"
+ swe "Kan inte skapa tabellen '%-.200s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_CREATE_DB
- cze "Nemohu vytvo-Bøit databázi '%-.64s' (chybový kód: %d)"
- dan "Kan ikke oprette databasen '%-.64s' (Fejlkode: %d)"
- nla "Kan database '%-.64s' niet aanmaken (Errcode: %d)"
- eng "Can't create database '%-.64s' (errno: %d)"
- jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
- est "Ei suuda luua andmebaasi '%-.64s' (veakood: %d)"
- fre "Ne peut créer la base '%-.64s' (Erreur %d)"
- ger "Kann Datenbank '%-.64s' nicht erzeugen (Fehler: %d)"
- greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Az '%-.64s' adatbazis nem hozhato letre (hibakod: %d)"
- ita "Impossibile creare il database '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
- kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke opprette databasen '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje opprette databasen '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na stworzyæ bazy danych '%-.64s' (Kod b³êdu: %d)"
- por "Não pode criar o banco de dados '%-.64s' (erro no. %d)"
- rum "Nu pot sa creez baza de date '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da kreiram bazu '%-.64s' (errno: %d)"
- slo "Nemô¾em vytvori» databázu '%-.64s' (chybový kód: %d)"
- spa "No puedo crear base de datos '%-.64s' (Error: %d)"
- swe "Kan inte skapa databasen '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Nemohu vytvo-Bøit databázi '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke oprette databasen '%-.192s' (Fejlkode: %d)"
+ nla "Kan database '%-.192s' niet aanmaken (Errcode: %d)"
+ eng "Can't create database '%-.192s' (errno: %d)"
+ jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ (errno: %d)",
+ est "Ei suuda luua andmebaasi '%-.192s' (veakood: %d)"
+ fre "Ne peut créer la base '%-.192s' (Erreur %d)"
+ ger "Kann Datenbank '%-.192s' nicht erzeugen (Fehler: %d)"
+ greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Az '%-.192s' adatbazis nem hozhato letre (hibakod: %d)"
+ ita "Impossibile creare il database '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó (errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke opprette databasen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje opprette databasen '%-.192s' (Feilkode: %d)"
+ pol "Nie mo¿na stworzyæ bazy danych '%-.192s' (Kod b³êdu: %d)"
+ por "Não pode criar o banco de dados '%-.192s' (erro no. %d)"
+ rum "Nu pot sa creez baza de date '%-.192s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da kreiram bazu '%-.192s' (errno: %d)"
+ slo "Nemô¾em vytvori» databázu '%-.192s' (chybový kód: %d)"
+ spa "No puedo crear base de datos '%-.192s' (Error: %d)"
+ swe "Kan inte skapa databasen '%-.192s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_DB_CREATE_EXISTS
- cze "Nemohu vytvo-Bøit databázi '%-.64s'; databáze ji¾ existuje"
- dan "Kan ikke oprette databasen '%-.64s'; databasen eksisterer"
- nla "Kan database '%-.64s' niet aanmaken; database bestaat reeds"
- eng "Can't create database '%-.64s'; database exists"
- jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ.Šù‚É‚»‚̃f[ƒ^ƒx[ƒX‚ª‘¶Ý‚µ‚Ü‚·",
- est "Ei suuda luua andmebaasi '%-.64s': andmebaas juba eksisteerib"
- fre "Ne peut créer la base '%-.64s'; elle existe déjà"
- ger "Kann Datenbank '%-.64s' nicht erzeugen. Datenbank existiert bereits"
- greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç"
- hun "Az '%-.64s' adatbazis nem hozhato letre Az adatbazis mar letezik"
- ita "Impossibile creare il database '%-.64s'; il database esiste"
- jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹"
- kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ"
- nor "Kan ikke opprette databasen '%-.64s'; databasen eksisterer"
- norwegian-ny "Kan ikkje opprette databasen '%-.64s'; databasen eksisterer"
- pol "Nie mo¿na stworzyæ bazy danych '%-.64s'; baza danych ju¿ istnieje"
- por "Não pode criar o banco de dados '%-.64s'; este banco de dados já existe"
- rum "Nu pot sa creez baza de date '%-.64s'; baza de date exista deja"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Ne mogu da kreiram bazu '%-.64s'; baza veæ postoji."
- slo "Nemô¾em vytvori» databázu '%-.64s'; databáza existuje"
- spa "No puedo crear base de datos '%-.64s'; la base de datos ya existe"
- swe "Databasen '%-.64s' existerar redan"
- ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤"
+ cze "Nemohu vytvo-Bøit databázi '%-.192s'; databáze ji¾ existuje"
+ dan "Kan ikke oprette databasen '%-.192s'; databasen eksisterer"
+ nla "Kan database '%-.192s' niet aanmaken; database bestaat reeds"
+ eng "Can't create database '%-.192s'; database exists"
+ jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ªì‚ê‚Ü‚¹‚ñ.Šù‚É‚»‚̃f[ƒ^ƒx[ƒX‚ª‘¶Ý‚µ‚Ü‚·",
+ est "Ei suuda luua andmebaasi '%-.192s': andmebaas juba eksisteerib"
+ fre "Ne peut créer la base '%-.192s'; elle existe déjà"
+ ger "Kann Datenbank '%-.192s' nicht erzeugen. Datenbank existiert bereits"
+ greek "Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.192s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç"
+ hun "Az '%-.192s' adatbazis nem hozhato letre Az adatbazis mar letezik"
+ ita "Impossibile creare il database '%-.192s'; il database esiste"
+ jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ºî¤ì¤Þ¤»¤ó.´û¤Ë¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬Â¸ºß¤·¤Þ¤¹"
+ kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ ¸¸µéÁö ¸øÇß½À´Ï´Ù.. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÔ"
+ nor "Kan ikke opprette databasen '%-.192s'; databasen eksisterer"
+ norwegian-ny "Kan ikkje opprette databasen '%-.192s'; databasen eksisterer"
+ pol "Nie mo¿na stworzyæ bazy danych '%-.192s'; baza danych ju¿ istnieje"
+ por "Não pode criar o banco de dados '%-.192s'; este banco de dados já existe"
+ rum "Nu pot sa creez baza de date '%-.192s'; baza de date exista deja"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Ne mogu da kreiram bazu '%-.192s'; baza veæ postoji."
+ slo "Nemô¾em vytvori» databázu '%-.192s'; databáza existuje"
+ spa "No puedo crear base de datos '%-.192s'; la base de datos ya existe"
+ swe "Databasen '%-.192s' existerar redan"
+ ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤"
ER_DB_DROP_EXISTS
- cze "Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje"
- dan "Kan ikke slette (droppe) '%-.64s'; databasen eksisterer ikke"
- nla "Kan database '%-.64s' niet verwijderen; database bestaat niet"
- eng "Can't drop database '%-.64s'; database doesn't exist"
- jps "'%-.64s' ƒf[ƒ^ƒx[ƒX‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ. ‚»‚̃f[ƒ^ƒx[ƒX‚ª‚È‚¢‚̂ł·.",
- est "Ei suuda kustutada andmebaasi '%-.64s': andmebaasi ei eksisteeri"
- fre "Ne peut effacer la base '%-.64s'; elle n'existe pas"
- ger "Kann Datenbank '%-.64s' nicht löschen; Datenbank nicht vorhanden"
- greek "Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé"
- hun "A(z) '%-.64s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik"
- ita "Impossibile cancellare '%-.64s'; il database non esiste"
- jpn "'%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹."
- kor "µ¥ÀÌŸº£À̽º '%-.64s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ "
- nor "Kan ikke fjerne (drop) '%-.64s'; databasen eksisterer ikke"
- norwegian-ny "Kan ikkje fjerne (drop) '%-.64s'; databasen eksisterer ikkje"
- pol "Nie mo¿na usun?æ bazy danych '%-.64s'; baza danych nie istnieje"
- por "Não pode eliminar o banco de dados '%-.64s'; este banco de dados não existe"
- rum "Nu pot sa drop baza de date '%-.64s'; baza da date este inexistenta"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ"
- serbian "Ne mogu da izbrišem bazu '%-.64s'; baza ne postoji."
- slo "Nemô¾em zmaza» databázu '%-.64s'; databáza neexistuje"
- spa "No puedo eliminar base de datos '%-.64s'; la base de datos no existe"
- swe "Kan inte radera databasen '%-.64s'; databasen finns inte"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤"
+ cze "Nemohu zru-B¹it databázi '%-.192s', databáze neexistuje"
+ dan "Kan ikke slette (droppe) '%-.192s'; databasen eksisterer ikke"
+ nla "Kan database '%-.192s' niet verwijderen; database bestaat niet"
+ eng "Can't drop database '%-.192s'; database doesn't exist"
+ jps "'%-.192s' ƒf[ƒ^ƒx[ƒX‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ. ‚»‚̃f[ƒ^ƒx[ƒX‚ª‚È‚¢‚̂ł·.",
+ est "Ei suuda kustutada andmebaasi '%-.192s': andmebaasi ei eksisteeri"
+ fre "Ne peut effacer la base '%-.192s'; elle n'existe pas"
+ ger "Kann Datenbank '%-.192s' nicht löschen; Datenbank nicht vorhanden"
+ greek "Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.192s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé"
+ hun "A(z) '%-.192s' adatbazis nem szuntetheto meg. Az adatbazis nem letezik"
+ ita "Impossibile cancellare '%-.192s'; il database non esiste"
+ jpn "'%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤òÇË´þ¤Ç¤­¤Þ¤»¤ó. ¤½¤Î¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬¤Ê¤¤¤Î¤Ç¤¹."
+ kor "µ¥ÀÌŸº£À̽º '%-.192s'¸¦ Á¦°ÅÇÏÁö ¸øÇß½À´Ï´Ù. µ¥ÀÌŸº£À̽º°¡ Á¸ÀçÇÏÁö ¾ÊÀ½ "
+ nor "Kan ikke fjerne (drop) '%-.192s'; databasen eksisterer ikke"
+ norwegian-ny "Kan ikkje fjerne (drop) '%-.192s'; databasen eksisterer ikkje"
+ pol "Nie mo¿na usun?æ bazy danych '%-.192s'; baza danych nie istnieje"
+ por "Não pode eliminar o banco de dados '%-.192s'; este banco de dados não existe"
+ rum "Nu pot sa drop baza de date '%-.192s'; baza da date este inexistenta"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.192s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ"
+ serbian "Ne mogu da izbrišem bazu '%-.192s'; baza ne postoji."
+ slo "Nemô¾em zmaza» databázu '%-.192s'; databáza neexistuje"
+ spa "No puedo eliminar base de datos '%-.192s'; la base de datos no existe"
+ swe "Kan inte radera databasen '%-.192s'; databasen finns inte"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.192s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤"
ER_DB_DROP_DELETE
- cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)"
- dan "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejlkode %d)"
- nla "Fout bij verwijderen database (kan '%-.64s' niet verwijderen, Errcode: %d)"
- eng "Error dropping database (can't delete '%-.64s', errno: %d)"
- jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð휂ł«‚Ü‚¹‚ñ, errno: %d)",
- est "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.64s', veakood: %d)"
- fre "Ne peut effacer la base '%-.64s' (erreur %d)"
- ger "Fehler beim Löschen der Datenbank ('%-.64s' kann nicht gelöscht werden, Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.64s', êùäéêüò ëÜèïõò: %d)"
- hun "Adatbazis megszuntetesi hiba ('%-.64s' nem torolheto, hibakod: %d)"
- ita "Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)"
- jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)"
- kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.64s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
- nor "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)"
- norwegian-ny "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)"
- pol "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)"
- por "Erro ao eliminar banco de dados (não pode eliminar '%-.64s' - erro no. %d)"
- rum "Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.64s', ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)"
- slo "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)"
- spa "Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)"
- swe "Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s', ÐÏÍÉÌËÁ: %d)"
+ cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.192s', chyba %d)"
+ dan "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.192s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan '%-.192s' niet verwijderen, Errcode: %d)"
+ eng "Error dropping database (can't delete '%-.192s', errno: %d)"
+ jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.192s' ‚ð휂ł«‚Ü‚¹‚ñ, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.192s', veakood: %d)"
+ fre "Ne peut effacer la base '%-.192s' (erreur %d)"
+ ger "Fehler beim Löschen der Datenbank ('%-.192s' kann nicht gelöscht werden, Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.192s', êùäéêüò ëÜèïõò: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.192s' nem torolheto, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile cancellare '%-.192s', errno: %d)"
+ jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.192s' ¤òºï½ü¤Ç¤­¤Þ¤»¤ó, errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯('%-.192s'¸¦ »èÁ¦ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.192s', feil %d)"
+ norwegian-ny "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.192s', feil %d)"
+ pol "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.192s', b³?d %d)"
+ por "Erro ao eliminar banco de dados (não pode eliminar '%-.192s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa sterg '%-.192s', Eroare: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.192s', ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.192s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.192s', chybový kód: %d)"
+ spa "Error eliminando la base de datos(no puedo borrar '%-.192s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera '%-.192s'. Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.192s', ÐÏÍÉÌËÁ: %d)"
ER_DB_DROP_RMDIR
- cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)"
- dan "Fejl ved sletting af database (kan ikke slette folderen '%-.64s', Fejlkode %d)"
- nla "Fout bij verwijderen database (kan rmdir '%-.64s' niet uitvoeren, Errcode: %d)"
- eng "Error dropping database (can't rmdir '%-.64s', errno: %d)"
- jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.64s' ‚ð rmdir ‚Å‚«‚Ü‚¹‚ñ, errno: %d)",
- est "Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.64s', veakood: %d)"
- fre "Erreur en effaçant la base (rmdir '%-.64s', erreur %d)"
- ger "Fehler beim Löschen der Datenbank (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.64s', êùäéêüò ëÜèïõò: %d)"
- hun "Adatbazis megszuntetesi hiba ('%-.64s' nem szuntetheto meg, hibakod: %d)"
- ita "Errore durante la cancellazione del database (impossibile rmdir '%-.64s', errno: %d)"
- jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.64s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)"
- kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.64s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
- nor "Feil ved sletting av database (kan ikke slette katalogen '%-.64s', feil %d)"
- norwegian-ny "Feil ved sletting av database (kan ikkje slette katalogen '%-.64s', feil %d)"
- pol "B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.64s', b³?d %d)"
- por "Erro ao eliminar banco de dados (não pode remover diretório '%-.64s' - erro no. %d)"
- rum "Eroare dropuind baza de date (nu pot sa rmdir '%-.64s', Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.64s', ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)"
- slo "Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.64s', chybový kód: %d)"
- spa "Error eliminando la base de datos (No puedo borrar directorio '%-.64s', error %d)"
- swe "Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÔÅËÕ '%-.64s', ÐÏÍÉÌËÁ: %d)"
+ cze "Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.192s', chyba %d)"
+ dan "Fejl ved sletting af database (kan ikke slette folderen '%-.192s', Fejlkode %d)"
+ nla "Fout bij verwijderen database (kan rmdir '%-.192s' niet uitvoeren, Errcode: %d)"
+ eng "Error dropping database (can't rmdir '%-.192s', errno: %d)"
+ jps "ƒf[ƒ^ƒx[ƒX”jŠüƒGƒ‰[ ('%-.192s' ‚ð rmdir ‚Å‚«‚Ü‚¹‚ñ, errno: %d)",
+ est "Viga andmebaasi kustutamisel (ei suuda kustutada kataloogi '%-.192s', veakood: %d)"
+ fre "Erreur en effaçant la base (rmdir '%-.192s', erreur %d)"
+ ger "Fehler beim Löschen der Datenbank (Verzeichnis '%-.192s' kann nicht gelöscht werden, Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.192s', êùäéêüò ëÜèïõò: %d)"
+ hun "Adatbazis megszuntetesi hiba ('%-.192s' nem szuntetheto meg, hibakod: %d)"
+ ita "Errore durante la cancellazione del database (impossibile rmdir '%-.192s', errno: %d)"
+ jpn "¥Ç¡¼¥¿¥Ù¡¼¥¹ÇË´þ¥¨¥é¡¼ ('%-.192s' ¤ò rmdir ¤Ç¤­¤Þ¤»¤ó, errno: %d)"
+ kor "µ¥ÀÌŸº£À̽º Á¦°Å ¿¡·¯(rmdir '%-.192s'¸¦ ÇÒ ¼ö ¾øÀ¾´Ï´Ù, ¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved sletting av database (kan ikke slette katalogen '%-.192s', feil %d)"
+ norwegian-ny "Feil ved sletting av database (kan ikkje slette katalogen '%-.192s', feil %d)"
+ pol "B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.192s', b³?d %d)"
+ por "Erro ao eliminar banco de dados (não pode remover diretório '%-.192s' - erro no. %d)"
+ rum "Eroare dropuind baza de date (nu pot sa rmdir '%-.192s', Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ËÁÔÁÌÏÇ '%-.192s', ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.192s', errno: %d)"
+ slo "Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.192s', chybový kód: %d)"
+ spa "Error eliminando la base de datos (No puedo borrar directorio '%-.192s', error %d)"
+ swe "Fel vid radering av databasen (Kan inte radera biblioteket '%-.192s'. Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÔÅËÕ '%-.192s', ÐÏÍÉÌËÁ: %d)"
ER_CANT_DELETE_FILE
- cze "Chyba p-Bøi výmazu '%-.64s' (chybový kód: %d)"
- dan "Fejl ved sletning af '%-.64s' (Fejlkode: %d)"
- nla "Fout bij het verwijderen van '%-.64s' (Errcode: %d)"
- eng "Error on delete of '%-.64s' (errno: %d)"
- jps "'%-.64s' ‚Ì휂ªƒGƒ‰[ (errno: %d)",
- est "Viga '%-.64s' kustutamisel (veakood: %d)"
- fre "Erreur en effaçant '%-.64s' (Errcode: %d)"
- ger "Fehler beim Löschen von '%-.64s' (Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Torlesi hiba: '%-.64s' (hibakod: %d)"
- ita "Errore durante la cancellazione di '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)"
- kor "'%-.64s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved sletting av '%-.64s' (Feilkode: %d)"
- norwegian-ny "Feil ved sletting av '%-.64s' (Feilkode: %d)"
- pol "B³?d podczas usuwania '%-.64s' (Kod b³êdu: %d)"
- por "Erro na remoção de '%-.64s' (erro no. %d)"
- rum "Eroare incercind sa delete '%-.64s' (Eroare: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri brisanju '%-.64s' (errno: %d)"
- slo "Chyba pri mazaní '%-.64s' (chybový kód: %d)"
- spa "Error en el borrado de '%-.64s' (Error: %d)"
- swe "Kan inte radera filen '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Chyba p-Bøi výmazu '%-.192s' (chybový kód: %d)"
+ dan "Fejl ved sletning af '%-.192s' (Fejlkode: %d)"
+ nla "Fout bij het verwijderen van '%-.192s' (Errcode: %d)"
+ eng "Error on delete of '%-.192s' (errno: %d)"
+ jps "'%-.192s' ‚Ì휂ªƒGƒ‰[ (errno: %d)",
+ est "Viga '%-.192s' kustutamisel (veakood: %d)"
+ fre "Erreur en effaçant '%-.192s' (Errcode: %d)"
+ ger "Fehler beim Löschen von '%-.192s' (Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Torlesi hiba: '%-.192s' (hibakod: %d)"
+ ita "Errore durante la cancellazione di '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ¤Îºï½ü¤¬¥¨¥é¡¼ (errno: %d)"
+ kor "'%-.192s' »èÁ¦ Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved sletting av '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Feil ved sletting av '%-.192s' (Feilkode: %d)"
+ pol "B³?d podczas usuwania '%-.192s' (Kod b³êdu: %d)"
+ por "Erro na remoção de '%-.192s' (erro no. %d)"
+ rum "Eroare incercind sa delete '%-.192s' (Eroare: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri brisanju '%-.192s' (errno: %d)"
+ slo "Chyba pri mazaní '%-.192s' (chybový kód: %d)"
+ spa "Error en el borrado de '%-.192s' (Error: %d)"
+ swe "Kan inte radera filen '%-.192s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_FIND_SYSTEM_REC
cze "Nemohu -Bèíst záznam v systémové tabulce"
dan "Kan ikke læse posten i systemfolderen"
@@ -275,30 +275,30 @@ ER_CANT_FIND_SYSTEM_REC
swe "Hittar inte posten i systemregistret"
ukr "îÅ ÍÏÖÕ ÚÞÉÔÁÔÉ ÚÁÐÉÓ Ú ÓÉÓÔÅÍÎϧ ÔÁÂÌÉæ"
ER_CANT_GET_STAT
- cze "Nemohu z-Bískat stav '%-.64s' (chybový kód: %d)"
- dan "Kan ikke læse status af '%-.64s' (Fejlkode: %d)"
- nla "Kan de status niet krijgen van '%-.64s' (Errcode: %d)"
+ cze "Nemohu z-Bískat stav '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke læse status af '%-.200s' (Fejlkode: %d)"
+ nla "Kan de status niet krijgen van '%-.200s' (Errcode: %d)"
eng "Can't get status of '%-.200s' (errno: %d)"
- jps "'%-.64s' ‚̃XƒeƒCƒ^ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñ. (errno: %d)",
- est "Ei suuda lugeda '%-.64s' olekut (veakood: %d)"
- fre "Ne peut obtenir le status de '%-.64s' (Errcode: %d)"
- ger "Kann Status von '%-.64s' nicht ermitteln (Fehler: %d)"
- greek "Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.64s' statusza nem allapithato meg (hibakod: %d)"
- ita "Impossibile leggere lo stato di '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)"
- kor "'%-.64s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke lese statusen til '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje lese statusen til '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na otrzymaæ statusu '%-.64s' (Kod b³êdu: %d)"
- por "Não pode obter o status de '%-.64s' (erro no. %d)"
- rum "Nu pot sa obtin statusul lui '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da dobijem stanje file-a '%-.64s' (errno: %d)"
- slo "Nemô¾em zisti» stav '%-.64s' (chybový kód: %d)"
- spa "No puedo obtener el estado de '%-.64s' (Error: %d)"
- swe "Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÏÔÒÉÍÁÔÉ ÓÔÁÔÕÓ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ jps "'%-.200s' ‚̃XƒeƒCƒ^ƒX‚ª“¾‚ç‚ê‚Ü‚¹‚ñ. (errno: %d)",
+ est "Ei suuda lugeda '%-.200s' olekut (veakood: %d)"
+ fre "Ne peut obtenir le status de '%-.200s' (Errcode: %d)"
+ ger "Kann Status von '%-.200s' nicht ermitteln (Fehler: %d)"
+ greek "Áäýíáôç ç ëÞøç ðëçñïöïñéþí ãéá ôçí êáôÜóôáóç ôïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.200s' statusza nem allapithato meg (hibakod: %d)"
+ ita "Impossibile leggere lo stato di '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¤Î¥¹¥Æ¥¤¥¿¥¹¤¬ÆÀ¤é¤ì¤Þ¤»¤ó. (errno: %d)"
+ kor "'%-.200s'ÀÇ »óŸ¦ ¾òÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke lese statusen til '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese statusen til '%-.200s' (Feilkode: %d)"
+ pol "Nie mo¿na otrzymaæ statusu '%-.200s' (Kod b³êdu: %d)"
+ por "Não pode obter o status de '%-.200s' (erro no. %d)"
+ rum "Nu pot sa obtin statusul lui '%-.200s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÓÔÁÔÕÓÎÕÀ ÉÎÆÏÒÍÁÃÉÀ Ï '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da dobijem stanje file-a '%-.200s' (errno: %d)"
+ slo "Nemô¾em zisti» stav '%-.200s' (chybový kód: %d)"
+ spa "No puedo obtener el estado de '%-.200s' (Error: %d)"
+ swe "Kan inte läsa filinformationen (stat) från '%-.200s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÏÔÒÉÍÁÔÉ ÓÔÁÔÕÓ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_GET_WD
cze "Chyba p-Bøi zji¹»ování pracovní adresáø (chybový kód: %d)"
dan "Kan ikke læse aktive folder (Fejlkode: %d)"
@@ -350,128 +350,128 @@ ER_CANT_LOCK
swe "Kan inte låsa filen. (Felkod: %d)"
ukr "îÅ ÍÏÖÕ ÚÁÂÌÏËÕ×ÁÔÉ ÆÁÊÌ (ÐÏÍÉÌËÁ: %d)"
ER_CANT_OPEN_FILE
- cze "Nemohu otev-Bøít soubor '%-.64s' (chybový kód: %d)"
- dan "Kan ikke åbne fil: '%-.64s' (Fejlkode: %d)"
- nla "Kan de file '%-.64s' niet openen (Errcode: %d)"
+ cze "Nemohu otev-Bøít soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke åbne fil: '%-.200s' (Fejlkode: %d)"
+ nla "Kan de file '%-.200s' niet openen (Errcode: %d)"
eng "Can't open file: '%-.200s' (errno: %d)"
- jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Ei suuda avada faili '%-.64s' (veakood: %d)"
- fre "Ne peut ouvrir le fichier: '%-.64s' (Errcode: %d)"
- ger "Kann Datei '%-.64s' nicht öffnen (Fehler: %d)"
- greek "Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A '%-.64s' file nem nyithato meg (hibakod: %d)"
- ita "Impossibile aprire il file: '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke åpne fila: '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje åpne fila: '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na otworzyæ pliku: '%-.64s' (Kod b³êdu: %d)"
- por "Não pode abrir o arquivo '%-.64s' (erro no. %d)"
- rum "Nu pot sa deschid fisierul: '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da otvorim file: '%-.64s' (errno: %d)"
- slo "Nemô¾em otvori» súbor: '%-.64s' (chybový kód: %d)"
- spa "No puedo abrir archivo: '%-.64s' (Error: %d)"
- swe "Kan inte använda '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Ei suuda avada faili '%-.200s' (veakood: %d)"
+ fre "Ne peut ouvrir le fichier: '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht öffnen (Fehler: %d)"
+ greek "Äåí åßíáé äõíáôü íá áíïé÷ôåß ôï áñ÷åßï: '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A '%-.200s' file nem nyithato meg (hibakod: %d)"
+ ita "Impossibile aprire il file: '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "È­ÀÏÀ» ¿­Áö ¸øÇß½À´Ï´Ù.: '%-.200s' (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke åpne fila: '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje åpne fila: '%-.200s' (Feilkode: %d)"
+ pol "Nie mo¿na otworzyæ pliku: '%-.200s' (Kod b³êdu: %d)"
+ por "Não pode abrir o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa deschid fisierul: '%-.200s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÆÁÊÌ: '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da otvorim file: '%-.200s' (errno: %d)"
+ slo "Nemô¾em otvori» súbor: '%-.200s' (chybový kód: %d)"
+ spa "No puedo abrir archivo: '%-.200s' (Error: %d)"
+ swe "Kan inte använda '%-.200s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÆÁÊÌ: '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_FILE_NOT_FOUND
- cze "Nemohu naj-Bít soubor '%-.64s' (chybový kód: %d)"
- dan "Kan ikke finde fila: '%-.64s' (Fejlkode: %d)"
- nla "Kan de file: '%-.64s' niet vinden (Errcode: %d)"
+ cze "Nemohu naj-Bít soubor '%-.200s' (chybový kód: %d)"
+ dan "Kan ikke finde fila: '%-.200s' (Fejlkode: %d)"
+ nla "Kan de file: '%-.200s' niet vinden (Errcode: %d)"
eng "Can't find file: '%-.200s' (errno: %d)"
- jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ðŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda leida faili '%-.64s' (veakood: %d)"
- fre "Ne peut trouver le fichier: '%-.64s' (Errcode: %d)"
- ger "Kann Datei '%-.64s' nicht finden (Fehler: %d)"
- greek "Äåí âñÝèçêå ôï áñ÷åßï: '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.64s' file nem talalhato (hibakod: %d)"
- ita "Impossibile trovare il file: '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
- kor "È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.64s' (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke finne fila: '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje finne fila: '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na znale¥æ pliku: '%-.64s' (Kod b³êdu: %d)"
- por "Não pode encontrar o arquivo '%-.64s' (erro no. %d)"
- rum "Nu pot sa gasesc fisierul: '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da pronaðem file: '%-.64s' (errno: %d)"
- slo "Nemô¾em nájs» súbor: '%-.64s' (chybový kód: %d)"
- spa "No puedo encontrar archivo: '%-.64s' (Error: %d)"
- swe "Hittar inte filen '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÁÊÌ: '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ðŒ©•t‚¯‚鎖‚ª‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda leida faili '%-.200s' (veakood: %d)"
+ fre "Ne peut trouver le fichier: '%-.200s' (Errcode: %d)"
+ ger "Kann Datei '%-.200s' nicht finden (Fehler: %d)"
+ greek "Äåí âñÝèçêå ôï áñ÷åßï: '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.200s' file nem talalhato (hibakod: %d)"
+ ita "Impossibile trovare il file: '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò¸«ÉÕ¤±¤ë»ö¤¬¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
+ kor "È­ÀÏÀ» ãÁö ¸øÇß½À´Ï´Ù.: '%-.200s' (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke finne fila: '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje finne fila: '%-.200s' (Feilkode: %d)"
+ pol "Nie mo¿na znale¥æ pliku: '%-.200s' (Kod b³êdu: %d)"
+ por "Não pode encontrar o arquivo '%-.200s' (erro no. %d)"
+ rum "Nu pot sa gasesc fisierul: '%-.200s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÆÁÊÌ: '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da pronaðem file: '%-.200s' (errno: %d)"
+ slo "Nemô¾em nájs» súbor: '%-.200s' (chybový kód: %d)"
+ spa "No puedo encontrar archivo: '%-.200s' (Error: %d)"
+ swe "Hittar inte filen '%-.200s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÁÊÌ: '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_READ_DIR
- cze "Nemohu -Bèíst adresáø '%-.64s' (chybový kód: %d)"
- dan "Kan ikke læse folder '%-.64s' (Fejlkode: %d)"
- nla "Kan de directory niet lezen van '%-.64s' (Errcode: %d)"
- eng "Can't read dir of '%-.64s' (errno: %d)"
- jps "'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚ª“ǂ߂܂¹‚ñ.(errno: %d)",
- est "Ei suuda lugeda kataloogi '%-.64s' (veakood: %d)"
- fre "Ne peut lire le répertoire de '%-.64s' (Errcode: %d)"
- ger "Verzeichnis von '%-.64s' nicht lesbar (Fehler: %d)"
- greek "Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "A(z) '%-.64s' konyvtar nem olvashato. (hibakod: %d)"
- ita "Impossibile leggere la directory di '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬ÆÉ¤á¤Þ¤»¤ó.(errno: %d)"
- kor "'%-.64s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke lese katalogen '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje lese katalogen '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na odczytaæ katalogu '%-.64s' (Kod b³êdu: %d)"
- por "Não pode ler o diretório de '%-.64s' (erro no. %d)"
- rum "Nu pot sa citesc directorul '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da proèitam direktorijum '%-.64s' (errno: %d)"
- slo "Nemô¾em èíta» adresár '%-.64s' (chybový kód: %d)"
- spa "No puedo leer el directorio de '%-.64s' (Error: %d)"
- swe "Kan inte läsa från bibliotek '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Nemohu -Bèíst adresáø '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke læse folder '%-.192s' (Fejlkode: %d)"
+ nla "Kan de directory niet lezen van '%-.192s' (Errcode: %d)"
+ eng "Can't read dir of '%-.192s' (errno: %d)"
+ jps "'%-.192s' ƒfƒBƒŒƒNƒgƒŠ‚ª“ǂ߂܂¹‚ñ.(errno: %d)",
+ est "Ei suuda lugeda kataloogi '%-.192s' (veakood: %d)"
+ fre "Ne peut lire le répertoire de '%-.192s' (Errcode: %d)"
+ ger "Verzeichnis von '%-.192s' nicht lesbar (Fehler: %d)"
+ greek "Äåí åßíáé äõíáôü íá äéáâáóôåß ï öÜêåëëïò ôïõ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "A(z) '%-.192s' konyvtar nem olvashato. (hibakod: %d)"
+ ita "Impossibile leggere la directory di '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ¥Ç¥£¥ì¥¯¥È¥ê¤¬ÆÉ¤á¤Þ¤»¤ó.(errno: %d)"
+ kor "'%-.192s'µð·ºÅ丮¸¦ ÀÐÁö ¸øÇß½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke lese katalogen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje lese katalogen '%-.192s' (Feilkode: %d)"
+ pol "Nie mo¿na odczytaæ katalogu '%-.192s' (Kod b³êdu: %d)"
+ por "Não pode ler o diretório de '%-.192s' (erro no. %d)"
+ rum "Nu pot sa citesc directorul '%-.192s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÞÉÔÁÔØ ËÁÔÁÌÏÇ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da proèitam direktorijum '%-.192s' (errno: %d)"
+ slo "Nemô¾em èíta» adresár '%-.192s' (chybový kód: %d)"
+ spa "No puedo leer el directorio de '%-.192s' (Error: %d)"
+ swe "Kan inte läsa från bibliotek '%-.192s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_CANT_SET_WD
- cze "Nemohu zm-Bìnit adresáø na '%-.64s' (chybový kód: %d)"
- dan "Kan ikke skifte folder til '%-.64s' (Fejlkode: %d)"
- nla "Kan de directory niet veranderen naar '%-.64s' (Errcode: %d)"
- eng "Can't change dir to '%-.64s' (errno: %d)"
- jps "'%-.64s' ƒfƒBƒŒƒNƒgƒŠ‚É chdir ‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
- est "Ei suuda siseneda kataloogi '%-.64s' (veakood: %d)"
- fre "Ne peut changer le répertoire pour '%-.64s' (Errcode: %d)"
- ger "Kann nicht in das Verzeichnis '%-.64s' wechseln (Fehler: %d)"
- greek "Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Konyvtarvaltas nem lehetseges a(z) '%-.64s'-ba. (hibakod: %d)"
- ita "Impossibile cambiare la directory in '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
- kor "'%-.64s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
- nor "Kan ikke skifte katalog til '%-.64s' (Feilkode: %d)"
- norwegian-ny "Kan ikkje skifte katalog til '%-.64s' (Feilkode: %d)"
- pol "Nie mo¿na zmieniæ katalogu na '%-.64s' (Kod b³êdu: %d)"
- por "Não pode mudar para o diretório '%-.64s' (erro no. %d)"
- rum "Nu pot sa schimb directorul '%-.64s' (Eroare: %d)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Ne mogu da promenim direktorijum na '%-.64s' (errno: %d)"
- slo "Nemô¾em vojs» do adresára '%-.64s' (chybový kód: %d)"
- spa "No puedo cambiar al directorio de '%-.64s' (Error: %d)"
- swe "Kan inte byta till '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÔÉ Õ ÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Nemohu zm-Bìnit adresáø na '%-.192s' (chybový kód: %d)"
+ dan "Kan ikke skifte folder til '%-.192s' (Fejlkode: %d)"
+ nla "Kan de directory niet veranderen naar '%-.192s' (Errcode: %d)"
+ eng "Can't change dir to '%-.192s' (errno: %d)"
+ jps "'%-.192s' ƒfƒBƒŒƒNƒgƒŠ‚É chdir ‚Å‚«‚Ü‚¹‚ñ.(errno: %d)",
+ est "Ei suuda siseneda kataloogi '%-.192s' (veakood: %d)"
+ fre "Ne peut changer le répertoire pour '%-.192s' (Errcode: %d)"
+ ger "Kann nicht in das Verzeichnis '%-.192s' wechseln (Fehler: %d)"
+ greek "Áäýíáôç ç áëëáãÞ ôïõ ôñÝ÷ïíôïò êáôáëüãïõ óå '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Konyvtarvaltas nem lehetseges a(z) '%-.192s'-ba. (hibakod: %d)"
+ ita "Impossibile cambiare la directory in '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ¥Ç¥£¥ì¥¯¥È¥ê¤Ë chdir ¤Ç¤­¤Þ¤»¤ó.(errno: %d)"
+ kor "'%-.192s'µð·ºÅ丮·Î À̵¿ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù. (¿¡·¯¹øÈ£: %d)"
+ nor "Kan ikke skifte katalog til '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Kan ikkje skifte katalog til '%-.192s' (Feilkode: %d)"
+ pol "Nie mo¿na zmieniæ katalogu na '%-.192s' (Kod b³êdu: %d)"
+ por "Não pode mudar para o diretório '%-.192s' (erro no. %d)"
+ rum "Nu pot sa schimb directorul '%-.192s' (Eroare: %d)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÅÒÅÊÔÉ × ËÁÔÁÌÏÇ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Ne mogu da promenim direktorijum na '%-.192s' (errno: %d)"
+ slo "Nemô¾em vojs» do adresára '%-.192s' (chybový kód: %d)"
+ spa "No puedo cambiar al directorio de '%-.192s' (Error: %d)"
+ swe "Kan inte byta till '%-.192s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÔÉ Õ ÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_CHECKREAD
- cze "Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.64s'"
- dan "Posten er ændret siden sidste læsning '%-.64s'"
- nla "Record is veranderd sinds de laatste lees activiteit in de tabel '%-.64s'"
- eng "Record has changed since last read in table '%-.64s'"
- est "Kirje tabelis '%-.64s' on muutunud viimasest lugemisest saadik"
- fre "Enregistrement modifié depuis sa dernière lecture dans la table '%-.64s'"
- ger "Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.64s' geändert"
- greek "Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.64s'"
- hun "A(z) '%-.64s' tablaban talalhato rekord megvaltozott az utolso olvasas ota"
- ita "Il record e` cambiato dall'ultima lettura della tabella '%-.64s'"
- kor "Å×À̺í '%-.64s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù."
- nor "Posten har blitt endret siden den ble lest '%-.64s'"
- norwegian-ny "Posten har vorte endra sidan den sist vart lesen '%-.64s'"
- pol "Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.64s'"
- por "Registro alterado desde a última leitura da tabela '%-.64s'"
- rum "Cimpul a fost schimbat de la ultima citire a tabelei '%-.64s'"
- rus "úÁÐÉÓØ ÉÚÍÅÎÉÌÁÓØ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ×ÙÂÏÒËÉ × ÔÁÂÌÉÃÅ '%-.64s'"
- serbian "Slog je promenjen od zadnjeg èitanja tabele '%-.64s'"
- slo "Záznam bol zmenený od posledného èítania v tabuµke '%-.64s'"
- spa "El registro ha cambiado desde la ultima lectura de la tabla '%-.64s'"
- swe "Posten har förändrats sedan den lästes i register '%-.64s'"
- ukr "úÁÐÉÓ ÂÕÌÏ ÚͦÎÅÎÏ Ú ÞÁÓÕ ÏÓÔÁÎÎØÏÇÏ ÞÉÔÁÎÎÑ Ú ÔÁÂÌÉæ '%-.64s'"
+ cze "Z-Báznam byl zmìnìn od posledního ètení v tabulce '%-.192s'"
+ dan "Posten er ændret siden sidste læsning '%-.192s'"
+ nla "Record is veranderd sinds de laatste lees activiteit in de tabel '%-.192s'"
+ eng "Record has changed since last read in table '%-.192s'"
+ est "Kirje tabelis '%-.192s' on muutunud viimasest lugemisest saadik"
+ fre "Enregistrement modifié depuis sa dernière lecture dans la table '%-.192s'"
+ ger "Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.192s' geändert"
+ greek "Ç åããñáöÞ Ý÷åé áëëÜîåé áðü ôçí ôåëåõôáßá öïñÜ ðïõ áíáóýñèçêå áðü ôïí ðßíáêá '%-.192s'"
+ hun "A(z) '%-.192s' tablaban talalhato rekord megvaltozott az utolso olvasas ota"
+ ita "Il record e` cambiato dall'ultima lettura della tabella '%-.192s'"
+ kor "Å×À̺í '%-.192s'¿¡¼­ ¸¶Áö¸·À¸·Î ÀÐÀº ÈÄ Record°¡ º¯°æµÇ¾ú½À´Ï´Ù."
+ nor "Posten har blitt endret siden den ble lest '%-.192s'"
+ norwegian-ny "Posten har vorte endra sidan den sist vart lesen '%-.192s'"
+ pol "Rekord zosta³ zmieniony od ostaniego odczytania z tabeli '%-.192s'"
+ por "Registro alterado desde a última leitura da tabela '%-.192s'"
+ rum "Cimpul a fost schimbat de la ultima citire a tabelei '%-.192s'"
+ rus "úÁÐÉÓØ ÉÚÍÅÎÉÌÁÓØ Ó ÍÏÍÅÎÔÁ ÐÏÓÌÅÄÎÅÊ ×ÙÂÏÒËÉ × ÔÁÂÌÉÃÅ '%-.192s'"
+ serbian "Slog je promenjen od zadnjeg èitanja tabele '%-.192s'"
+ slo "Záznam bol zmenený od posledného èítania v tabuµke '%-.192s'"
+ spa "El registro ha cambiado desde la ultima lectura de la tabla '%-.192s'"
+ swe "Posten har förändrats sedan den lästes i register '%-.192s'"
+ ukr "úÁÐÉÓ ÂÕÌÏ ÚͦÎÅÎÏ Ú ÞÁÓÕ ÏÓÔÁÎÎØÏÇÏ ÞÉÔÁÎÎÑ Ú ÔÁÂÌÉæ '%-.192s'"
ER_DISK_FULL
cze "Disk je pln-Bý (%s), èekám na uvolnìní nìjakého místa ..."
dan "Ikke mere diskplads (%s). Venter på at få frigjort plads..."
@@ -480,7 +480,7 @@ ER_DISK_FULL
jps "Disk full (%s). ’N‚©‚ª‰½‚©‚ðŒ¸‚ç‚·‚܂ł܂Á‚Ä‚­‚¾‚³‚¢...",
est "Ketas täis (%s). Ootame kuni tekib vaba ruumi..."
fre "Disque plein (%s). J'attend que quelqu'un libère de l'espace..."
- ger "Festplatte voll (%-.64s). Warte, bis jemand Platz schafft ..."
+ ger "Festplatte voll (%s). Warte, bis jemand Platz schafft ..."
greek "Äåí õðÜñ÷åé ÷þñïò óôï äßóêï (%s). Ðáñáêáëþ, ðåñéìÝíåôå íá åëåõèåñùèåß ÷þñïò..."
hun "A lemez megtelt (%s)."
ita "Disco pieno (%s). In attesa che qualcuno liberi un po' di spazio..."
@@ -498,153 +498,153 @@ ER_DISK_FULL
swe "Disken är full (%s). Väntar tills det finns ledigt utrymme..."
ukr "äÉÓË ÚÁÐÏ×ÎÅÎÉÊ (%s). ÷ÉÞÉËÕÀ, ÄÏËÉ Ú×¦ÌØÎÉÔØÓÑ ÔÒÏÈÉ Í¦ÓÃÑ..."
ER_DUP_KEY 23000
- cze "Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.64s'"
- dan "Kan ikke skrive, flere ens nøgler i tabellen '%-.64s'"
- nla "Kan niet schrijven, dubbele zoeksleutel in tabel '%-.64s'"
- eng "Can't write; duplicate key in table '%-.64s'"
- jps "table '%-.64s' ‚É key ‚ªd•¡‚µ‚Ä‚¢‚Ä‘‚«‚±‚߂܂¹‚ñ",
- est "Ei saa kirjutada, korduv võti tabelis '%-.64s'"
- fre "Ecriture impossible, doublon dans une clé de la table '%-.64s'"
- ger "Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.64s'"
- greek "Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.64s'"
- hun "Irasi hiba, duplikalt kulcs a '%-.64s' tablaban."
- ita "Scrittura impossibile: chiave duplicata nella tabella '%-.64s'"
- jpn "table '%-.64s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó"
- kor "±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.64s'¿¡¼­ Áߺ¹ Ű"
- nor "Kan ikke skrive, flere like nøkler i tabellen '%-.64s'"
- norwegian-ny "Kan ikkje skrive, flere like nyklar i tabellen '%-.64s'"
- pol "Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.64s'"
- por "Não pode gravar. Chave duplicada na tabela '%-.64s'"
- rum "Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉÃÅ '%-.64s'"
- serbian "Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.64s'"
- slo "Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.64s'"
- spa "No puedo escribir, clave duplicada en la tabla '%-.64s'"
- swe "Kan inte skriva, dubbel söknyckel i register '%-.64s'"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ, ÄÕÂÌÀÀÞÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉæ '%-.64s'"
+ cze "Nemohu zapsat, zdvojen-Bý klíè v tabulce '%-.192s'"
+ dan "Kan ikke skrive, flere ens nøgler i tabellen '%-.192s'"
+ nla "Kan niet schrijven, dubbele zoeksleutel in tabel '%-.192s'"
+ eng "Can't write; duplicate key in table '%-.192s'"
+ jps "table '%-.192s' ‚É key ‚ªd•¡‚µ‚Ä‚¢‚Ä‘‚«‚±‚߂܂¹‚ñ",
+ est "Ei saa kirjutada, korduv võti tabelis '%-.192s'"
+ fre "Ecriture impossible, doublon dans une clé de la table '%-.192s'"
+ ger "Kann nicht speichern, Grund: doppelter Schlüssel in Tabelle '%-.192s'"
+ greek "Äåí åßíáé äõíáôÞ ç êáôá÷þñçóç, ç ôéìÞ õðÜñ÷åé Þäç óôïí ðßíáêá '%-.192s'"
+ hun "Irasi hiba, duplikalt kulcs a '%-.192s' tablaban."
+ ita "Scrittura impossibile: chiave duplicata nella tabella '%-.192s'"
+ jpn "table '%-.192s' ¤Ë key ¤¬½ÅÊ£¤·¤Æ¤¤¤Æ½ñ¤­¤³¤á¤Þ¤»¤ó"
+ kor "±â·ÏÇÒ ¼ö ¾øÀ¾´Ï´Ù., Å×À̺í '%-.192s'¿¡¼­ Áߺ¹ Ű"
+ nor "Kan ikke skrive, flere like nøkler i tabellen '%-.192s'"
+ norwegian-ny "Kan ikkje skrive, flere like nyklar i tabellen '%-.192s'"
+ pol "Nie mo¿na zapisaæ, powtórzone klucze w tabeli '%-.192s'"
+ por "Não pode gravar. Chave duplicada na tabela '%-.192s'"
+ rum "Nu pot sa scriu (can't write), cheie duplicata in tabela '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÚÁÐÉÓØ, ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉÃÅ '%-.192s'"
+ serbian "Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.192s'"
+ slo "Nemô¾em zapísa», duplikát kµúèa v tabuµke '%-.192s'"
+ spa "No puedo escribir, clave duplicada en la tabla '%-.192s'"
+ swe "Kan inte skriva, dubbel söknyckel i register '%-.192s'"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ, ÄÕÂÌÀÀÞÉÊÓÑ ËÌÀÞ × ÔÁÂÌÉæ '%-.192s'"
ER_ERROR_ON_CLOSE
- cze "Chyba p-Bøi zavírání '%-.64s' (chybový kód: %d)"
- dan "Fejl ved lukning af '%-.64s' (Fejlkode: %d)"
- nla "Fout bij het sluiten van '%-.64s' (Errcode: %d)"
- eng "Error on close of '%-.64s' (errno: %d)"
- est "Viga faili '%-.64s' sulgemisel (veakood: %d)"
- fre "Erreur a la fermeture de '%-.64s' (Errcode: %d)"
- ger "Fehler beim Schließen von '%-.64s' (Fehler: %d)"
- greek "ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a(z) '%-.64s' zarasakor. (hibakod: %d)"
- ita "Errore durante la chiusura di '%-.64s' (errno: %d)"
- kor "'%-.64s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved lukking av '%-.64s' (Feilkode: %d)"
- norwegian-ny "Feil ved lukking av '%-.64s' (Feilkode: %d)"
- pol "B³?d podczas zamykania '%-.64s' (Kod b³êdu: %d)"
- por "Erro ao fechar '%-.64s' (erro no. %d)"
- rum "Eroare inchizind '%-.64s' (errno: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri zatvaranju '%-.64s' (errno: %d)"
- slo "Chyba pri zatváraní '%-.64s' (chybový kód: %d)"
- spa "Error en el cierre de '%-.64s' (Error: %d)"
- swe "Fick fel vid stängning av '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÚÁËÒÉÔÉ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Chyba p-Bøi zavírání '%-.192s' (chybový kód: %d)"
+ dan "Fejl ved lukning af '%-.192s' (Fejlkode: %d)"
+ nla "Fout bij het sluiten van '%-.192s' (Errcode: %d)"
+ eng "Error on close of '%-.192s' (errno: %d)"
+ est "Viga faili '%-.192s' sulgemisel (veakood: %d)"
+ fre "Erreur a la fermeture de '%-.192s' (Errcode: %d)"
+ ger "Fehler beim Schließen von '%-.192s' (Fehler: %d)"
+ greek "ÐáñïõóéÜóôçêå ðñüâëçìá êëåßíïíôáò ôï '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a(z) '%-.192s' zarasakor. (hibakod: %d)"
+ ita "Errore durante la chiusura di '%-.192s' (errno: %d)"
+ kor "'%-.192s'´Ý´Â Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved lukking av '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lukking av '%-.192s' (Feilkode: %d)"
+ pol "B³?d podczas zamykania '%-.192s' (Kod b³êdu: %d)"
+ por "Erro ao fechar '%-.192s' (erro no. %d)"
+ rum "Eroare inchizind '%-.192s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÚÁËÒÙÔÉÉ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri zatvaranju '%-.192s' (errno: %d)"
+ slo "Chyba pri zatváraní '%-.192s' (chybový kód: %d)"
+ spa "Error en el cierre de '%-.192s' (Error: %d)"
+ swe "Fick fel vid stängning av '%-.192s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÚÁËÒÉÔÉ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_ERROR_ON_READ
- cze "Chyba p-Bøi ètení souboru '%-.64s' (chybový kód: %d)"
- dan "Fejl ved læsning af '%-.64s' (Fejlkode: %d)"
- nla "Fout bij het lezen van file '%-.64s' (Errcode: %d)"
+ cze "Chyba p-Bøi ètení souboru '%-.200s' (chybový kód: %d)"
+ dan "Fejl ved læsning af '%-.200s' (Fejlkode: %d)"
+ nla "Fout bij het lezen van file '%-.200s' (Errcode: %d)"
eng "Error reading file '%-.200s' (errno: %d)"
- jps "'%-.64s' ƒtƒ@ƒCƒ‹‚̓ǂݞ‚݃Gƒ‰[ (errno: %d)",
- est "Viga faili '%-.64s' lugemisel (veakood: %d)"
- fre "Erreur en lecture du fichier '%-.64s' (Errcode: %d)"
- ger "Fehler beim Lesen der Datei '%-.64s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.64s'file olvasasakor. (hibakod: %d)"
- ita "Errore durante la lettura del file '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ÎÆÉ¤ß¹þ¤ß¥¨¥é¡¼ (errno: %d)"
- kor "'%-.64s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved lesing av '%-.64s' (Feilkode: %d)"
- norwegian-ny "Feil ved lesing av '%-.64s' (Feilkode: %d)"
- pol "B³?d podczas odczytu pliku '%-.64s' (Kod b³êdu: %d)"
- por "Erro ao ler arquivo '%-.64s' (erro no. %d)"
- rum "Eroare citind fisierul '%-.64s' (errno: %d)"
- rus "ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri èitanju file-a '%-.64s' (errno: %d)"
- slo "Chyba pri èítaní súboru '%-.64s' (chybový kód: %d)"
- spa "Error leyendo el fichero '%-.64s' (Error: %d)"
- swe "Fick fel vid läsning av '%-.64s' (Felkod %d)"
- ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ jps "'%-.200s' ƒtƒ@ƒCƒ‹‚̓ǂݞ‚݃Gƒ‰[ (errno: %d)",
+ est "Viga faili '%-.200s' lugemisel (veakood: %d)"
+ fre "Erreur en lecture du fichier '%-.200s' (Errcode: %d)"
+ ger "Fehler beim Lesen der Datei '%-.200s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.200s'file olvasasakor. (hibakod: %d)"
+ ita "Errore durante la lettura del file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ÎÆÉ¤ß¹þ¤ß¥¨¥é¡¼ (errno: %d)"
+ kor "'%-.200s'È­ÀÏ Àб⠿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved lesing av '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Feil ved lesing av '%-.200s' (Feilkode: %d)"
+ pol "B³?d podczas odczytu pliku '%-.200s' (Kod b³êdu: %d)"
+ por "Erro ao ler arquivo '%-.200s' (erro no. %d)"
+ rum "Eroare citind fisierul '%-.200s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÞÔÅÎÉÑ ÆÁÊÌÁ '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri èitanju file-a '%-.200s' (errno: %d)"
+ slo "Chyba pri èítaní súboru '%-.200s' (chybový kód: %d)"
+ spa "Error leyendo el fichero '%-.200s' (Error: %d)"
+ swe "Fick fel vid läsning av '%-.200s' (Felkod %d)"
+ ukr "îÅ ÍÏÖÕ ÐÒÏÞÉÔÁÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_ERROR_ON_RENAME
- cze "Chyba p-Bøi pøejmenování '%-.64s' na '%-.64s' (chybový kód: %d)"
- dan "Fejl ved omdøbning af '%-.64s' til '%-.64s' (Fejlkode: %d)"
- nla "Fout bij het hernoemen van '%-.64s' naar '%-.64s' (Errcode: %d)"
- eng "Error on rename of '%-.64s' to '%-.64s' (errno: %d)"
- jps "'%-.64s' ‚ð '%-.64s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Viga faili '%-.64s' ümbernimetamisel '%-.64s'-ks (veakood: %d)"
- fre "Erreur en renommant '%-.64s' en '%-.64s' (Errcode: %d)"
- ger "Fehler beim Umbenennen von '%-.64s' in '%-.64s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.64s' to '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.64s' file atnevezesekor. (hibakod: %d)"
- ita "Errore durante la rinominazione da '%-.64s' a '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¤ò '%-.64s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "'%-.64s'¸¦ '%-.64s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved omdøping av '%-.64s' til '%-.64s' (Feilkode: %d)"
- norwegian-ny "Feil ved omdøyping av '%-.64s' til '%-.64s' (Feilkode: %d)"
- pol "B³?d podczas zmieniania nazwy '%-.64s' na '%-.64s' (Kod b³êdu: %d)"
- por "Erro ao renomear '%-.64s' para '%-.64s' (erro no. %d)"
- rum "Eroare incercind sa renumesc '%-.64s' in '%-.64s' (errno: %d)"
- rus "ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.64s' × '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri promeni imena '%-.64s' na '%-.64s' (errno: %d)"
- slo "Chyba pri premenovávaní '%-.64s' na '%-.64s' (chybový kód: %d)"
- spa "Error en el renombrado de '%-.64s' a '%-.64s' (Error: %d)"
- swe "Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÍÅÎÕ×ÁÔÉ '%-.64s' Õ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Chyba p-Bøi pøejmenování '%-.150s' na '%-.150s' (chybový kód: %d)"
+ dan "Fejl ved omdøbning af '%-.150s' til '%-.150s' (Fejlkode: %d)"
+ nla "Fout bij het hernoemen van '%-.150s' naar '%-.150s' (Errcode: %d)"
+ eng "Error on rename of '%-.150s' to '%-.150s' (errno: %d)"
+ jps "'%-.150s' ‚ð '%-.150s' ‚É rename ‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Viga faili '%-.150s' ümbernimetamisel '%-.150s'-ks (veakood: %d)"
+ fre "Erreur en renommant '%-.150s' en '%-.150s' (Errcode: %d)"
+ ger "Fehler beim Umbenennen von '%-.150s' in '%-.150s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí ìåôïíïìáóßá ôïõ áñ÷åßïõ '%-.150s' to '%-.150s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.150s' file atnevezesekor '%-.150s'. (hibakod: %d)"
+ ita "Errore durante la rinominazione da '%-.150s' a '%-.150s' (errno: %d)"
+ jpn "'%-.150s' ¤ò '%-.150s' ¤Ë rename ¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "'%-.150s'¸¦ '%-.150s'·Î À̸§ º¯°æÁß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved omdøping av '%-.150s' til '%-.150s' (Feilkode: %d)"
+ norwegian-ny "Feil ved omdøyping av '%-.150s' til '%-.150s' (Feilkode: %d)"
+ pol "B³?d podczas zmieniania nazwy '%-.150s' na '%-.150s' (Kod b³êdu: %d)"
+ por "Erro ao renomear '%-.150s' para '%-.150s' (erro no. %d)"
+ rum "Eroare incercind sa renumesc '%-.150s' in '%-.150s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÐÒÉ ÐÅÒÅÉÍÅÎÏ×ÁÎÉÉ '%-.150s' × '%-.150s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri promeni imena '%-.150s' na '%-.150s' (errno: %d)"
+ slo "Chyba pri premenovávaní '%-.150s' na '%-.150s' (chybový kód: %d)"
+ spa "Error en el renombrado de '%-.150s' a '%-.150s' (Error: %d)"
+ swe "Kan inte byta namn från '%-.150s' till '%-.150s' (Felkod: %d)"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅÊÍÅÎÕ×ÁÔÉ '%-.150s' Õ '%-.150s' (ÐÏÍÉÌËÁ: %d)"
ER_ERROR_ON_WRITE
- cze "Chyba p-Bøi zápisu do souboru '%-.64s' (chybový kód: %d)"
- dan "Fejl ved skriving av filen '%-.64s' (Fejlkode: %d)"
- nla "Fout bij het wegschrijven van file '%-.64s' (Errcode: %d)"
+ cze "Chyba p-Bøi zápisu do souboru '%-.200s' (chybový kód: %d)"
+ dan "Fejl ved skriving av filen '%-.200s' (Fejlkode: %d)"
+ nla "Fout bij het wegschrijven van file '%-.200s' (Errcode: %d)"
eng "Error writing file '%-.200s' (errno: %d)"
- jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ð‘‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
- est "Viga faili '%-.64s' kirjutamisel (veakood: %d)"
- fre "Erreur d'écriture du fichier '%-.64s' (Errcode: %d)"
- ger "Fehler beim Speichern der Datei '%-.64s' (Fehler: %d)"
- greek "Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Hiba a '%-.64s' file irasakor. (hibakod: %d)"
- ita "Errore durante la scrittura del file '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
- kor "'%-.64s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
- nor "Feil ved skriving av fila '%-.64s' (Feilkode: %d)"
- norwegian-ny "Feil ved skriving av fila '%-.64s' (Feilkode: %d)"
- pol "B³?d podczas zapisywania pliku '%-.64s' (Kod b³êdu: %d)"
- por "Erro ao gravar arquivo '%-.64s' (erro no. %d)"
- rum "Eroare scriind fisierul '%-.64s' (errno: %d)"
- rus "ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Greška pri upisu '%-.64s' (errno: %d)"
- slo "Chyba pri zápise do súboru '%-.64s' (chybový kód: %d)"
- spa "Error escribiendo el archivo '%-.64s' (Error: %d)"
- swe "Fick fel vid skrivning till '%-.64s' (Felkod %d)"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ jps "'%-.200s' ƒtƒ@ƒCƒ‹‚ð‘‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d)",
+ est "Viga faili '%-.200s' kirjutamisel (veakood: %d)"
+ fre "Erreur d'écriture du fichier '%-.200s' (Errcode: %d)"
+ ger "Fehler beim Speichern der Datei '%-.200s' (Fehler: %d)"
+ greek "Ðñüâëçìá êáôÜ ôçí áðïèÞêåõóç ôïõ áñ÷åßïõ '%-.200s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Hiba a '%-.200s' file irasakor. (hibakod: %d)"
+ ita "Errore durante la scrittura del file '%-.200s' (errno: %d)"
+ jpn "'%-.200s' ¥Õ¥¡¥¤¥ë¤ò½ñ¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d)"
+ kor "'%-.200s'È­ÀÏ ±â·Ï Áß ¿¡·¯ (¿¡·¯¹øÈ£: %d)"
+ nor "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
+ norwegian-ny "Feil ved skriving av fila '%-.200s' (Feilkode: %d)"
+ pol "B³?d podczas zapisywania pliku '%-.200s' (Kod b³êdu: %d)"
+ por "Erro ao gravar arquivo '%-.200s' (erro no. %d)"
+ rum "Eroare scriind fisierul '%-.200s' (errno: %d)"
+ rus "ïÛÉÂËÁ ÚÁÐÉÓÉ × ÆÁÊÌ '%-.200s' (ÏÛÉÂËÁ: %d)"
+ serbian "Greška pri upisu '%-.200s' (errno: %d)"
+ slo "Chyba pri zápise do súboru '%-.200s' (chybový kód: %d)"
+ spa "Error escribiendo el archivo '%-.200s' (Error: %d)"
+ swe "Fick fel vid skrivning till '%-.200s' (Felkod %d)"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÆÁÊÌ '%-.200s' (ÐÏÍÉÌËÁ: %d)"
ER_FILE_USED
- cze "'%-.64s' je zam-Bèen proti zmìnám"
- dan "'%-.64s' er låst mod opdateringer"
- nla "'%-.64s' is geblokeerd tegen veranderingen"
- eng "'%-.64s' is locked against change"
- jps "'%-.64s' ‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·",
- est "'%-.64s' on lukustatud muudatuste vastu"
- fre "'%-.64s' est verrouillé contre les modifications"
- ger "'%-.64s' ist für Änderungen gesperrt"
- greek "'%-.64s' äåí åðéôñÝðïíôáé áëëáãÝò"
- hun "'%-.64s' a valtoztatas ellen zarolva"
- ita "'%-.64s' e` soggetto a lock contro i cambiamenti"
- jpn "'%-.64s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
- kor "'%-.64s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù."
- nor "'%-.64s' er låst mot oppdateringer"
- norwegian-ny "'%-.64s' er låst mot oppdateringar"
- pol "'%-.64s' jest zablokowany na wypadek zmian"
- por "'%-.64s' está com travamento contra alterações"
- rum "'%-.64s' este blocat pentry schimbari (loccked against change)"
- rus "'%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ"
- serbian "'%-.64s' je zakljuèan za upis"
- slo "'%-.64s' je zamknutý proti zmenám"
- spa "'%-.64s' esta bloqueado contra cambios"
- swe "'%-.64s' är låst mot användning"
- ukr "'%-.64s' ÚÁÂÌÏËÏ×ÁÎÉÊ ÎÁ ×ÎÅÓÅÎÎÑ ÚͦÎ"
+ cze "'%-.192s' je zam-Bèen proti zmìnám"
+ dan "'%-.192s' er låst mod opdateringer"
+ nla "'%-.192s' is geblokeerd tegen veranderingen"
+ eng "'%-.192s' is locked against change"
+ jps "'%-.192s' ‚̓ƒbƒN‚³‚ê‚Ä‚¢‚Ü‚·",
+ est "'%-.192s' on lukustatud muudatuste vastu"
+ fre "'%-.192s' est verrouillé contre les modifications"
+ ger "'%-.192s' ist für Änderungen gesperrt"
+ greek "'%-.192s' äåí åðéôñÝðïíôáé áëëáãÝò"
+ hun "'%-.192s' a valtoztatas ellen zarolva"
+ ita "'%-.192s' e` soggetto a lock contro i cambiamenti"
+ jpn "'%-.192s' ¤Ï¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤¹"
+ kor "'%-.192s'°¡ º¯°æÇÒ ¼ö ¾øµµ·Ï Àá°ÜÀÖÀ¾´Ï´Ù."
+ nor "'%-.192s' er låst mot oppdateringer"
+ norwegian-ny "'%-.192s' er låst mot oppdateringar"
+ pol "'%-.192s' jest zablokowany na wypadek zmian"
+ por "'%-.192s' está com travamento contra alterações"
+ rum "'%-.192s' este blocat pentry schimbari (loccked against change)"
+ rus "'%-.192s' ÚÁÂÌÏËÉÒÏ×ÁÎ ÄÌÑ ÉÚÍÅÎÅÎÉÊ"
+ serbian "'%-.192s' je zakljuèan za upis"
+ slo "'%-.192s' je zamknutý proti zmenám"
+ spa "'%-.192s' esta bloqueado contra cambios"
+ swe "'%-.192s' är låst mot användning"
+ ukr "'%-.192s' ÚÁÂÌÏËÏ×ÁÎÉÊ ÎÁ ×ÎÅÓÅÎÎÑ ÚͦÎ"
ER_FILSORT_ABORT
cze "T-Bøídìní pøeru¹eno"
dan "Sortering afbrudt"
@@ -671,30 +671,30 @@ ER_FILSORT_ABORT
swe "Sorteringen avbruten"
ukr "óÏÒÔÕ×ÁÎÎÑ ÐÅÒÅÒ×ÁÎÏ"
ER_FORM_NOT_FOUND
- cze "Pohled '%-.64s' pro '%-.64s' neexistuje"
- dan "View '%-.64s' eksisterer ikke for '%-.64s'"
- nla "View '%-.64s' bestaat niet voor '%-.64s'"
- eng "View '%-.64s' doesn't exist for '%-.64s'"
- jps "View '%-.64s' ‚ª '%-.64s' ‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Vaade '%-.64s' ei eksisteeri '%-.64s' jaoks"
- fre "La vue (View) '%-.64s' n'existe pas pour '%-.64s'"
- ger "View '%-.64s' existiert für '%-.64s' nicht"
- greek "Ôï View '%-.64s' äåí õðÜñ÷åé ãéá '%-.64s'"
- hun "A(z) '%-.64s' nezet nem letezik a(z) '%-.64s'-hoz"
- ita "La view '%-.64s' non esiste per '%-.64s'"
- jpn "View '%-.64s' ¤¬ '%-.64s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "ºä '%-.64s'°¡ '%-.64s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù."
- nor "View '%-.64s' eksisterer ikke for '%-.64s'"
- norwegian-ny "View '%-.64s' eksisterar ikkje for '%-.64s'"
- pol "Widok '%-.64s' nie istnieje dla '%-.64s'"
- por "Visão '%-.64s' não existe para '%-.64s'"
- rum "View '%-.64s' nu exista pentru '%-.64s'"
- rus "ðÒÅÄÓÔÁ×ÌÅÎÉÅ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.64s'"
- serbian "View '%-.64s' ne postoji za '%-.64s'"
- slo "Pohµad '%-.64s' neexistuje pre '%-.64s'"
- spa "La vista '%-.64s' no existe para '%-.64s'"
- swe "Formulär '%-.64s' finns inte i '%-.64s'"
- ukr "÷ÉÇÌÑÄ '%-.64s' ÎÅ ¦ÓÎÕ¤ ÄÌÑ '%-.64s'"
+ cze "Pohled '%-.192s' pro '%-.192s' neexistuje"
+ dan "View '%-.192s' eksisterer ikke for '%-.192s'"
+ nla "View '%-.192s' bestaat niet voor '%-.192s'"
+ eng "View '%-.192s' doesn't exist for '%-.192s'"
+ jps "View '%-.192s' ‚ª '%-.192s' ‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Vaade '%-.192s' ei eksisteeri '%-.192s' jaoks"
+ fre "La vue (View) '%-.192s' n'existe pas pour '%-.192s'"
+ ger "View '%-.192s' existiert für '%-.192s' nicht"
+ greek "Ôï View '%-.192s' äåí õðÜñ÷åé ãéá '%-.192s'"
+ hun "A(z) '%-.192s' nezet nem letezik a(z) '%-.192s'-hoz"
+ ita "La view '%-.192s' non esiste per '%-.192s'"
+ jpn "View '%-.192s' ¤¬ '%-.192s' ¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "ºä '%-.192s'°¡ '%-.192s'¿¡¼­´Â Á¸ÀçÇÏÁö ¾ÊÀ¾´Ï´Ù."
+ nor "View '%-.192s' eksisterer ikke for '%-.192s'"
+ norwegian-ny "View '%-.192s' eksisterar ikkje for '%-.192s'"
+ pol "Widok '%-.192s' nie istnieje dla '%-.192s'"
+ por "Visão '%-.192s' não existe para '%-.192s'"
+ rum "View '%-.192s' nu exista pentru '%-.192s'"
+ rus "ðÒÅÄÓÔÁ×ÌÅÎÉÅ '%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ ÄÌÑ '%-.192s'"
+ serbian "View '%-.192s' ne postoji za '%-.192s'"
+ slo "Pohµad '%-.192s' neexistuje pre '%-.192s'"
+ spa "La vista '%-.192s' no existe para '%-.192s'"
+ swe "Formulär '%-.192s' finns inte i '%-.192s'"
+ ukr "÷ÉÇÌÑÄ '%-.192s' ÎÅ ¦ÓÎÕ¤ ÄÌÑ '%-.192s'"
ER_GET_ERRNO
cze "Obsluha tabulky vr-Bátila chybu %d"
dan "Modtog fejl %d fra tabel håndteringen"
@@ -720,154 +720,154 @@ ER_GET_ERRNO
swe "Fick felkod %d från databashanteraren"
ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d ×¦Ä ÄÅÓËÒÉÐÔÏÒÁ ÔÁÂÌÉæ"
ER_ILLEGAL_HA
- cze "Obsluha tabulky '%-.64s' nem-Bá tento parametr"
- dan "Denne mulighed eksisterer ikke for tabeltypen '%-.64s'"
- nla "Tabel handler voor '%-.64s' heeft deze optie niet"
- eng "Table storage engine for '%-.64s' doesn't have this option"
- est "Tabeli '%-.64s' handler ei toeta antud operatsiooni"
- fre "Le handler de la table '%-.64s' n'a pas cette option"
- ger "Diese Option gibt es nicht (Speicher-Engine für '%-.64s')"
- greek "Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.64s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ"
- hun "A(z) '%-.64s' tablakezelonek nincs ilyen opcioja"
- ita "Il gestore delle tabelle per '%-.64s' non ha questa opzione"
- jpn "Table handler for '%-.64s' doesn't have this option"
- kor "'%-.64s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù."
- nor "Tabell håndtereren for '%-.64s' har ikke denne muligheten"
- norwegian-ny "Tabell håndteraren for '%-.64s' har ikkje denne moglegheita"
- pol "Obs³uga tabeli '%-.64s' nie posiada tej opcji"
- por "Manipulador de tabela para '%-.64s' não tem esta opção"
- rum "Handlerul tabelei pentru '%-.64s' nu are aceasta optiune"
- rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÕ ×ÏÚÍÏÖÎÏÓÔØ"
- serbian "Handler tabela za '%-.64s' nema ovu opciju"
- slo "Obsluha tabuµky '%-.64s' nemá tento parameter"
- spa "El manejador de la tabla de '%-.64s' no tiene esta opcion"
- swe "Registrets databas har inte denna facilitet"
- ukr "äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉæ '%-.64s' ÎÅ ÍÁ¤ 椧 ×ÌÁÓÔÉ×ÏÓÔ¦"
+ cze "Obsluha tabulky '%-.192s' nem-Bá tento parametr"
+ dan "Denne mulighed eksisterer ikke for tabeltypen '%-.192s'"
+ nla "Tabel handler voor '%-.192s' heeft deze optie niet"
+ eng "Table storage engine for '%-.192s' doesn't have this option"
+ est "Tabeli '%-.192s' handler ei toeta antud operatsiooni"
+ fre "Le handler de la table '%-.192s' n'a pas cette option"
+ ger "Diese Option gibt es nicht (Speicher-Engine für '%-.192s')"
+ greek "Ï ÷åéñéóôÞò ðßíáêá (table handler) ãéá '%-.192s' äåí äéáèÝôåé áõôÞ ôçí åðéëïãÞ"
+ hun "A(z) '%-.192s' tablakezelonek nincs ilyen opcioja"
+ ita "Il gestore delle tabelle per '%-.192s' non ha questa opzione"
+ jpn "Table handler for '%-.192s' doesn't have this option"
+ kor "'%-.192s'ÀÇ Å×À̺í handler´Â ÀÌ·¯ÇÑ ¿É¼ÇÀ» Á¦°øÇÏÁö ¾ÊÀ¾´Ï´Ù."
+ nor "Tabell håndtereren for '%-.192s' har ikke denne muligheten"
+ norwegian-ny "Tabell håndteraren for '%-.192s' har ikkje denne moglegheita"
+ pol "Obs³uga tabeli '%-.192s' nie posiada tej opcji"
+ por "Manipulador de tabela para '%-.192s' não tem esta opção"
+ rum "Handlerul tabelei pentru '%-.192s' nu are aceasta optiune"
+ rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ '%-.192s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÕ ×ÏÚÍÏÖÎÏÓÔØ"
+ serbian "Handler tabela za '%-.192s' nema ovu opciju"
+ slo "Obsluha tabuµky '%-.192s' nemá tento parameter"
+ spa "El manejador de la tabla de '%-.192s' no tiene esta opcion"
+ swe "Tabellhanteraren for tabell '%-.192s' stödjer ej detta"
+ ukr "äÅÓËÒÉÐÔÏÒ ÔÁÂÌÉæ '%-.192s' ÎÅ ÍÁ¤ 椧 ×ÌÁÓÔÉ×ÏÓÔ¦"
ER_KEY_NOT_FOUND
- cze "Nemohu naj-Bít záznam v '%-.64s'"
- dan "Kan ikke finde posten i '%-.64s'"
- nla "Kan record niet vinden in '%-.64s'"
- eng "Can't find record in '%-.64s'"
- jps "'%-.64s'‚̂Ȃ©‚ɃŒƒR[ƒh‚ªŒ©•t‚©‚è‚Ü‚¹‚ñ",
- est "Ei suuda leida kirjet '%-.64s'-s"
- fre "Ne peut trouver l'enregistrement dans '%-.64s'"
- ger "Kann Datensatz in '%-.64s' nicht finden"
- greek "Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.64s'"
- hun "Nem talalhato a rekord '%-.64s'-ben"
- ita "Impossibile trovare il record in '%-.64s'"
- jpn "'%-.64s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó"
- kor "'%-.64s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
- nor "Kan ikke finne posten i '%-.64s'"
- norwegian-ny "Kan ikkje finne posten i '%-.64s'"
- pol "Nie mo¿na znale¥æ rekordu w '%-.64s'"
- por "Não pode encontrar registro em '%-.64s'"
- rum "Nu pot sa gasesc recordul in '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.64s'"
- serbian "Ne mogu da pronaðem slog u '%-.64s'"
- slo "Nemô¾em nájs» záznam v '%-.64s'"
- spa "No puedo encontrar el registro en '%-.64s'"
- swe "Hittar inte posten"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ Õ '%-.64s'"
+ cze "Nemohu naj-Bít záznam v '%-.192s'"
+ dan "Kan ikke finde posten i '%-.192s'"
+ nla "Kan record niet vinden in '%-.192s'"
+ eng "Can't find record in '%-.192s'"
+ jps "'%-.192s'‚̂Ȃ©‚ɃŒƒR[ƒh‚ªŒ©•t‚©‚è‚Ü‚¹‚ñ",
+ est "Ei suuda leida kirjet '%-.192s'-s"
+ fre "Ne peut trouver l'enregistrement dans '%-.192s'"
+ ger "Kann Datensatz in '%-.192s' nicht finden"
+ greek "Áäýíáôç ç áíåýñåóç åããñáöÞò óôï '%-.192s'"
+ hun "Nem talalhato a rekord '%-.192s'-ben"
+ ita "Impossibile trovare il record in '%-.192s'"
+ jpn "'%-.192s'¤Î¤Ê¤«¤Ë¥ì¥³¡¼¥É¤¬¸«ÉÕ¤«¤ê¤Þ¤»¤ó"
+ kor "'%-.192s'¿¡¼­ ·¹Äڵ带 ãÀ» ¼ö ¾øÀ¾´Ï´Ù."
+ nor "Kan ikke finne posten i '%-.192s'"
+ norwegian-ny "Kan ikkje finne posten i '%-.192s'"
+ pol "Nie mo¿na znale¥æ rekordu w '%-.192s'"
+ por "Não pode encontrar registro em '%-.192s'"
+ rum "Nu pot sa gasesc recordul in '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÎÁÊÔÉ ÚÁÐÉÓØ × '%-.192s'"
+ serbian "Ne mogu da pronaðem slog u '%-.192s'"
+ slo "Nemô¾em nájs» záznam v '%-.192s'"
+ spa "No puedo encontrar el registro en '%-.192s'"
+ swe "Hittar inte posten '%-.192s'"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ Õ '%-.192s'"
ER_NOT_FORM_FILE
- cze "Nespr-Bávná informace v souboru '%-.64s'"
- dan "Forkert indhold i: '%-.64s'"
- nla "Verkeerde info in file: '%-.64s'"
+ cze "Nespr-Bávná informace v souboru '%-.200s'"
+ dan "Forkert indhold i: '%-.200s'"
+ nla "Verkeerde info in file: '%-.200s'"
eng "Incorrect information in file: '%-.200s'"
- jps "ƒtƒ@ƒCƒ‹ '%-.64s' ‚Ì info ‚ªŠÔˆá‚Á‚Ä‚¢‚邿‚¤‚Å‚·",
- est "Vigane informatsioon failis '%-.64s'"
- fre "Information erronnée dans le fichier: '%-.64s'"
- ger "Falsche Information in Datei '%-.64s'"
- greek "ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.64s'"
- hun "Ervenytelen info a file-ban: '%-.64s'"
- ita "Informazione errata nel file: '%-.64s'"
- jpn "¥Õ¥¡¥¤¥ë '%-.64s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
- kor "È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.64s'"
- nor "Feil informasjon i filen: '%-.64s'"
- norwegian-ny "Feil informasjon i fila: '%-.64s'"
- pol "Niew³a?ciwa informacja w pliku: '%-.64s'"
- por "Informação incorreta no arquivo '%-.64s'"
- rum "Informatie incorecta in fisierul: '%-.64s'"
- rus "îÅËÏÒÒÅËÔÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ '%-.64s'"
- serbian "Pogrešna informacija u file-u: '%-.64s'"
- slo "Nesprávna informácia v súbore: '%-.64s'"
- spa "Informacion erronea en el archivo: '%-.64s'"
- swe "Felaktig fil: '%-.64s'"
- ukr "èÉÂÎÁ ¦ÎÆÏÒÍÁÃ¦Ñ Õ ÆÁÊ̦: '%-.64s'"
+ jps "ƒtƒ@ƒCƒ‹ '%-.200s' ‚Ì info ‚ªŠÔˆá‚Á‚Ä‚¢‚邿‚¤‚Å‚·",
+ est "Vigane informatsioon failis '%-.200s'"
+ fre "Information erronnée dans le fichier: '%-.200s'"
+ ger "Falsche Information in Datei '%-.200s'"
+ greek "ËÜèïò ðëçñïöïñßåò óôï áñ÷åßï: '%-.200s'"
+ hun "Ervenytelen info a file-ban: '%-.200s'"
+ ita "Informazione errata nel file: '%-.200s'"
+ jpn "¥Õ¥¡¥¤¥ë '%-.200s' ¤Î info ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹"
+ kor "È­ÀÏÀÇ ºÎÁ¤È®ÇÑ Á¤º¸: '%-.200s'"
+ nor "Feil informasjon i filen: '%-.200s'"
+ norwegian-ny "Feil informasjon i fila: '%-.200s'"
+ pol "Niew³a?ciwa informacja w pliku: '%-.200s'"
+ por "Informação incorreta no arquivo '%-.200s'"
+ rum "Informatie incorecta in fisierul: '%-.200s'"
+ rus "îÅËÏÒÒÅËÔÎÁÑ ÉÎÆÏÒÍÁÃÉÑ × ÆÁÊÌÅ '%-.200s'"
+ serbian "Pogrešna informacija u file-u: '%-.200s'"
+ slo "Nesprávna informácia v súbore: '%-.200s'"
+ spa "Informacion erronea en el archivo: '%-.200s'"
+ swe "Felaktig fil: '%-.200s'"
+ ukr "èÉÂÎÁ ¦ÎÆÏÒÍÁÃ¦Ñ Õ ÆÁÊ̦: '%-.200s'"
ER_NOT_KEYFILE
- cze "Nespr-Bávný klíè pro tabulku '%-.64s'; pokuste se ho opravit"
- dan "Fejl i indeksfilen til tabellen '%-.64s'; prøv at reparere den"
- nla "Verkeerde zoeksleutel file voor tabel: '%-.64s'; probeer het te repareren"
+ cze "Nespr-Bávný klíè pro tabulku '%-.200s'; pokuste se ho opravit"
+ dan "Fejl i indeksfilen til tabellen '%-.200s'; prøv at reparere den"
+ nla "Verkeerde zoeksleutel file voor tabel: '%-.200s'; probeer het te repareren"
eng "Incorrect key file for table '%-.200s'; try to repair it"
- jps "'%-.64s' ƒe[ƒuƒ‹‚Ì key file ‚ªŠÔˆá‚Á‚Ä‚¢‚邿‚¤‚Å‚·. C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabeli '%-.64s' võtmefail on vigane; proovi seda parandada"
- fre "Index corrompu dans la table: '%-.64s'; essayez de le réparer"
- ger "Fehlerhafte Index-Datei für Tabelle '%-.64s'; versuche zu reparieren"
- greek "ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
- hun "Ervenytelen kulcsfile a tablahoz: '%-.64s'; probalja kijavitani!"
- ita "File chiave errato per la tabella : '%-.64s'; prova a riparalo"
- jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
- kor "'%-.64s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
- nor "Tabellen '%-.64s' har feil i nøkkelfilen; forsøk å reparer den"
- norwegian-ny "Tabellen '%-.64s' har feil i nykkelfila; prøv å reparere den"
- pol "Niew³a?ciwy plik kluczy dla tabeli: '%-.64s'; spróbuj go naprawiæ"
- por "Arquivo de índice incorreto para tabela '%-.64s'; tente repará-lo"
- rum "Cheia fisierului incorecta pentru tabela: '%-.64s'; incearca s-o repari"
- rus "îÅËÏÒÒÅËÔÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.64s'. ðÏÐÒÏÂÕÊÔÅ ×ÏÓÓÔÁÎÏ×ÉÔØ ÅÇÏ"
- serbian "Pogrešan key file za tabelu: '%-.64s'; probajte da ga ispravite"
- slo "Nesprávny kµúè pre tabuµku '%-.64s'; pokúste sa ho opravi»"
- spa "Clave de archivo erronea para la tabla: '%-.64s'; intente repararlo"
- swe "Fatalt fel vid hantering av register '%-.64s'; kör en reparation"
- ukr "èÉÂÎÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ: '%-.64s'; óÐÒÏÂÕÊÔÅ ÊÏÇÏ ×¦ÄÎÏ×ÉÔÉ"
+ jps "'%-.200s' ƒe[ƒuƒ‹‚Ì key file ‚ªŠÔˆá‚Á‚Ä‚¢‚邿‚¤‚Å‚·. C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabeli '%-.200s' võtmefail on vigane; proovi seda parandada"
+ fre "Index corrompu dans la table: '%-.200s'; essayez de le réparer"
+ ger "Fehlerhafte Index-Datei für Tabelle '%-.200s'; versuche zu reparieren"
+ greek "ËÜèïò áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá: '%-.200s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
+ hun "Ervenytelen kulcsfile a tablahoz: '%-.200s'; probalja kijavitani!"
+ ita "File chiave errato per la tabella : '%-.200s'; prova a riparalo"
+ jpn "'%-.200s' ¥Æ¡¼¥Ö¥ë¤Î key file ¤¬´Ö°ã¤Ã¤Æ¤¤¤ë¤è¤¦¤Ç¤¹. ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "'%-.200s' Å×À̺íÀÇ ºÎÁ¤È®ÇÑ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
+ nor "Tabellen '%-.200s' har feil i nøkkelfilen; forsøk å reparer den"
+ norwegian-ny "Tabellen '%-.200s' har feil i nykkelfila; prøv å reparere den"
+ pol "Niew³a?ciwy plik kluczy dla tabeli: '%-.200s'; spróbuj go naprawiæ"
+ por "Arquivo de índice incorreto para tabela '%-.200s'; tente repará-lo"
+ rum "Cheia fisierului incorecta pentru tabela: '%-.200s'; incearca s-o repari"
+ rus "îÅËÏÒÒÅËÔÎÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ: '%-.200s'. ðÏÐÒÏÂÕÊÔÅ ×ÏÓÓÔÁÎÏ×ÉÔØ ÅÇÏ"
+ serbian "Pogrešan key file za tabelu: '%-.200s'; probajte da ga ispravite"
+ slo "Nesprávny kµúè pre tabuµku '%-.200s'; pokúste sa ho opravi»"
+ spa "Clave de archivo erronea para la tabla: '%-.200s'; intente repararlo"
+ swe "Fatalt fel vid hantering av register '%-.200s'; kör en reparation"
+ ukr "èÉÂÎÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ: '%-.200s'; óÐÒÏÂÕÊÔÅ ÊÏÇÏ ×¦ÄÎÏ×ÉÔÉ"
ER_OLD_KEYFILE
- cze "Star-Bý klíèový soubor pro '%-.64s'; opravte ho."
- dan "Gammel indeksfil for tabellen '%-.64s'; reparer den"
- nla "Oude zoeksleutel file voor tabel '%-.64s'; repareer het!"
- eng "Old key file for table '%-.64s'; repair it!"
- jps "'%-.64s' ƒe[ƒuƒ‹‚͌¢Œ`Ž®‚Ì key file ‚̂悤‚Å‚·; C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabeli '%-.64s' võtmefail on aegunud; paranda see!"
- fre "Vieux fichier d'index pour la table '%-.64s'; réparez le!"
- ger "Alte Index-Datei für Tabelle '%-.64s'. Bitte reparieren"
- greek "Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.64s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
- hun "Regi kulcsfile a '%-.64s'tablahoz; probalja kijavitani!"
- ita "File chiave vecchio per la tabella '%-.64s'; riparalo!"
- jpn "'%-.64s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
- kor "'%-.64s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
- nor "Gammel nøkkelfil for tabellen '%-.64s'; reparer den!"
- norwegian-ny "Gammel nykkelfil for tabellen '%-.64s'; reparer den!"
- pol "Plik kluczy dla tabeli '%-.64s' jest starego typu; napraw go!"
- por "Arquivo de índice desatualizado para tabela '%-.64s'; repare-o!"
- rum "Cheia fisierului e veche pentru tabela '%-.64s'; repar-o!"
- rus "óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'; ÏÔÒÅÍÏÎÔÉÒÕÊÔÅ ÅÇÏ!"
- serbian "Zastareo key file za tabelu '%-.64s'; ispravite ga"
- slo "Starý kµúèový súbor pre '%-.64s'; opravte ho!"
- spa "Clave de archivo antigua para la tabla '%-.64s'; reparelo!"
- swe "Gammal nyckelfil '%-.64s'; reparera registret"
- ukr "óÔÁÒÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ '%-.64s'; ÷¦ÄÎÏ×¦ÔØ ÊÏÇÏ!"
+ cze "Star-Bý klíèový soubor pro '%-.192s'; opravte ho."
+ dan "Gammel indeksfil for tabellen '%-.192s'; reparer den"
+ nla "Oude zoeksleutel file voor tabel '%-.192s'; repareer het!"
+ eng "Old key file for table '%-.192s'; repair it!"
+ jps "'%-.192s' ƒe[ƒuƒ‹‚͌¢Œ`Ž®‚Ì key file ‚̂悤‚Å‚·; C•œ‚ð‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabeli '%-.192s' võtmefail on aegunud; paranda see!"
+ fre "Vieux fichier d'index pour la table '%-.192s'; réparez le!"
+ ger "Alte Index-Datei für Tabelle '%-.192s'. Bitte reparieren"
+ greek "Ðáëáéü áñ÷åßï ôáîéíüìéóçò (key file) ãéá ôïí ðßíáêá '%-.192s'; Ðáñáêáëþ, äéïñèþóôå ôï!"
+ hun "Regi kulcsfile a '%-.192s'tablahoz; probalja kijavitani!"
+ ita "File chiave vecchio per la tabella '%-.192s'; riparalo!"
+ jpn "'%-.192s' ¥Æ¡¼¥Ö¥ë¤Ï¸Å¤¤·Á¼°¤Î key file ¤Î¤è¤¦¤Ç¤¹; ½¤Éü¤ò¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "'%-.192s' Å×À̺íÀÇ ÀÌÀü¹öÁ¯ÀÇ Å° Á¸Àç. ¼öÁ¤ÇϽÿÀ!"
+ nor "Gammel nøkkelfil for tabellen '%-.192s'; reparer den!"
+ norwegian-ny "Gammel nykkelfil for tabellen '%-.192s'; reparer den!"
+ pol "Plik kluczy dla tabeli '%-.192s' jest starego typu; napraw go!"
+ por "Arquivo de índice desatualizado para tabela '%-.192s'; repare-o!"
+ rum "Cheia fisierului e veche pentru tabela '%-.192s'; repar-o!"
+ rus "óÔÁÒÙÊ ÉÎÄÅËÓÎÙÊ ÆÁÊÌ ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'; ÏÔÒÅÍÏÎÔÉÒÕÊÔÅ ÅÇÏ!"
+ serbian "Zastareo key file za tabelu '%-.192s'; ispravite ga"
+ slo "Starý kµúèový súbor pre '%-.192s'; opravte ho!"
+ spa "Clave de archivo antigua para la tabla '%-.192s'; reparelo!"
+ swe "Gammal nyckelfil '%-.192s'; reparera registret"
+ ukr "óÔÁÒÉÊ ÆÁÊÌ ËÌÀÞÅÊ ÄÌÑ ÔÁÂÌÉæ '%-.192s'; ÷¦ÄÎÏ×¦ÔØ ÊÏÇÏ!"
ER_OPEN_AS_READONLY
- cze "'%-.64s' je jen pro -Bètení"
- dan "'%-.64s' er skrivebeskyttet"
- nla "'%-.64s' is alleen leesbaar"
- eng "Table '%-.64s' is read only"
- jps "'%-.64s' ‚͓ǂݞ‚Ýê—p‚Å‚·",
- est "Tabel '%-.64s' on ainult lugemiseks"
- fre "'%-.64s' est en lecture seulement"
- ger "Tabelle '%-.64s' ist nur lesbar"
- greek "'%-.64s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç"
- hun "'%-.64s' irasvedett"
- ita "'%-.64s' e` di sola lettura"
- jpn "'%-.64s' ¤ÏÆÉ¤ß¹þ¤ßÀìÍѤǤ¹"
- kor "Å×À̺í '%-.64s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù."
- nor "'%-.64s' er skrivebeskyttet"
- norwegian-ny "'%-.64s' er skrivetryggja"
- pol "'%-.64s' jest tylko do odczytu"
- por "Tabela '%-.64s' é somente para leitura"
- rum "Tabela '%-.64s' e read-only"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ"
- serbian "Tabelu '%-.64s' je dozvoljeno samo èitati"
- slo "'%-.64s' is èíta» only"
- spa "'%-.64s' es de solo lectura"
- swe "'%-.64s' är skyddad mot förändring"
- ukr "ôÁÂÌÉÃÑ '%-.64s' Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ"
+ cze "'%-.192s' je jen pro -Bètení"
+ dan "'%-.192s' er skrivebeskyttet"
+ nla "'%-.192s' is alleen leesbaar"
+ eng "Table '%-.192s' is read only"
+ jps "'%-.192s' ‚͓ǂݞ‚Ýê—p‚Å‚·",
+ est "Tabel '%-.192s' on ainult lugemiseks"
+ fre "'%-.192s' est en lecture seulement"
+ ger "Tabelle '%-.192s' ist nur lesbar"
+ greek "'%-.192s' åðéôñÝðåôáé ìüíï ç áíÜãíùóç"
+ hun "'%-.192s' irasvedett"
+ ita "'%-.192s' e` di sola lettura"
+ jpn "'%-.192s' ¤ÏÆÉ¤ß¹þ¤ßÀìÍѤǤ¹"
+ kor "Å×À̺í '%-.192s'´Â ÀбâÀü¿ë ÀÔ´Ï´Ù."
+ nor "'%-.192s' er skrivebeskyttet"
+ norwegian-ny "'%-.192s' er skrivetryggja"
+ pol "'%-.192s' jest tylko do odczytu"
+ por "Tabela '%-.192s' é somente para leitura"
+ rum "Tabela '%-.192s' e read-only"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÔÏÌØËÏ ÄÌÑ ÞÔÅÎÉÑ"
+ serbian "Tabelu '%-.192s' je dozvoljeno samo èitati"
+ slo "'%-.192s' is èíta» only"
+ spa "'%-.192s' es de solo lectura"
+ swe "'%-.192s' är skyddad mot förändring"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ"
ER_OUTOFMEMORY HY001 S1001
cze "M-Bálo pamìti. Pøestartujte daemona a zkuste znovu (je potøeba %d bytù)"
dan "Ikke mere hukommelse. Genstart serveren og prøv igen (mangler %d bytes)"
@@ -919,30 +919,30 @@ ER_OUT_OF_SORTMEMORY HY001 S1001
swe "Sorteringsbufferten räcker inte till. Kontrollera startparametrarna"
ukr "âÒÁË ÐÁÍ'ÑÔ¦ ÄÌÑ ÓÏÒÔÕ×ÁÎÎÑ. ôÒÅÂÁ ÚÂ¦ÌØÛÉÔÉ ÒÏÚÍ¦Ò ÂÕÆÅÒÁ ÓÏÒÔÕ×ÁÎÎÑ Õ ÓÅÒ×ÅÒÁ"
ER_UNEXPECTED_EOF
- cze "Neo-Bèekávaný konec souboru pøi ètení '%-.64s' (chybový kód: %d)"
- dan "Uventet afslutning på fil (eof) ved læsning af filen '%-.64s' (Fejlkode: %d)"
- nla "Onverwachte eof gevonden tijdens het lezen van file '%-.64s' (Errcode: %d)"
- eng "Unexpected EOF found when reading file '%-.64s' (errno: %d)"
- jps "'%-.64s' ƒtƒ@ƒCƒ‹‚ð“ǂݞ‚Ý’†‚É EOF ‚ª—\Šú‚¹‚ÊŠ‚ÅŒ»‚ê‚Ü‚µ‚½. (errno: %d)",
- est "Ootamatu faililõpumärgend faili '%-.64s' lugemisel (veakood: %d)"
- fre "Fin de fichier inattendue en lisant '%-.64s' (Errcode: %d)"
- ger "Unerwartetes Ende beim Lesen der Datei '%-.64s' (Fehler: %d)"
- greek "ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)"
- hun "Varatlan filevege-jel a '%-.64s'olvasasakor. (hibakod: %d)"
- ita "Fine del file inaspettata durante la lettura del file '%-.64s' (errno: %d)"
- jpn "'%-.64s' ¥Õ¥¡¥¤¥ë¤òÆÉ¤ß¹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)"
- kor "'%-.64s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)"
- nor "Uventet slutt på fil (eof) ved lesing av filen '%-.64s' (Feilkode: %d)"
- norwegian-ny "Uventa slutt på fil (eof) ved lesing av fila '%-.64s' (Feilkode: %d)"
- pol "Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.64s' (Kod b³êdu: %d)"
- por "Encontrado fim de arquivo inesperado ao ler arquivo '%-.64s' (erro no. %d)"
- rum "Sfirsit de fisier neasteptat in citirea fisierului '%-.64s' (errno: %d)"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.64s' (ÏÛÉÂËÁ: %d)"
- serbian "Neoèekivani kraj pri èitanju file-a '%-.64s' (errno: %d)"
- slo "Neoèakávaný koniec súboru pri èítaní '%-.64s' (chybový kód: %d)"
- spa "Inesperado fin de ficheroU mientras leiamos el archivo '%-.64s' (Error: %d)"
- swe "Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)"
- ukr "èÉÂÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ '%-.64s' (ÐÏÍÉÌËÁ: %d)"
+ cze "Neo-Bèekávaný konec souboru pøi ètení '%-.192s' (chybový kód: %d)"
+ dan "Uventet afslutning på fil (eof) ved læsning af filen '%-.192s' (Fejlkode: %d)"
+ nla "Onverwachte eof gevonden tijdens het lezen van file '%-.192s' (Errcode: %d)"
+ eng "Unexpected EOF found when reading file '%-.192s' (errno: %d)"
+ jps "'%-.192s' ƒtƒ@ƒCƒ‹‚ð“ǂݞ‚Ý’†‚É EOF ‚ª—\Šú‚¹‚ÊŠ‚ÅŒ»‚ê‚Ü‚µ‚½. (errno: %d)",
+ est "Ootamatu faililõpumärgend faili '%-.192s' lugemisel (veakood: %d)"
+ fre "Fin de fichier inattendue en lisant '%-.192s' (Errcode: %d)"
+ ger "Unerwartetes Ende beim Lesen der Datei '%-.192s' (Fehler: %d)"
+ greek "ÊáôÜ ôç äéÜñêåéá ôçò áíÜãíùóçò, âñÝèçêå áðñïóäüêçôá ôï ôÝëïò ôïõ áñ÷åßïõ '%-.192s' (êùäéêüò ëÜèïõò: %d)"
+ hun "Varatlan filevege-jel a '%-.192s'olvasasakor. (hibakod: %d)"
+ ita "Fine del file inaspettata durante la lettura del file '%-.192s' (errno: %d)"
+ jpn "'%-.192s' ¥Õ¥¡¥¤¥ë¤òÆÉ¤ß¹þ¤ßÃæ¤Ë EOF ¤¬Í½´ü¤»¤Ì½ê¤Ç¸½¤ì¤Þ¤·¤¿. (errno: %d)"
+ kor "'%-.192s' È­ÀÏÀ» Àд µµÁß À߸øµÈ eofÀ» ¹ß°ß (¿¡·¯¹øÈ£: %d)"
+ nor "Uventet slutt på fil (eof) ved lesing av filen '%-.192s' (Feilkode: %d)"
+ norwegian-ny "Uventa slutt på fil (eof) ved lesing av fila '%-.192s' (Feilkode: %d)"
+ pol "Nieoczekiwany 'eof' napotkany podczas czytania z pliku '%-.192s' (Kod b³êdu: %d)"
+ por "Encontrado fim de arquivo inesperado ao ler arquivo '%-.192s' (erro no. %d)"
+ rum "Sfirsit de fisier neasteptat in citirea fisierului '%-.192s' (errno: %d)"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ '%-.192s' (ÏÛÉÂËÁ: %d)"
+ serbian "Neoèekivani kraj pri èitanju file-a '%-.192s' (errno: %d)"
+ slo "Neoèakávaný koniec súboru pri èítaní '%-.192s' (chybový kód: %d)"
+ spa "Inesperado fin de ficheroU mientras leiamos el archivo '%-.192s' (Error: %d)"
+ swe "Oväntat filslut vid läsning från '%-.192s' (Felkod: %d)"
+ ukr "èÉÂÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ '%-.192s' (ÐÏÍÉÌËÁ: %d)"
ER_CON_COUNT_ERROR 08004
cze "P-Bøíli¹ mnoho spojení"
dan "For mange forbindelser (connections)"
@@ -950,7 +950,7 @@ ER_CON_COUNT_ERROR 08004
eng "Too many connections"
jps "Ú‘±‚ª‘½‚·‚¬‚Ü‚·",
est "Liiga palju samaaegseid ühendusi"
- fre "Trop de connections"
+ fre "Trop de connexions"
ger "Zu viele Verbindungen"
greek "ÕðÜñ÷ïõí ðïëëÝò óõíäÝóåéò..."
hun "Tul sok kapcsolat"
@@ -1041,53 +1041,53 @@ ER_HANDSHAKE_ERROR 08S01
swe "Fel vid initiering av kommunikationen med klienten"
ukr "îÅצÒÎÁ ÕÓÔÁÎÏ×ËÁ Ú×'ÑÚËÕ"
ER_DBACCESS_DENIED_ERROR 42000
- cze "P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' k databázi '%-.64s' není povolen"
- dan "Adgang nægtet bruger: '%-.32s'@'%-.64s' til databasen '%-.64s'"
- nla "Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' naar database '%-.64s'"
- eng "Access denied for user '%-.32s'@'%-.64s' to database '%-.64s'"
- jps "ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚Ì '%-.64s' ƒf[ƒ^ƒx[ƒX‚ւ̃AƒNƒZƒX‚ð‹‘”Û‚µ‚Ü‚·",
- est "Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' andmebaasile '%-.64s'"
- fre "Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s'. Base '%-.64s'"
- ger "Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.64s'"
- greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'"
- hun "A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz."
- ita "Accesso non consentito per l'utente: '%-.32s'@'%-.64s' al database '%-.64s'"
- jpn "¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹"
- kor "'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù."
- nor "Tilgang nektet for bruker: '%-.32s'@'%-.64s' til databasen '%-.64s' nektet"
- norwegian-ny "Tilgang ikkje tillate for brukar: '%-.32s'@'%-.64s' til databasen '%-.64s' nekta"
- por "Acesso negado para o usuário '%-.32s'@'%-.64s' ao banco de dados '%-.64s'"
- rum "Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' la baza de date '%-.64s'"
- rus "äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÚÁËÒÙÔ"
- serbian "Pristup je zabranjen korisniku '%-.32s'@'%-.64s' za bazu '%-.64s'"
- slo "Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' k databázi '%-.64s'"
- spa "Acceso negado para usuario: '%-.32s'@'%-.64s' para la base de datos '%-.64s'"
- swe "Användare '%-.32s'@'%-.64s' är ej berättigad att använda databasen %-.64s"
- ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.64s'"
+ cze "P-Bøístup pro u¾ivatele '%-.48s'@'%-.64s' k databázi '%-.192s' není povolen"
+ dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' til databasen '%-.192s'"
+ nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' naar database '%-.192s'"
+ eng "Access denied for user '%-.48s'@'%-.64s' to database '%-.192s'"
+ jps "ƒ†[ƒU[ '%-.48s'@'%-.64s' ‚Ì '%-.192s' ƒf[ƒ^ƒx[ƒX‚ւ̃AƒNƒZƒX‚ð‹‘”Û‚µ‚Ü‚·",
+ est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' andmebaasile '%-.192s'"
+ fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s'. Base '%-.192s'"
+ ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung für Datenbank '%-.192s'"
+ greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.48s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.192s'"
+ hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.192s' adabazishoz."
+ ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' al database '%-.192s'"
+ jpn "¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ¤Î '%-.192s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹"
+ kor "'%-.48s'@'%-.64s' »ç¿ëÀÚ´Â '%-.192s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù."
+ nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' til databasen '%-.192s' nektet"
+ norwegian-ny "Tilgang ikkje tillate for brukar: '%-.48s'@'%-.64s' til databasen '%-.192s' nekta"
+ por "Acesso negado para o usuário '%-.48s'@'%-.64s' ao banco de dados '%-.192s'"
+ rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' la baza de date '%-.192s'"
+ rus "äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÚÁËÒÙÔ"
+ serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' za bazu '%-.192s'"
+ slo "Zakázaný prístup pre u¾ívateµa: '%-.48s'@'%-.64s' k databázi '%-.192s'"
+ spa "Acceso negado para usuario: '%-.48s'@'%-.64s' para la base de datos '%-.192s'"
+ swe "Användare '%-.48s'@'%-.64s' är ej berättigad att använda databasen %-.192s"
+ ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.192s'"
ER_ACCESS_DENIED_ERROR 28000
- cze "P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' (s heslem %s)"
- dan "Adgang nægtet bruger: '%-.32s'@'%-.64s' (Bruger adgangskode: %s)"
- nla "Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' (Wachtwoord gebruikt: %s)"
- eng "Access denied for user '%-.32s'@'%-.64s' (using password: %s)"
- jps "ƒ†[ƒU[ '%-.32s'@'%-.64s' ‚ð‹‘”Û‚µ‚Ü‚·.uUsing password: %s)",
- est "Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' (kasutab parooli: %s)"
- fre "Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s' (mot de passe: %s)"
- ger "Benutzer '%-.32s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %-.64s)"
- greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' (÷ñÞóç password: %s)"
- hun "A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)"
- ita "Accesso non consentito per l'utente: '%-.32s'@'%-.64s' (Password: %s)"
- jpn "¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.uUsing password: %s)"
- kor "'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (using password: %s)"
- nor "Tilgang nektet for bruker: '%-.32s'@'%-.64s' (Bruker passord: %s)"
- norwegian-ny "Tilgang ikke tillate for brukar: '%-.32s'@'%-.64s' (Brukar passord: %s)"
- por "Acesso negado para o usuário '%-.32s'@'%-.64s' (senha usada: %s)"
- rum "Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' (Folosind parola: %s)"
- rus "äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)"
- serbian "Pristup je zabranjen korisniku '%-.32s'@'%-.64s' (koristi lozinku: '%s')"
- slo "Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' (pou¾itie hesla: %s)"
- spa "Acceso negado para usuario: '%-.32s'@'%-.64s' (Usando clave: %s)"
- swe "Användare '%-.32s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)"
- ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)"
+ cze "P-Bøístup pro u¾ivatele '%-.48s'@'%-.64s' (s heslem %s)"
+ dan "Adgang nægtet bruger: '%-.48s'@'%-.64s' (Bruger adgangskode: %s)"
+ nla "Toegang geweigerd voor gebruiker: '%-.48s'@'%-.64s' (Wachtwoord gebruikt: %s)"
+ eng "Access denied for user '%-.48s'@'%-.64s' (using password: %s)"
+ jps "ƒ†[ƒU[ '%-.48s'@'%-.64s' ‚ð‹‘”Û‚µ‚Ü‚·.uUsing password: %s)",
+ est "Ligipääs keelatud kasutajale '%-.48s'@'%-.64s' (kasutab parooli: %s)"
+ fre "Accès refusé pour l'utilisateur: '%-.48s'@'@%-.64s' (mot de passe: %s)"
+ ger "Benutzer '%-.48s'@'%-.64s' hat keine Zugriffsberechtigung (verwendetes Passwort: %s)"
+ greek "Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.48s'@'%-.64s' (÷ñÞóç password: %s)"
+ hun "A(z) '%-.48s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)"
+ ita "Accesso non consentito per l'utente: '%-.48s'@'%-.64s' (Password: %s)"
+ jpn "¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.uUsing password: %s)"
+ kor "'%-.48s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (using password: %s)"
+ nor "Tilgang nektet for bruker: '%-.48s'@'%-.64s' (Bruker passord: %s)"
+ norwegian-ny "Tilgang ikke tillate for brukar: '%-.48s'@'%-.64s' (Brukar passord: %s)"
+ por "Acesso negado para o usuário '%-.48s'@'%-.64s' (senha usada: %s)"
+ rum "Acces interzis pentru utilizatorul: '%-.48s'@'%-.64s' (Folosind parola: %s)"
+ rus "äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)"
+ serbian "Pristup je zabranjen korisniku '%-.48s'@'%-.64s' (koristi lozinku: '%s')"
+ slo "Zakázaný prístup pre u¾ívateµa: '%-.48s'@'%-.64s' (pou¾itie hesla: %s)"
+ spa "Acceso negado para usuario: '%-.48s'@'%-.64s' (Usando clave: %s)"
+ swe "Användare '%-.48s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)"
+ ukr "äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)"
ER_NO_DB_ERROR 3D000
cze "Nebyla vybr-Bána ¾ádná databáze"
dan "Ingen database valgt"
@@ -1139,80 +1139,80 @@ ER_UNKNOWN_COM_ERROR 08S01
swe "Okänt commando"
ukr "îÅצÄÏÍÁ ËÏÍÁÎÄÁ"
ER_BAD_NULL_ERROR 23000
- cze "Sloupec '%-.64s' nem-Bù¾e být null"
- dan "Kolonne '%-.64s' kan ikke være NULL"
- nla "Kolom '%-.64s' kan niet null zijn"
- eng "Column '%-.64s' cannot be null"
- jps "Column '%-.64s' ‚Í null ‚ɂ͂ł«‚È‚¢‚̂ł·",
- est "Tulp '%-.64s' ei saa omada nullväärtust"
- fre "Le champ '%-.64s' ne peut être vide (null)"
- ger "Feld '%-.64s' darf nicht NULL sein"
- greek "Ôï ðåäßï '%-.64s' äåí ìðïñåß íá åßíáé êåíü (null)"
- hun "A(z) '%-.64s' oszlop erteke nem lehet nulla"
- ita "La colonna '%-.64s' non puo` essere nulla"
- jpn "Column '%-.64s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹"
- kor "Ä®·³ '%-.64s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. "
- nor "Kolonne '%-.64s' kan ikke vere null"
- norwegian-ny "Kolonne '%-.64s' kan ikkje vere null"
- pol "Kolumna '%-.64s' nie mo¿e byæ null"
- por "Coluna '%-.64s' não pode ser vazia"
- rum "Coloana '%-.64s' nu poate sa fie null"
- rus "óÔÏÌÂÅà '%-.64s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL"
- serbian "Kolona '%-.64s' ne može biti NULL"
- slo "Pole '%-.64s' nemô¾e by» null"
- spa "La columna '%-.64s' no puede ser nula"
- swe "Kolumn '%-.64s' får inte vara NULL"
- ukr "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ"
+ cze "Sloupec '%-.192s' nem-Bù¾e být null"
+ dan "Kolonne '%-.192s' kan ikke være NULL"
+ nla "Kolom '%-.192s' kan niet null zijn"
+ eng "Column '%-.192s' cannot be null"
+ jps "Column '%-.192s' ‚Í null ‚ɂ͂ł«‚È‚¢‚̂ł·",
+ est "Tulp '%-.192s' ei saa omada nullväärtust"
+ fre "Le champ '%-.192s' ne peut être vide (null)"
+ ger "Feld '%-.192s' darf nicht NULL sein"
+ greek "Ôï ðåäßï '%-.192s' äåí ìðïñåß íá åßíáé êåíü (null)"
+ hun "A(z) '%-.192s' oszlop erteke nem lehet nulla"
+ ita "La colonna '%-.192s' non puo` essere nulla"
+ jpn "Column '%-.192s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹"
+ kor "Ä®·³ '%-.192s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. "
+ nor "Kolonne '%-.192s' kan ikke vere null"
+ norwegian-ny "Kolonne '%-.192s' kan ikkje vere null"
+ pol "Kolumna '%-.192s' nie mo¿e byæ null"
+ por "Coluna '%-.192s' não pode ser vazia"
+ rum "Coloana '%-.192s' nu poate sa fie null"
+ rus "óÔÏÌÂÅà '%-.192s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL"
+ serbian "Kolona '%-.192s' ne može biti NULL"
+ slo "Pole '%-.192s' nemô¾e by» null"
+ spa "La columna '%-.192s' no puede ser nula"
+ swe "Kolumn '%-.192s' får inte vara NULL"
+ ukr "óÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ"
ER_BAD_DB_ERROR 42000
- cze "Nezn-Bámá databáze '%-.64s'"
- dan "Ukendt database '%-.64s'"
- nla "Onbekende database '%-.64s'"
- eng "Unknown database '%-.64s'"
- jps "'%-.64s' ‚È‚ñ‚ăf[ƒ^ƒx[ƒX‚Í’m‚è‚Ü‚¹‚ñ.",
- est "Tundmatu andmebaas '%-.64s'"
- fre "Base '%-.64s' inconnue"
- ger "Unbekannte Datenbank '%-.64s'"
- greek "Áãíùóôç âÜóç äåäïìÝíùí '%-.64s'"
- hun "Ervenytelen adatbazis: '%-.64s'"
- ita "Database '%-.64s' sconosciuto"
- jpn "'%-.64s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó."
- kor "µ¥ÀÌŸº£À̽º '%-.64s'´Â ¾Ë¼ö ¾øÀ½"
- nor "Ukjent database '%-.64s'"
- norwegian-ny "Ukjent database '%-.64s'"
- pol "Nieznana baza danych '%-.64s'"
- por "Banco de dados '%-.64s' desconhecido"
- rum "Baza de data invalida '%-.64s'"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ ÄÁÎÎÙÈ '%-.64s'"
- serbian "Nepoznata baza '%-.64s'"
- slo "Neznáma databáza '%-.64s'"
- spa "Base de datos desconocida '%-.64s'"
- swe "Okänd databas: '%-.64s'"
- ukr "îÅצÄÏÍÁ ÂÁÚÁ ÄÁÎÎÉÈ '%-.64s'"
+ cze "Nezn-Bámá databáze '%-.192s'"
+ dan "Ukendt database '%-.192s'"
+ nla "Onbekende database '%-.192s'"
+ eng "Unknown database '%-.192s'"
+ jps "'%-.192s' ‚È‚ñ‚ăf[ƒ^ƒx[ƒX‚Í’m‚è‚Ü‚¹‚ñ.",
+ est "Tundmatu andmebaas '%-.192s'"
+ fre "Base '%-.192s' inconnue"
+ ger "Unbekannte Datenbank '%-.192s'"
+ greek "Áãíùóôç âÜóç äåäïìÝíùí '%-.192s'"
+ hun "Ervenytelen adatbazis: '%-.192s'"
+ ita "Database '%-.192s' sconosciuto"
+ jpn "'%-.192s' ¤Ê¤ó¤Æ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÏÃΤê¤Þ¤»¤ó."
+ kor "µ¥ÀÌŸº£À̽º '%-.192s'´Â ¾Ë¼ö ¾øÀ½"
+ nor "Ukjent database '%-.192s'"
+ norwegian-ny "Ukjent database '%-.192s'"
+ pol "Nieznana baza danych '%-.192s'"
+ por "Banco de dados '%-.192s' desconhecido"
+ rum "Baza de data invalida '%-.192s'"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÂÁÚÁ ÄÁÎÎÙÈ '%-.192s'"
+ serbian "Nepoznata baza '%-.192s'"
+ slo "Neznáma databáza '%-.192s'"
+ spa "Base de datos desconocida '%-.192s'"
+ swe "Okänd databas: '%-.192s'"
+ ukr "îÅצÄÏÍÁ ÂÁÚÁ ÄÁÎÎÉÈ '%-.192s'"
ER_TABLE_EXISTS_ERROR 42S01
- cze "Tabulka '%-.64s' ji-B¾ existuje"
- dan "Tabellen '%-.64s' findes allerede"
- nla "Tabel '%-.64s' bestaat al"
- eng "Table '%-.64s' already exists"
- jps "Table '%-.64s' ‚ÍŠù‚É‚ ‚è‚Ü‚·",
- est "Tabel '%-.64s' juba eksisteerib"
- fre "La table '%-.64s' existe déjà"
- ger "Tabelle '%-.64s' bereits vorhanden"
- greek "Ï ðßíáêáò '%-.64s' õðÜñ÷åé Þäç"
- hun "A(z) '%-.64s' tabla mar letezik"
- ita "La tabella '%-.64s' esiste gia`"
- jpn "Table '%-.64s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹"
- kor "Å×À̺í '%-.64s'´Â ÀÌ¹Ì Á¸ÀçÇÔ"
- nor "Tabellen '%-.64s' eksisterer allerede"
- norwegian-ny "Tabellen '%-.64s' eksisterar allereide"
- pol "Tabela '%-.64s' ju¿ istnieje"
- por "Tabela '%-.64s' já existe"
- rum "Tabela '%-.64s' exista deja"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Tabela '%-.64s' veæ postoji"
- slo "Tabuµka '%-.64s' u¾ existuje"
- spa "La tabla '%-.64s' ya existe"
- swe "Tabellen '%-.64s' finns redan"
- ukr "ôÁÂÌÉÃÑ '%-.64s' ×ÖÅ ¦ÓÎÕ¤"
+ cze "Tabulka '%-.192s' ji-B¾ existuje"
+ dan "Tabellen '%-.192s' findes allerede"
+ nla "Tabel '%-.192s' bestaat al"
+ eng "Table '%-.192s' already exists"
+ jps "Table '%-.192s' ‚ÍŠù‚É‚ ‚è‚Ü‚·",
+ est "Tabel '%-.192s' juba eksisteerib"
+ fre "La table '%-.192s' existe déjà"
+ ger "Tabelle '%-.192s' bereits vorhanden"
+ greek "Ï ðßíáêáò '%-.192s' õðÜñ÷åé Þäç"
+ hun "A(z) '%-.192s' tabla mar letezik"
+ ita "La tabella '%-.192s' esiste gia`"
+ jpn "Table '%-.192s' ¤Ï´û¤Ë¤¢¤ê¤Þ¤¹"
+ kor "Å×À̺í '%-.192s'´Â ÀÌ¹Ì Á¸ÀçÇÔ"
+ nor "Tabellen '%-.192s' eksisterer allerede"
+ norwegian-ny "Tabellen '%-.192s' eksisterar allereide"
+ pol "Tabela '%-.192s' ju¿ istnieje"
+ por "Tabela '%-.192s' já existe"
+ rum "Tabela '%-.192s' exista deja"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Tabela '%-.192s' veæ postoji"
+ slo "Tabuµka '%-.192s' u¾ existuje"
+ spa "La tabla '%-.192s' ya existe"
+ swe "Tabellen '%-.192s' finns redan"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' ×ÖÅ ¦ÓÎÕ¤"
ER_BAD_TABLE_ERROR 42S02
cze "Nezn-Bámá tabulka '%-.100s'"
dan "Ukendt tabel '%-.100s'"
@@ -1239,29 +1239,29 @@ ER_BAD_TABLE_ERROR 42S02
swe "Okänd tabell '%-.100s'"
ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.100s'"
ER_NON_UNIQ_ERROR 23000
- cze "Sloupec '%-.64s' v %s nen-Bí zcela jasný"
- dan "Felt: '%-.64s' i tabel %s er ikke entydigt"
- nla "Kolom: '%-.64s' in %s is niet eenduidig"
- eng "Column '%-.64s' in %-.64s is ambiguous"
- est "Väli '%-.64s' %-.64s-s ei ole ühene"
- fre "Champ: '%-.64s' dans %s est ambigu"
- ger "Feld '%-.64s' in %-.64s ist nicht eindeutig"
- greek "Ôï ðåäßï: '%-.64s' óå %-.64s äåí Ý÷åé êáèïñéóôåß"
- hun "A(z) '%-.64s' oszlop %-.64s-ben ketertelmu"
- ita "Colonna: '%-.64s' di %-.64s e` ambigua"
- jpn "Column: '%-.64s' in %-.64s is ambiguous"
- kor "Ä®·³: '%-.64s' in '%-.64s' ÀÌ ¸ðÈ£ÇÔ"
- nor "Felt: '%-.64s' i tabell %s er ikke entydig"
- norwegian-ny "Kolonne: '%-.64s' i tabell %s er ikkje eintydig"
- pol "Kolumna: '%-.64s' w %s jest dwuznaczna"
- por "Coluna '%-.64s' em '%-.64s' é ambígua"
- rum "Coloana: '%-.64s' in %-.64s este ambigua"
- rus "óÔÏÌÂÅÃ '%-.64s' × %-.64s ÚÁÄÁÎ ÎÅÏÄÎÏÚÎÁÞÎÏ"
- serbian "Kolona '%-.64s' u %-.64s nije jedinstvena u kontekstu"
- slo "Pole: '%-.64s' v %-.64s je nejasné"
- spa "La columna: '%-.64s' en %s es ambigua"
- swe "Kolumn '%-.64s' i %s är inte unik"
- ukr "óÔÏ×ÂÅÃØ '%-.64s' Õ %-.64s ×ÉÚÎÁÞÅÎÉÊ ÎÅÏÄÎÏÚÎÁÞÎÏ"
+ cze "Sloupec '%-.192s' v %-.192s nen-Bí zcela jasný"
+ dan "Felt: '%-.192s' i tabel %-.192s er ikke entydigt"
+ nla "Kolom: '%-.192s' in %-.192s is niet eenduidig"
+ eng "Column '%-.192s' in %-.192s is ambiguous"
+ est "Väli '%-.192s' %-.192s-s ei ole ühene"
+ fre "Champ: '%-.192s' dans %-.192s est ambigu"
+ ger "Feld '%-.192s' in %-.192s ist nicht eindeutig"
+ greek "Ôï ðåäßï: '%-.192s' óå %-.192s äåí Ý÷åé êáèïñéóôåß"
+ hun "A(z) '%-.192s' oszlop %-.192s-ben ketertelmu"
+ ita "Colonna: '%-.192s' di %-.192s e` ambigua"
+ jpn "Column: '%-.192s' in %-.192s is ambiguous"
+ kor "Ä®·³: '%-.192s' in '%-.192s' ÀÌ ¸ðÈ£ÇÔ"
+ nor "Felt: '%-.192s' i tabell %-.192s er ikke entydig"
+ norwegian-ny "Kolonne: '%-.192s' i tabell %-.192s er ikkje eintydig"
+ pol "Kolumna: '%-.192s' w %-.192s jest dwuznaczna"
+ por "Coluna '%-.192s' em '%-.192s' é ambígua"
+ rum "Coloana: '%-.192s' in %-.192s este ambigua"
+ rus "óÔÏÌÂÅÃ '%-.192s' × %-.192s ÚÁÄÁÎ ÎÅÏÄÎÏÚÎÁÞÎÏ"
+ serbian "Kolona '%-.192s' u %-.192s nije jedinstvena u kontekstu"
+ slo "Pole: '%-.192s' v %-.192s je nejasné"
+ spa "La columna: '%-.192s' en %-.192s es ambigua"
+ swe "Kolumn '%-.192s' i %-.192s är inte unik"
+ ukr "óÔÏ×ÂÅÃØ '%-.192s' Õ %-.192s ×ÉÚÎÁÞÅÎÉÊ ÎÅÏÄÎÏÚÎÁÞÎÏ"
ER_SERVER_SHUTDOWN 08S01
cze "Prob-Bíhá ukonèování práce serveru"
dan "Database nedlukning er i gang"
@@ -1288,77 +1288,77 @@ ER_SERVER_SHUTDOWN 08S01
swe "Servern går nu ned"
ukr "úÁ×ÅÒÛÕ¤ÔØÓÑ ÒÁÂÏÔÁ ÓÅÒ×ÅÒÁ"
ER_BAD_FIELD_ERROR 42S22 S0022
- cze "Nezn-Bámý sloupec '%-.64s' v %s"
- dan "Ukendt kolonne '%-.64s' i tabel %s"
- nla "Onbekende kolom '%-.64s' in %s"
- eng "Unknown column '%-.64s' in '%-.64s'"
- jps "'%-.64s' column ‚Í '%-.64s' ‚ɂ͂ ‚è‚Ü‚¹‚ñ.",
- est "Tundmatu tulp '%-.64s' '%-.64s'-s"
- fre "Champ '%-.64s' inconnu dans %s"
- ger "Unbekanntes Tabellenfeld '%-.64s' in %-.64s"
- greek "Áãíùóôï ðåäßï '%-.64s' óå '%-.64s'"
- hun "A(z) '%-.64s' oszlop ervenytelen '%-.64s'-ben"
- ita "Colonna sconosciuta '%-.64s' in '%-.64s'"
- jpn "'%-.64s' column ¤Ï '%-.64s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó."
- kor "Unknown Ä®·³ '%-.64s' in '%-.64s'"
- nor "Ukjent kolonne '%-.64s' i tabell %s"
- norwegian-ny "Ukjent felt '%-.64s' i tabell %s"
- pol "Nieznana kolumna '%-.64s' w %s"
- por "Coluna '%-.64s' desconhecida em '%-.64s'"
- rum "Coloana invalida '%-.64s' in '%-.64s'"
- rus "îÅÉÚ×ÅÓÔÎÙÊ ÓÔÏÌÂÅà '%-.64s' × '%-.64s'"
- serbian "Nepoznata kolona '%-.64s' u '%-.64s'"
- slo "Neznáme pole '%-.64s' v '%-.64s'"
- spa "La columna '%-.64s' en %s es desconocida"
- swe "Okänd kolumn '%-.64s' i %s"
- ukr "îÅצÄÏÍÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' Õ '%-.64s'"
+ cze "Nezn-Bámý sloupec '%-.192s' v %-.192s"
+ dan "Ukendt kolonne '%-.192s' i tabel %-.192s"
+ nla "Onbekende kolom '%-.192s' in %-.192s"
+ eng "Unknown column '%-.192s' in '%-.192s'"
+ jps "'%-.192s' column ‚Í '%-.192s' ‚ɂ͂ ‚è‚Ü‚¹‚ñ.",
+ est "Tundmatu tulp '%-.192s' '%-.192s'-s"
+ fre "Champ '%-.192s' inconnu dans %-.192s"
+ ger "Unbekanntes Tabellenfeld '%-.192s' in %-.192s"
+ greek "Áãíùóôï ðåäßï '%-.192s' óå '%-.192s'"
+ hun "A(z) '%-.192s' oszlop ervenytelen '%-.192s'-ben"
+ ita "Colonna sconosciuta '%-.192s' in '%-.192s'"
+ jpn "'%-.192s' column ¤Ï '%-.192s' ¤Ë¤Ï¤¢¤ê¤Þ¤»¤ó."
+ kor "Unknown Ä®·³ '%-.192s' in '%-.192s'"
+ nor "Ukjent kolonne '%-.192s' i tabell %-.192s"
+ norwegian-ny "Ukjent felt '%-.192s' i tabell %-.192s"
+ pol "Nieznana kolumna '%-.192s' w %-.192s"
+ por "Coluna '%-.192s' desconhecida em '%-.192s'"
+ rum "Coloana invalida '%-.192s' in '%-.192s'"
+ rus "îÅÉÚ×ÅÓÔÎÙÊ ÓÔÏÌÂÅà '%-.192s' × '%-.192s'"
+ serbian "Nepoznata kolona '%-.192s' u '%-.192s'"
+ slo "Neznáme pole '%-.192s' v '%-.192s'"
+ spa "La columna '%-.192s' en %-.192s es desconocida"
+ swe "Okänd kolumn '%-.192s' i %-.192s"
+ ukr "îÅצÄÏÍÉÊ ÓÔÏ×ÂÅÃØ '%-.192s' Õ '%-.192s'"
ER_WRONG_FIELD_WITH_GROUP 42000 S1009
- cze "Pou-B¾ité '%-.64s' nebylo v group by"
- dan "Brugte '%-.64s' som ikke var i group by"
- nla "Opdracht gebruikt '%-.64s' dat niet in de GROUP BY voorkomt"
- eng "'%-.64s' isn't in GROUP BY"
- jps "'%-.64s' isn't in GROUP BY",
- est "'%-.64s' puudub GROUP BY klauslis"
- fre "'%-.64s' n'est pas dans 'group by'"
- ger "'%-.64s' ist nicht in GROUP BY vorhanden"
- greek "×ñçóéìïðïéÞèçêå '%-.64s' ðïõ äåí õðÞñ÷å óôï group by"
- hun "Used '%-.64s' with wasn't in group by"
- ita "Usato '%-.64s' che non e` nel GROUP BY"
- kor "'%-.64s'Àº GROUP BY¼Ó¿¡ ¾øÀ½"
- nor "Brukte '%-.64s' som ikke var i group by"
- norwegian-ny "Brukte '%-.64s' som ikkje var i group by"
- pol "U¿yto '%-.64s' bez umieszczenia w group by"
- por "'%-.64s' não está em 'GROUP BY'"
- rum "'%-.64s' nu exista in clauza GROUP BY"
- rus "'%-.64s' ÎÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × GROUP BY"
- serbian "Entitet '%-.64s' nije naveden u komandi 'GROUP BY'"
- slo "Pou¾ité '%-.64s' nebolo v 'group by'"
- spa "Usado '%-.64s' el cual no esta group by"
- swe "'%-.64s' finns inte i GROUP BY"
- ukr "'%-.64s' ÎÅ ¤ Õ GROUP BY"
+ cze "Pou-B¾ité '%-.192s' nebylo v group by"
+ dan "Brugte '%-.192s' som ikke var i group by"
+ nla "Opdracht gebruikt '%-.192s' dat niet in de GROUP BY voorkomt"
+ eng "'%-.192s' isn't in GROUP BY"
+ jps "'%-.192s' isn't in GROUP BY",
+ est "'%-.192s' puudub GROUP BY klauslis"
+ fre "'%-.192s' n'est pas dans 'group by'"
+ ger "'%-.192s' ist nicht in GROUP BY vorhanden"
+ greek "×ñçóéìïðïéÞèçêå '%-.192s' ðïõ äåí õðÞñ÷å óôï group by"
+ hun "Used '%-.192s' with wasn't in group by"
+ ita "Usato '%-.192s' che non e` nel GROUP BY"
+ kor "'%-.192s'Àº GROUP BY¼Ó¿¡ ¾øÀ½"
+ nor "Brukte '%-.192s' som ikke var i group by"
+ norwegian-ny "Brukte '%-.192s' som ikkje var i group by"
+ pol "U¿yto '%-.192s' bez umieszczenia w group by"
+ por "'%-.192s' não está em 'GROUP BY'"
+ rum "'%-.192s' nu exista in clauza GROUP BY"
+ rus "'%-.192s' ÎÅ ÐÒÉÓÕÔÓÔ×ÕÅÔ × GROUP BY"
+ serbian "Entitet '%-.192s' nije naveden u komandi 'GROUP BY'"
+ slo "Pou¾ité '%-.192s' nebolo v 'group by'"
+ spa "Usado '%-.192s' el cual no esta group by"
+ swe "'%-.192s' finns inte i GROUP BY"
+ ukr "'%-.192s' ÎÅ ¤ Õ GROUP BY"
ER_WRONG_GROUP_FIELD 42000 S1009
- cze "Nemohu pou-B¾ít group na '%-.64s'"
- dan "Kan ikke gruppere på '%-.64s'"
- nla "Kan '%-.64s' niet groeperen"
- eng "Can't group on '%-.64s'"
- est "Ei saa grupeerida '%-.64s' järgi"
- fre "Ne peut regrouper '%-.64s'"
- ger "Gruppierung über '%-.64s' nicht möglich"
- greek "Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.64s'"
- hun "A group nem hasznalhato: '%-.64s'"
- ita "Impossibile raggruppare per '%-.64s'"
- kor "'%-.64s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½"
- nor "Kan ikke gruppere på '%-.64s'"
- norwegian-ny "Kan ikkje gruppere på '%-.64s'"
- pol "Nie mo¿na grupowaæ po '%-.64s'"
- por "Não pode agrupar em '%-.64s'"
- rum "Nu pot sa grupez pe (group on) '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.64s'"
- serbian "Ne mogu da grupišem po '%-.64s'"
- slo "Nemô¾em pou¾i» 'group' na '%-.64s'"
- spa "No puedo agrupar por '%-.64s'"
- swe "Kan inte använda GROUP BY med '%-.64s'"
- ukr "îÅ ÍÏÖÕ ÇÒÕÐÕ×ÁÔÉ ÐÏ '%-.64s'"
+ cze "Nemohu pou-B¾ít group na '%-.192s'"
+ dan "Kan ikke gruppere på '%-.192s'"
+ nla "Kan '%-.192s' niet groeperen"
+ eng "Can't group on '%-.192s'"
+ est "Ei saa grupeerida '%-.192s' järgi"
+ fre "Ne peut regrouper '%-.192s'"
+ ger "Gruppierung über '%-.192s' nicht möglich"
+ greek "Áäýíáôç ç ïìáäïðïßçóç (group on) '%-.192s'"
+ hun "A group nem hasznalhato: '%-.192s'"
+ ita "Impossibile raggruppare per '%-.192s'"
+ kor "'%-.192s'¸¦ ±×·ìÇÒ ¼ö ¾øÀ½"
+ nor "Kan ikke gruppere på '%-.192s'"
+ norwegian-ny "Kan ikkje gruppere på '%-.192s'"
+ pol "Nie mo¿na grupowaæ po '%-.192s'"
+ por "Não pode agrupar em '%-.192s'"
+ rum "Nu pot sa grupez pe (group on) '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÐÒÏÉÚ×ÅÓÔÉ ÇÒÕÐÐÉÒÏ×ËÕ ÐÏ '%-.192s'"
+ serbian "Ne mogu da grupišem po '%-.192s'"
+ slo "Nemô¾em pou¾i» 'group' na '%-.192s'"
+ spa "No puedo agrupar por '%-.192s'"
+ swe "Kan inte använda GROUP BY med '%-.192s'"
+ ukr "îÅ ÍÏÖÕ ÇÒÕÐÕ×ÁÔÉ ÐÏ '%-.192s'"
ER_WRONG_SUM_SELECT 42000 S1009
cze "P-Bøíkaz obsahuje zároveò funkci sum a sloupce"
dan "Udtrykket har summer (sum) funktioner og kolonner i samme udtryk"
@@ -1404,152 +1404,152 @@ ER_WRONG_VALUE_COUNT 21S01
swe "Antalet kolumner motsvarar inte antalet värden"
ukr "ë¦ÌØË¦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØË¦ÓÔÀ ÚÎÁÞÅÎØ"
ER_TOO_LONG_IDENT 42000 S1009
- cze "Jm-Béno identifikátoru '%-.64s' je pøíli¹ dlouhé"
- dan "Navnet '%-.64s' er for langt"
- nla "Naam voor herkenning '%-.64s' is te lang"
+ cze "Jm-Béno identifikátoru '%-.100s' je pøíli¹ dlouhé"
+ dan "Navnet '%-.100s' er for langt"
+ nla "Naam voor herkenning '%-.100s' is te lang"
eng "Identifier name '%-.100s' is too long"
jps "Identifier name '%-.100s' ‚Í’·‚·‚¬‚Ü‚·",
est "Identifikaatori '%-.100s' nimi on liiga pikk"
- fre "Le nom de l'identificateur '%-.64s' est trop long"
+ fre "Le nom de l'identificateur '%-.100s' est trop long"
ger "Name des Bezeichners '%-.100s' ist zu lang"
greek "Ôï identifier name '%-.100s' åßíáé ðïëý ìåãÜëï"
hun "A(z) '%-.100s' azonositonev tul hosszu."
ita "Il nome dell'identificatore '%-.100s' e` troppo lungo"
jpn "Identifier name '%-.100s' ¤ÏŤ¹¤®¤Þ¤¹"
kor "Identifier '%-.100s'´Â ³Ê¹« ±æ±º¿ä."
- nor "Identifikator '%-.64s' er for lang"
- norwegian-ny "Identifikator '%-.64s' er for lang"
- pol "Nazwa identyfikatora '%-.64s' jest zbyt d³uga"
+ nor "Identifikator '%-.100s' er for lang"
+ norwegian-ny "Identifikator '%-.100s' er for lang"
+ pol "Nazwa identyfikatora '%-.100s' jest zbyt d³uga"
por "Nome identificador '%-.100s' é longo demais"
rum "Numele indentificatorului '%-.100s' este prea lung"
rus "óÌÉÛËÏÍ ÄÌÉÎÎÙÊ ÉÄÅÎÔÉÆÉËÁÔÏÒ '%-.100s'"
serbian "Ime '%-.100s' je predugaèko"
slo "Meno identifikátora '%-.100s' je príli¹ dlhé"
- spa "El nombre del identificador '%-.64s' es demasiado grande"
- swe "Kolumnnamn '%-.64s' är för långt"
+ spa "El nombre del identificador '%-.100s' es demasiado grande"
+ swe "Kolumnnamn '%-.100s' är för långt"
ukr "¶Í'Ñ ¦ÄÅÎÔÉÆ¦ËÁÔÏÒÁ '%-.100s' ÚÁÄÏ×ÇÅ"
ER_DUP_FIELDNAME 42S21 S1009
- cze "Zdvojen-Bé jméno sloupce '%-.64s'"
- dan "Feltnavnet '%-.64s' findes allerede"
- nla "Dubbele kolom naam '%-.64s'"
- eng "Duplicate column name '%-.64s'"
- jps "'%-.64s' ‚Æ‚¢‚¤ column –¼‚Íd•¡‚µ‚Ă܂·",
- est "Kattuv tulba nimi '%-.64s'"
- fre "Nom du champ '%-.64s' déjà utilisé"
- ger "Doppelter Spaltenname: '%-.64s'"
- greek "ÅðáíÜëçøç column name '%-.64s'"
- hun "Duplikalt oszlopazonosito: '%-.64s'"
- ita "Nome colonna duplicato '%-.64s'"
- jpn "'%-.64s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹"
- kor "Áߺ¹µÈ Ä®·³ À̸§: '%-.64s'"
- nor "Feltnavnet '%-.64s' eksisterte fra før"
- norwegian-ny "Feltnamnet '%-.64s' eksisterte frå før"
- pol "Powtórzona nazwa kolumny '%-.64s'"
- por "Nome da coluna '%-.64s' duplicado"
- rum "Numele coloanei '%-.64s' e duplicat"
- rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ÓÔÏÌÂÃÁ '%-.64s'"
- serbian "Duplirano ime kolone '%-.64s'"
- slo "Opakované meno poµa '%-.64s'"
- spa "Nombre de columna duplicado '%-.64s'"
- swe "Kolumnnamn '%-.64s finns flera gånger"
- ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.64s'"
+ cze "Zdvojen-Bé jméno sloupce '%-.192s'"
+ dan "Feltnavnet '%-.192s' findes allerede"
+ nla "Dubbele kolom naam '%-.192s'"
+ eng "Duplicate column name '%-.192s'"
+ jps "'%-.192s' ‚Æ‚¢‚¤ column –¼‚Íd•¡‚µ‚Ă܂·",
+ est "Kattuv tulba nimi '%-.192s'"
+ fre "Nom du champ '%-.192s' déjà utilisé"
+ ger "Doppelter Spaltenname: '%-.192s'"
+ greek "ÅðáíÜëçøç column name '%-.192s'"
+ hun "Duplikalt oszlopazonosito: '%-.192s'"
+ ita "Nome colonna duplicato '%-.192s'"
+ jpn "'%-.192s' ¤È¤¤¤¦ column ̾¤Ï½ÅÊ£¤·¤Æ¤Þ¤¹"
+ kor "Áߺ¹µÈ Ä®·³ À̸§: '%-.192s'"
+ nor "Feltnavnet '%-.192s' eksisterte fra før"
+ norwegian-ny "Feltnamnet '%-.192s' eksisterte frå før"
+ pol "Powtórzona nazwa kolumny '%-.192s'"
+ por "Nome da coluna '%-.192s' duplicado"
+ rum "Numele coloanei '%-.192s' e duplicat"
+ rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ÓÔÏÌÂÃÁ '%-.192s'"
+ serbian "Duplirano ime kolone '%-.192s'"
+ slo "Opakované meno poµa '%-.192s'"
+ spa "Nombre de columna duplicado '%-.192s'"
+ swe "Kolumnnamn '%-.192s finns flera gånger"
+ ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.192s'"
ER_DUP_KEYNAME 42000 S1009
- cze "Zdvojen-Bé jméno klíèe '%-.64s'"
- dan "Indeksnavnet '%-.64s' findes allerede"
- nla "Dubbele zoeksleutel naam '%-.64s'"
- eng "Duplicate key name '%-.64s'"
- jps "'%-.64s' ‚Æ‚¢‚¤ key ‚Ì–¼‘O‚Íd•¡‚µ‚Ä‚¢‚Ü‚·",
- est "Kattuv võtme nimi '%-.64s'"
- fre "Nom de clef '%-.64s' déjà utilisé"
- ger "Doppelter Name für Schlüssel vorhanden: '%-.64s'"
- greek "ÅðáíÜëçøç key name '%-.64s'"
- hun "Duplikalt kulcsazonosito: '%-.64s'"
- ita "Nome chiave duplicato '%-.64s'"
- jpn "'%-.64s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
- kor "Áߺ¹µÈ Ű À̸§ : '%-.64s'"
- nor "Nøkkelnavnet '%-.64s' eksisterte fra før"
- norwegian-ny "Nøkkelnamnet '%-.64s' eksisterte frå før"
- pol "Powtórzony nazwa klucza '%-.64s'"
- por "Nome da chave '%-.64s' duplicado"
- rum "Numele cheiei '%-.64s' e duplicat"
- rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ËÌÀÞÁ '%-.64s'"
- serbian "Duplirano ime kljuèa '%-.64s'"
- slo "Opakované meno kµúèa '%-.64s'"
- spa "Nombre de clave duplicado '%-.64s'"
- swe "Nyckelnamn '%-.64s' finns flera gånger"
- ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.64s'"
+ cze "Zdvojen-Bé jméno klíèe '%-.192s'"
+ dan "Indeksnavnet '%-.192s' findes allerede"
+ nla "Dubbele zoeksleutel naam '%-.192s'"
+ eng "Duplicate key name '%-.192s'"
+ jps "'%-.192s' ‚Æ‚¢‚¤ key ‚Ì–¼‘O‚Íd•¡‚µ‚Ä‚¢‚Ü‚·",
+ est "Kattuv võtme nimi '%-.192s'"
+ fre "Nom de clef '%-.192s' déjà utilisé"
+ ger "Doppelter Name für Schlüssel vorhanden: '%-.192s'"
+ greek "ÅðáíÜëçøç key name '%-.192s'"
+ hun "Duplikalt kulcsazonosito: '%-.192s'"
+ ita "Nome chiave duplicato '%-.192s'"
+ jpn "'%-.192s' ¤È¤¤¤¦ key ¤Î̾Á°¤Ï½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+ kor "Áߺ¹µÈ Ű À̸§ : '%-.192s'"
+ nor "Nøkkelnavnet '%-.192s' eksisterte fra før"
+ norwegian-ny "Nøkkelnamnet '%-.192s' eksisterte frå før"
+ pol "Powtórzony nazwa klucza '%-.192s'"
+ por "Nome da chave '%-.192s' duplicado"
+ rum "Numele cheiei '%-.192s' e duplicat"
+ rus "äÕÂÌÉÒÕÀÝÅÅÓÑ ÉÍÑ ËÌÀÞÁ '%-.192s'"
+ serbian "Duplirano ime kljuèa '%-.192s'"
+ slo "Opakované meno kµúèa '%-.192s'"
+ spa "Nombre de clave duplicado '%-.192s'"
+ swe "Nyckelnamn '%-.192s' finns flera gånger"
+ ukr "äÕÂÌÀÀÞÅ ¦Í'Ñ ËÌÀÞÁ '%-.192s'"
ER_DUP_ENTRY 23000 S1009
- cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.64s')"
- dan "Ens værdier '%-.64s' for indeks '%-.64s'"
- nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.64s'"
- eng "Duplicate entry '%-.64s' for key '%-.64s'"
- jps "'%-.64s' ‚Í key '%-.64s' ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
- est "Kattuv väärtus '%-.64s' võtmele '%-.64s'"
- fre "Duplicata du champ '%-.64s' pour la clef '%-.64s'"
- ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.64s'"
- greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß '%-.64s'"
- hun "Duplikalt bejegyzes '%-.64s' a '%-.64s' kulcs szerint."
- ita "Valore duplicato '%-.64s' per la chiave '%-.64s'"
- jpn "'%-.64s' ¤Ï key '%-.64s' ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
- kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key '%-.64s'"
- nor "Like verdier '%-.64s' for nøkkel '%-.64s'"
- norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.64s'"
- pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.64s'"
- por "Entrada '%-.64s' duplicada para a chave '%-.64s'"
- rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.64s'"
- rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ '%-.64s'"
- serbian "Dupliran unos '%-.64s' za kljuè '%-.64s'"
- slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa '%-.64s')"
- spa "Entrada duplicada '%-.64s' para la clave '%-.64s'"
- swe "Dubbel nyckel '%-.64s' för nyckel '%-.64s'"
- ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ '%-.64s'"
+ cze "Zdvojen-Bý klíè '%-.192s' (èíslo klíèe %d)"
+ dan "Ens værdier '%-.192s' for indeks %d"
+ nla "Dubbele ingang '%-.192s' voor zoeksleutel %d"
+ eng "Duplicate entry '%-.192s' for key %d"
+ jps "'%-.192s' ‚Í key %d ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
+ est "Kattuv väärtus '%-.192s' võtmele %d"
+ fre "Duplicata du champ '%-.192s' pour la clef %d"
+ ger "Doppelter Eintrag '%-.192s' für Schlüssel %d"
+ greek "ÄéðëÞ åããñáöÞ '%-.192s' ãéá ôï êëåéäß %d"
+ hun "Duplikalt bejegyzes '%-.192s' a %d kulcs szerint."
+ ita "Valore duplicato '%-.192s' per la chiave %d"
+ jpn "'%-.192s' ¤Ï key %d ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+ kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.192s': key %d"
+ nor "Like verdier '%-.192s' for nøkkel %d"
+ norwegian-ny "Like verdiar '%-.192s' for nykkel %d"
+ pol "Powtórzone wyst?pienie '%-.192s' dla klucza %d"
+ por "Entrada '%-.192s' duplicada para a chave %d"
+ rum "Cimpul '%-.192s' e duplicat pentru cheia %d"
+ rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.192s' ÐÏ ËÌÀÞÕ %d"
+ serbian "Dupliran unos '%-.192s' za kljuè '%d'"
+ slo "Opakovaný kµúè '%-.192s' (èíslo kµúèa %d)"
+ spa "Entrada duplicada '%-.192s' para la clave %d"
+ swe "Dubbel nyckel '%-.192s' för nyckel %d"
+ ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.192s' ÄÌÑ ËÌÀÞÁ %d"
ER_WRONG_FIELD_SPEC 42000 S1009
- cze "Chybn-Bá specifikace sloupce '%-.64s'"
- dan "Forkert kolonnespecifikaton for felt '%-.64s'"
- nla "Verkeerde kolom specificatie voor kolom '%-.64s'"
- eng "Incorrect column specifier for column '%-.64s'"
- est "Vigane tulba kirjeldus tulbale '%-.64s'"
- fre "Mauvais paramètre de champ pour le champ '%-.64s'"
- ger "Falsche Spezifikation für Feld '%-.64s'"
- greek "ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.64s'"
- hun "Rossz oszlopazonosito: '%-.64s'"
- ita "Specifica errata per la colonna '%-.64s'"
- kor "Ä®·³ '%-.64s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ"
- nor "Feil kolonne spesifikator for felt '%-.64s'"
- norwegian-ny "Feil kolonne spesifikator for kolonne '%-.64s'"
- pol "B³êdna specyfikacja kolumny dla kolumny '%-.64s'"
- por "Especificador de coluna incorreto para a coluna '%-.64s'"
- rum "Specificandul coloanei '%-.64s' este incorect"
- rus "îÅËÏÒÒÅËÔÎÙÊ ÏÐÒÅÄÅÌÉÔÅÌØ ÓÔÏÌÂÃÁ ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s'"
- serbian "Pogrešan naziv kolone za kolonu '%-.64s'"
- slo "Chyba v ¹pecifikácii poµa '%-.64s'"
- spa "Especificador de columna erroneo para la columna '%-.64s'"
- swe "Felaktigt kolumntyp för kolumn '%-.64s'"
- ukr "îÅצÒÎÉÊ ÓÐÅÃÉÆ¦ËÁÔÏÒ ÓÔÏ×ÂÃÑ '%-.64s'"
-ER_PARSE_ERROR 42000
- cze "%s bl-Bízko '%-.64s' na øádku %d"
- dan "%s nær '%-.64s' på linje %d"
- nla "%s bij '%-.64s' in regel %d"
+ cze "Chybn-Bá specifikace sloupce '%-.192s'"
+ dan "Forkert kolonnespecifikaton for felt '%-.192s'"
+ nla "Verkeerde kolom specificatie voor kolom '%-.192s'"
+ eng "Incorrect column specifier for column '%-.192s'"
+ est "Vigane tulba kirjeldus tulbale '%-.192s'"
+ fre "Mauvais paramètre de champ pour le champ '%-.192s'"
+ ger "Falsche Spezifikation für Feld '%-.192s'"
+ greek "ÅóöáëìÝíï column specifier ãéá ôï ðåäßï '%-.192s'"
+ hun "Rossz oszlopazonosito: '%-.192s'"
+ ita "Specifica errata per la colonna '%-.192s'"
+ kor "Ä®·³ '%-.192s'ÀÇ ºÎÁ¤È®ÇÑ Ä®·³ Á¤ÀÇÀÚ"
+ nor "Feil kolonne spesifikator for felt '%-.192s'"
+ norwegian-ny "Feil kolonne spesifikator for kolonne '%-.192s'"
+ pol "B³êdna specyfikacja kolumny dla kolumny '%-.192s'"
+ por "Especificador de coluna incorreto para a coluna '%-.192s'"
+ rum "Specificandul coloanei '%-.192s' este incorect"
+ rus "îÅËÏÒÒÅËÔÎÙÊ ÏÐÒÅÄÅÌÉÔÅÌØ ÓÔÏÌÂÃÁ ÄÌÑ ÓÔÏÌÂÃÁ '%-.192s'"
+ serbian "Pogrešan naziv kolone za kolonu '%-.192s'"
+ slo "Chyba v ¹pecifikácii poµa '%-.192s'"
+ spa "Especificador de columna erroneo para la columna '%-.192s'"
+ swe "Felaktigt kolumntyp för kolumn '%-.192s'"
+ ukr "îÅצÒÎÉÊ ÓÐÅÃÉÆ¦ËÁÔÏÒ ÓÔÏ×ÂÃÑ '%-.192s'"
+ER_PARSE_ERROR 42000 s1009
+ cze "%s bl-Bízko '%-.80s' na øádku %d"
+ dan "%s nær '%-.80s' på linje %d"
+ nla "%s bij '%-.80s' in regel %d"
eng "%s near '%-.80s' at line %d"
jps "%s : '%-.80s' •t‹ß : %d s–Ú",
est "%s '%-.80s' ligidal real %d"
- fre "%s près de '%-.64s' à la ligne %d"
+ fre "%s près de '%-.80s' à la ligne %d"
ger "%s bei '%-.80s' in Zeile %d"
greek "%s ðëçóßïí '%-.80s' óôç ãñáììÞ %d"
hun "A %s a '%-.80s'-hez kozeli a %d sorban"
ita "%s vicino a '%-.80s' linea %d"
jpn "%s : '%-.80s' ÉÕ¶á : %d ¹ÔÌÜ"
- kor "'%-.64s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)"
- nor "%s nær '%-.64s' på linje %d"
- norwegian-ny "%s attmed '%-.64s' på line %d"
- pol "%s obok '%-.64s' w linii %d"
+ kor "'%s' ¿¡·¯ °°À¾´Ï´Ù. ('%-.80s' ¸í·É¾î ¶óÀÎ %d)"
+ nor "%s nær '%-.80s' på linje %d"
+ norwegian-ny "%s attmed '%-.80s' på line %d"
+ pol "%s obok '%-.80s' w linii %d"
por "%s próximo a '%-.80s' na linha %d"
rum "%s linga '%-.80s' pe linia %d"
rus "%s ÏËÏÌÏ '%-.80s' ÎÁ ÓÔÒÏËÅ %d"
serbian "'%s' u iskazu '%-.80s' na liniji %d"
slo "%s blízko '%-.80s' na riadku %d"
- spa "%s cerca '%-.64s' en la linea %d"
- swe "%s nära '%-.64s' på rad %d"
+ spa "%s cerca '%-.80s' en la linea %d"
+ swe "%s nära '%-.80s' på rad %d"
ukr "%s ¦ÌÑ '%-.80s' × ÓÔÒÏæ %d"
ER_EMPTY_QUERY 42000
cze "V-Býsledek dotazu je prázdný"
@@ -1577,53 +1577,53 @@ ER_EMPTY_QUERY 42000
swe "Frågan var tom"
ukr "ðÕÓÔÉÊ ÚÁÐÉÔ"
ER_NONUNIQ_TABLE 42000 S1009
- cze "Nejednozna-Bèná tabulka/alias: '%-.64s'"
- dan "Tabellen/aliaset: '%-.64s' er ikke unikt"
- nla "Niet unieke waarde tabel/alias: '%-.64s'"
- eng "Not unique table/alias: '%-.64s'"
- jps "'%-.64s' ‚͈êˆÓ‚Ì table/alias –¼‚ł͂ ‚è‚Ü‚¹‚ñ",
- est "Ei ole unikaalne tabel/alias '%-.64s'"
- fre "Table/alias: '%-.64s' non unique"
- ger "Tabellenname/Alias '%-.64s' nicht eindeutig"
- greek "Áäýíáôç ç áíåýñåóç unique table/alias: '%-.64s'"
- hun "Nem egyedi tabla/alias: '%-.64s'"
- ita "Tabella/alias non unico: '%-.64s'"
- jpn "'%-.64s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
- kor "Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.64s'"
- nor "Ikke unikt tabell/alias: '%-.64s'"
- norwegian-ny "Ikkje unikt tabell/alias: '%-.64s'"
- pol "Tabela/alias nie s? unikalne: '%-.64s'"
- por "Tabela/alias '%-.64s' não única"
- rum "Tabela/alias: '%-.64s' nu este unic"
- rus "ðÏ×ÔÏÒÑÀÝÁÑÓÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ '%-.64s'"
- serbian "Tabela ili alias nisu bili jedinstveni: '%-.64s'"
- slo "Nie jednoznaèná tabuµka/alias: '%-.64s'"
- spa "Tabla/alias: '%-.64s' es no unica"
- swe "Icke unikt tabell/alias: '%-.64s'"
- ukr "îÅÕΦËÁÌØÎÁ ÔÁÂÌÉÃÑ/ÐÓÅ×ÄÏΦÍ: '%-.64s'"
+ cze "Nejednozna-Bèná tabulka/alias: '%-.192s'"
+ dan "Tabellen/aliaset: '%-.192s' er ikke unikt"
+ nla "Niet unieke waarde tabel/alias: '%-.192s'"
+ eng "Not unique table/alias: '%-.192s'"
+ jps "'%-.192s' ‚͈êˆÓ‚Ì table/alias –¼‚ł͂ ‚è‚Ü‚¹‚ñ",
+ est "Ei ole unikaalne tabel/alias '%-.192s'"
+ fre "Table/alias: '%-.192s' non unique"
+ ger "Tabellenname/Alias '%-.192s' nicht eindeutig"
+ greek "Áäýíáôç ç áíåýñåóç unique table/alias: '%-.192s'"
+ hun "Nem egyedi tabla/alias: '%-.192s'"
+ ita "Tabella/alias non unico: '%-.192s'"
+ jpn "'%-.192s' ¤Ï°ì°Õ¤Î table/alias ̾¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó"
+ kor "Unique ÇÏÁö ¾ÊÀº Å×À̺í/alias: '%-.192s'"
+ nor "Ikke unikt tabell/alias: '%-.192s'"
+ norwegian-ny "Ikkje unikt tabell/alias: '%-.192s'"
+ pol "Tabela/alias nie s? unikalne: '%-.192s'"
+ por "Tabela/alias '%-.192s' não única"
+ rum "Tabela/alias: '%-.192s' nu este unic"
+ rus "ðÏ×ÔÏÒÑÀÝÁÑÓÑ ÔÁÂÌÉÃÁ/ÐÓÅ×ÄÏÎÉÍ '%-.192s'"
+ serbian "Tabela ili alias nisu bili jedinstveni: '%-.192s'"
+ slo "Nie jednoznaèná tabuµka/alias: '%-.192s'"
+ spa "Tabla/alias: '%-.192s' es no unica"
+ swe "Icke unikt tabell/alias: '%-.192s'"
+ ukr "îÅÕΦËÁÌØÎÁ ÔÁÂÌÉÃÑ/ÐÓÅ×ÄÏΦÍ: '%-.192s'"
ER_INVALID_DEFAULT 42000 S1009
- cze "Chybn-Bá defaultní hodnota pro '%-.64s'"
- dan "Ugyldig standardværdi for '%-.64s'"
- nla "Foutieve standaard waarde voor '%-.64s'"
- eng "Invalid default value for '%-.64s'"
- est "Vigane vaikeväärtus '%-.64s' jaoks"
- fre "Valeur par défaut invalide pour '%-.64s'"
- ger "Fehlerhafter Vorgabewert (DEFAULT) für '%-.64s'"
- greek "ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.64s'"
- hun "Ervenytelen ertek: '%-.64s'"
- ita "Valore di default non valido per '%-.64s'"
- kor "'%-.64s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù."
- nor "Ugyldig standardverdi for '%-.64s'"
- norwegian-ny "Ugyldig standardverdi for '%-.64s'"
- pol "Niew³a?ciwa warto?æ domy?lna dla '%-.64s'"
- por "Valor padrão (default) inválido para '%-.64s'"
- rum "Valoarea de default este invalida pentru '%-.64s'"
- rus "îÅËÏÒÒÅËÔÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ '%-.64s'"
- serbian "Loša default vrednost za '%-.64s'"
- slo "Chybná implicitná hodnota pre '%-.64s'"
- spa "Valor por defecto invalido para '%-.64s'"
- swe "Ogiltigt DEFAULT värde för '%-.64s'"
- ukr "îÅצÒÎÅ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ ÄÌÑ '%-.64s'"
+ cze "Chybn-Bá defaultní hodnota pro '%-.192s'"
+ dan "Ugyldig standardværdi for '%-.192s'"
+ nla "Foutieve standaard waarde voor '%-.192s'"
+ eng "Invalid default value for '%-.192s'"
+ est "Vigane vaikeväärtus '%-.192s' jaoks"
+ fre "Valeur par défaut invalide pour '%-.192s'"
+ ger "Fehlerhafter Vorgabewert (DEFAULT) für '%-.192s'"
+ greek "ÅóöáëìÝíç ðñïêáèïñéóìÝíç ôéìÞ (default value) ãéá '%-.192s'"
+ hun "Ervenytelen ertek: '%-.192s'"
+ ita "Valore di default non valido per '%-.192s'"
+ kor "'%-.192s'ÀÇ À¯È¿ÇÏÁö ¸øÇÑ µðÆúÆ® °ªÀ» »ç¿ëÇϼ̽À´Ï´Ù."
+ nor "Ugyldig standardverdi for '%-.192s'"
+ norwegian-ny "Ugyldig standardverdi for '%-.192s'"
+ pol "Niew³a?ciwa warto?æ domy?lna dla '%-.192s'"
+ por "Valor padrão (default) inválido para '%-.192s'"
+ rum "Valoarea de default este invalida pentru '%-.192s'"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ '%-.192s'"
+ serbian "Loša default vrednost za '%-.192s'"
+ slo "Chybná implicitná hodnota pre '%-.192s'"
+ spa "Valor por defecto invalido para '%-.192s'"
+ swe "Ogiltigt DEFAULT värde för '%-.192s'"
+ ukr "îÅצÒÎÅ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ ÄÌÑ '%-.192s'"
ER_MULTIPLE_PRI_KEY 42000 S1009
cze "Definov-Báno více primárních klíèù"
dan "Flere primærnøgler specificeret"
@@ -1723,78 +1723,78 @@ ER_TOO_LONG_KEY 42000 S1009
swe "För lång nyckel. Högsta tillåtna nyckellängd är %d"
ukr "úÁÚÎÁÞÅÎÉÊ ËÌÀÞ ÚÁÄÏ×ÇÉÊ. îÁÊÂ¦ÌØÛÁ ÄÏ×ÖÉÎÁ ËÌÀÞÁ %d ÂÁÊÔ¦×"
ER_KEY_COLUMN_DOES_NOT_EXITS 42000 S1009
- cze "Kl-Bíèový sloupec '%-.64s' v tabulce neexistuje"
- dan "Nøglefeltet '%-.64s' eksisterer ikke i tabellen"
- nla "Zoeksleutel kolom '%-.64s' bestaat niet in tabel"
- eng "Key column '%-.64s' doesn't exist in table"
- jps "Key column '%-.64s' ‚ªƒe[ƒuƒ‹‚É‚ ‚è‚Ü‚¹‚ñ.",
- est "Võtme tulp '%-.64s' puudub tabelis"
- fre "La clé '%-.64s' n'existe pas dans la table"
- ger "In der Tabelle gibt es kein Schlüsselfeld '%-.64s'"
- greek "Ôï ðåäßï êëåéäß '%-.64s' äåí õðÜñ÷åé óôïí ðßíáêá"
- hun "A(z) '%-.64s'kulcsoszlop nem letezik a tablaban"
- ita "La colonna chiave '%-.64s' non esiste nella tabella"
- jpn "Key column '%-.64s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó."
- kor "Key Ä®·³ '%-.64s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Nøkkel felt '%-.64s' eksiterer ikke i tabellen"
- norwegian-ny "Nykkel kolonne '%-.64s' eksiterar ikkje i tabellen"
- pol "Kolumna '%-.64s' zdefiniowana w kluczu nie istnieje w tabeli"
- por "Coluna chave '%-.64s' não existe na tabela"
- rum "Coloana cheie '%-.64s' nu exista in tabela"
- rus "ëÌÀÞÅ×ÏÊ ÓÔÏÌÂÅà '%-.64s' × ÔÁÂÌÉÃÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Kljuèna kolona '%-.64s' ne postoji u tabeli"
- slo "Kµúèový ståpec '%-.64s' v tabuµke neexistuje"
- spa "La columna clave '%-.64s' no existe en la tabla"
- swe "Nyckelkolumn '%-.64s' finns inte"
- ukr "ëÌÀÞÏ×ÉÊ ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ¦ÓÎÕ¤ Õ ÔÁÂÌÉæ"
+ cze "Kl-Bíèový sloupec '%-.192s' v tabulce neexistuje"
+ dan "Nøglefeltet '%-.192s' eksisterer ikke i tabellen"
+ nla "Zoeksleutel kolom '%-.192s' bestaat niet in tabel"
+ eng "Key column '%-.192s' doesn't exist in table"
+ jps "Key column '%-.192s' ‚ªƒe[ƒuƒ‹‚É‚ ‚è‚Ü‚¹‚ñ.",
+ est "Võtme tulp '%-.192s' puudub tabelis"
+ fre "La clé '%-.192s' n'existe pas dans la table"
+ ger "In der Tabelle gibt es kein Schlüsselfeld '%-.192s'"
+ greek "Ôï ðåäßï êëåéäß '%-.192s' äåí õðÜñ÷åé óôïí ðßíáêá"
+ hun "A(z) '%-.192s'kulcsoszlop nem letezik a tablaban"
+ ita "La colonna chiave '%-.192s' non esiste nella tabella"
+ jpn "Key column '%-.192s' ¤¬¥Æ¡¼¥Ö¥ë¤Ë¤¢¤ê¤Þ¤»¤ó."
+ kor "Key Ä®·³ '%-.192s'´Â Å×ÀÌºí¿¡ Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Nøkkel felt '%-.192s' eksiterer ikke i tabellen"
+ norwegian-ny "Nykkel kolonne '%-.192s' eksiterar ikkje i tabellen"
+ pol "Kolumna '%-.192s' zdefiniowana w kluczu nie istnieje w tabeli"
+ por "Coluna chave '%-.192s' não existe na tabela"
+ rum "Coloana cheie '%-.192s' nu exista in tabela"
+ rus "ëÌÀÞÅ×ÏÊ ÓÔÏÌÂÅà '%-.192s' × ÔÁÂÌÉÃÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Kljuèna kolona '%-.192s' ne postoji u tabeli"
+ slo "Kµúèový ståpec '%-.192s' v tabuµke neexistuje"
+ spa "La columna clave '%-.192s' no existe en la tabla"
+ swe "Nyckelkolumn '%-.192s' finns inte"
+ ukr "ëÌÀÞÏ×ÉÊ ÓÔÏ×ÂÅÃØ '%-.192s' ÎÅ ¦ÓÎÕ¤ Õ ÔÁÂÌÉæ"
ER_BLOB_USED_AS_KEY 42000 S1009
- cze "Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè"
- dan "BLOB feltet '%-.64s' kan ikke bruges ved specifikation af indeks"
- nla "BLOB kolom '%-.64s' kan niet gebruikt worden bij zoeksleutel specificatie"
- eng "BLOB column '%-.64s' can't be used in key specification with the used table type"
- est "BLOB-tüüpi tulpa '%-.64s' ei saa kasutada võtmena"
- fre "Champ BLOB '%-.64s' ne peut être utilisé dans une clé"
- ger "BLOB-Feld '%-.64s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden"
- greek "Ðåäßï ôýðïõ Blob '%-.64s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)"
- hun "Blob objektum '%-.64s' nem hasznalhato kulcskent"
- ita "La colonna BLOB '%-.64s' non puo` essere usata nella specifica della chiave"
- kor "BLOB Ä®·³ '%-.64s'´Â Ű Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù."
- nor "Blob felt '%-.64s' kan ikke brukes ved spesifikasjon av nøkler"
- norwegian-ny "Blob kolonne '%-.64s' kan ikkje brukast ved spesifikasjon av nyklar"
- pol "Kolumna typu Blob '%-.64s' nie mo¿e byæ u¿yta w specyfikacji klucza"
- por "Coluna BLOB '%-.64s' não pode ser utilizada na especificação de chave para o tipo de tabela usado"
- rum "Coloana de tip BLOB '%-.64s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit"
- rus "óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ"
- serbian "BLOB kolona '%-.64s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi"
- slo "Blob pole '%-.64s' nemô¾e by» pou¾ité ako kµúè"
- spa "La columna Blob '%-.64s' no puede ser usada en una declaracion de clave"
- swe "En BLOB '%-.64s' kan inte vara nyckel med den använda tabelltypen"
- ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ"
+ cze "Blob sloupec '%-.192s' nem-Bù¾e být pou¾it jako klíè"
+ dan "BLOB feltet '%-.192s' kan ikke bruges ved specifikation af indeks"
+ nla "BLOB kolom '%-.192s' kan niet gebruikt worden bij zoeksleutel specificatie"
+ eng "BLOB column '%-.192s' can't be used in key specification with the used table type"
+ est "BLOB-tüüpi tulpa '%-.192s' ei saa kasutada võtmena"
+ fre "Champ BLOB '%-.192s' ne peut être utilisé dans une clé"
+ ger "BLOB-Feld '%-.192s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden"
+ greek "Ðåäßï ôýðïõ Blob '%-.192s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)"
+ hun "Blob objektum '%-.192s' nem hasznalhato kulcskent"
+ ita "La colonna BLOB '%-.192s' non puo` essere usata nella specifica della chiave"
+ kor "BLOB Ä®·³ '%-.192s'´Â Ű Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù."
+ nor "Blob felt '%-.192s' kan ikke brukes ved spesifikasjon av nøkler"
+ norwegian-ny "Blob kolonne '%-.192s' kan ikkje brukast ved spesifikasjon av nyklar"
+ pol "Kolumna typu Blob '%-.192s' nie mo¿e byæ u¿yta w specyfikacji klucza"
+ por "Coluna BLOB '%-.192s' não pode ser utilizada na especificação de chave para o tipo de tabela usado"
+ rum "Coloana de tip BLOB '%-.192s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit"
+ rus "óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.192s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ"
+ serbian "BLOB kolona '%-.192s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi"
+ slo "Blob pole '%-.192s' nemô¾e by» pou¾ité ako kµúè"
+ spa "La columna Blob '%-.192s' no puede ser usada en una declaracion de clave"
+ swe "En BLOB '%-.192s' kan inte vara nyckel med den använda tabelltypen"
+ ukr "BLOB ÓÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ"
ER_TOO_BIG_FIELDLENGTH 42000 S1009
- cze "P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB"
- dan "For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet"
- nla "Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB"
- eng "Column length too big for column '%-.64s' (max = %d); use BLOB or TEXT instead"
- jps "column '%-.64s' ‚Í,Šm•Û‚·‚é column ‚̑傫‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢.",
- est "Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi"
- fre "Champ '%-.64s' trop long (max = %d). Utilisez un BLOB"
- ger "Feldlänge für Feld '%-.64s' zu groß (maximal %d). BLOB- oder TEXT-Spaltentyp verwenden!"
- greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB"
- hun "A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb."
- ita "La colonna '%-.64s' e` troppo grande (max=%d). Utilizza un BLOB."
- jpn "column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤."
- kor "Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀ̰¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä."
- nor "For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor"
- norwegian-ny "For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor"
- pol "Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB"
- por "Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar"
- rum "Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ"
- serbian "Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje"
- slo "Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB"
- spa "Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar"
- swe "För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället"
- ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB"
+ cze "P-Bøíli¹ velká délka sloupce '%-.192s' (nejvíce %d). Pou¾ijte BLOB"
+ dan "For stor feltlængde for kolonne '%-.192s' (maks = %d). Brug BLOB i stedet"
+ nla "Te grote kolomlengte voor '%-.192s' (max = %d). Maak hiervoor gebruik van het type BLOB"
+ eng "Column length too big for column '%-.192s' (max = %d); use BLOB or TEXT instead"
+ jps "column '%-.192s' ‚Í,Šm•Û‚·‚é column ‚̑傫‚³‚ª‘½‚·‚¬‚Ü‚·. (Å‘å %d ‚Ü‚Å). BLOB ‚ð‚©‚í‚è‚ÉŽg—p‚µ‚Ä‚­‚¾‚³‚¢.",
+ est "Tulba '%-.192s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi"
+ fre "Champ '%-.192s' trop long (max = %d). Utilisez un BLOB"
+ ger "Feldlänge für Feld '%-.192s' zu groß (maximal %d). BLOB- oder TEXT-Spaltentyp verwenden!"
+ greek "Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.192s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB"
+ hun "A(z) '%-.192s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb."
+ ita "La colonna '%-.192s' e` troppo grande (max=%d). Utilizza un BLOB."
+ jpn "column '%-.192s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤."
+ kor "Ä®·³ '%-.192s'ÀÇ Ä®·³ ±æÀ̰¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä."
+ nor "For stor nøkkellengde for kolonne '%-.192s' (maks = %d). Bruk BLOB istedenfor"
+ norwegian-ny "For stor nykkellengde for felt '%-.192s' (maks = %d). Bruk BLOB istadenfor"
+ pol "Zbyt du¿a d³ugo?æ kolumny '%-.192s' (maks. = %d). W zamian u¿yj typu BLOB"
+ por "Comprimento da coluna '%-.192s' grande demais (max = %d); use BLOB em seu lugar"
+ rum "Lungimea coloanei '%-.192s' este prea lunga (maximum = %d). Foloseste BLOB mai bine"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.192s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ÉÌÉ TEXT ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ"
+ serbian "Previše podataka za kolonu '%-.192s' (maksimum je %d). Upotrebite BLOB polje"
+ slo "Príli¹ veµká då¾ka pre pole '%-.192s' (maximum = %d). Pou¾ite BLOB"
+ spa "Longitud de columna demasiado grande para la columna '%-.192s' (maximo = %d).Usar BLOB en su lugar"
+ swe "För stor kolumnlängd angiven för '%-.192s' (max= %d). Använd en BLOB instället"
+ ukr "úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.192s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB"
ER_WRONG_AUTO_KEY 42000 S1009
cze "M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè"
dan "Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret"
@@ -1821,30 +1821,30 @@ ER_WRONG_AUTO_KEY 42000 S1009
swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
ukr "îÅצÒÎÅ ×ÉÚÎÁÞÅÎÎÑ ÔÁÂÌÉæ; íÏÖÅ ÂÕÔÉ ÌÉÛÅ ÏÄÉÎ Á×ÔÏÍÁÔÉÞÎÉÊ ÓÔÏ×ÂÅÃØ, ÝÏ ÐÏ×ÉÎÅÎ ÂÕÔÉ ×ÉÚÎÁÞÅÎÉÊ ÑË ËÌÀÞ"
ER_READY
- cze "%s: p-Bøipraven na spojení"
- dan "%s: klar til tilslutninger"
- nla "%s: klaar voor verbindingen"
+ cze "%s: p-Bøipraven na spojení\nVersion: '%s' socket: '%s' port: %d""
+ dan "%s: klar til tilslutninger\nVersion: '%s' socket: '%s' port: %d""
+ nla "%s: klaar voor verbindingen\nVersion: '%s' socket: '%s' port: %d""
eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
- jps "%s: €”õŠ®—¹",
- est "%s: ootab ühendusi"
- fre "%s: Prêt pour des connections"
- ger "%-.64s: Bereit für Verbindungen.\nVersion: '%2' Socket: '%s' Port: %d"
- greek "%s: óå áíáìïíÞ óõíäÝóåùí"
- hun "%s: kapcsolatra kesz"
- ita "%s: Pronto per le connessioni\n"
- jpn "%s: ½àÈ÷´°Î»"
- kor "%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù"
- nor "%s: klar for tilkoblinger"
- norwegian-ny "%s: klar for tilkoblingar"
- pol "%s: gotowe do po³?czenia"
- por "%s: Pronto para conexões"
- rum "%s: sint gata pentru conectii"
- rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d %s"
- serbian "%s: Spreman za konekcije\n"
- slo "%s: pripravený na spojenie"
- spa "%s: preparado para conexiones"
- swe "%s: klar att ta emot klienter"
- ukr "%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!"
+ jps "%s: €”õŠ®—¹\nVersion: '%s' socket: '%s' port: %d"",
+ est "%s: ootab ühendusi\nVersion: '%s' socket: '%s' port: %d""
+ fre "%s: Prêt pour des connexions\nVersion: '%s' socket: '%s' port: %d""
+ ger "%s: Bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d"
+ greek "%s: óå áíáìïíÞ óõíäÝóåùí\nVersion: '%s' socket: '%s' port: %d""
+ hun "%s: kapcsolatra kesz\nVersion: '%s' socket: '%s' port: %d""
+ ita "%s: Pronto per le connessioni\nVersion: '%s' socket: '%s' port: %d""
+ jpn "%s: ½àÈ÷´°Î»\nVersion: '%s' socket: '%s' port: %d""
+ kor "%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù\nVersion: '%s' socket: '%s' port: %d""
+ nor "%s: klar for tilkoblinger\nVersion: '%s' socket: '%s' port: %d""
+ norwegian-ny "%s: klar for tilkoblingar\nVersion: '%s' socket: '%s' port: %d""
+ pol "%s: gotowe do po³?czenia\nVersion: '%s' socket: '%s' port: %d""
+ por "%s: Pronto para conexões\nVersion: '%s' socket: '%s' port: %d""
+ rum "%s: sint gata pentru conectii\nVersion: '%s' socket: '%s' port: %d""
+ rus "%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d"
+ serbian "%s: Spreman za konekcije\nVersion: '%s' socket: '%s' port: %d""
+ slo "%s: pripravený na spojenie\nVersion: '%s' socket: '%s' port: %d""
+ spa "%s: preparado para conexiones\nVersion: '%s' socket: '%s' port: %d""
+ swe "%s: klar att ta emot klienter\nVersion: '%s' socket: '%s' port: %d""
+ ukr "%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!\nVersion: '%s' socket: '%s' port: %d""
ER_NORMAL_SHUTDOWN
cze "%s: norm-Bální ukonèení\n"
dan "%s: Normal nedlukning\n"
@@ -1852,7 +1852,7 @@ ER_NORMAL_SHUTDOWN
eng "%s: Normal shutdown\n"
est "%s: MySQL lõpetas\n"
fre "%s: Arrêt normal du serveur\n"
- ger "%-.64s: Normal heruntergefahren\n"
+ ger "%s: Normal heruntergefahren\n"
greek "%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n"
hun "%s: Normal leallitas\n"
ita "%s: Shutdown normale\n"
@@ -1876,7 +1876,7 @@ ER_GOT_SIGNAL
jps "%s: Got signal %d. ’†’f!\n",
est "%s: sain signaali %d. Lõpetan!\n"
fre "%s: Reçu le signal %d. Abandonne!\n"
- ger "%-.64s: Signal %d erhalten. Abbruch!\n"
+ ger "%s: Signal %d erhalten. Abbruch!\n"
greek "%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n"
hun "%s: %d jelzes. Megszakitva!\n"
ita "%s: Ricevuto segnale %d. Interruzione!\n"
@@ -1901,7 +1901,7 @@ ER_SHUTDOWN_COMPLETE
jps "%s: Shutdown Š®—¹\n",
est "%s: Lõpp\n"
fre "%s: Arrêt du serveur terminé\n"
- ger "%-.64s: Herunterfahren beendet\n"
+ ger "%s: Herunterfahren beendet\n"
greek "%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n"
hun "%s: A leallitas kesz\n"
ita "%s: Shutdown completato\n"
@@ -1919,30 +1919,30 @@ ER_SHUTDOWN_COMPLETE
swe "%s: Avslutning klar\n"
ukr "%s: òÏÂÏÔÕ ÚÁ×ÅÒÛÅÎÏ\n"
ER_FORCING_CLOSE 08S01
- cze "%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.64s'\n"
- dan "%s: Forceret nedlukning af tråd: %ld bruger: '%-.64s'\n"
- nla "%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.64s'\n"
- eng "%s: Forcing close of thread %ld user: '%-.32s'\n"
- jps "%s: ƒXƒŒƒbƒh %ld ‹­§I—¹ user: '%-.64s'\n",
- est "%s: Sulgen jõuga lõime %ld kasutaja: '%-.32s'\n"
- fre "%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.64s'\n"
- ger "%s: Thread %ld zwangsweise beendet. Benutzer: '%-.32s'\n"
- greek "%s: Ôï thread èá êëåßóåé %ld user: '%-.64s'\n"
- hun "%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.64s'\n"
- ita "%s: Forzata la chiusura del thread %ld utente: '%-.64s'\n"
- jpn "%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.64s'\n"
- kor "%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.64s'\n"
- nor "%s: Påtvinget avslutning av tråd %ld bruker: '%-.64s'\n"
- norwegian-ny "%s: Påtvinga avslutning av tråd %ld brukar: '%-.64s'\n"
- pol "%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.64s'\n"
- por "%s: Forçando finalização da 'thread' %ld - usuário '%-.32s'\n"
- rum "%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.32s'\n"
- rus "%s: ðÒÉÎÕÄÉÔÅÌØÎÏ ÚÁËÒÙ×ÁÅÍ ÐÏÔÏË %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.32s'\n"
- serbian "%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.32s'\n"
- slo "%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.64s'\n"
- spa "%s: Forzando a cerrar el thread %ld usuario: '%-.64s'\n"
- swe "%s: Stänger av tråd %ld; användare: '%-.64s'\n"
- ukr "%s: ðÒÉÓËÏÒÀÀ ÚÁËÒÉÔÔÑ Ç¦ÌËÉ %ld ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'\n"
+ cze "%s: n-Básilné uzavøení threadu %ld u¾ivatele '%-.48s'\n"
+ dan "%s: Forceret nedlukning af tråd: %ld bruger: '%-.48s'\n"
+ nla "%s: Afsluiten afgedwongen van thread %ld gebruiker: '%-.48s'\n"
+ eng "%s: Forcing close of thread %ld user: '%-.48s'\n"
+ jps "%s: ƒXƒŒƒbƒh %ld ‹­§I—¹ user: '%-.48s'\n",
+ est "%s: Sulgen jõuga lõime %ld kasutaja: '%-.48s'\n"
+ fre "%s: Arrêt forcé de la tâche (thread) %ld utilisateur: '%-.48s'\n"
+ ger "%s: Thread %ld zwangsweise beendet. Benutzer: '%-.48s'\n"
+ greek "%s: Ôï thread èá êëåßóåé %ld user: '%-.48s'\n"
+ hun "%s: A(z) %ld thread kenyszeritett zarasa. Felhasznalo: '%-.48s'\n"
+ ita "%s: Forzata la chiusura del thread %ld utente: '%-.48s'\n"
+ jpn "%s: ¥¹¥ì¥Ã¥É %ld ¶¯À©½ªÎ» user: '%-.48s'\n"
+ kor "%s: thread %ldÀÇ °­Á¦ Á¾·á user: '%-.48s'\n"
+ nor "%s: Påtvinget avslutning av tråd %ld bruker: '%-.48s'\n"
+ norwegian-ny "%s: Påtvinga avslutning av tråd %ld brukar: '%-.48s'\n"
+ pol "%s: Wymuszenie zamkniêcia w?tku %ld u¿ytkownik: '%-.48s'\n"
+ por "%s: Forçando finalização da 'thread' %ld - usuário '%-.48s'\n"
+ rum "%s: Terminare fortata a thread-ului %ld utilizatorului: '%-.48s'\n"
+ rus "%s: ðÒÉÎÕÄÉÔÅÌØÎÏ ÚÁËÒÙ×ÁÅÍ ÐÏÔÏË %ld ÐÏÌØÚÏ×ÁÔÅÌÑ: '%-.48s'\n"
+ serbian "%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.48s'\n"
+ slo "%s: násilné ukonèenie vlákna %ld u¾ívateµa '%-.48s'\n"
+ spa "%s: Forzando a cerrar el thread %ld usuario: '%-.48s'\n"
+ swe "%s: Stänger av tråd %ld; användare: '%-.48s'\n"
+ ukr "%s: ðÒÉÓËÏÒÀÀ ÚÁËÒÉÔÔÑ Ç¦ÌËÉ %ld ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s'\n"
ER_IPSOCK_ERROR 08S01
cze "Nemohu vytvo-Bøit IP socket"
dan "Kan ikke oprette IP socket"
@@ -1950,7 +1950,7 @@ ER_IPSOCK_ERROR 08S01
eng "Can't create IP socket"
jps "IP socket ‚ªì‚ê‚Ü‚¹‚ñ",
est "Ei suuda luua IP socketit"
- fre "Ne peut créer la connection IP (socket)"
+ fre "Ne peut créer la connexion IP (socket)"
ger "Kann IP-Socket nicht erzeugen"
greek "Äåí åßíáé äõíáôÞ ç äçìéïõñãßá IP socket"
hun "Az IP socket nem hozhato letre"
@@ -1969,30 +1969,30 @@ ER_IPSOCK_ERROR 08S01
swe "Kan inte skapa IP-socket"
ukr "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ IP ÒÏÚ'¤Í"
ER_NO_SUCH_INDEX 42S12 S1009
- cze "Tabulka '%-.64s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu"
- dan "Tabellen '%-.64s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen"
- nla "Tabel '%-.64s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw"
- eng "Table '%-.64s' has no index like the one used in CREATE INDEX; recreate the table"
- jps "Table '%-.64s' ‚Í‚»‚̂悤‚È index ‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñ(CREATE INDEX ŽÀsŽž‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ). ƒe[ƒuƒ‹‚ðì‚è’¼‚µ‚Ä‚­‚¾‚³‚¢",
- est "Tabelil '%-.64s' puuduvad võtmed. Loo tabel uuesti"
- fre "La table '%-.64s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table"
- ger "Tabelle '%-.64s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Tabelle neu anlegen"
- greek "Ï ðßíáêáò '%-.64s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá"
- hun "A(z) '%-.64s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat"
- ita "La tabella '%-.64s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella"
- jpn "Table '%-.64s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤"
- kor "Å×À̺í '%-.64s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä..."
- nor "Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen"
- norwegian-ny "Tabellen '%-.64s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt"
- pol "Tabela '%-.64s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê"
- por "Tabela '%-.64s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela"
- rum "Tabela '%-.64s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela"
- rus "÷ ÔÁÂÌÉÃÅ '%-.64s' ÎÅÔ ÔÁËÏÇÏ ÉÎÄÅËÓÁ, ËÁË × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÚÁÎÏ×Ï"
- serbian "Tabela '%-.64s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo"
- slo "Tabuµka '%-.64s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova"
- spa "La tabla '%-.64s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla"
- swe "Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen"
- ukr "ôÁÂÌÉÃÑ '%-.64s' ÍÁ¤ ¦ÎÄÅËÓ, ÝÏ ÎÅ ÓЦ×ÐÁÄÁ¤ Ú ×ËÁÚÁÎÎÉÍ Õ CREATE INDEX. óÔ×ÏÒ¦ÔØ ÔÁÂÌÉÃÀ ÚÎÏ×Õ"
+ cze "Tabulka '%-.192s' nem-Bá index odpovídající CREATE INDEX. Vytvoøte tabulku znovu"
+ dan "Tabellen '%-.192s' har ikke den nøgle, som blev brugt i CREATE INDEX. Genopret tabellen"
+ nla "Tabel '%-.192s' heeft geen INDEX zoals deze gemaakt worden met CREATE INDEX. Maak de tabel opnieuw"
+ eng "Table '%-.192s' has no index like the one used in CREATE INDEX; recreate the table"
+ jps "Table '%-.192s' ‚Í‚»‚̂悤‚È index ‚ðŽ‚Á‚Ä‚¢‚Ü‚¹‚ñ(CREATE INDEX ŽÀsŽž‚ÉŽw’肳‚ê‚Ä‚¢‚Ü‚¹‚ñ). ƒe[ƒuƒ‹‚ðì‚è’¼‚µ‚Ä‚­‚¾‚³‚¢",
+ est "Tabelil '%-.192s' puuduvad võtmed. Loo tabel uuesti"
+ fre "La table '%-.192s' n'a pas d'index comme celle utilisée dans CREATE INDEX. Recréez la table"
+ ger "Tabelle '%-.192s' besitzt keinen wie den in CREATE INDEX verwendeten Index. Tabelle neu anlegen"
+ greek "Ï ðßíáêáò '%-.192s' äåí Ý÷åé åõñåôÞñéï (index) óáí áõôü ðïõ ÷ñçóéìïðïéåßôå óôçí CREATE INDEX. Ðáñáêáëþ, îáíáäçìéïõñãÞóôå ôïí ðßíáêá"
+ hun "A(z) '%-.192s' tablahoz nincs meg a CREATE INDEX altal hasznalt index. Alakitsa at a tablat"
+ ita "La tabella '%-.192s' non ha nessun indice come quello specificatato dalla CREATE INDEX. Ricrea la tabella"
+ jpn "Table '%-.192s' ¤Ï¤½¤Î¤è¤¦¤Ê index ¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó(CREATE INDEX ¼Â¹Ô»þ¤Ë»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó). ¥Æ¡¼¥Ö¥ë¤òºî¤êľ¤·¤Æ¤¯¤À¤µ¤¤"
+ kor "Å×À̺í '%-.192s'´Â À妽º¸¦ ¸¸µéÁö ¾Ê¾Ò½À´Ï´Ù. alter Å×À̺í¸í·ÉÀ» ÀÌ¿ëÇÏ¿© Å×À̺íÀ» ¼öÁ¤Çϼ¼¿ä..."
+ nor "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Gjenopprett tabellen"
+ norwegian-ny "Tabellen '%-.192s' har ingen index som den som er brukt i CREATE INDEX. Oprett tabellen på nytt"
+ pol "Tabela '%-.192s' nie ma indeksu takiego jak w CREATE INDEX. Stwórz tabelê"
+ por "Tabela '%-.192s' não possui um índice como o usado em CREATE INDEX. Recrie a tabela"
+ rum "Tabela '%-.192s' nu are un index ca acela folosit in CREATE INDEX. Re-creeaza tabela"
+ rus "÷ ÔÁÂÌÉÃÅ '%-.192s' ÎÅÔ ÔÁËÏÇÏ ÉÎÄÅËÓÁ, ËÁË × CREATE INDEX. óÏÚÄÁÊÔÅ ÔÁÂÌÉÃÕ ÚÁÎÏ×Ï"
+ serbian "Tabela '%-.192s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo"
+ slo "Tabuµka '%-.192s' nemá index zodpovedajúci CREATE INDEX. Vytvorte tabulku znova"
+ spa "La tabla '%-.192s' no tiene indice como el usado en CREATE INDEX. Crea de nuevo la tabla"
+ swe "Tabellen '%-.192s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' ÍÁ¤ ¦ÎÄÅËÓ, ÝÏ ÎÅ ÓЦ×ÐÁÄÁ¤ Ú ×ËÁÚÁÎÎÉÍ Õ CREATE INDEX. óÔ×ÏÒ¦ÔØ ÔÁÂÌÉÃÀ ÚÎÏ×Õ"
ER_WRONG_FIELD_TERMINATORS 42000 S1009
cze "Argument separ-Bátoru polo¾ek nebyl oèekáván. Pøeètìte si manuál"
dan "Felt adskiller er ikke som forventet, se dokumentationen"
@@ -2041,55 +2041,55 @@ ER_BLOBS_AND_NO_TERMINATED 42000 S1009
swe "Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'"
ukr "îÅ ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÓÔÁÌÕ ÄÏ×ÖÉÎÕ ÓÔÒÏËÉ Ú BLOB. úËÏÒÉÓÔÁÊÔÅÓÑ 'fields terminated by'"
ER_TEXTFILE_NOT_READABLE
- cze "Soubor '%-.64s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny"
- dan "Filen '%-.64s' skal være i database-folderen og kunne læses af alle"
- nla "Het bestand '%-.64s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
+ cze "Soubor '%-.128s' mus-Bí být v adresáøi databáze nebo èitelný pro v¹echny"
+ dan "Filen '%-.128s' skal være i database-folderen og kunne læses af alle"
+ nla "Het bestand '%-.128s' dient in de database directory voor the komen of leesbaar voor iedereen te zijn."
eng "The file '%-.128s' must be in the database directory or be readable by all"
- jps "ƒtƒ@ƒCƒ‹ '%-.64s' ‚Í databse ‚Ì directory ‚É‚ ‚é‚©‘S‚Ẵ†[ƒU[‚ª“Ç‚ß‚é‚æ‚¤‚É‹–‰Â‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
- est "Fail '%-.64s' peab asuma andmebaasi kataloogis või olema kõigile loetav"
- fre "Le fichier '%-.64s' doit être dans le répertoire de la base et lisible par tous"
- ger "Datei '%-.64s' muss im Datenbank-Verzeichnis vorhanden oder lesbar für alle sein"
- greek "Ôï áñ÷åßï '%-.64s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò"
- hun "A(z) '%-.64s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak"
- ita "Il file '%-.64s' deve essere nella directory del database e deve essere leggibile da tutti"
- jpn "¥Õ¥¡¥¤¥ë '%-.64s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬ÆÉ¤á¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
- kor "'%-.64s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù."
- nor "Filen '%-.64s' må være i database-katalogen for å være lesbar for alle"
- norwegian-ny "Filen '%-.64s' må være i database-katalogen for å være lesbar for alle"
- pol "Plik '%-.64s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich"
- por "Arquivo '%-.64s' tem que estar no diretório do banco de dados ou ter leitura possível para todos"
- rum "Fisierul '%-.64s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)"
- rus "æÁÊÌ '%-.64s' ÄÏÌÖÅÎ ÎÁÈÏÄÉÔØÓÑ × ÔÏÍ ÖÅ ËÁÔÁÌÏÇÅ, ÞÔÏ É ÂÁÚÁ ÄÁÎÎÙÈ, ÉÌÉ ÂÙÔØ ÏÂÝÅÄÏÓÔÕÐÎÙÍ ÄÌÑ ÞÔÅÎÉÑ"
- serbian "File '%-.64s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa"
- slo "Súbor '%-.64s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých"
- spa "El archivo '%-.64s' debe estar en el directorio de la base de datos o ser de lectura por todos"
- swe "Textfilen '%.64s' måste finnas i databasbiblioteket eller vara läsbar för alla"
- ukr "æÁÊÌ '%-.64s' ÐÏ×ÉÎÅÎ ÂÕÔÉ Õ ÔÅæ ÂÁÚÉ ÄÁÎÎÉÈ ÁÂÏ ÍÁÔÉ ×ÓÔÁÎÏ×ÌÅÎÅ ÐÒÁ×Ï ÎÁ ÞÉÔÁÎÎÑ ÄÌÑ ÕÓ¦È"
+ jps "ƒtƒ@ƒCƒ‹ '%-.128s' ‚Í databse ‚Ì directory ‚É‚ ‚é‚©‘S‚Ẵ†[ƒU[‚ª“Ç‚ß‚é‚æ‚¤‚É‹–‰Â‚³‚ê‚Ä‚¢‚È‚¯‚ê‚΂Ȃè‚Ü‚¹‚ñ.",
+ est "Fail '%-.128s' peab asuma andmebaasi kataloogis või olema kõigile loetav"
+ fre "Le fichier '%-.128s' doit être dans le répertoire de la base et lisible par tous"
+ ger "Datei '%-.128s' muss im Datenbank-Verzeichnis vorhanden oder lesbar für alle sein"
+ greek "Ôï áñ÷åßï '%-.128s' ðñÝðåé íá õðÜñ÷åé óôï database directory Þ íá ìðïñåß íá äéáâáóôåß áðü üëïõò"
+ hun "A(z) '%-.128s'-nak az adatbazis konyvtarban kell lennie, vagy mindenki szamara olvashatonak"
+ ita "Il file '%-.128s' deve essere nella directory del database e deve essere leggibile da tutti"
+ jpn "¥Õ¥¡¥¤¥ë '%-.128s' ¤Ï databse ¤Î directory ¤Ë¤¢¤ë¤«Á´¤Æ¤Î¥æ¡¼¥¶¡¼¤¬ÆÉ¤á¤ë¤è¤¦¤Ëµö²Ä¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó."
+ kor "'%-.128s' È­ÀÏ´Â µ¥ÀÌŸº£À̽º µð·ºÅ丮¿¡ Á¸ÀçÇϰųª ¸ðµÎ¿¡°Ô Àб⠰¡´ÉÇÏ¿©¾ß ÇÕ´Ï´Ù."
+ nor "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
+ norwegian-ny "Filen '%-.128s' må være i database-katalogen for å være lesbar for alle"
+ pol "Plik '%-.128s' musi znajdowaæ sie w katalogu bazy danych lub mieæ prawa czytania przez wszystkich"
+ por "Arquivo '%-.128s' tem que estar no diretório do banco de dados ou ter leitura possível para todos"
+ rum "Fisierul '%-.128s' trebuie sa fie in directorul bazei de data sau trebuie sa poata sa fie citit de catre toata lumea (verifica permisiile)"
+ rus "æÁÊÌ '%-.128s' ÄÏÌÖÅÎ ÎÁÈÏÄÉÔØÓÑ × ÔÏÍ ÖÅ ËÁÔÁÌÏÇÅ, ÞÔÏ É ÂÁÚÁ ÄÁÎÎÙÈ, ÉÌÉ ÂÙÔØ ÏÂÝÅÄÏÓÔÕÐÎÙÍ ÄÌÑ ÞÔÅÎÉÑ"
+ serbian "File '%-.128s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa"
+ slo "Súbor '%-.128s' musí by» v adresári databázy, alebo èitateµný pre v¹etkých"
+ spa "El archivo '%-.128s' debe estar en el directorio de la base de datos o ser de lectura por todos"
+ swe "Textfilen '%-.128s' måste finnas i databasbiblioteket eller vara läsbar för alla"
+ ukr "æÁÊÌ '%-.128s' ÐÏ×ÉÎÅÎ ÂÕÔÉ Õ ÔÅæ ÂÁÚÉ ÄÁÎÎÉÈ ÁÂÏ ÍÁÔÉ ×ÓÔÁÎÏ×ÌÅÎÅ ÐÒÁ×Ï ÎÁ ÞÉÔÁÎÎÑ ÄÌÑ ÕÓ¦È"
ER_FILE_EXISTS_ERROR
- cze "Soubor '%-.64s' ji-B¾ existuje"
- dan "Filen '%-.64s' eksisterer allerede"
- nla "Het bestand '%-.64s' bestaat reeds"
+ cze "Soubor '%-.200s' ji-B¾ existuje"
+ dan "Filen '%-.200s' eksisterer allerede"
+ nla "Het bestand '%-.200s' bestaat reeds"
eng "File '%-.200s' already exists"
- jps "File '%-.64s' ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·",
- est "Fail '%-.80s' juba eksisteerib"
- fre "Le fichier '%-.64s' existe déjà"
- ger "Datei '%-.80s' bereits vorhanden"
- greek "Ôï áñ÷åßï '%-.64s' õðÜñ÷åé Þäç"
- hun "A '%-.64s' file mar letezik."
- ita "Il file '%-.64s' esiste gia`"
- jpn "File '%-.64s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
- kor "'%-.64s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
- nor "Filen '%-.64s' eksisterte allerede"
- norwegian-ny "Filen '%-.64s' eksisterte allereide"
- pol "Plik '%-.64s' ju¿ istnieje"
- por "Arquivo '%-.80s' já existe"
- rum "Fisierul '%-.80s' exista deja"
- rus "æÁÊÌ '%-.80s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "File '%-.80s' veæ postoji"
- slo "Súbor '%-.64s' u¾ existuje"
- spa "El archivo '%-.64s' ya existe"
- swe "Filen '%-.64s' existerar redan"
- ukr "æÁÊÌ '%-.80s' ×ÖÅ ¦ÓÎÕ¤"
+ jps "File '%-.200s' ‚ÍŠù‚É‘¶Ý‚µ‚Ü‚·",
+ est "Fail '%-.200s' juba eksisteerib"
+ fre "Le fichier '%-.200s' existe déjà"
+ ger "Datei '%-.200s' bereits vorhanden"
+ greek "Ôï áñ÷åßï '%-.200s' õðÜñ÷åé Þäç"
+ hun "A '%-.200s' file mar letezik."
+ ita "Il file '%-.200s' esiste gia`"
+ jpn "File '%-.200s' ¤Ï´û¤Ë¸ºß¤·¤Þ¤¹"
+ kor "'%-.200s' È­ÀÏÀº ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
+ nor "Filen '%-.200s' eksisterte allerede"
+ norwegian-ny "Filen '%-.200s' eksisterte allereide"
+ pol "Plik '%-.200s' ju¿ istnieje"
+ por "Arquivo '%-.200s' já existe"
+ rum "Fisierul '%-.200s' exista deja"
+ rus "æÁÊÌ '%-.200s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "File '%-.200s' veæ postoji"
+ slo "Súbor '%-.200s' u¾ existuje"
+ spa "El archivo '%-.200s' ya existe"
+ swe "Filen '%-.200s' existerar redan"
+ ukr "æÁÊÌ '%-.200s' ×ÖÅ ¦ÓÎÕ¤"
ER_LOAD_INFO
cze "Z-Báznamù: %ld Vymazáno: %ld Pøeskoèeno: %ld Varování: %ld"
dan "Poster: %ld Fjernet: %ld Sprunget over: %ld Advarsler: %ld"
@@ -2190,30 +2190,30 @@ ER_CANT_REMOVE_ALL_FIELDS 42000
swe "Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället"
ukr "îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE"
ER_CANT_DROP_FIELD_OR_KEY 42000
- cze "Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe"
- dan "Kan ikke udføre DROP '%-.64s'. Undersøg om feltet/nøglen eksisterer."
- nla "Kan '%-.64s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat."
- eng "Can't DROP '%-.64s'; check that column/key exists"
- jps "'%-.64s' ‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½; check that column/key exists",
- est "Ei suuda kustutada '%-.64s'. Kontrolli kas tulp/võti eksisteerib"
- fre "Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe"
- ger "Kann '%-.64s' nicht löschen. Existiert die Spalte oder der Schlüssel?"
- greek "Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé"
- hun "A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e"
- ita "Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista"
- jpn "'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿; check that column/key exists"
- kor "'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª ۰¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä."
- nor "Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer."
- norwegian-ny "Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar."
- pol "Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje"
- por "Não se pode fazer DROP '%-.64s'. Confira se esta coluna/chave existe"
- rum "Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ (DROP) '%-.64s'. õÂÅÄÉÔÅÓØ ÞÔÏ ÓÔÏÌÂÅÃ/ËÌÀÞ ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Ne mogu da izvršim komandu drop 'DROP' na '%-.64s'. Proverite da li ta kolona (odnosno kljuè) postoji"
- slo "Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe"
- spa "No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe"
- swe "Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns"
- ukr "îÅ ÍÏÖÕ DROP '%-.64s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤"
+ cze "Nemohu zru-B¹it '%-.192s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe"
+ dan "Kan ikke udføre DROP '%-.192s'. Undersøg om feltet/nøglen eksisterer."
+ nla "Kan '%-.192s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat."
+ eng "Can't DROP '%-.192s'; check that column/key exists"
+ jps "'%-.192s' ‚ð”jŠü‚Å‚«‚Ü‚¹‚ñ‚Å‚µ‚½; check that column/key exists",
+ est "Ei suuda kustutada '%-.192s'. Kontrolli kas tulp/võti eksisteerib"
+ fre "Ne peut effacer (DROP) '%-.192s'. Vérifiez s'il existe"
+ ger "Kann '%-.192s' nicht löschen. Existiert die Spalte oder der Schlüssel?"
+ greek "Áäýíáôç ç äéáãñáöÞ (DROP) '%-.192s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé"
+ hun "A DROP '%-.192s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e"
+ ita "Impossibile cancellare '%-.192s'. Controllare che il campo chiave esista"
+ jpn "'%-.192s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿; check that column/key exists"
+ kor "'%-.192s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª ۰¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä."
+ nor "Kan ikke DROP '%-.192s'. Undersøk om felt/nøkkel eksisterer."
+ norwegian-ny "Kan ikkje DROP '%-.192s'. Undersøk om felt/nøkkel eksisterar."
+ pol "Nie mo¿na wykonaæ operacji DROP '%-.192s'. Sprawd¥, czy to pole/klucz istnieje"
+ por "Não se pode fazer DROP '%-.192s'. Confira se esta coluna/chave existe"
+ rum "Nu pot sa DROP '%-.192s'. Verifica daca coloana/cheia exista"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ (DROP) '%-.192s'. õÂÅÄÉÔÅÓØ ÞÔÏ ÓÔÏÌÂÅÃ/ËÌÀÞ ÄÅÊÓÔ×ÉÔÅÌØÎÏ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Ne mogu da izvršim komandu drop 'DROP' na '%-.192s'. Proverite da li ta kolona (odnosno kljuè) postoji"
+ slo "Nemô¾em zru¹i» (DROP) '%-.192s'. Skontrolujte, èi neexistujú záznamy/kµúèe"
+ spa "No puedo ELIMINAR '%-.192s'. compuebe que el campo/clave existe"
+ swe "Kan inte ta bort '%-.192s'. Kontrollera att fältet/nyckel finns"
+ ukr "îÅ ÍÏÖÕ DROP '%-.192s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤"
ER_INSERT_INFO
cze "Z-Báznamù: %ld Zdvojených: %ld Varování: %ld"
dan "Poster: %ld Ens: %ld Advarsler: %ld"
@@ -2240,11 +2240,11 @@ ER_INSERT_INFO
swe "Rader: %ld Dubletter: %ld Varningar: %ld"
ukr "úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld"
ER_UPDATE_TABLE_USED
- eng "You can't specify target table '%-.64s' for update in FROM clause"
- ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.64s' ist in der FROM-Klausel nicht zulässig."
- rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ ÕËÁÚÁÎÉÅ ÔÁÂÌÉÃÙ '%-.64s' × ÓÐÉÓËÅ ÔÁÂÌÉà FROM ÄÌÑ ×ÎÅÓÅÎÉÑ × ÎÅÅ ÉÚÍÅÎÅÎÉÊ"
- swe "INSERT-table '%-.64s' får inte finnas i FROM tabell-listan"
- ukr "ôÁÂÌÉÃÑ '%-.64s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM"
+ eng "You can't specify target table '%-.192s' for update in FROM clause"
+ ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.192s' ist in der FROM-Klausel nicht zulässig."
+ rus "îÅ ÄÏÐÕÓËÁÅÔÓÑ ÕËÁÚÁÎÉÅ ÔÁÂÌÉÃÙ '%-.192s' × ÓÐÉÓËÅ ÔÁÂÌÉà FROM ÄÌÑ ×ÎÅÓÅÎÉÑ × ÎÅÅ ÉÚÍÅÎÅÎÉÊ"
+ swe "INSERT-table '%-.192s' får inte finnas i FROM tabell-listan"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM"
ER_NO_SUCH_THREAD
cze "Nezn-Bámá identifikace threadu: %lu"
dan "Ukendt tråd id: %lu"
@@ -2319,174 +2319,174 @@ ER_NO_TABLES_USED
swe "Inga tabeller angivna"
ukr "îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ"
ER_TOO_BIG_SET
- cze "P-Bøíli¹ mnoho øetìzcù pro sloupec %s a SET"
- dan "For mange tekststrenge til specifikationen af SET i kolonne %-.64s"
- nla "Teveel strings voor kolom %s en SET"
- eng "Too many strings for column %-.64s and SET"
- est "Liiga palju string tulbale %-.64s tüübile SET"
- fre "Trop de chaînes dans la colonne %s avec SET"
- ger "Zu viele Strings für Feld %-.64s und SET angegeben"
- greek "ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.64s êáé SET"
- hun "Tul sok karakter: %-.64s es SET"
- ita "Troppe stringhe per la colonna %-.64s e la SET"
- kor "Ä®·³ %-.64s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
- nor "For mange tekststrenger kolonne %s og SET"
- norwegian-ny "For mange tekststrengar felt %s og SET"
- pol "Zbyt wiele ³añcuchów dla kolumny %s i polecenia SET"
- por "'Strings' demais para coluna '%-.64s' e SET"
- rum "Prea multe siruri pentru coloana %-.64s si SET"
- rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÚÎÁÞÅÎÉÊ ÄÌÑ ÓÔÏÌÂÃÁ %-.64s × SET"
- serbian "Previše string-ova za kolonu '%-.64s' i komandu 'SET'"
- slo "Príli¹ mnoho re»azcov pre pole %-.64s a SET"
- spa "Muchas strings para columna %s y SET"
- swe "För många alternativ till kolumn %s för SET"
- ukr "úÁÂÁÇÁÔÏ ÓÔÒÏË ÄÌÑ ÓÔÏ×ÂÃÑ %-.64s ÔÁ SET"
+ cze "P-Bøíli¹ mnoho øetìzcù pro sloupec %-.192s a SET"
+ dan "For mange tekststrenge til specifikationen af SET i kolonne %-.192s"
+ nla "Teveel strings voor kolom %-.192s en SET"
+ eng "Too many strings for column %-.192s and SET"
+ est "Liiga palju string tulbale %-.192s tüübile SET"
+ fre "Trop de chaînes dans la colonne %-.192s avec SET"
+ ger "Zu viele Strings für Feld %-.192s und SET angegeben"
+ greek "ÐÜñá ðïëëÜ strings ãéá ôï ðåäßï %-.192s êáé SET"
+ hun "Tul sok karakter: %-.192s es SET"
+ ita "Troppe stringhe per la colonna %-.192s e la SET"
+ kor "Ä®·³ %-.192s¿Í SET¿¡¼­ ½ºÆ®¸µÀÌ ³Ê¹« ¸¹½À´Ï´Ù."
+ nor "For mange tekststrenger kolonne %-.192s og SET"
+ norwegian-ny "For mange tekststrengar felt %-.192s og SET"
+ pol "Zbyt wiele ³añcuchów dla kolumny %-.192s i polecenia SET"
+ por "'Strings' demais para coluna '%-.192s' e SET"
+ rum "Prea multe siruri pentru coloana %-.192s si SET"
+ rus "óÌÉÛËÏÍ ÍÎÏÇÏ ÚÎÁÞÅÎÉÊ ÄÌÑ ÓÔÏÌÂÃÁ %-.192s × SET"
+ serbian "Previše string-ova za kolonu '%-.192s' i komandu 'SET'"
+ slo "Príli¹ mnoho re»azcov pre pole %-.192s a SET"
+ spa "Muchas strings para columna %-.192s y SET"
+ swe "För många alternativ till kolumn %-.192s för SET"
+ ukr "úÁÂÁÇÁÔÏ ÓÔÒÏË ÄÌÑ ÓÔÏ×ÂÃÑ %-.192s ÔÁ SET"
ER_NO_UNIQUE_LOGFILE
- cze "Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %s.(1-999)\n"
- dan "Kan ikke lave unikt log-filnavn %s.(1-999)\n"
- nla "Het is niet mogelijk een unieke naam te maken voor de logfile %s.(1-999)\n"
+ cze "Nemohu vytvo-Bøit jednoznaèné jméno logovacího souboru %-.200s.(1-999)\n"
+ dan "Kan ikke lave unikt log-filnavn %-.200s.(1-999)\n"
+ nla "Het is niet mogelijk een unieke naam te maken voor de logfile %-.200s.(1-999)\n"
eng "Can't generate a unique log-filename %-.200s.(1-999)\n"
- est "Ei suuda luua unikaalset logifaili nime %-.64s.(1-999)\n"
- fre "Ne peut générer un unique nom de journal %s.(1-999)\n"
- ger "Kann keinen eindeutigen Dateinamen für die Logdatei %-.64s(1-999) erzeugen\n"
- greek "Áäýíáôç ç äçìéïõñãßá unique log-filename %-.64s.(1-999)\n"
- hun "Egyedi log-filenev nem generalhato: %-.64s.(1-999)\n"
- ita "Impossibile generare un nome del file log unico %-.64s.(1-999)\n"
- kor "Unique ·Î±×È­ÀÏ '%-.64s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n"
- nor "Kan ikke lage unikt loggfilnavn %s.(1-999)\n"
- norwegian-ny "Kan ikkje lage unikt loggfilnavn %s.(1-999)\n"
- pol "Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %s.(1-999)\n"
- por "Não pode gerar um nome de arquivo de 'log' único '%-.64s'.(1-999)\n"
- rum "Nu pot sa generez un nume de log unic %-.64s.(1-999)\n"
- rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÏÅ ÉÍÑ ÆÁÊÌÁ ÖÕÒÎÁÌÁ %-.64s.(1-999)\n"
- serbian "Ne mogu da generišem jedinstveno ime log-file-a: '%-.64s.(1-999)'\n"
- slo "Nemô¾em vytvori» unikátne meno log-súboru %-.64s.(1-999)\n"
- spa "No puede crear un unico archivo log %s.(1-999)\n"
- swe "Kan inte generera ett unikt filnamn %s.(1-999)\n"
- ukr "îÅ ÍÏÖÕ ÚÇÅÎÅÒÕ×ÁÔÉ ÕΦËÁÌØÎÅ ¦Í'Ñ log-ÆÁÊÌÕ %-.64s.(1-999)\n"
+ est "Ei suuda luua unikaalset logifaili nime %-.200s.(1-999)\n"
+ fre "Ne peut générer un unique nom de journal %-.200s.(1-999)\n"
+ ger "Kann keinen eindeutigen Dateinamen für die Logdatei %-.200s(1-999) erzeugen\n"
+ greek "Áäýíáôç ç äçìéïõñãßá unique log-filename %-.200s.(1-999)\n"
+ hun "Egyedi log-filenev nem generalhato: %-.200s.(1-999)\n"
+ ita "Impossibile generare un nome del file log unico %-.200s.(1-999)\n"
+ kor "Unique ·Î±×È­ÀÏ '%-.200s'¸¦ ¸¸µé¼ö ¾ø½À´Ï´Ù.(1-999)\n"
+ nor "Kan ikke lage unikt loggfilnavn %-.200s.(1-999)\n"
+ norwegian-ny "Kan ikkje lage unikt loggfilnavn %-.200s.(1-999)\n"
+ pol "Nie mo¿na stworzyæ unikalnej nazwy pliku z logiem %-.200s.(1-999)\n"
+ por "Não pode gerar um nome de arquivo de 'log' único '%-.200s'.(1-999)\n"
+ rum "Nu pot sa generez un nume de log unic %-.200s.(1-999)\n"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÕÎÉËÁÌØÎÏÅ ÉÍÑ ÆÁÊÌÁ ÖÕÒÎÁÌÁ %-.200s.(1-999)\n"
+ serbian "Ne mogu da generišem jedinstveno ime log-file-a: '%-.200s.(1-999)'\n"
+ slo "Nemô¾em vytvori» unikátne meno log-súboru %-.200s.(1-999)\n"
+ spa "No puede crear un unico archivo log %-.200s.(1-999)\n"
+ swe "Kan inte generera ett unikt filnamn %-.200s.(1-999)\n"
+ ukr "îÅ ÍÏÖÕ ÚÇÅÎÅÒÕ×ÁÔÉ ÕΦËÁÌØÎÅ ¦Í'Ñ log-ÆÁÊÌÕ %-.200s.(1-999)\n"
ER_TABLE_NOT_LOCKED_FOR_WRITE
- cze "Tabulka '%-.64s' byla zam-Bèena s READ a nemù¾e být zmìnìna"
- dan "Tabellen '%-.64s' var låst med READ lås og kan ikke opdateres"
- nla "Tabel '%-.64s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen."
- eng "Table '%-.64s' was locked with a READ lock and can't be updated"
- jps "Table '%-.64s' ‚Í READ lock ‚ɂȂÁ‚Ä‚¢‚ÄAXV‚͂ł«‚Ü‚¹‚ñ",
- est "Tabel '%-.64s' on lukustatud READ lukuga ning ei ole muudetav"
- fre "Table '%-.64s' verrouillée lecture (READ): modification impossible"
- ger "Tabelle '%-.64s' ist mit Lesesperre versehen und kann nicht aktualisiert werden"
- greek "Ï ðßíáêáò '%-.64s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò"
- hun "A(z) '%-.64s' tabla zarolva lett (READ lock) es nem lehet frissiteni"
- ita "La tabella '%-.64s' e` soggetta a lock in lettura e non puo` essere aggiornata"
- jpn "Table '%-.64s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó"
- kor "Å×À̺í '%-.64s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù."
- nor "Tabellen '%-.64s' var låst med READ lås og kan ikke oppdateres"
- norwegian-ny "Tabellen '%-.64s' var låst med READ lås og kan ikkje oppdaterast"
- pol "Tabela '%-.64s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana"
- por "Tabela '%-.64s' foi travada com trava de leitura e não pode ser atualizada"
- rum "Tabela '%-.64s' a fost locked cu un READ lock si nu poate fi actualizata"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ ÕÒÏ×ÎÅÍ READ lock É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ"
- serbian "Tabela '%-.64s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati"
- slo "Tabuµka '%-.64s' bola zamknutá s READ a nemô¾e by» zmenená"
- spa "Tabla '%-.64s' fue trabada con un READ lock y no puede ser actualizada"
- swe "Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning"
- ukr "ôÁÂÌÉÃÀ '%-.64s' ÚÁÂÌÏËÏ×ÁÎÏ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÔÏÍÕ §§ ÎÅ ÍÏÖÎÁ ÏÎÏ×ÉÔÉ"
+ cze "Tabulka '%-.192s' byla zam-Bèena s READ a nemù¾e být zmìnìna"
+ dan "Tabellen '%-.192s' var låst med READ lås og kan ikke opdateres"
+ nla "Tabel '%-.192s' was gelocked met een lock om te lezen. Derhalve kunnen geen wijzigingen worden opgeslagen."
+ eng "Table '%-.192s' was locked with a READ lock and can't be updated"
+ jps "Table '%-.192s' ‚Í READ lock ‚ɂȂÁ‚Ä‚¢‚ÄAXV‚͂ł«‚Ü‚¹‚ñ",
+ est "Tabel '%-.192s' on lukustatud READ lukuga ning ei ole muudetav"
+ fre "Table '%-.192s' verrouillée lecture (READ): modification impossible"
+ ger "Tabelle '%-.192s' ist mit Lesesperre versehen und kann nicht aktualisiert werden"
+ greek "Ï ðßíáêáò '%-.192s' Ý÷åé êëåéäùèåß ìå READ lock êáé äåí åðéôñÝðïíôáé áëëáãÝò"
+ hun "A(z) '%-.192s' tabla zarolva lett (READ lock) es nem lehet frissiteni"
+ ita "La tabella '%-.192s' e` soggetta a lock in lettura e non puo` essere aggiornata"
+ jpn "Table '%-.192s' ¤Ï READ lock ¤Ë¤Ê¤Ã¤Æ¤¤¤Æ¡¢¹¹¿·¤Ï¤Ç¤­¤Þ¤»¤ó"
+ kor "Å×À̺í '%-.192s'´Â READ ¶ôÀÌ Àá°ÜÀ־ °»½ÅÇÒ ¼ö ¾ø½À´Ï´Ù."
+ nor "Tabellen '%-.192s' var låst med READ lås og kan ikke oppdateres"
+ norwegian-ny "Tabellen '%-.192s' var låst med READ lås og kan ikkje oppdaterast"
+ pol "Tabela '%-.192s' zosta³a zablokowana przez READ i nie mo¿e zostaæ zaktualizowana"
+ por "Tabela '%-.192s' foi travada com trava de leitura e não pode ser atualizada"
+ rum "Tabela '%-.192s' a fost locked cu un READ lock si nu poate fi actualizata"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÚÁÂÌÏËÉÒÏ×ÁÎÁ ÕÒÏ×ÎÅÍ READ lock É ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÚÍÅÎÅÎÁ"
+ serbian "Tabela '%-.192s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati"
+ slo "Tabuµka '%-.192s' bola zamknutá s READ a nemô¾e by» zmenená"
+ spa "Tabla '%-.192s' fue trabada con un READ lock y no puede ser actualizada"
+ swe "Tabell '%-.192s' kan inte uppdateras emedan den är låst för läsning"
+ ukr "ôÁÂÌÉÃÀ '%-.192s' ÚÁÂÌÏËÏ×ÁÎÏ Ô¦ÌØËÉ ÄÌÑ ÞÉÔÁÎÎÑ, ÔÏÍÕ §§ ÎÅ ÍÏÖÎÁ ÏÎÏ×ÉÔÉ"
ER_TABLE_NOT_LOCKED
- cze "Tabulka '%-.64s' nebyla zam-Bèena s LOCK TABLES"
- dan "Tabellen '%-.64s' var ikke låst med LOCK TABLES"
- nla "Tabel '%-.64s' was niet gelocked met LOCK TABLES"
- eng "Table '%-.64s' was not locked with LOCK TABLES"
- jps "Table '%-.64s' ‚Í LOCK TABLES ‚É‚æ‚Á‚ăƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Tabel '%-.64s' ei ole lukustatud käsuga LOCK TABLES"
- fre "Table '%-.64s' non verrouillée: utilisez LOCK TABLES"
- ger "Tabelle '%-.64s' wurde nicht mit LOCK TABLES gesperrt"
- greek "Ï ðßíáêáò '%-.64s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES"
- hun "A(z) '%-.64s' tabla nincs zarolva a LOCK TABLES-szel"
- ita "Non e` stato impostato il lock per la tabella '%-.64s' con LOCK TABLES"
- jpn "Table '%-.64s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "Å×À̺í '%-.64s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù."
- nor "Tabellen '%-.64s' var ikke låst med LOCK TABLES"
- norwegian-ny "Tabellen '%-.64s' var ikkje låst med LOCK TABLES"
- pol "Tabela '%-.64s' nie zosta³a zablokowana poleceniem LOCK TABLES"
- por "Tabela '%-.64s' não foi travada com LOCK TABLES"
- rum "Tabela '%-.64s' nu a fost locked cu LOCK TABLES"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÎÅ ÂÙÌÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
- serbian "Tabela '%-.64s' nije bila zakljuèana komandom 'LOCK TABLES'"
- slo "Tabuµka '%-.64s' nebola zamknutá s LOCK TABLES"
- spa "Tabla '%-.64s' no fue trabada con LOCK TABLES"
- swe "Tabell '%-.64s' är inte låst med LOCK TABLES"
- ukr "ôÁÂÌÉÃÀ '%-.64s' ÎÅ ÂÕÌÏ ÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
+ cze "Tabulka '%-.192s' nebyla zam-Bèena s LOCK TABLES"
+ dan "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
+ nla "Tabel '%-.192s' was niet gelocked met LOCK TABLES"
+ eng "Table '%-.192s' was not locked with LOCK TABLES"
+ jps "Table '%-.192s' ‚Í LOCK TABLES ‚É‚æ‚Á‚ăƒbƒN‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Tabel '%-.192s' ei ole lukustatud käsuga LOCK TABLES"
+ fre "Table '%-.192s' non verrouillée: utilisez LOCK TABLES"
+ ger "Tabelle '%-.192s' wurde nicht mit LOCK TABLES gesperrt"
+ greek "Ï ðßíáêáò '%-.192s' äåí Ý÷åé êëåéäùèåß ìå LOCK TABLES"
+ hun "A(z) '%-.192s' tabla nincs zarolva a LOCK TABLES-szel"
+ ita "Non e` stato impostato il lock per la tabella '%-.192s' con LOCK TABLES"
+ jpn "Table '%-.192s' ¤Ï LOCK TABLES ¤Ë¤è¤Ã¤Æ¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "Å×À̺í '%-.192s'´Â LOCK TABLES ¸í·ÉÀ¸·Î Àá±âÁö ¾Ê¾Ò½À´Ï´Ù."
+ nor "Tabellen '%-.192s' var ikke låst med LOCK TABLES"
+ norwegian-ny "Tabellen '%-.192s' var ikkje låst med LOCK TABLES"
+ pol "Tabela '%-.192s' nie zosta³a zablokowana poleceniem LOCK TABLES"
+ por "Tabela '%-.192s' não foi travada com LOCK TABLES"
+ rum "Tabela '%-.192s' nu a fost locked cu LOCK TABLES"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÎÅ ÂÙÌÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
+ serbian "Tabela '%-.192s' nije bila zakljuèana komandom 'LOCK TABLES'"
+ slo "Tabuµka '%-.192s' nebola zamknutá s LOCK TABLES"
+ spa "Tabla '%-.192s' no fue trabada con LOCK TABLES"
+ swe "Tabell '%-.192s' är inte låst med LOCK TABLES"
+ ukr "ôÁÂÌÉÃÀ '%-.192s' ÎÅ ÂÕÌÏ ÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
ER_BLOB_CANT_HAVE_DEFAULT 42000
- cze "Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu"
- dan "BLOB feltet '%-.64s' kan ikke have en standard værdi"
- nla "Blob veld '%-.64s' can geen standaardwaarde bevatten"
- eng "BLOB/TEXT column '%-.64s' can't have a default value"
- est "BLOB-tüüpi tulp '%-.64s' ei saa omada vaikeväärtust"
- fre "BLOB '%-.64s' ne peut avoir de valeur par défaut"
- ger "BLOB/TEXT-Feld '%-.64s' darf keinen Vorgabewert (DEFAULT) haben"
- greek "Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)"
- hun "A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke"
- ita "Il campo BLOB '%-.64s' non puo` avere un valore di default"
- jpn "BLOB column '%-.64s' can't have a default value"
- kor "BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù."
- nor "Blob feltet '%-.64s' kan ikke ha en standard verdi"
- norwegian-ny "Blob feltet '%-.64s' kan ikkje ha ein standard verdi"
- pol "Pole typu blob '%-.64s' nie mo¿e mieæ domy?lnej warto?ci"
- por "Coluna BLOB '%-.64s' não pode ter um valor padrão (default)"
- rum "Coloana BLOB '%-.64s' nu poate avea o valoare default"
- rus "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.64s'"
- serbian "BLOB kolona '%-.64s' ne može imati default vrednost"
- slo "Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu"
- spa "Campo Blob '%-.64s' no puede tener valores patron"
- swe "BLOB fält '%-.64s' kan inte ha ett DEFAULT-värde"
- ukr "óÔÏ×ÂÅÃØ BLOB '%-.64s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ"
+ cze "Blob polo-B¾ka '%-.192s' nemù¾e mít defaultní hodnotu"
+ dan "BLOB feltet '%-.192s' kan ikke have en standard værdi"
+ nla "Blob veld '%-.192s' can geen standaardwaarde bevatten"
+ eng "BLOB/TEXT column '%-.192s' can't have a default value"
+ est "BLOB-tüüpi tulp '%-.192s' ei saa omada vaikeväärtust"
+ fre "BLOB '%-.192s' ne peut avoir de valeur par défaut"
+ ger "BLOB/TEXT-Feld '%-.192s' darf keinen Vorgabewert (DEFAULT) haben"
+ greek "Ôá Blob ðåäßá '%-.192s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)"
+ hun "A(z) '%-.192s' blob objektumnak nem lehet alapertelmezett erteke"
+ ita "Il campo BLOB '%-.192s' non puo` avere un valore di default"
+ jpn "BLOB column '%-.192s' can't have a default value"
+ kor "BLOB Ä®·³ '%-.192s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù."
+ nor "Blob feltet '%-.192s' kan ikke ha en standard verdi"
+ norwegian-ny "Blob feltet '%-.192s' kan ikkje ha ein standard verdi"
+ pol "Pole typu blob '%-.192s' nie mo¿e mieæ domy?lnej warto?ci"
+ por "Coluna BLOB '%-.192s' não pode ter um valor padrão (default)"
+ rum "Coloana BLOB '%-.192s' nu poate avea o valoare default"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.192s'"
+ serbian "BLOB kolona '%-.192s' ne može imati default vrednost"
+ slo "Pole BLOB '%-.192s' nemô¾e ma» implicitnú hodnotu"
+ spa "Campo Blob '%-.192s' no puede tener valores patron"
+ swe "BLOB fält '%-.192s' kan inte ha ett DEFAULT-värde"
+ ukr "óÔÏ×ÂÅÃØ BLOB '%-.192s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ"
ER_WRONG_DB_NAME 42000
- cze "Nep-Bøípustné jméno databáze '%-.64s'"
- dan "Ugyldigt database navn '%-.64s'"
- nla "Databasenaam '%-.64s' is niet getoegestaan"
+ cze "Nep-Bøípustné jméno databáze '%-.100s'"
+ dan "Ugyldigt database navn '%-.100s'"
+ nla "Databasenaam '%-.100s' is niet getoegestaan"
eng "Incorrect database name '%-.100s'"
jps "Žw’肵‚½ database –¼ '%-.100s' ‚ªŠÔˆá‚Á‚Ä‚¢‚Ü‚·",
est "Vigane andmebaasi nimi '%-.100s'"
- fre "Nom de base de donnée illégal: '%-.64s'"
+ fre "Nom de base de donnée illégal: '%-.100s'"
ger "Unerlaubter Datenbankname '%-.100s'"
greek "ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'"
hun "Hibas adatbazisnev: '%-.100s'"
ita "Nome database errato '%-.100s'"
jpn "»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹"
kor "'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
- nor "Ugyldig database navn '%-.64s'"
- norwegian-ny "Ugyldig database namn '%-.64s'"
- pol "Niedozwolona nazwa bazy danych '%-.64s'"
+ nor "Ugyldig database navn '%-.100s'"
+ norwegian-ny "Ugyldig database namn '%-.100s'"
+ pol "Niedozwolona nazwa bazy danych '%-.100s'"
por "Nome de banco de dados '%-.100s' incorreto"
rum "Numele bazei de date este incorect '%-.100s'"
rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'"
serbian "Pogrešno ime baze '%-.100s'"
slo "Neprípustné meno databázy '%-.100s'"
- spa "Nombre de base de datos ilegal '%-.64s'"
- swe "Felaktigt databasnamn '%-.64s'"
+ spa "Nombre de base de datos ilegal '%-.100s'"
+ swe "Felaktigt databasnamn '%-.100s'"
ukr "îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'"
ER_WRONG_TABLE_NAME 42000
- cze "Nep-Bøípustné jméno tabulky '%-.64s'"
- dan "Ugyldigt tabel navn '%-.64s'"
- nla "Niet toegestane tabelnaam '%-.64s'"
+ cze "Nep-Bøípustné jméno tabulky '%-.100s'"
+ dan "Ugyldigt tabel navn '%-.100s'"
+ nla "Niet toegestane tabelnaam '%-.100s'"
eng "Incorrect table name '%-.100s'"
jps "Žw’肵‚½ table –¼ '%-.100s' ‚͂܂¿‚ª‚Á‚Ä‚¢‚Ü‚·",
est "Vigane tabeli nimi '%-.100s'"
- fre "Nom de table illégal: '%-.64s'"
+ fre "Nom de table illégal: '%-.100s'"
ger "Unerlaubter Tabellenname '%-.100s'"
greek "ËÜèïò üíïìá ðßíáêá '%-.100s'"
hun "Hibas tablanev: '%-.100s'"
ita "Nome tabella errato '%-.100s'"
jpn "»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹"
kor "'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù."
- nor "Ugyldig tabell navn '%-.64s'"
- norwegian-ny "Ugyldig tabell namn '%-.64s'"
- pol "Niedozwolona nazwa tabeli '%-.64s'..."
+ nor "Ugyldig tabell navn '%-.100s'"
+ norwegian-ny "Ugyldig tabell namn '%-.100s'"
+ pol "Niedozwolona nazwa tabeli '%-.100s'..."
por "Nome de tabela '%-.100s' incorreto"
rum "Numele tabelei este incorect '%-.100s'"
rus "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'"
serbian "Pogrešno ime tabele '%-.100s'"
slo "Neprípustné meno tabuµky '%-.100s'"
- spa "Nombre de tabla ilegal '%-.64s'"
- swe "Felaktigt tabellnamn '%-.64s'"
+ spa "Nombre de tabla ilegal '%-.100s'"
+ swe "Felaktigt tabellnamn '%-.100s'"
ukr "îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'"
ER_TOO_BIG_SELECT 42000
cze "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"
@@ -2534,121 +2534,121 @@ ER_UNKNOWN_ERROR
swe "Oidentifierat fel"
ukr "îÅצÄÏÍÁ ÐÏÍÉÌËÁ"
ER_UNKNOWN_PROCEDURE 42000
- cze "Nezn-Bámá procedura %s"
- dan "Ukendt procedure %s"
- nla "Onbekende procedure %s"
- eng "Unknown procedure '%-.64s'"
- est "Tundmatu protseduur '%-.64s'"
- fre "Procédure %s inconnue"
- ger "Unbekannte Prozedur '%-.64s'"
- greek "Áãíùóôç äéáäéêáóßá '%-.64s'"
- hun "Ismeretlen eljaras: '%-.64s'"
- ita "Procedura '%-.64s' sconosciuta"
- kor "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'"
- nor "Ukjent prosedyre %s"
- norwegian-ny "Ukjend prosedyre %s"
- pol "Unkown procedure %s"
- por "'Procedure' '%-.64s' desconhecida"
- rum "Procedura unknown '%-.64s'"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.64s'"
- serbian "Nepoznata procedura '%-.64s'"
- slo "Neznámá procedúra '%-.64s'"
- spa "Procedimiento desconocido %s"
- swe "Okänd procedur: %s"
- ukr "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.64s'"
+ cze "Nezn-Bámá procedura %-.192s"
+ dan "Ukendt procedure %-.192s"
+ nla "Onbekende procedure %-.192s"
+ eng "Unknown procedure '%-.192s'"
+ est "Tundmatu protseduur '%-.192s'"
+ fre "Procédure %-.192s inconnue"
+ ger "Unbekannte Prozedur '%-.192s'"
+ greek "Áãíùóôç äéáäéêáóßá '%-.192s'"
+ hun "Ismeretlen eljaras: '%-.192s'"
+ ita "Procedura '%-.192s' sconosciuta"
+ kor "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.192s'"
+ nor "Ukjent prosedyre %-.192s"
+ norwegian-ny "Ukjend prosedyre %-.192s"
+ pol "Unkown procedure %-.192s"
+ por "'Procedure' '%-.192s' desconhecida"
+ rum "Procedura unknown '%-.192s'"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.192s'"
+ serbian "Nepoznata procedura '%-.192s'"
+ slo "Neznámá procedúra '%-.192s'"
+ spa "Procedimiento desconocido %-.192s"
+ swe "Okänd procedur: %-.192s"
+ ukr "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.192s'"
ER_WRONG_PARAMCOUNT_TO_PROCEDURE 42000
- cze "Chybn-Bý poèet parametrù procedury %s"
- dan "Forkert antal parametre til proceduren %s"
- nla "Foutief aantal parameters doorgegeven aan procedure %s"
- eng "Incorrect parameter count to procedure '%-.64s'"
- est "Vale parameetrite hulk protseduurile '%-.64s'"
- fre "Mauvais nombre de paramètres pour la procedure %s"
- ger "Falsche Parameterzahl für Prozedur '%-.64s'"
- greek "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'"
- hun "Rossz parameter a(z) '%-.64s'eljaras szamitasanal"
- ita "Numero di parametri errato per la procedura '%-.64s'"
- kor "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆÄ¶ó¸ÞÅÍ"
- nor "Feil parameter antall til prosedyren %s"
- norwegian-ny "Feil parameter tal til prosedyra %s"
- pol "Incorrect parameter count to procedure %s"
- por "Número de parâmetros incorreto para a 'procedure' '%-.64s'"
- rum "Procedura '%-.64s' are un numar incorect de parametri"
- rus "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'"
- serbian "Pogrešan broj parametara za proceduru '%-.64s'"
- slo "Chybný poèet parametrov procedúry '%-.64s'"
- spa "Equivocado parametro count para procedimiento %s"
- swe "Felaktigt antal parametrar till procedur %s"
- ukr "èÉÂÎÁ Ë¦ÌØË¦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.64s'"
+ cze "Chybn-Bý poèet parametrù procedury %-.192s"
+ dan "Forkert antal parametre til proceduren %-.192s"
+ nla "Foutief aantal parameters doorgegeven aan procedure %-.192s"
+ eng "Incorrect parameter count to procedure '%-.192s'"
+ est "Vale parameetrite hulk protseduurile '%-.192s'"
+ fre "Mauvais nombre de paramètres pour la procedure %-.192s"
+ ger "Falsche Parameterzahl für Prozedur '%-.192s'"
+ greek "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.192s'"
+ hun "Rossz parameter a(z) '%-.192s'eljaras szamitasanal"
+ ita "Numero di parametri errato per la procedura '%-.192s'"
+ kor "'%-.192s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆÄ¶ó¸ÞÅÍ"
+ nor "Feil parameter antall til prosedyren %-.192s"
+ norwegian-ny "Feil parameter tal til prosedyra %-.192s"
+ pol "Incorrect parameter count to procedure %-.192s"
+ por "Número de parâmetros incorreto para a 'procedure' '%-.192s'"
+ rum "Procedura '%-.192s' are un numar incorect de parametri"
+ rus "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.192s'"
+ serbian "Pogrešan broj parametara za proceduru '%-.192s'"
+ slo "Chybný poèet parametrov procedúry '%-.192s'"
+ spa "Equivocado parametro count para procedimiento %-.192s"
+ swe "Felaktigt antal parametrar till procedur %-.192s"
+ ukr "èÉÂÎÁ Ë¦ÌØË¦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.192s'"
ER_WRONG_PARAMETERS_TO_PROCEDURE
- cze "Chybn-Bé parametry procedury %s"
- dan "Forkert(e) parametre til proceduren %s"
- nla "Foutieve parameters voor procedure %s"
- eng "Incorrect parameters to procedure '%-.64s'"
- est "Vigased parameetrid protseduurile '%-.64s'"
- fre "Paramètre erroné pour la procedure %s"
- ger "Falsche Parameter für Prozedur '%-.64s'"
- greek "ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.64s'"
- hun "Rossz parameter a(z) '%-.64s' eljarasban"
- ita "Parametri errati per la procedura '%-.64s'"
- kor "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆÄ¶ó¸ÞÅÍ"
- nor "Feil parametre til prosedyren %s"
- norwegian-ny "Feil parameter til prosedyra %s"
- pol "Incorrect parameters to procedure %s"
- por "Parâmetros incorretos para a 'procedure' '%-.64s'"
- rum "Procedura '%-.64s' are parametrii incorecti"
- rus "îÅËÏÒÒÅËÔÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'"
- serbian "Pogrešni parametri prosleðeni proceduri '%-.64s'"
- slo "Chybné parametre procedúry '%-.64s'"
- spa "Equivocados parametros para procedimiento %s"
- swe "Felaktiga parametrar till procedur %s"
- ukr "èÉÂÎÉÊ ÐÁÒÁÍÅÔÅÒ ÐÒÏÃÅÄÕÒÉ '%-.64s'"
+ cze "Chybn-Bé parametry procedury %-.192s"
+ dan "Forkert(e) parametre til proceduren %-.192s"
+ nla "Foutieve parameters voor procedure %-.192s"
+ eng "Incorrect parameters to procedure '%-.192s'"
+ est "Vigased parameetrid protseduurile '%-.192s'"
+ fre "Paramètre erroné pour la procedure %-.192s"
+ ger "Falsche Parameter für Prozedur '%-.192s'"
+ greek "ËÜèïò ðáñÜìåôñïé óôçí äéáäéêáóßá '%-.192s'"
+ hun "Rossz parameter a(z) '%-.192s' eljarasban"
+ ita "Parametri errati per la procedura '%-.192s'"
+ kor "'%-.192s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆÄ¶ó¸ÞÅÍ"
+ nor "Feil parametre til prosedyren %-.192s"
+ norwegian-ny "Feil parameter til prosedyra %-.192s"
+ pol "Incorrect parameters to procedure %-.192s"
+ por "Parâmetros incorretos para a 'procedure' '%-.192s'"
+ rum "Procedura '%-.192s' are parametrii incorecti"
+ rus "îÅËÏÒÒÅËÔÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.192s'"
+ serbian "Pogrešni parametri prosleðeni proceduri '%-.192s'"
+ slo "Chybné parametre procedúry '%-.192s'"
+ spa "Equivocados parametros para procedimiento %-.192s"
+ swe "Felaktiga parametrar till procedur %-.192s"
+ ukr "èÉÂÎÉÊ ÐÁÒÁÍÅÔÅÒ ÐÒÏÃÅÄÕÒÉ '%-.192s'"
ER_UNKNOWN_TABLE 42S02
- cze "Nezn-Bámá tabulka '%-.64s' v %s"
- dan "Ukendt tabel '%-.64s' i %s"
- nla "Onbekende tabel '%-.64s' in %s"
- eng "Unknown table '%-.64s' in %-.32s"
- est "Tundmatu tabel '%-.64s' %-.32s-s"
- fre "Table inconnue '%-.64s' dans %s"
- ger "Unbekannte Tabelle '%-.64s' in '%-.64s'"
- greek "Áãíùóôïò ðßíáêáò '%-.64s' óå %s"
- hun "Ismeretlen tabla: '%-.64s' %s-ban"
- ita "Tabella '%-.64s' sconosciuta in %s"
- jpn "Unknown table '%-.64s' in %s"
- kor "¾Ë¼ö ¾ø´Â Å×À̺í '%-.64s' (µ¥ÀÌŸº£À̽º %s)"
- nor "Ukjent tabell '%-.64s' i %s"
- norwegian-ny "Ukjend tabell '%-.64s' i %s"
- pol "Unknown table '%-.64s' in %s"
- por "Tabela '%-.64s' desconhecida em '%-.32s'"
- rum "Tabla '%-.64s' invalida in %-.32s"
- rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.64s' × %-.32s"
- serbian "Nepoznata tabela '%-.64s' u '%-.32s'"
- slo "Neznáma tabuµka '%-.64s' v %s"
- spa "Tabla desconocida '%-.64s' in %s"
- swe "Okänd tabell '%-.64s' i '%-.64s'"
- ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.64s' Õ %-.32s"
+ cze "Nezn-Bámá tabulka '%-.192s' v %-.32s"
+ dan "Ukendt tabel '%-.192s' i %-.32s"
+ nla "Onbekende tabel '%-.192s' in %-.32s"
+ eng "Unknown table '%-.192s' in %-.32s"
+ est "Tundmatu tabel '%-.192s' %-.32s-s"
+ fre "Table inconnue '%-.192s' dans %-.32s"
+ ger "Unbekannte Tabelle '%-.192s' in '%-.32s'"
+ greek "Áãíùóôïò ðßíáêáò '%-.192s' óå %-.32s"
+ hun "Ismeretlen tabla: '%-.192s' %-.32s-ban"
+ ita "Tabella '%-.192s' sconosciuta in %-.32s"
+ jpn "Unknown table '%-.192s' in %-.32s"
+ kor "¾Ë¼ö ¾ø´Â Å×À̺í '%-.192s' (µ¥ÀÌŸº£À̽º %-.32s)"
+ nor "Ukjent tabell '%-.192s' i %-.32s"
+ norwegian-ny "Ukjend tabell '%-.192s' i %-.32s"
+ pol "Unknown table '%-.192s' in %-.32s"
+ por "Tabela '%-.192s' desconhecida em '%-.32s'"
+ rum "Tabla '%-.192s' invalida in %-.32s"
+ rus "îÅÉÚ×ÅÓÔÎÁÑ ÔÁÂÌÉÃÁ '%-.192s' × %-.32s"
+ serbian "Nepoznata tabela '%-.192s' u '%-.32s'"
+ slo "Neznáma tabuµka '%-.192s' v %-.32s"
+ spa "Tabla desconocida '%-.192s' in %-.32s"
+ swe "Okänd tabell '%-.192s' i '%-.32s'"
+ ukr "îÅצÄÏÍÁ ÔÁÂÌÉÃÑ '%-.192s' Õ %-.32s"
ER_FIELD_SPECIFIED_TWICE 42000
- cze "Polo-B¾ka '%-.64s' je zadána dvakrát"
- dan "Feltet '%-.64s' er anvendt to gange"
- nla "Veld '%-.64s' is dubbel gespecificeerd"
- eng "Column '%-.64s' specified twice"
- est "Tulp '%-.64s' on määratletud topelt"
- fre "Champ '%-.64s' spécifié deux fois"
- ger "Feld '%-.64s' wurde zweimal angegeben"
- greek "Ôï ðåäßï '%-.64s' Ý÷åé ïñéóèåß äýï öïñÝò"
- hun "A(z) '%-.64s' mezot ketszer definialta"
- ita "Campo '%-.64s' specificato 2 volte"
- kor "Ä®·³ '%-.64s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù."
- nor "Feltet '%-.64s' er spesifisert to ganger"
- norwegian-ny "Feltet '%-.64s' er spesifisert to gangar"
- pol "Field '%-.64s' specified twice"
- por "Coluna '%-.64s' especificada duas vezes"
- rum "Coloana '%-.64s' specificata de doua ori"
- rus "óÔÏÌÂÅà '%-.64s' ÕËÁÚÁÎ Ä×ÁÖÄÙ"
- serbian "Kolona '%-.64s' je navedena dva puta"
- slo "Pole '%-.64s' je zadané dvakrát"
- spa "Campo '%-.64s' especificado dos veces"
- swe "Fält '%-.64s' är redan använt"
- ukr "óÔÏ×ÂÅÃØ '%-.64s' ÚÁÚÎÁÞÅÎÏ Äצަ"
+ cze "Polo-B¾ka '%-.192s' je zadána dvakrát"
+ dan "Feltet '%-.192s' er anvendt to gange"
+ nla "Veld '%-.192s' is dubbel gespecificeerd"
+ eng "Column '%-.192s' specified twice"
+ est "Tulp '%-.192s' on määratletud topelt"
+ fre "Champ '%-.192s' spécifié deux fois"
+ ger "Feld '%-.192s' wurde zweimal angegeben"
+ greek "Ôï ðåäßï '%-.192s' Ý÷åé ïñéóèåß äýï öïñÝò"
+ hun "A(z) '%-.192s' mezot ketszer definialta"
+ ita "Campo '%-.192s' specificato 2 volte"
+ kor "Ä®·³ '%-.192s'´Â µÎ¹ø Á¤ÀǵǾî ÀÖÀ¾´Ï´Ù."
+ nor "Feltet '%-.192s' er spesifisert to ganger"
+ norwegian-ny "Feltet '%-.192s' er spesifisert to gangar"
+ pol "Field '%-.192s' specified twice"
+ por "Coluna '%-.192s' especificada duas vezes"
+ rum "Coloana '%-.192s' specificata de doua ori"
+ rus "óÔÏÌÂÅà '%-.192s' ÕËÁÚÁÎ Ä×ÁÖÄÙ"
+ serbian "Kolona '%-.192s' je navedena dva puta"
+ slo "Pole '%-.192s' je zadané dvakrát"
+ spa "Campo '%-.192s' especificado dos veces"
+ swe "Fält '%-.192s' är redan använt"
+ ukr "óÔÏ×ÂÅÃØ '%-.192s' ÚÁÚÎÁÞÅÎÏ Äצަ"
ER_INVALID_GROUP_FUNC_USE
cze "Nespr-Bávné pou¾ití funkce group"
dan "Forkert brug af grupperings-funktion"
@@ -2670,28 +2670,28 @@ ER_INVALID_GROUP_FUNC_USE
swe "Felaktig användning av SQL grupp function"
ukr "èÉÂÎÅ ×ÉËÏÒÉÓÔÁÎÎÑ ÆÕÎËæ§ ÇÒÕÐÕ×ÁÎÎÑ"
ER_UNSUPPORTED_EXTENSION 42000
- cze "Tabulka '%-.64s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není"
- dan "Tabellen '%-.64s' bruger et filtypenavn som ikke findes i denne MySQL version"
- nla "Tabel '%-.64s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt."
- eng "Table '%-.64s' uses an extension that doesn't exist in this MySQL version"
- est "Tabel '%-.64s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis"
- fre "Table '%-.64s' : utilise une extension invalide pour cette version de MySQL"
- ger "Tabelle '%-.64s' verwendet eine Erweiterung, die in dieser MySQL-Version nicht verfügbar ist"
- greek "Ï ðßíáêò '%-.64s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL"
- hun "A(z) '%-.64s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban."
- ita "La tabella '%-.64s' usa un'estensione che non esiste in questa versione di MySQL"
- kor "Å×À̺í '%-.64s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
- norwegian-ny "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
- pol "Table '%-.64s' uses a extension that doesn't exist in this MySQL version"
- por "Tabela '%-.64s' usa uma extensão que não existe nesta versão do MySQL"
- rum "Tabela '%-.64s' foloseste o extensire inexistenta in versiunea curenta de MySQL"
- rus "÷ ÔÁÂÌÉÃÅ '%-.64s' ÉÓÐÏÌØÚÕÀÔÓÑ ×ÏÚÍÏÖÎÏÓÔÉ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÍÙÅ × ÜÔÏÊ ×ÅÒÓÉÉ MySQL"
- serbian "Tabela '%-.64s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a"
- slo "Tabuµka '%-.64s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je"
- spa "Tabla '%-.64s' usa una extensión que no existe en esta MySQL versión"
- swe "Tabell '%-.64s' har en extension som inte finns i denna version av MySQL"
- ukr "ôÁÂÌÉÃÑ '%-.64s' ×ÉËÏÒÉÓÔÏ×Õ¤ ÒÏÚÛÉÒÅÎÎÑ, ÝÏ ÎÅ ¦ÓÎÕ¤ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
+ cze "Tabulka '%-.192s' pou-B¾ívá roz¹íøení, které v této verzi MySQL není"
+ dan "Tabellen '%-.192s' bruger et filtypenavn som ikke findes i denne MySQL version"
+ nla "Tabel '%-.192s' gebruikt een extensie, die niet in deze MySQL-versie voorkomt."
+ eng "Table '%-.192s' uses an extension that doesn't exist in this MySQL version"
+ est "Tabel '%-.192s' kasutab laiendust, mis ei eksisteeri antud MySQL versioonis"
+ fre "Table '%-.192s' : utilise une extension invalide pour cette version de MySQL"
+ ger "Tabelle '%-.192s' verwendet eine Erweiterung, die in dieser MySQL-Version nicht verfügbar ist"
+ greek "Ï ðßíáêò '%-.192s' ÷ñçóéìïðïéåß êÜðïéï extension ðïõ äåí õðÜñ÷åé óôçí Ýêäïóç áõôÞ ôçò MySQL"
+ hun "A(z) '%-.192s' tabla olyan bovitest hasznal, amely nem letezik ebben a MySQL versioban."
+ ita "La tabella '%-.192s' usa un'estensione che non esiste in questa versione di MySQL"
+ kor "Å×À̺í '%-.192s'´Â È®Àå¸í·ÉÀ» ÀÌ¿ëÇÏÁö¸¸ ÇöÀçÀÇ MySQL ¹öÁ¯¿¡¼­´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ norwegian-ny "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ pol "Table '%-.192s' uses a extension that doesn't exist in this MySQL version"
+ por "Tabela '%-.192s' usa uma extensão que não existe nesta versão do MySQL"
+ rum "Tabela '%-.192s' foloseste o extensire inexistenta in versiunea curenta de MySQL"
+ rus "÷ ÔÁÂÌÉÃÅ '%-.192s' ÉÓÐÏÌØÚÕÀÔÓÑ ×ÏÚÍÏÖÎÏÓÔÉ, ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÍÙÅ × ÜÔÏÊ ×ÅÒÓÉÉ MySQL"
+ serbian "Tabela '%-.192s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a"
+ slo "Tabuµka '%-.192s' pou¾íva roz¹írenie, ktoré v tejto verzii MySQL nie je"
+ spa "Tabla '%-.192s' usa una extensión que no existe en esta MySQL versión"
+ swe "Tabell '%-.192s' har en extension som inte finns i denna version av MySQL"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' ×ÉËÏÒÉÓÔÏ×Õ¤ ÒÏÚÛÉÒÅÎÎÑ, ÝÏ ÎÅ ¦ÓÎÕ¤ Õ Ã¦Ê ×ÅÒÓ¦§ MySQL"
ER_TABLE_MUST_HAVE_COLUMNS 42000
cze "Tabulka mus-Bí mít alespoò jeden sloupec"
dan "En tabel skal have mindst een kolonne"
@@ -2715,27 +2715,27 @@ ER_TABLE_MUST_HAVE_COLUMNS 42000
swe "Tabeller måste ha minst 1 kolumn"
ukr "ôÁÂÌÉÃÑ ÐÏ×ÉÎÎÁ ÍÁÔÉ ÈÏÞÁ ÏÄÉÎ ÓÔÏ×ÂÅÃØ"
ER_RECORD_FILE_FULL
- cze "Tabulka '%-.64s' je pln-Bá"
- dan "Tabellen '%-.64s' er fuld"
- nla "De tabel '%-.64s' is vol"
- eng "The table '%-.64s' is full"
- jps "table '%-.64s' ‚Í‚¢‚Á‚Ï‚¢‚Å‚·",
- est "Tabel '%-.64s' on täis"
- fre "La table '%-.64s' est pleine"
- ger "Tabelle '%-.64s' ist voll"
- greek "Ï ðßíáêáò '%-.64s' åßíáé ãåìÜôïò"
- hun "A '%-.64s' tabla megtelt"
- ita "La tabella '%-.64s' e` piena"
- jpn "table '%-.64s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹"
- kor "Å×À̺í '%-.64s'°¡ full³µ½À´Ï´Ù. "
- por "Tabela '%-.64s' está cheia"
- rum "Tabela '%-.64s' e plina"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÐÅÒÅÐÏÌÎÅÎÁ"
- serbian "Tabela '%-.64s' je popunjena do kraja"
- slo "Tabuµka '%-.64s' je plná"
- spa "La tabla '%-.64s' está llena"
- swe "Tabellen '%-.64s' är full"
- ukr "ôÁÂÌÉÃÑ '%-.64s' ÚÁÐÏ×ÎÅÎÁ"
+ cze "Tabulka '%-.192s' je pln-Bá"
+ dan "Tabellen '%-.192s' er fuld"
+ nla "De tabel '%-.192s' is vol"
+ eng "The table '%-.192s' is full"
+ jps "table '%-.192s' ‚Í‚¢‚Á‚Ï‚¢‚Å‚·",
+ est "Tabel '%-.192s' on täis"
+ fre "La table '%-.192s' est pleine"
+ ger "Tabelle '%-.192s' ist voll"
+ greek "Ï ðßíáêáò '%-.192s' åßíáé ãåìÜôïò"
+ hun "A '%-.192s' tabla megtelt"
+ ita "La tabella '%-.192s' e` piena"
+ jpn "table '%-.192s' ¤Ï¤¤¤Ã¤Ñ¤¤¤Ç¤¹"
+ kor "Å×À̺í '%-.192s'°¡ full³µ½À´Ï´Ù. "
+ por "Tabela '%-.192s' está cheia"
+ rum "Tabela '%-.192s' e plina"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÐÅÒÅÐÏÌÎÅÎÁ"
+ serbian "Tabela '%-.192s' je popunjena do kraja"
+ slo "Tabuµka '%-.192s' je plná"
+ spa "La tabla '%-.192s' está llena"
+ swe "Tabellen '%-.192s' är full"
+ ukr "ôÁÂÌÉÃÑ '%-.192s' ÚÁÐÏ×ÎÅÎÁ"
ER_UNKNOWN_CHARACTER_SET 42000
cze "Nezn-Bámá znaková sada: '%-.64s'"
dan "Ukendt tegnsæt: '%-.64s'"
@@ -2803,27 +2803,27 @@ ER_TOO_MANY_FIELDS
swe "För många fält"
ukr "úÁÂÁÇÁÔÏ ÓÔÏ×Âæ×"
ER_TOO_BIG_ROWSIZE 42000
- cze "-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %d. Musíte zmìnit nìkteré polo¾ky na blob"
- dan "For store poster. Max post størrelse, uden BLOB's, er %d. Du må lave nogle felter til BLOB's"
- nla "Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %d. U dient sommige velden in blobs te veranderen."
+ cze "-BØádek je pøíli¹ velký. Maximální velikost øádku, nepoèítaje polo¾ky blob, je %ld. Musíte zmìnit nìkteré polo¾ky na blob"
+ dan "For store poster. Max post størrelse, uden BLOB's, er %ld. Du må lave nogle felter til BLOB's"
+ nla "Rij-grootte is groter dan toegestaan. Maximale rij grootte, blobs niet meegeteld, is %ld. U dient sommige velden in blobs te veranderen."
eng "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs"
- jps "row size ‚ª‘å‚«‚·‚¬‚Ü‚·. BLOB ‚ðŠÜ‚܂Ȃ¢ê‡‚Ì row size ‚ÌÅ‘å‚Í %d ‚Å‚·. ‚¢‚­‚‚©‚Ì field ‚ð BLOB ‚ɕς¦‚Ä‚­‚¾‚³‚¢.",
- est "Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %d. Muuda mõned väljad BLOB-tüüpi väljadeks"
- fre "Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %d. Changez le type de quelques colonnes en BLOB"
+ jps "row size ‚ª‘å‚«‚·‚¬‚Ü‚·. BLOB ‚ðŠÜ‚܂Ȃ¢ê‡‚Ì row size ‚ÌÅ‘å‚Í %ld ‚Å‚·. ‚¢‚­‚‚©‚Ì field ‚ð BLOB ‚ɕς¦‚Ä‚­‚¾‚³‚¢.",
+ est "Liiga pikk kirje. Kirje maksimumpikkus arvestamata BLOB-tüüpi välju on %ld. Muuda mõned väljad BLOB-tüüpi väljadeks"
+ fre "Ligne trop grande. Le taille maximale d'une ligne, sauf les BLOBs, est %ld. Changez le type de quelques colonnes en BLOB"
ger "Zeilenlänge zu groß. Die maximale Zeilenlänge für den verwendeten Tabellentyp (ohne BLOB-Felder) beträgt %ld. Einige Felder müssen in BLOB oder TEXT umgewandelt werden"
- greek "Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %d. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs"
- hun "Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %d. Nehany mezot meg kell valtoztatnia"
- ita "Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %d. Devi cambiare alcuni campi in BLOB"
- jpn "row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %d ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤."
- kor "³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %dÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä.."
- por "Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %d. Você tem que mudar alguns campos para BLOBs"
- rum "Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %d. Trebuie sa schimbati unele cimpuri in BLOB-uri"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÓÔÒÏËÉ, ÉÓËÌÀÞÁÑ ÐÏÌÑ BLOB, - %d. ÷ÏÚÍÏÖÎÏ, ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÍÅÎÉÔØ ÔÉÐ ÎÅËÏÔÏÒÙÈ ÐÏÌÅÊ ÎÁ BLOB"
- serbian "Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %d. Trebali bi da promenite tip nekih polja u BLOB"
- slo "Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %d. Musíte zmeni» niektoré polo¾ky na BLOB"
- spa "Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %d. Tu tienes que cambiar algunos campos para blob"
- swe "För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB"
- ukr "úÁÄÏ×ÇÁ ÓÔÒÏËÁ. îÁÊÂ¦ÌØÛÏÀ ÄÏ×ÖÉÎÏÀ ÓÔÒÏËÉ, ÎÅ ÒÁÈÕÀÞÉ BLOB, ¤ %d. ÷ÁÍ ÐÏÔÒ¦ÂÎÏ ÐÒÉ×ÅÓÔÉ ÄÅÑ˦ ÓÔÏ×Âæ ÄÏ ÔÉÐÕ BLOB"
+ greek "Ðïëý ìåãÜëï ìÝãåèïò åããñáöÞò. Ôï ìÝãéóôï ìÝãåèïò åããñáöÞò, ÷ùñßò íá õðïëïãßæïíôáé ôá blobs, åßíáé %ld. ÐñÝðåé íá ïñßóåôå êÜðïéá ðåäßá óáí blobs"
+ hun "Tul nagy sormeret. A maximalis sormeret (nem szamolva a blob objektumokat) %ld. Nehany mezot meg kell valtoztatnia"
+ ita "Riga troppo grande. La massima grandezza di una riga, non contando i BLOB, e` %ld. Devi cambiare alcuni campi in BLOB"
+ jpn "row size ¤¬Â礭¤¹¤®¤Þ¤¹. BLOB ¤ò´Þ¤Þ¤Ê¤¤¾ì¹ç¤Î row size ¤ÎºÇÂç¤Ï %ld ¤Ç¤¹. ¤¤¤¯¤Ä¤«¤Î field ¤ò BLOB ¤ËÊѤ¨¤Æ¤¯¤À¤µ¤¤."
+ kor "³Ê¹« Å« row »çÀÌÁîÀÔ´Ï´Ù. BLOB¸¦ °è»êÇÏÁö ¾Ê°í ÃÖ´ë row »çÀÌÁî´Â %ldÀÔ´Ï´Ù. ¾ó¸¶°£ÀÇ ÇʵåµéÀ» BLOB·Î ¹Ù²Ù¼Å¾ß °Ú±º¿ä.."
+ por "Tamanho de linha grande demais. O máximo tamanho de linha, não contando BLOBs, é %ld. Você tem que mudar alguns campos para BLOBs"
+ rum "Marimea liniei (row) prea mare. Marimea maxima a liniei, excluzind BLOB-urile este de %ld. Trebuie sa schimbati unele cimpuri in BLOB-uri"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ÒÁÚÍÅÒ ÚÁÐÉÓÉ. íÁËÓÉÍÁÌØÎÙÊ ÒÁÚÍÅÒ ÓÔÒÏËÉ, ÉÓËÌÀÞÁÑ ÐÏÌÑ BLOB, - %ld. ÷ÏÚÍÏÖÎÏ, ×ÁÍ ÓÌÅÄÕÅÔ ÉÚÍÅÎÉÔØ ÔÉÐ ÎÅËÏÔÏÒÙÈ ÐÏÌÅÊ ÎÁ BLOB"
+ serbian "Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %ld. Trebali bi da promenite tip nekih polja u BLOB"
+ slo "Riadok je príli¹ veµký. Maximálna veµkos» riadku, okrem 'BLOB', je %ld. Musíte zmeni» niektoré polo¾ky na BLOB"
+ spa "Tamaño de línea muy grande. Máximo tamaño de línea, no contando blob, es %ld. Tu tienes que cambiar algunos campos para blob"
+ swe "För stor total radlängd. Den högst tillåtna radlängden, förutom BLOBs, är %ld. Ändra några av dina fält till BLOB"
+ ukr "úÁÄÏ×ÇÁ ÓÔÒÏËÁ. îÁÊÂ¦ÌØÛÏÀ ÄÏ×ÖÉÎÏÀ ÓÔÒÏËÉ, ÎÅ ÒÁÈÕÀÞÉ BLOB, ¤ %ld. ÷ÁÍ ÐÏÔÒ¦ÂÎÏ ÐÒÉ×ÅÓÔÉ ÄÅÑ˦ ÓÔÏ×Âæ ÄÏ ÔÉÐÕ BLOB"
ER_STACK_OVERRUN
cze "P-Bøeteèení zásobníku threadu: pou¾ito %ld z %ld. Pou¾ijte 'mysqld -O thread_stack=#' k zadání vìt¹ího zásobníku"
dan "Thread stack brugt: Brugt: %ld af en %ld stak. Brug 'mysqld -O thread_stack=#' for at allokere en større stak om nødvendigt"
@@ -2865,52 +2865,52 @@ ER_WRONG_OUTER_JOIN 42000
swe "Felaktigt referens i OUTER JOIN. Kontrollera ON-uttrycket"
ukr "ðÅÒÅÈÒÅÓÎÁ ÚÁÌÅÖΦÓÔØ Õ OUTER JOIN. ðÅÒÅצÒÔÅ ÕÍÏ×Õ ON"
ER_NULL_COLUMN_IN_INDEX 42000
- eng "Table handler doesn't support NULL in given index. Please change column '%-.64s' to be NOT NULL or use another handler"
- swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.64s' till NOT NULL eller använd en annan hanterare"
+ eng "Table handler doesn't support NULL in given index. Please change column '%-.192s' to be NOT NULL or use another handler"
+ swe "Tabell hanteraren kan inte indexera NULL kolumner för den givna index typen. Ändra '%-.192s' till NOT NULL eller använd en annan hanterare"
ER_CANT_FIND_UDF
- cze "Nemohu na-Bèíst funkci '%-.64s'"
- dan "Kan ikke læse funktionen '%-.64s'"
- nla "Kan functie '%-.64s' niet laden"
- eng "Can't load function '%-.64s'"
- jps "function '%-.64s' ‚ð ƒ[ƒh‚Å‚«‚Ü‚¹‚ñ",
- est "Ei suuda avada funktsiooni '%-.64s'"
- fre "Imposible de charger la fonction '%-.64s'"
- ger "Kann Funktion '%-.64s' nicht laden"
- greek "Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.64s'"
- hun "A(z) '%-.64s' fuggveny nem toltheto be"
- ita "Impossibile caricare la funzione '%-.64s'"
- jpn "function '%-.64s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó"
- kor "'%-.64s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù."
- por "Não pode carregar a função '%-.64s'"
- rum "Nu pot incarca functia '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.64s'"
- serbian "Ne mogu da uèitam funkciju '%-.64s'"
- slo "Nemô¾em naèíta» funkciu '%-.64s'"
- spa "No puedo cargar función '%-.64s'"
- swe "Kan inte ladda funktionen '%-.64s'"
- ukr "îÅ ÍÏÖÕ ÚÁ×ÁÎÔÁÖÉÔÉ ÆÕÎËæÀ '%-.64s'"
+ cze "Nemohu na-Bèíst funkci '%-.192s'"
+ dan "Kan ikke læse funktionen '%-.192s'"
+ nla "Kan functie '%-.192s' niet laden"
+ eng "Can't load function '%-.192s'"
+ jps "function '%-.192s' ‚ð ƒ[ƒh‚Å‚«‚Ü‚¹‚ñ",
+ est "Ei suuda avada funktsiooni '%-.192s'"
+ fre "Imposible de charger la fonction '%-.192s'"
+ ger "Kann Funktion '%-.192s' nicht laden"
+ greek "Äåí åßíáé äõíáôÞ ç äéáäéêáóßá load ãéá ôç óõíÜñôçóç '%-.192s'"
+ hun "A(z) '%-.192s' fuggveny nem toltheto be"
+ ita "Impossibile caricare la funzione '%-.192s'"
+ jpn "function '%-.192s' ¤ò ¥í¡¼¥É¤Ç¤­¤Þ¤»¤ó"
+ kor "'%-.192s' ÇÔ¼ö¸¦ ·ÎµåÇÏÁö ¸øÇß½À´Ï´Ù."
+ por "Não pode carregar a função '%-.192s'"
+ rum "Nu pot incarca functia '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÇÒÕÚÉÔØ ÆÕÎËÃÉÀ '%-.192s'"
+ serbian "Ne mogu da uèitam funkciju '%-.192s'"
+ slo "Nemô¾em naèíta» funkciu '%-.192s'"
+ spa "No puedo cargar función '%-.192s'"
+ swe "Kan inte ladda funktionen '%-.192s'"
+ ukr "îÅ ÍÏÖÕ ÚÁ×ÁÎÔÁÖÉÔÉ ÆÕÎËæÀ '%-.192s'"
ER_CANT_INITIALIZE_UDF
- cze "Nemohu inicializovat funkci '%-.64s'; %-.80s"
- dan "Kan ikke starte funktionen '%-.64s'; %-.80s"
- nla "Kan functie '%-.64s' niet initialiseren; %-.80s"
- eng "Can't initialize function '%-.64s'; %-.80s"
- jps "function '%-.64s' ‚ð‰Šú‰»‚Å‚«‚Ü‚¹‚ñ; %-.80s",
- est "Ei suuda algväärtustada funktsiooni '%-.64s'; %-.80s"
- fre "Impossible d'initialiser la fonction '%-.64s'; %-.80s"
- ger "Kann Funktion '%-.64s' nicht initialisieren: %-.80s"
- greek "Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.64s'; %-.80s"
- hun "A(z) '%-.64s' fuggveny nem inicializalhato; %-.80s"
- ita "Impossibile inizializzare la funzione '%-.64s'; %-.80s"
- jpn "function '%-.64s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s"
- kor "'%-.64s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s"
- por "Não pode inicializar a função '%-.64s' - '%-.80s'"
- rum "Nu pot initializa functia '%-.64s'; %-.80s"
- rus "îÅ×ÏÚÍÏÖÎÏ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.64s'; %-.80s"
- serbian "Ne mogu da inicijalizujem funkciju '%-.64s'; %-.80s"
- slo "Nemô¾em inicializova» funkciu '%-.64s'; %-.80s"
- spa "No puedo inicializar función '%-.64s'; %-.80s"
- swe "Kan inte initialisera funktionen '%-.64s'; '%-.80s'"
- ukr "îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÆÕÎËæÀ '%-.64s'; %-.80s"
+ cze "Nemohu inicializovat funkci '%-.192s'; %-.80s"
+ dan "Kan ikke starte funktionen '%-.192s'; %-.80s"
+ nla "Kan functie '%-.192s' niet initialiseren; %-.80s"
+ eng "Can't initialize function '%-.192s'; %-.80s"
+ jps "function '%-.192s' ‚ð‰Šú‰»‚Å‚«‚Ü‚¹‚ñ; %-.80s",
+ est "Ei suuda algväärtustada funktsiooni '%-.192s'; %-.80s"
+ fre "Impossible d'initialiser la fonction '%-.192s'; %-.80s"
+ ger "Kann Funktion '%-.192s' nicht initialisieren: %-.80s"
+ greek "Äåí åßíáé äõíáôÞ ç Ýíáñîç ôçò óõíÜñôçóçò '%-.192s'; %-.80s"
+ hun "A(z) '%-.192s' fuggveny nem inicializalhato; %-.80s"
+ ita "Impossibile inizializzare la funzione '%-.192s'; %-.80s"
+ jpn "function '%-.192s' ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó; %-.80s"
+ kor "'%-.192s' ÇÔ¼ö¸¦ ÃʱâÈ­ ÇÏÁö ¸øÇß½À´Ï´Ù.; %-.80s"
+ por "Não pode inicializar a função '%-.192s' - '%-.80s'"
+ rum "Nu pot initializa functia '%-.192s'; %-.80s"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÉÎÉÃÉÁÌÉÚÉÒÏ×ÁÔØ ÆÕÎËÃÉÀ '%-.192s'; %-.80s"
+ serbian "Ne mogu da inicijalizujem funkciju '%-.192s'; %-.80s"
+ slo "Nemô¾em inicializova» funkciu '%-.192s'; %-.80s"
+ spa "No puedo inicializar función '%-.192s'; %-.80s"
+ swe "Kan inte initialisera funktionen '%-.192s'; '%-.80s'"
+ ukr "îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÆÕÎËæÀ '%-.192s'; %-.80s"
ER_UDF_NO_PATHS
cze "Pro sd-Bílenou knihovnu nejsou povoleny cesty"
dan "Angivelse af sti ikke tilladt for delt bibliotek"
@@ -2934,52 +2934,52 @@ ER_UDF_NO_PATHS
swe "Man får inte ange sökväg för dynamiska bibliotek"
ukr "îÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ ÐÕÔ¦ ÄÌÑ ÒÏÚĦÌÀ×ÁÎÉÈ Â¦Â̦ÏÔÅË"
ER_UDF_EXISTS
- cze "Funkce '%-.64s' ji-B¾ existuje"
- dan "Funktionen '%-.64s' findes allerede"
- nla "Functie '%-.64s' bestaat reeds"
- eng "Function '%-.64s' already exists"
- jps "Function '%-.64s' ‚ÍŠù‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·",
- est "Funktsioon '%-.64s' juba eksisteerib"
- fre "La fonction '%-.64s' existe déjà"
- ger "Funktion '%-.64s' existiert schon"
- greek "Ç óõíÜñôçóç '%-.64s' õðÜñ÷åé Þäç"
- hun "A '%-.64s' fuggveny mar letezik"
- ita "La funzione '%-.64s' esiste gia`"
- jpn "Function '%-.64s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹"
- kor "'%-.64s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
- por "Função '%-.64s' já existe"
- rum "Functia '%-.64s' exista deja"
- rus "æÕÎËÃÉÑ '%-.64s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Funkcija '%-.64s' veæ postoji"
- slo "Funkcia '%-.64s' u¾ existuje"
- spa "Función '%-.64s' ya existe"
- swe "Funktionen '%-.64s' finns redan"
- ukr "æÕÎËÃ¦Ñ '%-.64s' ×ÖÅ ¦ÓÎÕ¤"
+ cze "Funkce '%-.192s' ji-B¾ existuje"
+ dan "Funktionen '%-.192s' findes allerede"
+ nla "Functie '%-.192s' bestaat reeds"
+ eng "Function '%-.192s' already exists"
+ jps "Function '%-.192s' ‚ÍŠù‚É’è‹`‚³‚ê‚Ä‚¢‚Ü‚·",
+ est "Funktsioon '%-.192s' juba eksisteerib"
+ fre "La fonction '%-.192s' existe déjà"
+ ger "Funktion '%-.192s' existiert schon"
+ greek "Ç óõíÜñôçóç '%-.192s' õðÜñ÷åé Þäç"
+ hun "A '%-.192s' fuggveny mar letezik"
+ ita "La funzione '%-.192s' esiste gia`"
+ jpn "Function '%-.192s' ¤Ï´û¤ËÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤¹"
+ kor "'%-.192s' ÇÔ¼ö´Â ÀÌ¹Ì Á¸ÀçÇÕ´Ï´Ù."
+ por "Função '%-.192s' já existe"
+ rum "Functia '%-.192s' exista deja"
+ rus "æÕÎËÃÉÑ '%-.192s' ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Funkcija '%-.192s' veæ postoji"
+ slo "Funkcia '%-.192s' u¾ existuje"
+ spa "Función '%-.192s' ya existe"
+ swe "Funktionen '%-.192s' finns redan"
+ ukr "æÕÎËÃ¦Ñ '%-.192s' ×ÖÅ ¦ÓÎÕ¤"
ER_CANT_OPEN_LIBRARY
- cze "Nemohu otev-Bøít sdílenou knihovnu '%-.64s' (errno: %d %-.128s)"
- dan "Kan ikke åbne delt bibliotek '%-.64s' (errno: %d %-.128s)"
- nla "Kan shared library '%-.64s' niet openen (Errcode: %d %-.128s)"
- eng "Can't open shared library '%-.64s' (errno: %d %-.128s)"
- jps "shared library '%-.64s' ‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d %-.128s)",
- est "Ei suuda avada jagatud teeki '%-.64s' (veakood: %d %-.128s)"
- fre "Impossible d'ouvrir la bibliothèque partagée '%-.64s' (errno: %d %-.128s)"
- ger "Kann Shared Library '%-.64s' nicht öffnen (Fehler: %d %-.128s)"
- greek "Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.64s' (êùäéêüò ëÜèïõò: %d %-.128s)"
- hun "A(z) '%-.64s' megosztott konyvtar nem hasznalhato (hibakod: %d %-.128s)"
- ita "Impossibile aprire la libreria condivisa '%-.64s' (errno: %d %-.128s)"
- jpn "shared library '%-.64s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %-.128s)"
- kor "'%-.64s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %-.128s)"
- nor "Can't open shared library '%-.64s' (errno: %d %-.128s)"
- norwegian-ny "Can't open shared library '%-.64s' (errno: %d %-.128s)"
- pol "Can't open shared library '%-.64s' (errno: %d %-.128s)"
- por "Não pode abrir biblioteca compartilhada '%-.64s' (erro no. %d '%-.128s')"
- rum "Nu pot deschide libraria shared '%-.64s' (Eroare: %d %-.128s)"
- rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÄÉÎÁÍÉÞÅÓËÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.64s' (ÏÛÉÂËÁ: %d %-.128s)"
- serbian "Ne mogu da otvorim share-ovanu biblioteku '%-.64s' (errno: %d %-.128s)"
- slo "Nemô¾em otvori» zdieµanú kni¾nicu '%-.64s' (chybový kód: %d %-.128s)"
- spa "No puedo abrir libraria conjugada '%-.64s' (errno: %d %-.128s)"
- swe "Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %-.128s)"
- ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÒÏÚĦÌÀ×ÁÎÕ Â¦Â̦ÏÔÅËÕ '%-.64s' (ÐÏÍÉÌËÁ: %d %-.128s)"
+ cze "Nemohu otev-Bøít sdílenou knihovnu '%-.192s' (errno: %d %-.128s)"
+ dan "Kan ikke åbne delt bibliotek '%-.192s' (errno: %d %-.128s)"
+ nla "Kan shared library '%-.192s' niet openen (Errcode: %d %-.128s)"
+ eng "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ jps "shared library '%-.192s' ‚ðŠJ‚­Ž–‚ª‚Å‚«‚Ü‚¹‚ñ (errno: %d %-.128s)",
+ est "Ei suuda avada jagatud teeki '%-.192s' (veakood: %d %-.128s)"
+ fre "Impossible d'ouvrir la bibliothèque partagée '%-.192s' (errno: %d %-.128s)"
+ ger "Kann Shared Library '%-.192s' nicht öffnen (Fehler: %d %-.128s)"
+ greek "Äåí åßíáé äõíáôÞ ç áíÜãíùóç ôçò shared library '%-.192s' (êùäéêüò ëÜèïõò: %d %-.128s)"
+ hun "A(z) '%-.192s' megosztott konyvtar nem hasznalhato (hibakod: %d %-.128s)"
+ ita "Impossibile aprire la libreria condivisa '%-.192s' (errno: %d %-.128s)"
+ jpn "shared library '%-.192s' ¤ò³«¤¯»ö¤¬¤Ç¤­¤Þ¤»¤ó (errno: %d %-.128s)"
+ kor "'%-.192s' °øÀ¯ ¶óÀ̹ö·¯¸®¸¦ ¿­¼ö ¾ø½À´Ï´Ù.(¿¡·¯¹øÈ£: %d %-.128s)"
+ nor "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ norwegian-ny "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ pol "Can't open shared library '%-.192s' (errno: %d %-.128s)"
+ por "Não pode abrir biblioteca compartilhada '%-.192s' (erro no. %d '%-.128s')"
+ rum "Nu pot deschide libraria shared '%-.192s' (Eroare: %d %-.128s)"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÏÔËÒÙÔØ ÄÉÎÁÍÉÞÅÓËÕÀ ÂÉÂÌÉÏÔÅËÕ '%-.192s' (ÏÛÉÂËÁ: %d %-.128s)"
+ serbian "Ne mogu da otvorim share-ovanu biblioteku '%-.192s' (errno: %d %-.128s)"
+ slo "Nemô¾em otvori» zdieµanú kni¾nicu '%-.192s' (chybový kód: %d %-.128s)"
+ spa "No puedo abrir libraria conjugada '%-.192s' (errno: %d %-.128s)"
+ swe "Kan inte öppna det dynamiska biblioteket '%-.192s' (Felkod: %d %-.128s)"
+ ukr "îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÒÏÚĦÌÀ×ÁÎÕ Â¦Â̦ÏÔÅËÕ '%-.192s' (ÐÏÍÉÌËÁ: %d %-.128s)"
ER_CANT_FIND_DL_ENTRY
cze "Nemohu naj-Bít funkci '%-.128s' v knihovnì"
dan "Kan ikke finde funktionen '%-.128s' i bibliotek"
@@ -3003,37 +3003,37 @@ ER_CANT_FIND_DL_ENTRY
swe "Hittar inte funktionen '%-.128s' in det dynamiska biblioteket"
ukr "îÅ ÍÏÖÕ ÚÎÁÊÔÉ ÆÕÎËæÀ '%-.128s' Õ Â¦Â̦ÏÔÅæ"
ER_FUNCTION_NOT_DEFINED
- cze "Funkce '%-.64s' nen-Bí definována"
- dan "Funktionen '%-.64s' er ikke defineret"
- nla "Functie '%-.64s' is niet gedefinieerd"
- eng "Function '%-.64s' is not defined"
- jps "Function '%-.64s' ‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Funktsioon '%-.64s' ei ole defineeritud"
- fre "La fonction '%-.64s' n'est pas définie"
- ger "Funktion '%-.64s' ist nicht definiert"
- greek "Ç óõíÜñôçóç '%-.64s' äåí Ý÷åé ïñéóèåß"
- hun "A '%-.64s' fuggveny nem definialt"
- ita "La funzione '%-.64s' non e` definita"
- jpn "Function '%-.64s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.64s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
- por "Função '%-.64s' não está definida"
- rum "Functia '%-.64s' nu e definita"
- rus "æÕÎËÃÉÑ '%-.64s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ"
- serbian "Funkcija '%-.64s' nije definisana"
- slo "Funkcia '%-.64s' nie je definovaná"
- spa "Función '%-.64s' no está definida"
- swe "Funktionen '%-.64s' är inte definierad"
- ukr "æÕÎËæÀ '%-.64s' ÎÅ ×ÉÚÎÁÞÅÎÏ"
+ cze "Funkce '%-.192s' nen-Bí definována"
+ dan "Funktionen '%-.192s' er ikke defineret"
+ nla "Functie '%-.192s' is niet gedefinieerd"
+ eng "Function '%-.192s' is not defined"
+ jps "Function '%-.192s' ‚Í’è‹`‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Funktsioon '%-.192s' ei ole defineeritud"
+ fre "La fonction '%-.192s' n'est pas définie"
+ ger "Funktion '%-.192s' ist nicht definiert"
+ greek "Ç óõíÜñôçóç '%-.192s' äåí Ý÷åé ïñéóèåß"
+ hun "A '%-.192s' fuggveny nem definialt"
+ ita "La funzione '%-.192s' non e` definita"
+ jpn "Function '%-.192s' ¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.192s' ÇÔ¼ö°¡ Á¤ÀǵǾî ÀÖÁö ¾Ê½À´Ï´Ù."
+ por "Função '%-.192s' não está definida"
+ rum "Functia '%-.192s' nu e definita"
+ rus "æÕÎËÃÉÑ '%-.192s' ÎÅ ÏÐÒÅÄÅÌÅÎÁ"
+ serbian "Funkcija '%-.192s' nije definisana"
+ slo "Funkcia '%-.192s' nie je definovaná"
+ spa "Función '%-.192s' no está definida"
+ swe "Funktionen '%-.192s' är inte definierad"
+ ukr "æÕÎËæÀ '%-.192s' ÎÅ ×ÉÚÎÁÞÅÎÏ"
ER_HOST_IS_BLOCKED
cze "Stroj '%-.64s' je zablokov-Bán kvùli mnoha chybám pøi pøipojování. Odblokujete pou¾itím 'mysqladmin flush-hosts'"
- dan "Værten er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'"
+ dan "Værten '%-.64s' er blokeret på grund af mange fejlforespørgsler. Lås op med 'mysqladmin flush-hosts'"
nla "Host '%-.64s' is geblokkeeerd vanwege te veel verbindings fouten. Deblokkeer met 'mysqladmin flush-hosts'"
eng "Host '%-.64s' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"
jps "Host '%-.64s' ‚Í many connection error ‚Ì‚½‚ßA‹‘”Û‚³‚ê‚Ü‚µ‚½. 'mysqladmin flush-hosts' ‚ʼn𜂵‚Ä‚­‚¾‚³‚¢",
est "Masin '%-.64s' on blokeeritud hulgaliste ühendusvigade tõttu. Blokeeringu saab tühistada 'mysqladmin flush-hosts' käsuga"
- fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connection. Débloquer le par 'mysqladmin flush-hosts'"
+ fre "L'hôte '%-.64s' est bloqué à cause d'un trop grand nombre d'erreur de connexion. Débloquer le par 'mysqladmin flush-hosts'"
ger "Host '%-.64s' blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'"
- greek "Ï õðïëïãéóôÞò Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'"
+ greek "Ï õðïëïãéóôÞò '%-.64s' Ý÷åé áðïêëåéóèåß ëüãù ðïëëáðëþí ëáèþí óýíäåóçò. ÐñïóðáèÞóôå íá äéïñþóåôå ìå 'mysqladmin flush-hosts'"
hun "A '%-.64s' host blokkolodott, tul sok kapcsolodasi hiba miatt. Hasznalja a 'mysqladmin flush-hosts' parancsot"
ita "Sistema '%-.64s' bloccato a causa di troppi errori di connessione. Per sbloccarlo: 'mysqladmin flush-hosts'"
jpn "Host '%-.64s' ¤Ï many connection error ¤Î¤¿¤á¡¢µñÈݤµ¤ì¤Þ¤·¤¿. 'mysqladmin flush-hosts' ¤Ç²ò½ü¤·¤Æ¤¯¤À¤µ¤¤"
@@ -3054,7 +3054,7 @@ ER_HOST_NOT_PRIVILEGED
est "Masinal '%-.64s' puudub ligipääs sellele MySQL serverile"
fre "Le hôte '%-.64s' n'est pas authorisé à se connecter à ce serveur MySQL"
ger "Host '%-.64s' hat keine Berechtigung, sich mit diesem MySQL-Server zu verbinden"
- greek "Ï õðïëïãéóôÞò äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server"
+ greek "Ï õðïëïãéóôÞò '%-.64s' äåí Ý÷åé äéêáßùìá óýíäåóçò ìå ôïí MySQL server"
hun "A '%-.64s' host szamara nem engedelyezett a kapcsolodas ehhez a MySQL szerverhez"
ita "Al sistema '%-.64s' non e` consentita la connessione a questo server MySQL"
jpn "Host '%-.64s' ¤Ï MySQL server ¤ËÀܳ¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
@@ -3188,27 +3188,27 @@ ER_WRONG_VALUE_COUNT_ON_ROW 21S01
swe "Antalet kolumner motsvarar inte antalet värden på rad: %ld"
ukr "ë¦ÌØË¦ÓÔØ ÓÔÏ×ÂÃ¦× ÎÅ ÓЦ×ÐÁÄÁ¤ Ú Ë¦ÌØË¦ÓÔÀ ÚÎÁÞÅÎØ Õ ÓÔÒÏæ %ld"
ER_CANT_REOPEN_TABLE
- cze "Nemohu znovuotev-Bøít tabulku: '%-.64s"
- dan "Kan ikke genåbne tabel '%-.64s"
- nla "Kan tabel niet opnieuw openen: '%-.64s"
- eng "Can't reopen table: '%-.64s'"
- est "Ei suuda taasavada tabelit '%-.64s'"
- fre "Impossible de réouvrir la table: '%-.64s"
- ger "Kann Tabelle'%-.64s' nicht erneut öffnen"
- hun "Nem lehet ujra-megnyitni a tablat: '%-.64s"
- ita "Impossibile riaprire la tabella: '%-.64s'"
- kor "Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.64s"
- nor "Can't reopen table: '%-.64s"
- norwegian-ny "Can't reopen table: '%-.64s"
- pol "Can't reopen table: '%-.64s"
- por "Não pode reabrir a tabela '%-.64s"
- rum "Nu pot redeschide tabela: '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ '%-.64s'"
- serbian "Ne mogu da ponovo otvorim tabelu '%-.64s'"
- slo "Can't reopen table: '%-.64s"
- spa "No puedo reabrir tabla: '%-.64s"
- swe "Kunde inte stänga och öppna tabell '%-.64s"
- ukr "îÅ ÍÏÖÕ ÐÅÒÅצÄËÒÉÔÉ ÔÁÂÌÉÃÀ: '%-.64s'"
+ cze "Nemohu znovuotev-Bøít tabulku: '%-.192s"
+ dan "Kan ikke genåbne tabel '%-.192s"
+ nla "Kan tabel niet opnieuw openen: '%-.192s"
+ eng "Can't reopen table: '%-.192s'"
+ est "Ei suuda taasavada tabelit '%-.192s'"
+ fre "Impossible de réouvrir la table: '%-.192s"
+ ger "Kann Tabelle'%-.192s' nicht erneut öffnen"
+ hun "Nem lehet ujra-megnyitni a tablat: '%-.192s"
+ ita "Impossibile riaprire la tabella: '%-.192s'"
+ kor "Å×À̺íÀ» ´Ù½Ã ¿­¼ö ¾ø±º¿ä: '%-.192s"
+ nor "Can't reopen table: '%-.192s"
+ norwegian-ny "Can't reopen table: '%-.192s"
+ pol "Can't reopen table: '%-.192s"
+ por "Não pode reabrir a tabela '%-.192s"
+ rum "Nu pot redeschide tabela: '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÎÏ×Ï ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ '%-.192s'"
+ serbian "Ne mogu da ponovo otvorim tabelu '%-.192s'"
+ slo "Can't reopen table: '%-.192s"
+ spa "No puedo reabrir tabla: '%-.192s"
+ swe "Kunde inte stänga och öppna tabell '%-.192s"
+ ukr "îÅ ÍÏÖÕ ÐÅÒÅצÄËÒÉÔÉ ÔÁÂÌÉÃÀ: '%-.192s'"
ER_INVALID_USE_OF_NULL 22004
cze "Neplatn-Bé u¾ití hodnoty NULL"
dan "Forkert brug af nulværdi (NULL)"
@@ -3266,65 +3266,65 @@ ER_MIX_OF_GROUP_FUNC_AND_FIELDS 42000
swe "Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del"
ukr "úͦÛÕ×ÁÎÎÑ GROUP ÓÔÏ×ÂÃ¦× (MIN(),MAX(),COUNT()...) Ú ÎÅ GROUP ÓÔÏ×ÂÃÑÍÉ ¤ ÚÁÂÏÒÏÎÅÎÉÍ, ÑËÝÏ ÎÅ ÍÁ¤ GROUP BY"
ER_NONEXISTING_GRANT 42000
- cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'"
- dan "Denne tilladelse findes ikke for brugeren '%-.32s' på vært '%-.64s'"
- nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s'"
- eng "There is no such grant defined for user '%-.32s' on host '%-.64s'"
- jps "ƒ†[ƒU[ '%-.32s' (ƒzƒXƒg '%-.64s' ‚̃†[ƒU[) ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s'"
- fre "Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s'"
- ger "Für Benutzer '%-.32s' auf Host '%-.64s' gibt es keine solche Berechtigung"
- hun "A '%-.32s' felhasznalonak nincs ilyen joga a '%-.64s' host-on"
- ita "GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s'"
- jpn "¥æ¡¼¥¶¡¼ '%-.32s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "»ç¿ëÀÚ '%-.32s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù."
- por "Não existe tal permissão (grant) definida para o usuário '%-.32s' no 'host' '%-.64s'"
- rum "Nu exista un astfel de grant definit pentru utilzatorul '%-.32s' de pe host-ul '%-.64s'"
- rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ÈÏÓÔÅ '%-.64s'"
- serbian "Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'"
- spa "No existe permiso definido para usuario '%-.32s' en el servidor '%-.64s'"
- swe "Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'"
- ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s'"
+ cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.48s' na stroji '%-.64s'"
+ dan "Denne tilladelse findes ikke for brugeren '%-.48s' på vært '%-.64s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s'"
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s'"
+ jps "ƒ†[ƒU[ '%-.48s' (ƒzƒXƒg '%-.64s' ‚̃†[ƒU[) ‚Í‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s'"
+ ger "Für Benutzer '%-.48s' auf Host '%-.64s' gibt es keine solche Berechtigung"
+ hun "A '%-.48s' felhasznalonak nincs ilyen joga a '%-.64s' host-on"
+ ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s'"
+ jpn "¥æ¡¼¥¶¡¼ '%-.48s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "»ç¿ëÀÚ '%-.48s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù."
+ por "Não existe tal permissão (grant) definida para o usuário '%-.48s' no 'host' '%-.64s'"
+ rum "Nu exista un astfel de grant definit pentru utilzatorul '%-.48s' de pe host-ul '%-.64s'"
+ rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' ÎÁ ÈÏÓÔÅ '%-.64s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s'"
+ spa "No existe permiso definido para usuario '%-.48s' en el servidor '%-.64s'"
+ swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'"
+ ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.48s' Ú ÈÏÓÔÕ '%-.64s'"
ER_TABLEACCESS_DENIED_ERROR 42000
- cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro tabulku '%-.64s'"
- dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for tabellen '%-.64s'"
- nla "%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor tabel '%-.64s'"
- eng "%-.16s command denied to user '%-.32s'@'%-.64s' for table '%-.64s'"
- jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s' ,ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tabelis '%-.64s'"
- fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la table '%-.64s'"
- ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' auf Tabelle '%-.64s'"
- hun "%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban"
- ita "Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla tabella '%-.64s'"
- jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Å×À̺í '%-.64s'"
- por "Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na tabela '%-.64s'"
- rum "Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru tabela '%-.64s'"
- rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'"
- serbian "%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za tabelu '%-.64s'"
- spa "%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para tabla '%-.64s'"
- swe "%-.16s ej tillåtet för '%-.32s'@'%-.64s' för tabell '%-.64s'"
- ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.64s'"
+ cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.48s'@'%-.64s' pro tabulku '%-.192s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for tabellen '%-.192s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor tabel '%-.192s'"
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for table '%-.192s'"
+ jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.48s'@'%-.64s' ,ƒe[ƒuƒ‹ '%-.192s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tabelis '%-.192s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la table '%-.192s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' auf Tabelle '%-.192s'"
+ hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla tabella '%-.192s'"
+ jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.192s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.48s'@'%-.64s' for Å×À̺í '%-.192s'"
+ por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na tabela '%-.192s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru tabela '%-.192s'"
+ rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.48s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za tabelu '%-.192s'"
+ spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para tabla '%-.192s'"
+ swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för tabell '%-.192s'"
+ ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.48s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.192s'"
ER_COLUMNACCESS_DENIED_ERROR 42000
- cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'"
- dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'"
- nla "%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor kolom '%-.64s' in tabel '%-.64s'"
- eng "%-.16s command denied to user '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'"
- jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.32s'@'%-.64s'\n ƒJƒ‰ƒ€ '%-.64s' ƒe[ƒuƒ‹ '%-.64s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
- est "%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tulbale '%-.64s' tabelis '%-.64s'"
- fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la colonne '%-.64s' de la table '%-.64s'"
- ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.32s'@'%-.64s' und Feld '%-.64s' in Tabelle '%-.64s'"
- hun "%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban"
- ita "Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'"
- jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
- kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'"
- por "Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na coluna '%-.64s', na tabela '%-.64s'"
- rum "Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'"
- rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s' × ÔÁÂÌÉÃÅ '%-.64s'"
- serbian "%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'"
- spa "%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para columna '%-.64s' en la tabla '%-.64s'"
- swe "%-.16s ej tillåtet för '%-.32s'@'%-.64s' för kolumn '%-.64s' i tabell '%-.64s'"
- ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.64s' Õ ÔÁÂÌÉæ '%-.64s'"
+ cze "%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.48s'@'%-.64s' pro sloupec '%-.192s' v tabulce '%-.192s'"
+ dan "%-.16s-kommandoen er ikke tilladt for brugeren '%-.48s'@'%-.64s' for kolonne '%-.192s' in tabellen '%-.192s'"
+ nla "%-.16s commando geweigerd voor gebruiker: '%-.48s'@'%-.64s' voor kolom '%-.192s' in tabel '%-.192s'"
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for column '%-.192s' in table '%-.192s'"
+ jps "ƒRƒ}ƒ“ƒh %-.16s ‚Í ƒ†[ƒU[ '%-.48s'@'%-.64s'\n ƒJƒ‰ƒ€ '%-.192s' ƒe[ƒuƒ‹ '%-.192s' ‚ɑ΂µ‚Ä‹–‰Â‚³‚ê‚Ä‚¢‚Ü‚¹‚ñ",
+ est "%-.16s käsk ei ole lubatud kasutajale '%-.48s'@'%-.64s' tulbale '%-.192s' tabelis '%-.192s'"
+ fre "La commande '%-.16s' est interdite à l'utilisateur: '%-.48s'@'@%-.64s' sur la colonne '%-.192s' de la table '%-.192s'"
+ ger "%-.16s Befehl nicht erlaubt für Benutzer '%-.48s'@'%-.64s' und Feld '%-.192s' in Tabelle '%-.192s'"
+ hun "%-.16s parancs a '%-.48s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.192s' mezo eseten a '%-.192s' tablaban"
+ ita "Comando %-.16s negato per l'utente: '%-.48s'@'%-.64s' sulla colonna '%-.192s' della tabella '%-.192s'"
+ jpn "¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.48s'@'%-.64s'\n ¥«¥é¥à '%-.192s' ¥Æ¡¼¥Ö¥ë '%-.192s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+ kor "'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.48s'@'%-.64s' for Ä®·³ '%-.192s' in Å×À̺í '%-.192s'"
+ por "Comando '%-.16s' negado para o usuário '%-.48s'@'%-.64s' na coluna '%-.192s', na tabela '%-.192s'"
+ rum "Comanda %-.16s interzisa utilizatorului: '%-.48s'@'%-.64s' pentru coloana '%-.192s' in tabela '%-.192s'"
+ rus "ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.48s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.192s' × ÔÁÂÌÉÃÅ '%-.192s'"
+ serbian "%-.16s komanda zabranjena za korisnika '%-.48s'@'%-.64s' za kolonu '%-.192s' iz tabele '%-.192s'"
+ spa "%-.16s comando negado para usuario: '%-.48s'@'%-.64s' para columna '%-.192s' en la tabla '%-.192s'"
+ swe "%-.16s ej tillåtet för '%-.48s'@'%-.64s' för kolumn '%-.192s' i tabell '%-.192s'"
+ ukr "%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.48s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.192s' Õ ÔÁÂÌÉæ '%-.192s'"
ER_ILLEGAL_GRANT_FOR_TABLE 42000
cze "Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít."
dan "Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres."
@@ -3368,46 +3368,46 @@ ER_GRANT_WRONG_HOST_OR_USER 42000
swe "Felaktigt maskinnamn eller användarnamn använt med GRANT"
ukr "áÒÇÕÍÅÎÔ host ÁÂÏ user ÄÌÑ GRANT ÚÁÄÏ×ÇÉÊ"
ER_NO_SUCH_TABLE 42S02
- cze "Tabulka '%-.64s.%s' neexistuje"
- dan "Tabellen '%-.64s.%-.64s' eksisterer ikke"
- nla "Tabel '%-.64s.%s' bestaat niet"
- eng "Table '%-.64s.%-.64s' doesn't exist"
- est "Tabelit '%-.64s.%-.64s' ei eksisteeri"
- fre "La table '%-.64s.%s' n'existe pas"
- ger "Tabelle '%-.64s.%-.64s' existiert nicht"
- hun "A '%-.64s.%s' tabla nem letezik"
- ita "La tabella '%-.64s.%s' non esiste"
- jpn "Table '%-.64s.%s' doesn't exist"
- kor "Å×À̺í '%-.64s.%s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
- nor "Table '%-.64s.%s' doesn't exist"
- norwegian-ny "Table '%-.64s.%s' doesn't exist"
- pol "Table '%-.64s.%s' doesn't exist"
- por "Tabela '%-.64s.%-.64s' não existe"
- rum "Tabela '%-.64s.%-.64s' nu exista"
- rus "ôÁÂÌÉÃÁ '%-.64s.%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
- serbian "Tabela '%-.64s.%-.64s' ne postoji"
- slo "Table '%-.64s.%s' doesn't exist"
- spa "Tabla '%-.64s.%s' no existe"
- swe "Det finns ingen tabell som heter '%-.64s.%s'"
- ukr "ôÁÂÌÉÃÑ '%-.64s.%-.64s' ÎÅ ¦ÓÎÕ¤"
+ cze "Tabulka '%-.192s.%-.192s' neexistuje"
+ dan "Tabellen '%-.192s.%-.192s' eksisterer ikke"
+ nla "Tabel '%-.192s.%-.192s' bestaat niet"
+ eng "Table '%-.192s.%-.192s' doesn't exist"
+ est "Tabelit '%-.192s.%-.192s' ei eksisteeri"
+ fre "La table '%-.192s.%-.192s' n'existe pas"
+ ger "Tabelle '%-.192s.%-.192s' existiert nicht"
+ hun "A '%-.192s.%-.192s' tabla nem letezik"
+ ita "La tabella '%-.192s.%-.192s' non esiste"
+ jpn "Table '%-.192s.%-.192s' doesn't exist"
+ kor "Å×À̺í '%-.192s.%-.192s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù."
+ nor "Table '%-.192s.%-.192s' doesn't exist"
+ norwegian-ny "Table '%-.192s.%-.192s' doesn't exist"
+ pol "Table '%-.192s.%-.192s' doesn't exist"
+ por "Tabela '%-.192s.%-.192s' não existe"
+ rum "Tabela '%-.192s.%-.192s' nu exista"
+ rus "ôÁÂÌÉÃÁ '%-.192s.%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
+ serbian "Tabela '%-.192s.%-.192s' ne postoji"
+ slo "Table '%-.192s.%-.192s' doesn't exist"
+ spa "Tabla '%-.192s.%-.192s' no existe"
+ swe "Det finns ingen tabell som heter '%-.192s.%-.192s'"
+ ukr "ôÁÂÌÉÃÑ '%-.192s.%-.192s' ÎÅ ¦ÓÎÕ¤"
ER_NONEXISTING_TABLE_GRANT 42000
- cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s' pro tabulku '%-.64s'"
- dan "Denne tilladelse eksisterer ikke for brugeren '%-.32s' på vært '%-.64s' for tabellen '%-.64s'"
- nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s' op tabel '%-.64s'"
- eng "There is no such grant defined for user '%-.32s' on host '%-.64s' on table '%-.64s'"
- est "Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s' tabelile '%-.64s'"
- fre "Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s' sur la table '%-.64s'"
- ger "Eine solche Berechtigung ist für User '%-.32s' auf Host '%-.64s' an Tabelle '%-.64s' nicht definiert"
- hun "A '%-.32s' felhasznalo szamara a '%-.64s' host '%-.64s' tablajaban ez a parancs nem engedelyezett"
- ita "GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s' sulla tabella '%-.64s'"
- kor "»ç¿ëÀÚ '%-.32s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.64s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. "
- por "Não existe tal permissão (grant) definido para o usuário '%-.32s' no 'host' '%-.64s', na tabela '%-.64s'"
- rum "Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.32s' de pe host-ul '%-.64s' pentru tabela '%-.64s'"
- rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ËÏÍÐØÀÔÅÒÅ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'"
- serbian "Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s' tabeli '%-.64s'"
- spa "No existe tal permiso definido para usuario '%-.32s' en el servidor '%-.64s' en la tabla '%-.64s'"
- swe "Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'"
- ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s' ÄÌÑ ÔÁÂÌÉæ '%-.64s'"
+ cze "Neexistuje odpov-Bídající grant pro u¾ivatele '%-.48s' na stroji '%-.64s' pro tabulku '%-.192s'"
+ dan "Denne tilladelse eksisterer ikke for brugeren '%-.48s' på vært '%-.64s' for tabellen '%-.192s'"
+ nla "Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.48s' op host '%-.64s' op tabel '%-.192s'"
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on table '%-.192s'"
+ est "Sellist õigust ei ole defineeritud kasutajale '%-.48s' masinast '%-.64s' tabelile '%-.192s'"
+ fre "Un tel droit n'est pas défini pour l'utilisateur '%-.48s' sur l'hôte '%-.64s' sur la table '%-.192s'"
+ ger "Eine solche Berechtigung ist für User '%-.48s' auf Host '%-.64s' an Tabelle '%-.192s' nicht definiert"
+ hun "A '%-.48s' felhasznalo szamara a '%-.64s' host '%-.192s' tablajaban ez a parancs nem engedelyezett"
+ ita "GRANT non definita per l'utente '%-.48s' dalla macchina '%-.64s' sulla tabella '%-.192s'"
+ kor "»ç¿ëÀÚ '%-.48s'(È£½ºÆ® '%-.64s')´Â Å×À̺í '%-.192s'¸¦ »ç¿ëÇϱâ À§ÇÏ¿© Á¤ÀÇµÈ ½ÂÀÎÀº ¾ø½À´Ï´Ù. "
+ por "Não existe tal permissão (grant) definido para o usuário '%-.48s' no 'host' '%-.64s', na tabela '%-.192s'"
+ rum "Nu exista un astfel de privilegiu (grant) definit pentru utilizatorul '%-.48s' de pe host-ul '%-.64s' pentru tabela '%-.192s'"
+ rus "ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' ÎÁ ËÏÍÐØÀÔÅÒÅ '%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s'"
+ serbian "Ne postoji odobrenje za pristup korisniku '%-.48s' na host-u '%-.64s' tabeli '%-.192s'"
+ spa "No existe tal permiso definido para usuario '%-.48s' en el servidor '%-.64s' en la tabla '%-.192s'"
+ swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s' för tabell '%-.192s'"
+ ukr "ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.48s' Ú ÈÏÓÔÕ '%-.64s' ÄÌÑ ÔÁÂÌÉæ '%-.192s'"
ER_NOT_ALLOWED_COMMAND 42000
cze "Pou-B¾itý pøíkaz není v této verzi MySQL povolen"
dan "Den brugte kommando er ikke tilladt med denne udgave af MySQL"
@@ -3451,23 +3451,23 @@ ER_SYNTAX_ERROR 42000
swe "Du har något fel i din syntax"
ukr "õ ×ÁÓ ÐÏÍÉÌËÁ Õ ÓÉÎÔÁËÓÉÓ¦ SQL"
ER_DELAYED_CANT_CHANGE_LOCK
- cze "Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.64s"
- dan "Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.64s"
- nla "'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.64s"
- eng "Delayed insert thread couldn't get requested lock for table %-.64s"
- est "INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.64s"
- fre "La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.64s"
- ger "Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.64s' nicht erhalten"
- hun "A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.64s tablahoz"
- ita "Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.64s"
- kor "Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.64sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
- por "'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.64s'"
- rum "Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.64s"
- rus "ðÏÔÏË, ÏÂÓÌÕÖÉ×ÁÀÝÉÊ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert), ÎÅ ÓÍÏÇ ÐÏÌÕÞÉÔØ ÚÁÐÒÁÛÉ×ÁÅÍÕÀ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÔÁÂÌÉÃÕ %-.64s"
- serbian "Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.64s'"
- spa "Thread de inserción retarda no pudiendo bloquear para la tabla %-.64s"
- swe "DELAYED INSERT-tråden kunde inte låsa tabell '%-.64s'"
- ukr "ç¦ÌËÁ ÄÌÑ INSERT DELAYED ÎÅ ÍÏÖÅ ÏÔÒÉÍÁÔÉ ÂÌÏËÕ×ÁÎÎÑ ÄÌÑ ÔÁÂÌÉæ %-.64s"
+ cze "Zpo-B¾dìný insert threadu nebyl schopen získat po¾adovaný zámek pro tabulku %-.192s"
+ dan "Forsinket indsættelse tråden (delayed insert thread) kunne ikke opnå lås på tabellen %-.192s"
+ nla "'Delayed insert' thread kon de aangevraagde 'lock' niet krijgen voor tabel %-.192s"
+ eng "Delayed insert thread couldn't get requested lock for table %-.192s"
+ est "INSERT DELAYED lõim ei suutnud saada soovitud lukku tabelile %-.192s"
+ fre "La tâche 'delayed insert' n'a pas pu obtenir le verrou démandé sur la table %-.192s"
+ ger "Verzögerter (DELAYED) Einfüge-Thread konnte die angeforderte Sperre für Tabelle '%-.192s' nicht erhalten"
+ hun "A kesleltetett beillesztes (delayed insert) thread nem kapott zatolast a %-.192s tablahoz"
+ ita "Il thread di inserimento ritardato non riesce ad ottenere il lock per la tabella %-.192s"
+ kor "Áö¿¬µÈ insert ¾²·¹µå°¡ Å×À̺í %-.192sÀÇ ¿ä±¸µÈ ¶ôÅ·À» ó¸®ÇÒ ¼ö ¾ø¾ú½À´Ï´Ù."
+ por "'Thread' de inserção retardada (atrasada) pois não conseguiu obter a trava solicitada para tabela '%-.192s'"
+ rum "Thread-ul pentru inserarea aminata nu a putut obtine lacatul (lock) pentru tabela %-.192s"
+ rus "ðÏÔÏË, ÏÂÓÌÕÖÉ×ÁÀÝÉÊ ÏÔÌÏÖÅÎÎÕÀ ×ÓÔÁ×ËÕ (delayed insert), ÎÅ ÓÍÏÇ ÐÏÌÕÞÉÔØ ÚÁÐÒÁÛÉ×ÁÅÍÕÀ ÂÌÏËÉÒÏ×ËÕ ÎÁ ÔÁÂÌÉÃÕ %-.192s"
+ serbian "Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.192s'"
+ spa "Thread de inserción retarda no pudiendo bloquear para la tabla %-.192s"
+ swe "DELAYED INSERT-tråden kunde inte låsa tabell '%-.192s'"
+ ukr "ç¦ÌËÁ ÄÌÑ INSERT DELAYED ÎÅ ÍÏÖÅ ÏÔÒÉÍÁÔÉ ÂÌÏËÕ×ÁÎÎÑ ÄÌÑ ÔÁÂÌÉæ %-.192s"
ER_TOO_MANY_DELAYED_THREADS
cze "P-Bøíli¹ mnoho zpo¾dìných threadù"
dan "For mange slettede tråde (threads) i brug"
@@ -3487,28 +3487,28 @@ ER_TOO_MANY_DELAYED_THREADS
swe "Det finns redan 'max_delayed_threads' trådar i använding"
ukr "úÁÂÁÇÁÔÏ ÚÁÔÒÉÍÁÎÉÈ Ç¦ÌÏË ×ÉËÏÒÉÓÔÏ×Õ¤ÔØÓÑ"
ER_ABORTING_CONNECTION 08S01
- cze "Zru-B¹eno spojení %ld do databáze: '%-.64s' u¾ivatel: '%-.64s' (%s)"
- dan "Afbrudt forbindelse %ld til database: '%-.64s' bruger: '%-.64s' (%-.64s)"
- nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.64s' (%s)"
- eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' (%-.64s)"
- est "Ühendus katkestatud %ld andmebaasile: '%-.64s' kasutajale: '%-.32s' (%-.64s)"
- fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.64s' (%s)"
- ger "Abbruch der Verbindung %ld zur Datenbank '%-.64s'. Benutzer: '%-.64s' (%-.64s)"
- hun "Megszakitott kapcsolat %ld db: '%-.64s' adatbazishoz, felhasznalo: '%-.64s' (%s)"
- ita "Interrotta la connessione %ld al db: '%-.64s' utente: '%-.64s' (%s)"
- jpn "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
- kor "µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.64s' »ç¿ëÀÚ: '%-.64s' (%s)"
- nor "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
- norwegian-ny "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
- pol "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
- por "Conexão %ld abortou para o banco de dados '%-.64s' - usuário '%-.32s' (%-.64s)"
- rum "Conectie terminata %ld la baza de date: '%-.64s' utilizator: '%-.32s' (%-.64s)"
- rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' (%-.64s)"
- serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' (%-.64s)"
- slo "Aborted connection %ld to db: '%-.64s' user: '%-.64s' (%s)"
- spa "Conexión abortada %ld para db: '%-.64s' usuario: '%-.64s' (%s)"
- swe "Avbröt länken för tråd %ld till db '%-.64s', användare '%-.64s' (%s)"
- ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s' (%-.64s)"
+ cze "Zru-B¹eno spojení %ld do databáze: '%-.192s' u¾ivatel: '%-.48s' (%-.64s)"
+ dan "Afbrudt forbindelse %ld til database: '%-.192s' bruger: '%-.48s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' (%-.64s)"
+ eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ est "Ühendus katkestatud %ld andmebaasile: '%-.192s' kasutajale: '%-.48s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' (%-.64s)"
+ ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s' (%-.64s)"
+ hun "Megszakitott kapcsolat %ld db: '%-.192s' adatbazishoz, felhasznalo: '%-.48s' (%-.64s)"
+ ita "Interrotta la connessione %ld al db: '%-.192s' utente: '%-.48s' (%-.64s)"
+ jpn "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ kor "µ¥ÀÌŸº£À̽º Á¢¼ÓÀ» À§ÇÑ ¿¬°á %ld°¡ Áß´ÜµÊ : '%-.192s' »ç¿ëÀÚ: '%-.48s' (%-.64s)"
+ nor "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ norwegian-ny "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ pol "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ por "Conexão %ld abortou para o banco de dados '%-.192s' - usuário '%-.48s' (%-.64s)"
+ rum "Conectie terminata %ld la baza de date: '%-.192s' utilizator: '%-.48s' (%-.64s)"
+ rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' (%-.64s)"
+ slo "Aborted connection %ld to db: '%-.192s' user: '%-.48s' (%-.64s)"
+ spa "Conexión abortada %ld para db: '%-.192s' usuario: '%-.48s' (%-.64s)"
+ swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s' (%-.64s)"
+ ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞÁ: '%-.48s' (%-.64s)"
ER_NET_PACKET_TOO_LARGE 08S01
cze "Zji-B¹tìn pøíchozí packet del¹í ne¾ 'max_allowed_packet'"
dan "Modtog en datapakke som var større end 'max_allowed_packet'"
@@ -3533,7 +3533,7 @@ ER_NET_READ_ERROR_FROM_PIPE 08S01
nla "Kreeg leesfout van de verbindings pipe"
eng "Got a read error from the connection pipe"
est "Viga ühendustoru lugemisel"
- fre "Erreur de lecture reçue du pipe de connection"
+ fre "Erreur de lecture reçue du pipe de connexion"
ger "Lese-Fehler bei einer Verbindungs-Pipe"
hun "Olvasasi hiba a kapcsolat soran"
ita "Rilevato un errore di lettura dalla pipe di connessione"
@@ -3723,29 +3723,29 @@ ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 42000
swe "Den använda tabelltypen kan inte hantera AUTO_INCREMENT-kolumner"
ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ AUTO_INCREMENT ÓÔÏ×Âæ"
ER_DELAYED_INSERT_TABLE_LOCKED
- cze "INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.64s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES"
- dan "INSERT DELAYED kan ikke bruges med tabellen '%-.64s', fordi tabellen er låst med LOCK TABLES"
- nla "INSERT DELAYED kan niet worden gebruikt bij table '%-.64s', vanwege een 'lock met LOCK TABLES"
- eng "INSERT DELAYED can't be used with table '%-.64s' because it is locked with LOCK TABLES"
- est "INSERT DELAYED ei saa kasutada tabeli '%-.64s' peal, kuna see on lukustatud LOCK TABLES käsuga"
- fre "INSERT DELAYED ne peut être utilisé avec la table '%-.64s', car elle est verrouée avec LOCK TABLES"
- ger "INSERT DELAYED kann für Tabelle '%-.64s' nicht verwendet werden, da sie mit LOCK TABLES gesperrt ist"
- greek "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- hun "Az INSERT DELAYED nem hasznalhato a '%-.64s' tablahoz, mert a tabla zarolt (LOCK TABLES)"
- ita "L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.64s', perche` soggetta a lock da 'LOCK TABLES'"
- jpn "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- kor "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- nor "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- norwegian-ny "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- pol "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- por "INSERT DELAYED não pode ser usado com a tabela '%-.64s', porque ela está travada com LOCK TABLES"
- rum "INSERT DELAYED nu poate fi folosit cu tabela '%-.64s', deoarece este locked folosing LOCK TABLES"
- rus "îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ INSERT DELAYED ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s', ÐÏÔÏÍÕ ÞÔÏ ÏÎÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
- serbian "Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.64s', zbog toga što je zakljuèana komandom 'LOCK TABLES'"
- slo "INSERT DELAYED can't be used with table '%-.64s', because it is locked with LOCK TABLES"
- spa "INSERT DELAYED no puede ser usado con tablas '%-.64s', porque esta bloqueada con LOCK TABLES"
- swe "INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES"
- ukr "INSERT DELAYED ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÏ Ú ÔÁÂÌÉÃÅÀ '%-.64s', ÔÏÍÕ ÝÏ §§ ÚÁÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
+ cze "INSERT DELAYED nen-Bí mo¾no s tabulkou '%-.192s' pou¾ít, proto¾e je zamèená pomocí LOCK TABLES"
+ dan "INSERT DELAYED kan ikke bruges med tabellen '%-.192s', fordi tabellen er låst med LOCK TABLES"
+ nla "INSERT DELAYED kan niet worden gebruikt bij table '%-.192s', vanwege een 'lock met LOCK TABLES"
+ eng "INSERT DELAYED can't be used with table '%-.192s' because it is locked with LOCK TABLES"
+ est "INSERT DELAYED ei saa kasutada tabeli '%-.192s' peal, kuna see on lukustatud LOCK TABLES käsuga"
+ fre "INSERT DELAYED ne peut être utilisé avec la table '%-.192s', car elle est verrouée avec LOCK TABLES"
+ ger "INSERT DELAYED kann für Tabelle '%-.192s' nicht verwendet werden, da sie mit LOCK TABLES gesperrt ist"
+ greek "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ hun "Az INSERT DELAYED nem hasznalhato a '%-.192s' tablahoz, mert a tabla zarolt (LOCK TABLES)"
+ ita "L'inserimento ritardato (INSERT DELAYED) non puo` essere usato con la tabella '%-.192s', perche` soggetta a lock da 'LOCK TABLES'"
+ jpn "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ kor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ nor "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ norwegian-ny "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ pol "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ por "INSERT DELAYED não pode ser usado com a tabela '%-.192s', porque ela está travada com LOCK TABLES"
+ rum "INSERT DELAYED nu poate fi folosit cu tabela '%-.192s', deoarece este locked folosing LOCK TABLES"
+ rus "îÅÌØÚÑ ÉÓÐÏÌØÚÏ×ÁÔØ INSERT DELAYED ÄÌÑ ÔÁÂÌÉÃÙ '%-.192s', ÐÏÔÏÍÕ ÞÔÏ ÏÎÁ ÚÁÂÌÏËÉÒÏ×ÁÎÁ Ó ÐÏÍÏÝØÀ LOCK TABLES"
+ serbian "Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.192s', zbog toga što je zakljuèana komandom 'LOCK TABLES'"
+ slo "INSERT DELAYED can't be used with table '%-.192s', because it is locked with LOCK TABLES"
+ spa "INSERT DELAYED no puede ser usado con tablas '%-.192s', porque esta bloqueada con LOCK TABLES"
+ swe "INSERT DELAYED kan inte användas med tabell '%-.192s', emedan den är låst med LOCK TABLES"
+ ukr "INSERT DELAYED ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÏ Ú ÔÁÂÌÉÃÅÀ '%-.192s', ÔÏÍÕ ÝÏ §§ ÚÁÂÌÏËÏ×ÁÎÏ Ú LOCK TABLES"
ER_WRONG_COLUMN_NAME 42000
cze "Nespr-Bávné jméno sloupce '%-.100s'"
dan "Forkert kolonnenavn '%-.100s'"
@@ -3764,29 +3764,29 @@ ER_WRONG_COLUMN_NAME 42000
swe "Felaktigt kolumnnamn '%-.100s'"
ukr "îÅצÒÎÅ ¦Í'Ñ ÓÔÏ×ÂÃÑ '%-.100s'"
ER_WRONG_KEY_COLUMN 42000
- cze "Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.64s'"
- dan "Den brugte tabeltype kan ikke indeksere kolonnen '%-.64s'"
- nla "De gebruikte tabel 'handler' kan kolom '%-.64s' niet indexeren"
- eng "The used storage engine can't index column '%-.64s'"
- est "Tabelihandler ei oska indekseerida tulpa '%-.64s'"
- fre "Le handler de la table ne peut indexé la colonne '%-.64s'"
- ger "Die verwendete Speicher-Engine kann die Spalte '%-.64s' nicht indizieren"
- greek "The used table handler can't index column '%-.64s'"
- hun "A hasznalt tablakezelo nem tudja a '%-.64s' mezot indexelni"
- ita "Il gestore delle tabelle non puo` indicizzare la colonna '%-.64s'"
- jpn "The used table handler can't index column '%-.64s'"
- kor "The used table handler can't index column '%-.64s'"
- nor "The used table handler can't index column '%-.64s'"
- norwegian-ny "The used table handler can't index column '%-.64s'"
- pol "The used table handler can't index column '%-.64s'"
- por "O manipulador de tabela usado não pode indexar a coluna '%-.64s'"
- rum "Handler-ul tabelei folosite nu poate indexa coloana '%-.64s'"
- rus "éÓÐÏÌØÚÏ×ÁÎÎÙÊ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÍÏÖÅÔ ÐÒÏÉÎÄÅËÓÉÒÏ×ÁÔØ ÓÔÏÌÂÅà '%-.64s'"
- serbian "Handler tabele ne može da indeksira kolonu '%-.64s'"
- slo "The used table handler can't index column '%-.64s'"
- spa "El manipulador de tabla usado no puede indexar columna '%-.64s'"
- swe "Den använda tabelltypen kan inte indexera kolumn '%-.64s'"
- ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ÎÅ ÍÏÖÅ ¦ÎÄÅËÓÕ×ÁÔÉ ÓÔÏ×ÂÅÃØ '%-.64s'"
+ cze "Handler pou-B¾ité tabulky neumí indexovat sloupce '%-.192s'"
+ dan "Den brugte tabeltype kan ikke indeksere kolonnen '%-.192s'"
+ nla "De gebruikte tabel 'handler' kan kolom '%-.192s' niet indexeren"
+ eng "The used storage engine can't index column '%-.192s'"
+ est "Tabelihandler ei oska indekseerida tulpa '%-.192s'"
+ fre "Le handler de la table ne peut indexé la colonne '%-.192s'"
+ ger "Die verwendete Speicher-Engine kann die Spalte '%-.192s' nicht indizieren"
+ greek "The used table handler can't index column '%-.192s'"
+ hun "A hasznalt tablakezelo nem tudja a '%-.192s' mezot indexelni"
+ ita "Il gestore delle tabelle non puo` indicizzare la colonna '%-.192s'"
+ jpn "The used table handler can't index column '%-.192s'"
+ kor "The used table handler can't index column '%-.192s'"
+ nor "The used table handler can't index column '%-.192s'"
+ norwegian-ny "The used table handler can't index column '%-.192s'"
+ pol "The used table handler can't index column '%-.192s'"
+ por "O manipulador de tabela usado não pode indexar a coluna '%-.192s'"
+ rum "Handler-ul tabelei folosite nu poate indexa coloana '%-.192s'"
+ rus "éÓÐÏÌØÚÏ×ÁÎÎÙÊ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÍÏÖÅÔ ÐÒÏÉÎÄÅËÓÉÒÏ×ÁÔØ ÓÔÏÌÂÅà '%-.192s'"
+ serbian "Handler tabele ne može da indeksira kolonu '%-.192s'"
+ slo "The used table handler can't index column '%-.192s'"
+ spa "El manipulador de tabla usado no puede indexar columna '%-.192s'"
+ swe "Den använda tabelltypen kan inte indexera kolumn '%-.192s'"
+ ukr "÷ÉËÏÒÉÓÔÁÎÉÊ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ÎÅ ÍÏÖÅ ¦ÎÄÅËÓÕ×ÁÔÉ ÓÔÏ×ÂÅÃØ '%-.192s'"
ER_WRONG_MRG_TABLE
cze "V-B¹echny tabulky v MERGE tabulce nejsou definovány stejnì"
dan "Tabellerne i MERGE er ikke defineret ens"
@@ -3811,46 +3811,46 @@ ER_WRONG_MRG_TABLE
swe "Tabellerna i MERGE-tabellen är inte identiskt definierade"
ukr "ôÁÂÌÉæ Õ MERGE TABLE ÍÁÀÔØ Ò¦ÚÎÕ ÓÔÒÕËÔÕÒÕ"
ER_DUP_UNIQUE 23000
- cze "Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.64s'"
- dan "Kan ikke skrive til tabellen '%-.64s' fordi det vil bryde CONSTRAINT regler"
- nla "Kan niet opslaan naar table '%-.64s' vanwege 'unique' beperking"
- eng "Can't write, because of unique constraint, to table '%-.64s'"
- est "Ei suuda kirjutada tabelisse '%-.64s', kuna see rikub ühesuse kitsendust"
- fre "Écriture impossible à cause d'un index UNIQUE sur la table '%-.64s'"
- ger "Schreiben in Tabelle '%-.64s' nicht möglich wegen einer Eindeutigkeitsbeschränkung (unique constraint)"
- hun "A '%-.64s' nem irhato, az egyedi mezok miatt"
- ita "Impossibile scrivere nella tabella '%-.64s' per limitazione di unicita`"
- por "Não pode gravar, devido à restrição UNIQUE, na tabela '%-.64s'"
- rum "Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.64s'"
- rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÐÉÓÁÔØ × ÔÁÂÌÉÃÕ '%-.64s' ÉÚ-ÚÁ ÏÇÒÁÎÉÞÅÎÉÊ ÕÎÉËÁÌØÎÏÇÏ ËÌÀÞÁ"
- serbian "Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.64s'"
- spa "No puedo escribir, debido al único constraint, para tabla '%-.64s'"
- swe "Kan inte skriva till tabell '%-.64s'; UNIQUE-test"
- ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÄÏ ÔÁÂÌÉæ '%-.64s', Ú ÐÒÉÞÉÎÉ ×ÉÍÏÇ ÕΦËÁÌØÎÏÓÔ¦"
+ cze "Kv-Bùli unique constraintu nemozu zapsat do tabulky '%-.192s'"
+ dan "Kan ikke skrive til tabellen '%-.192s' fordi det vil bryde CONSTRAINT regler"
+ nla "Kan niet opslaan naar table '%-.192s' vanwege 'unique' beperking"
+ eng "Can't write, because of unique constraint, to table '%-.192s'"
+ est "Ei suuda kirjutada tabelisse '%-.192s', kuna see rikub ühesuse kitsendust"
+ fre "Écriture impossible à cause d'un index UNIQUE sur la table '%-.192s'"
+ ger "Schreiben in Tabelle '%-.192s' nicht möglich wegen einer Eindeutigkeitsbeschränkung (unique constraint)"
+ hun "A '%-.192s' nem irhato, az egyedi mezok miatt"
+ ita "Impossibile scrivere nella tabella '%-.192s' per limitazione di unicita`"
+ por "Não pode gravar, devido à restrição UNIQUE, na tabela '%-.192s'"
+ rum "Nu pot scrie pe hard-drive, din cauza constraintului unic (unique constraint) pentru tabela '%-.192s'"
+ rus "îÅ×ÏÚÍÏÖÎÏ ÚÁÐÉÓÁÔØ × ÔÁÂÌÉÃÕ '%-.192s' ÉÚ-ÚÁ ÏÇÒÁÎÉÞÅÎÉÊ ÕÎÉËÁÌØÎÏÇÏ ËÌÀÞÁ"
+ serbian "Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.192s'"
+ spa "No puedo escribir, debido al único constraint, para tabla '%-.192s'"
+ swe "Kan inte skriva till tabell '%-.192s'; UNIQUE-test"
+ ukr "îÅ ÍÏÖÕ ÚÁÐÉÓÁÔÉ ÄÏ ÔÁÂÌÉæ '%-.192s', Ú ÐÒÉÞÉÎÉ ×ÉÍÏÇ ÕΦËÁÌØÎÏÓÔ¦"
ER_BLOB_KEY_WITHOUT_LENGTH 42000
- cze "BLOB sloupec '%-.64s' je pou-B¾it ve specifikaci klíèe bez délky"
- dan "BLOB kolonnen '%-.64s' brugt i nøglespecifikation uden nøglelængde"
- nla "BLOB kolom '%-.64s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte"
- eng "BLOB/TEXT column '%-.64s' used in key specification without a key length"
- est "BLOB-tüüpi tulp '%-.64s' on kasutusel võtmes ilma pikkust määratlemata"
- fre "La colonne '%-.64s' de type BLOB est utilisée dans une définition d'index sans longueur d'index"
- ger "BLOB- oder TEXT-Spalte '%-.64s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet"
- greek "BLOB column '%-.64s' used in key specification without a key length"
- hun "BLOB mezo '%-.64s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul"
- ita "La colonna '%-.64s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza"
- jpn "BLOB column '%-.64s' used in key specification without a key length"
- kor "BLOB column '%-.64s' used in key specification without a key length"
- nor "BLOB column '%-.64s' used in key specification without a key length"
- norwegian-ny "BLOB column '%-.64s' used in key specification without a key length"
- pol "BLOB column '%-.64s' used in key specification without a key length"
- por "Coluna BLOB '%-.64s' usada na especificação de chave sem o comprimento da chave"
- rum "Coloana BLOB '%-.64s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita"
- rus "óÔÏÌÂÅÃ ÔÉÐÁ BLOB '%-.64s' ÂÙÌ ÕËÁÚÁÎ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ ÂÅÚ ÕËÁÚÁÎÉÑ ÄÌÉÎÙ ËÌÀÞÁ"
- serbian "BLOB kolona '%-.64s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa"
- slo "BLOB column '%-.64s' used in key specification without a key length"
- spa "Columna BLOB column '%-.64s' usada en especificación de clave sin tamaño de la clave"
- swe "Du har inte angett någon nyckellängd för BLOB '%-.64s'"
- ukr "óÔÏ×ÂÅÃØ BLOB '%-.64s' ×ÉËÏÒÉÓÔÁÎÏ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ ÂÅÚ ×ËÁÚÁÎÎÑ ÄÏ×ÖÉÎÉ ËÌÀÞÁ"
+ cze "BLOB sloupec '%-.192s' je pou-B¾it ve specifikaci klíèe bez délky"
+ dan "BLOB kolonnen '%-.192s' brugt i nøglespecifikation uden nøglelængde"
+ nla "BLOB kolom '%-.192s' gebruikt in zoeksleutel specificatie zonder zoeksleutel lengte"
+ eng "BLOB/TEXT column '%-.192s' used in key specification without a key length"
+ est "BLOB-tüüpi tulp '%-.192s' on kasutusel võtmes ilma pikkust määratlemata"
+ fre "La colonne '%-.192s' de type BLOB est utilisée dans une définition d'index sans longueur d'index"
+ ger "BLOB- oder TEXT-Spalte '%-.192s' wird in der Schlüsseldefinition ohne Schlüssellängenangabe verwendet"
+ greek "BLOB column '%-.192s' used in key specification without a key length"
+ hun "BLOB mezo '%-.192s' hasznalt a mezo specifikacioban, a mezohossz megadasa nelkul"
+ ita "La colonna '%-.192s' di tipo BLOB e` usata in una chiave senza specificarne la lunghezza"
+ jpn "BLOB column '%-.192s' used in key specification without a key length"
+ kor "BLOB column '%-.192s' used in key specification without a key length"
+ nor "BLOB column '%-.192s' used in key specification without a key length"
+ norwegian-ny "BLOB column '%-.192s' used in key specification without a key length"
+ pol "BLOB column '%-.192s' used in key specification without a key length"
+ por "Coluna BLOB '%-.192s' usada na especificação de chave sem o comprimento da chave"
+ rum "Coloana BLOB '%-.192s' este folosita in specificarea unei chei fara ca o lungime de cheie sa fie folosita"
+ rus "óÔÏÌÂÅÃ ÔÉÐÁ BLOB '%-.192s' ÂÙÌ ÕËÁÚÁÎ × ÏÐÒÅÄÅÌÅÎÉÉ ËÌÀÞÁ ÂÅÚ ÕËÁÚÁÎÉÑ ÄÌÉÎÙ ËÌÀÞÁ"
+ serbian "BLOB kolona '%-.192s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa"
+ slo "BLOB column '%-.192s' used in key specification without a key length"
+ spa "Columna BLOB column '%-.192s' usada en especificación de clave sin tamaño de la clave"
+ swe "Du har inte angett någon nyckellängd för BLOB '%-.192s'"
+ ukr "óÔÏ×ÂÅÃØ BLOB '%-.192s' ×ÉËÏÒÉÓÔÁÎÏ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ ÂÅÚ ×ËÁÚÁÎÎÑ ÄÏ×ÖÉÎÉ ËÌÀÞÁ"
ER_PRIMARY_CANT_HAVE_NULL 42000
cze "V-B¹echny èásti primárního klíèe musejí být NOT NULL; pokud potøebujete NULL, pou¾ijte UNIQUE"
dan "Alle dele af en PRIMARY KEY skal være NOT NULL; Hvis du skal bruge NULL i nøglen, brug UNIQUE istedet"
@@ -3936,21 +3936,21 @@ ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE
swe "Du använder 'säker uppdateringsmod' och försökte uppdatera en tabell utan en WHERE-sats som använder sig av en nyckel"
ukr "÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ"
ER_KEY_DOES_NOT_EXITS 42000 S1009
- cze "Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje"
- dan "Nøglen '%-.64s' eksisterer ikke i tabellen '%-.64s'"
- nla "Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'"
- eng "Key '%-.64s' doesn't exist in table '%-.64s'"
- est "Võti '%-.64s' ei eksisteeri tabelis '%-.64s'"
- fre "L'index '%-.64s' n'existe pas sur la table '%-.64s'"
- ger "Schlüssel '%-.64s' existiert in der Tabelle '%-.64s' nicht"
- hun "A '%-.64s' kulcs nem letezik a '%-.64s' tablaban"
- ita "La chiave '%-.64s' non esiste nella tabella '%-.64s'"
- por "Chave '%-.64s' não existe na tabela '%-.64s'"
- rus "ëÌÀÞ '%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÁÂÌÉÃÅ '%-.64s'"
- serbian "Kljuè '%-.64s' ne postoji u tabeli '%-.64s'"
- spa "Clave '%-.64s' no existe en la tabla '%-.64s'"
- swe "Nyckel '%-.64s' finns inte in tabell '%-.64s'"
- ukr "ëÌÀÞ '%-.64s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.64s'"
+ cze "Kl-Bíè '%-.192s' v tabulce '%-.192s' neexistuje"
+ dan "Nøglen '%-.192s' eksisterer ikke i tabellen '%-.192s'"
+ nla "Zoeksleutel '%-.192s' bestaat niet in tabel '%-.192s'"
+ eng "Key '%-.192s' doesn't exist in table '%-.192s'"
+ est "Võti '%-.192s' ei eksisteeri tabelis '%-.192s'"
+ fre "L'index '%-.192s' n'existe pas sur la table '%-.192s'"
+ ger "Schlüssel '%-.192s' existiert in der Tabelle '%-.192s' nicht"
+ hun "A '%-.192s' kulcs nem letezik a '%-.192s' tablaban"
+ ita "La chiave '%-.192s' non esiste nella tabella '%-.192s'"
+ por "Chave '%-.192s' não existe na tabela '%-.192s'"
+ rus "ëÌÀÞ '%-.192s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÁÂÌÉÃÅ '%-.192s'"
+ serbian "Kljuè '%-.192s' ne postoji u tabeli '%-.192s'"
+ spa "Clave '%-.192s' no existe en la tabla '%-.192s'"
+ swe "Nyckel '%-.192s' finns inte in tabell '%-.192s'"
+ ukr "ëÌÀÞ '%-.192s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.192s'"
ER_CHECK_NO_SUCH_TABLE 42000
cze "Nemohu otev-Bøít tabulku"
dan "Kan ikke åbne tabellen"
@@ -3986,7 +3986,7 @@ ER_CHECK_NOT_IMPLEMENTED 42000
por "O manipulador de tabela não suporta %s"
rum "The handler for the table doesn't support %s"
rus "ïÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÜÔÏÇÏ: %s"
- serbian "Handler za ovu tabelu ne dozvoljava 'check' odnosno 'repair' komande"
+ serbian "Handler za ovu tabelu ne dozvoljava %s komande"
slo "The handler for the table doesn't support %s"
spa "El manipulador de la tabla no permite soporte para %s"
swe "Tabellhanteraren för denna tabell kan inte göra %s"
@@ -4072,20 +4072,20 @@ ER_ERROR_DURING_CHECKPOINT
swe "Fick fel %d vid CHECKPOINT"
ukr "ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ CHECKPOINT"
ER_NEW_ABORTING_CONNECTION 08S01
- cze "Spojen-Bí %ld do databáze: '%-.64s' u¾ivatel: '%-.32s' stroj: '%-.64s' (%-.64s) bylo pøeru¹eno"
- dan "Afbrød forbindelsen %ld til databasen '%-.64s' bruger: '%-.32s' vært: '%-.64s' (%-.64s)"
- nla "Afgebroken verbinding %ld naar db: '%-.64s' gebruiker: '%-.32s' host: '%-.64s' (%-.64s)"
- eng "Aborted connection %ld to db: '%-.64s' user: '%-.32s' host: '%-.64s' (%-.64s)"
- est "Ühendus katkestatud %ld andmebaas: '%-.64s' kasutaja: '%-.32s' masin: '%-.64s' (%-.64s)"
- fre "Connection %ld avortée vers la bd: '%-.64s' utilisateur: '%-.32s' hôte: '%-.64s' (%-.64s)"
- ger "Abbruch der Verbindung %ld zur Datenbank '%-.64s'. Benutzer: '%-.32s', Host: '%-.64s' (%-.64s)"
- ita "Interrotta la connessione %ld al db: ''%-.64s' utente: '%-.32s' host: '%-.64s' (%-.64s)"
- por "Conexão %ld abortada para banco de dados '%-.64s' - usuário '%-.32s' - 'host' '%-.64s' ('%-.64s')"
- rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' Ó ÈÏÓÔÁ '%-.64s' (%-.64s)"
- serbian "Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: '%-.64s' (%-.64s)"
- spa "Abortada conexión %ld para db: '%-.64s' usuario: '%-.32s' servidor: '%-.64s' (%-.64s)"
- swe "Avbröt länken för tråd %ld till db '%-.64s', användare '%-.32s', host '%-.64s' (%-.64s)"
- ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.64s' ËÏÒÉÓÔÕ×ÁÞ: '%-.32s' ÈÏÓÔ: '%-.64s' (%-.64s)"
+ cze "Spojen-Bí %ld do databáze: '%-.192s' u¾ivatel: '%-.48s' stroj: '%-.64s' (%-.64s) bylo pøeru¹eno"
+ dan "Afbrød forbindelsen %ld til databasen '%-.192s' bruger: '%-.48s' vært: '%-.64s' (%-.64s)"
+ nla "Afgebroken verbinding %ld naar db: '%-.192s' gebruiker: '%-.48s' host: '%-.64s' (%-.64s)"
+ eng "Aborted connection %ld to db: '%-.192s' user: '%-.48s' host: '%-.64s' (%-.64s)"
+ est "Ühendus katkestatud %ld andmebaas: '%-.192s' kasutaja: '%-.48s' masin: '%-.64s' (%-.64s)"
+ fre "Connection %ld avortée vers la bd: '%-.192s' utilisateur: '%-.48s' hôte: '%-.64s' (%-.64s)"
+ ger "Abbruch der Verbindung %ld zur Datenbank '%-.192s'. Benutzer: '%-.48s', Host: '%-.64s' (%-.64s)"
+ ita "Interrotta la connessione %ld al db: ''%-.192s' utente: '%-.48s' host: '%-.64s' (%-.64s)"
+ por "Conexão %ld abortada para banco de dados '%-.192s' - usuário '%-.48s' - 'host' '%-.64s' ('%-.64s')"
+ rus "ðÒÅÒ×ÁÎÏ ÓÏÅÄÉÎÅÎÉÅ %ld Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.192s' ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.48s' Ó ÈÏÓÔÁ '%-.64s' (%-.64s)"
+ serbian "Prekinuta konekcija broj %ld ka bazi: '%-.192s' korisnik je bio: '%-.48s' a host: '%-.64s' (%-.64s)"
+ spa "Abortada conexión %ld para db: '%-.192s' usuario: '%-.48s' servidor: '%-.64s' (%-.64s)"
+ swe "Avbröt länken för tråd %ld till db '%-.192s', användare '%-.48s', host '%-.64s' (%-.64s)"
+ ukr "ðÅÒÅÒ×ÁÎÏ Ú'¤ÄÎÁÎÎÑ %ld ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ: '%-.192s' ËÏÒÉÓÔÕ×ÁÞ: '%-.48s' ÈÏÓÔ: '%-.64s' (%-.64s)"
ER_DUMP_NOT_IMPLEMENTED
cze "Handler tabulky nepodporuje bin-Bární dump"
dan "Denne tabeltype unserstøtter ikke binært tabeldump"
@@ -4110,20 +4110,20 @@ ER_FLUSH_MASTER_BINLOG_CLOSED
serbian "Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'"
ukr "òÅÐ̦ËÁæÊÎÉÊ ÌÏÇ ÚÁËÒÉÔÏ, ÎÅ ÍÏÖÕ ×ÉËÏÎÁÔÉ RESET MASTER"
ER_INDEX_REBUILD
- cze "P-Bøebudování indexu dumpnuté tabulky '%-.64s' nebylo úspì¹né"
- dan "Kunne ikke genopbygge indekset for den dumpede tabel '%-.64s'"
- nla "Gefaald tijdens heropbouw index van gedumpte tabel '%-.64s'"
- eng "Failed rebuilding the index of dumped table '%-.64s'"
- fre "La reconstruction de l'index de la table copiée '%-.64s' a échoué"
- ger "Neuerstellung des Index der Dump-Tabelle '%-.64s' fehlgeschlagen"
- greek "Failed rebuilding the index of dumped table '%-.64s'"
- hun "Failed rebuilding the index of dumped table '%-.64s'"
- ita "Fallita la ricostruzione dell'indice della tabella copiata '%-.64s'"
- por "Falhou na reconstrução do índice da tabela 'dumped' '%-.64s'"
- rus "ïÛÉÂËÁ ÐÅÒÅÓÔÒÏÊËÉ ÉÎÄÅËÓÁ ÓÏÈÒÁÎÅÎÎÏÊ ÔÁÂÌÉÃÙ '%-.64s'"
- serbian "Izgradnja indeksa dump-ovane tabele '%-.64s' nije uspela"
- spa "Falla reconstruyendo el indice de la tabla dumped '%-.64s'"
- ukr "îÅ×ÄÁÌŠצÄÎÏ×ÌÅÎÎÑ ¦ÎÄÅËÓÁ ÐÅÒÅÄÁÎϧ ÔÁÂÌÉæ '%-.64s'"
+ cze "P-Bøebudování indexu dumpnuté tabulky '%-.192s' nebylo úspì¹né"
+ dan "Kunne ikke genopbygge indekset for den dumpede tabel '%-.192s'"
+ nla "Gefaald tijdens heropbouw index van gedumpte tabel '%-.192s'"
+ eng "Failed rebuilding the index of dumped table '%-.192s'"
+ fre "La reconstruction de l'index de la table copiée '%-.192s' a échoué"
+ ger "Neuerstellung des Index der Dump-Tabelle '%-.192s' fehlgeschlagen"
+ greek "Failed rebuilding the index of dumped table '%-.192s'"
+ hun "Failed rebuilding the index of dumped table '%-.192s'"
+ ita "Fallita la ricostruzione dell'indice della tabella copiata '%-.192s'"
+ por "Falhou na reconstrução do índice da tabela 'dumped' '%-.192s'"
+ rus "ïÛÉÂËÁ ÐÅÒÅÓÔÒÏÊËÉ ÉÎÄÅËÓÁ ÓÏÈÒÁÎÅÎÎÏÊ ÔÁÂÌÉÃÙ '%-.192s'"
+ serbian "Izgradnja indeksa dump-ovane tabele '%-.192s' nije uspela"
+ spa "Falla reconstruyendo el indice de la tabla dumped '%-.192s'"
+ ukr "îÅ×ÄÁÌŠצÄÎÏ×ÌÅÎÎÑ ¦ÎÄÅËÓÁ ÐÅÒÅÄÁÎϧ ÔÁÂÌÉæ '%-.192s'"
ER_MASTER
cze "Chyba masteru: '%-.64s'"
dan "Fejl fra master: '%-.64s'"
@@ -4212,35 +4212,35 @@ ER_UNKNOWN_SYSTEM_VARIABLE
swe "Okänd systemvariabel: '%-.64s'"
ukr "îÅצÄÏÍÁ ÓÉÓÔÅÍÎÁ ÚͦÎÎÁ '%-.64s'"
ER_CRASHED_ON_USAGE
- cze "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena"
- dan "Tabellen '%-.64s' er markeret med fejl og bør repareres"
- nla "Tabel '%-.64s' staat als gecrashed gemarkeerd en dient te worden gerepareerd"
- eng "Table '%-.64s' is marked as crashed and should be repaired"
- est "Tabel '%-.64s' on märgitud vigaseks ja tuleb parandada"
- fre "La table '%-.64s' est marquée 'crashed' et devrait être réparée"
- ger "Tabelle '%-.64s' ist als defekt markiert und sollte repariert werden"
- ita "La tabella '%-.64s' e` segnalata come corrotta e deve essere riparata"
- por "Tabela '%-.64s' está marcada como danificada e deve ser reparada"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÄÏÌÖÎÁ ÐÒÏÊÔÉ ÐÒÏ×ÅÒËÕ É ÒÅÍÏÎÔ"
- serbian "Tabela '%-.64s' je markirana kao ošteæena i trebala bi biti popravljena"
- spa "Tabla '%-.64s' está marcada como crashed y debe ser reparada"
- swe "Tabell '%-.64s' är trasig och bör repareras med REPAIR TABLE"
- ukr "ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ §§ ÐÏÔÒ¦ÂÎÏ ×¦ÄÎÏ×ÉÔÉ"
+ cze "Tabulka '%-.192s' je ozna-Bèena jako poru¹ená a mìla by být opravena"
+ dan "Tabellen '%-.192s' er markeret med fejl og bør repareres"
+ nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en dient te worden gerepareerd"
+ eng "Table '%-.192s' is marked as crashed and should be repaired"
+ est "Tabel '%-.192s' on märgitud vigaseks ja tuleb parandada"
+ fre "La table '%-.192s' est marquée 'crashed' et devrait être réparée"
+ ger "Tabelle '%-.192s' ist als defekt markiert und sollte repariert werden"
+ ita "La tabella '%-.192s' e` segnalata come corrotta e deve essere riparata"
+ por "Tabela '%-.192s' está marcada como danificada e deve ser reparada"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÄÏÌÖÎÁ ÐÒÏÊÔÉ ÐÒÏ×ÅÒËÕ É ÒÅÍÏÎÔ"
+ serbian "Tabela '%-.192s' je markirana kao ošteæena i trebala bi biti popravljena"
+ spa "Tabla '%-.192s' está marcada como crashed y debe ser reparada"
+ swe "Tabell '%-.192s' är trasig och bör repareras med REPAIR TABLE"
+ ukr "ôÁÂÌÉÃÀ '%-.192s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ §§ ÐÏÔÒ¦ÂÎÏ ×¦ÄÎÏ×ÉÔÉ"
ER_CRASHED_ON_REPAIR
- cze "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila"
- dan "Tabellen '%-.64s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede"
- nla "Tabel '%-.64s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte"
- eng "Table '%-.64s' is marked as crashed and last (automatic?) repair failed"
- est "Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus"
- fre "La table '%-.64s' est marquée 'crashed' et le dernier 'repair' a échoué"
- ger "Tabelle '%-.64s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl"
- ita "La tabella '%-.64s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita"
- por "Tabela '%-.64s' está marcada como danificada e a última reparação (automática?) falhou"
- rus "ôÁÂÌÉÃÁ '%-.64s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÐÏÓÌÅÄÎÉÊ (Á×ÔÏÍÁÔÉÞÅÓËÉÊ?) ÒÅÍÏÎÔ ÎÅ ÂÙÌ ÕÓÐÅÛÎÙÍ"
- serbian "Tabela '%-.64s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela"
- spa "Tabla '%-.64s' está marcada como crashed y la última reparación (automactica?) falló"
- swe "Tabell '%-.64s' är trasig och senast (automatiska?) reparation misslyckades"
- ukr "ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ"
+ cze "Tabulka '%-.192s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila"
+ dan "Tabellen '%-.192s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede"
+ nla "Tabel '%-.192s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte"
+ eng "Table '%-.192s' is marked as crashed and last (automatic?) repair failed"
+ est "Tabel '%-.192s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus"
+ fre "La table '%-.192s' est marquée 'crashed' et le dernier 'repair' a échoué"
+ ger "Tabelle '%-.192s' ist als defekt markiert und der letzte (automatische?) Reparaturversuch schlug fehl"
+ ita "La tabella '%-.192s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita"
+ por "Tabela '%-.192s' está marcada como danificada e a última reparação (automática?) falhou"
+ rus "ôÁÂÌÉÃÁ '%-.192s' ÐÏÍÅÞÅÎÁ ËÁË ÉÓÐÏÒÞÅÎÎÁÑ É ÐÏÓÌÅÄÎÉÊ (Á×ÔÏÍÁÔÉÞÅÓËÉÊ?) ÒÅÍÏÎÔ ÎÅ ÂÙÌ ÕÓÐÅÛÎÙÍ"
+ serbian "Tabela '%-.192s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela"
+ spa "Tabla '%-.192s' está marcada como crashed y la última reparación (automactica?) falló"
+ swe "Tabell '%-.192s' är trasig och senast (automatiska?) reparation misslyckades"
+ ukr "ôÁÂÌÉÃÀ '%-.192s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ"
ER_WARNING_NOT_COMPLETE_ROLLBACK
dan "Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles"
nla "Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen"
@@ -4331,7 +4331,7 @@ ER_TOO_MANY_USER_CONNECTIONS 42000
nla "Gebruiker %-.64s heeft reeds meer dan 'max_user_connections' actieve verbindingen"
eng "User %-.64s already has more than 'max_user_connections' active connections"
est "Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga"
- fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connections actives"
+ fre "L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connexions actives"
ger "Benutzer '%-.64s' hat mehr als 'max_user_connections' aktive Verbindungen"
ita "L'utente %-.64s ha gia' piu' di 'max_user_connections' connessioni attive"
por "Usuário '%-.64s' já possui mais que o valor máximo de conexões (max_user_connections) ativas"
@@ -4438,18 +4438,18 @@ ER_WRONG_ARGUMENTS
swe "Felaktiga argument till %s"
ukr "èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s"
ER_NO_PERMISSION_TO_CREATE_USER 42000
- nla "'%-.32s'@'%-.64s' mag geen nieuwe gebruikers creeren"
- eng "'%-.32s'@'%-.64s' is not allowed to create new users"
- est "Kasutajal '%-.32s'@'%-.64s' ei ole lubatud luua uusi kasutajaid"
- fre "'%-.32s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs"
- ger "'%-.32s'@'%-.64s' ist nicht berechtigt, neue Benutzer hinzuzufügen"
- ita "A '%-.32s'@'%-.64s' non e' permesso creare nuovi utenti"
- por "Não é permitido a '%-.32s'@'%-.64s' criar novos usuários"
- rus "'%-.32s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
- serbian "Korisniku '%-.32s'@'%-.64s' nije dozvoljeno da kreira nove korisnike"
- spa "'%-.32s`@`%-.64s` no es permitido para crear nuevos usuarios"
- swe "'%-.32s'@'%-.64s' har inte rättighet att skapa nya användare"
- ukr "ëÏÒÉÓÔÕ×ÁÞÕ '%-.32s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×"
+ nla "'%-.48s'@'%-.64s' mag geen nieuwe gebruikers creeren"
+ eng "'%-.48s'@'%-.64s' is not allowed to create new users"
+ est "Kasutajal '%-.48s'@'%-.64s' ei ole lubatud luua uusi kasutajaid"
+ fre "'%-.48s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs"
+ ger "'%-.48s'@'%-.64s' ist nicht berechtigt, neue Benutzer hinzuzufügen"
+ ita "A '%-.48s'@'%-.64s' non e' permesso creare nuovi utenti"
+ por "Não é permitido a '%-.48s'@'%-.64s' criar novos usuários"
+ rus "'%-.48s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
+ serbian "Korisniku '%-.48s'@'%-.64s' nije dozvoljeno da kreira nove korisnike"
+ spa "'%-.48s`@`%-.64s` no es permitido para crear nuevos usuarios"
+ swe "'%-.48s'@'%-.64s' har inte rättighet att skapa nya användare"
+ ukr "ëÏÒÉÓÔÕ×ÁÞÕ '%-.48s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×"
ER_UNION_TABLES_IN_DIFFERENT_DIR
nla "Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren"
eng "Incorrect table definition; all MERGE tables must be in the same database"
@@ -4654,14 +4654,14 @@ ER_NO_DEFAULT 42000
spa "Variable '%-.64s' no tiene un valor patrón"
swe "Variabel '%-.64s' har inte ett DEFAULT-värde"
ER_WRONG_VALUE_FOR_VAR 42000
- nla "Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.64s'"
- eng "Variable '%-.64s' can't be set to the value of '%-.64s'"
- ger "Variable '%-.64s' kann nicht auf '%-.64s' gesetzt werden"
- ita "Alla variabile '%-.64s' non puo' essere assegato il valore '%-.64s'"
- por "Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'"
- rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.64s'"
- spa "Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'"
- swe "Variabel '%-.64s' kan inte sättas till '%-.64s'"
+ nla "Variabele '%-.64s' kan niet worden gewijzigd naar de waarde '%-.200s'"
+ eng "Variable '%-.64s' can't be set to the value of '%-.200s'"
+ ger "Variable '%-.64s' kann nicht auf '%-.200s' gesetzt werden"
+ ita "Alla variabile '%-.64s' non puo' essere assegato il valore '%-.200s'"
+ por "Variável '%-.64s' não pode ser configurada para o valor de '%-.200s'"
+ rus "ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.200s'"
+ spa "Variable '%-.64s' no puede ser configurada para el valor de '%-.200s'"
+ swe "Variabel '%-.64s' kan inte sättas till '%-.200s'"
ER_WRONG_TYPE_FOR_VAR 42000
nla "Foutief argumenttype voor variabele '%-.64s'"
eng "Incorrect argument type to variable '%-.64s'"
@@ -4715,19 +4715,19 @@ ER_SLAVE_IGNORED_TABLE
spa "Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
swe "Slav SQL tråden ignorerade frågan pga en replicate-*-table regel"
ER_INCORRECT_GLOBAL_LOCAL_VAR
- eng "Variable '%-.64s' is a %s variable"
- serbian "Incorrect foreign key definition for '%-.64s': %s"
- ger "Variable '%-.64s' ist eine %s-Variable"
- nla "Variabele '%-.64s' is geen %s variabele"
- spa "Variable '%-.64s' es una %s variable"
- swe "Variabel '%-.64s' är av typ %s"
+ eng "Variable '%-.192s' is a %s variable"
+ serbian "Incorrect foreign key definition for '%-.192s': %s"
+ ger "Variable '%-.192s' ist eine %s-Variable"
+ nla "Variabele '%-.192s' is geen %s variabele"
+ spa "Variable '%-.192s' es una %s variable"
+ swe "Variabel '%-.192s' är av typ %s"
ER_WRONG_FK_DEF 42000
- eng "Incorrect foreign key definition for '%-.64s': %s"
- ger "Falsche Fremdschlüssel-Definition für '%-.64s': %s"
- nla "Incorrecte foreign key definitie voor '%-.64s': %s"
- por "Definição errada da chave estrangeira para '%-.64s': %s"
- spa "Equivocada definición de llave extranjera para '%-.64s': %s"
- swe "Felaktig FOREIGN KEY-definition för '%-.64s': %s"
+ eng "Incorrect foreign key definition for '%-.192s': %s"
+ ger "Falsche Fremdschlüssel-Definition für '%-.192s': %s"
+ nla "Incorrecte foreign key definitie voor '%-.192s': %s"
+ por "Definição errada da chave estrangeira para '%-.192s': %s"
+ spa "Equivocada definición de llave extranjera para '%-.192s': %s"
+ swe "Felaktig FOREIGN KEY-definition för '%-.192s': %s"
ER_KEY_REF_DO_NOT_MATCH_TABLE_REF
eng "Key reference and table reference don't match"
ger "Schlüssel- und Tabellenverweis passen nicht zusammen"
@@ -4811,12 +4811,12 @@ ER_SELECT_REDUCED 01000
swe "Select %u reducerades vid optimiering"
ukr "Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii"
ER_TABLENAME_NOT_ALLOWED_HERE 42000
- eng "Table '%-.64s' from one of the SELECTs cannot be used in %-.32s"
- ger "Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden"
- nla "Tabel '%-.64s' uit een van de SELECTS kan niet in %-.32s gebruikt worden"
- por "Tabela '%-.64s' de um dos SELECTs não pode ser usada em %-.32s"
- spa "Tabla '%-.64s' de uno de los SELECT no puede ser usada en %-.32s"
- swe "Tabell '%-.64s' från en SELECT kan inte användas i %-.32s"
+ eng "Table '%-.192s' from one of the SELECTs cannot be used in %-.32s"
+ ger "Tabelle '%-.192s', die in einem der SELECT-Befehle verwendet wurde, kann nicht in %-.32s verwendet werden"
+ nla "Tabel '%-.192s' uit een van de SELECTS kan niet in %-.32s gebruikt worden"
+ por "Tabela '%-.192s' de um dos SELECTs não pode ser usada em %-.32s"
+ spa "Tabla '%-.192s' de uno de los SELECT no puede ser usada en %-.32s"
+ swe "Tabell '%-.192s' från en SELECT kan inte användas i %-.32s"
ER_NOT_SUPPORTED_AUTH_MODE 08004
eng "Client does not support authentication protocol requested by server; consider upgrading MySQL client"
ger "Client unterstützt das vom Server erwartete Authentifizierungsprotokoll nicht. Bitte aktualisieren Sie Ihren MySQL-Client"
@@ -4959,12 +4959,12 @@ ER_SERVER_IS_IN_SECURE_AUTH_MODE
rus "óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s'@'%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ"
spa "Servidor está rodando en modo --secure-auth, pero '%s'@'%s' tiene clave en el antiguo formato; por favor cambie la clave para el nuevo formato"
ER_WARN_FIELD_RESOLVED
- eng "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d"
- ger "Feld oder Verweis '%-.64s%s%-.64s%s%-.64s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst"
- por "Campo ou referência '%-.64s%s%-.64s%s%-.64s' de SELECT #%d foi resolvido em SELECT #%d"
- rus "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d"
- spa "Campo o referencia '%-.64s%s%-.64s%s%-.64s' de SELECT #%d fue resolvido en SELECT #%d"
- ukr "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d"
+ eng "Field or reference '%-.192s%s%-.192s%s%-.192s' of SELECT #%d was resolved in SELECT #%d"
+ ger "Feld oder Verweis '%-.192s%s%-.192s%s%-.192s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst"
+ por "Campo ou referência '%-.192s%s%-.192s%s%-.192s' de SELECT #%d foi resolvido em SELECT #%d"
+ rus "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.192s%s%-.192s%s%-.192s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d"
+ spa "Campo o referencia '%-.192s%s%-.192s%s%-.192s' de SELECT #%d fue resolvido en SELECT #%d"
+ ukr "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.192s%s%-.192s%s%-.192s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d"
ER_BAD_SLAVE_UNTIL_COND
eng "Incorrect parameter or combination of parameters for START SLAVE UNTIL"
ger "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL"
@@ -5001,11 +5001,11 @@ ER_WARN_QC_RESIZE
swe "Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu"
ukr "ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu"
ER_BAD_FT_COLUMN
- eng "Column '%-.64s' cannot be part of FULLTEXT index"
- ger "Feld '%-.64s' kann nicht Teil eines FULLTEXT-Index sein"
- por "Coluna '%-.64s' não pode ser parte de índice FULLTEXT"
- spa "Columna '%-.64s' no puede ser parte de FULLTEXT index"
- swe "Kolumn '%-.64s' kan inte vara del av ett FULLTEXT index"
+ eng "Column '%-.192s' cannot be part of FULLTEXT index"
+ ger "Feld '%-.192s' kann nicht Teil eines FULLTEXT-Index sein"
+ por "Coluna '%-.192s' não pode ser parte de índice FULLTEXT"
+ spa "Columna '%-.192s' no puede ser parte de FULLTEXT index"
+ swe "Kolumn '%-.192s' kan inte vara del av ett FULLTEXT index"
ER_UNKNOWN_KEY_CACHE
eng "Unknown key cache '%-.100s'"
ger "Unbekannter Schlüssel-Cache '%-.100s'"
@@ -5063,10 +5063,10 @@ ER_TOO_MUCH_AUTO_TIMESTAMP_COLS
por "Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
spa "Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
ER_INVALID_ON_UPDATE
- eng "Invalid ON UPDATE clause for '%-.64s' column"
- ger "Ungültige ON-UPDATE-Klausel für Spalte '%-.64s'"
- por "Inválida cláusula ON UPDATE para campo '%-.64s'"
- spa "Inválido ON UPDATE cláusula para campo '%-.64s'"
+ eng "Invalid ON UPDATE clause for '%-.192s' column"
+ ger "Ungültige ON-UPDATE-Klausel für Spalte '%-.192s'"
+ por "Inválida cláusula ON UPDATE para campo '%-.192s'"
+ spa "Inválido ON UPDATE cláusula para campo '%-.192s'"
ER_UNSUPPORTED_PS
eng "This command is not supported in the prepared statement protocol yet"
ger "Dieser Befehl wird im Protokoll für vorbereitete Anweisungen noch nicht unterstützt"
@@ -5209,50 +5209,50 @@ ER_SP_CASE_NOT_FOUND 20000
eng "Case not found for CASE statement"
ger "Fall für CASE-Anweisung nicht gefunden"
ER_FPARSER_TOO_BIG_FILE
- eng "Configuration file '%-.64s' is too big"
- ger "Konfigurationsdatei '%-.64s' ist zu groß"
- rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ '%-.64s'"
- ukr "úÁÎÁÄÔÏ ×ÅÌÉËÉÊ ËÏÎÆ¦ÇÕÒÁæÊÎÉÊ ÆÁÊÌ '%-.64s'"
+ eng "Configuration file '%-.192s' is too big"
+ ger "Konfigurationsdatei '%-.192s' ist zu groß"
+ rus "óÌÉÛËÏÍ ÂÏÌØÛÏÊ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ '%-.192s'"
+ ukr "úÁÎÁÄÔÏ ×ÅÌÉËÉÊ ËÏÎÆ¦ÇÕÒÁæÊÎÉÊ ÆÁÊÌ '%-.192s'"
ER_FPARSER_BAD_HEADER
- eng "Malformed file type header in file '%-.64s'"
- ger "Nicht wohlgeformter Dateityp-Header in Datei '%-.64s'"
- rus "îÅ×ÅÒÎÙÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÁ ÆÁÊÌÁ '%-.64s'"
- ukr "îÅצÒÎÉÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÕ Õ ÆÁÊ̦ '%-.64s'"
+ eng "Malformed file type header in file '%-.192s'"
+ ger "Nicht wohlgeformter Dateityp-Header in Datei '%-.192s'"
+ rus "îÅ×ÅÒÎÙÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÁ ÆÁÊÌÁ '%-.192s'"
+ ukr "îÅצÒÎÉÊ ÚÁÇÏÌÏ×ÏË ÔÉÐÕ Õ ÆÁÊ̦ '%-.192s'"
ER_FPARSER_EOF_IN_COMMENT
eng "Unexpected end of file while parsing comment '%-.200s'"
- ger "Unerwartetes Dateiende beim Parsen des Kommentars '%-.64s'"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ × ËÏÍÅÎÔÁÒÉÉ '%-.64s'"
- ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ËÏÍÅÎÔÁÒ¦ '%-.64s'"
+ ger "Unerwartetes Dateiende beim Parsen des Kommentars '%-.200s'"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ × ËÏÍÅÎÔÁÒÉÉ '%-.200s'"
+ ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ËÏÍÅÎÔÁÒ¦ '%-.200s'"
ER_FPARSER_ERROR_IN_PARAMETER
- eng "Error while parsing parameter '%-.64s' (line: '%-.64s')"
- ger "Fehler beim Parsen des Parameters '%-.64s' (Zeile: '%-.64s')"
- rus "ïÛÉÂËÁ ÐÒÉ ÒÁÓÐÏÚÎÁ×ÁÎÉÉ ÐÁÒÁÍÅÔÒÁ '%-.64s' (ÓÔÒÏËÁ: '%-.64s')"
- ukr "ðÏÍÉÌËÁ × ÒÏÓЦÚÎÁ×ÁÎΦ ÐÁÒÁÍÅÔÒÕ '%-.64s' (ÒÑÄÏË: '%-.64s')"
+ eng "Error while parsing parameter '%-.192s' (line: '%-.192s')"
+ ger "Fehler beim Parsen des Parameters '%-.192s' (Zeile: '%-.192s')"
+ rus "ïÛÉÂËÁ ÐÒÉ ÒÁÓÐÏÚÎÁ×ÁÎÉÉ ÐÁÒÁÍÅÔÒÁ '%-.192s' (ÓÔÒÏËÁ: '%-.192s')"
+ ukr "ðÏÍÉÌËÁ × ÒÏÓЦÚÎÁ×ÁÎΦ ÐÁÒÁÍÅÔÒÕ '%-.192s' (ÒÑÄÏË: '%-.192s')"
ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER
- eng "Unexpected end of file while skipping unknown parameter '%-.64s'"
- ger "Unerwartetes Dateiende beim Überspringen des unbekannten Parameters '%-.64s'"
- rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ ÐÒÉ ÐÒÏÐÕÓËÅ ÎÅÉÚ×ÅÓÔÎÏÇÏ ÐÁÒÁÍÅÔÒÁ '%-.64s'"
- ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ÓÐÒϦ ÐÒÏÍÉÎÕÔÉ ÎÅצÄÏÍÉÊ ÐÁÒÁÍÅÔÒ '%-.64s'"
+ eng "Unexpected end of file while skipping unknown parameter '%-.192s'"
+ ger "Unerwartetes Dateiende beim Überspringen des unbekannten Parameters '%-.192s'"
+ rus "îÅÏÖÉÄÁÎÎÙÊ ËÏÎÅà ÆÁÊÌÁ ÐÒÉ ÐÒÏÐÕÓËÅ ÎÅÉÚ×ÅÓÔÎÏÇÏ ÐÁÒÁÍÅÔÒÁ '%-.192s'"
+ ukr "îÅÓÐÏĦ×ÁÎÎÉÊ Ë¦ÎÅÃØ ÆÁÊÌÕ Õ ÓÐÒϦ ÐÒÏÍÉÎÕÔÉ ÎÅצÄÏÍÉÊ ÐÁÒÁÍÅÔÒ '%-.192s'"
ER_VIEW_NO_EXPLAIN
eng "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table"
ger "EXPLAIN/SHOW kann nicht verlangt werden. Rechte für zugrunde liegende Tabelle fehlen"
rus "EXPLAIN/SHOW ÎÅ ÍÏÖÅÔ ÂÙÔØ ×ÙÐÏÌÎÅÎÎÏ; ÎÅÄÏÓÔÁÔÏÞÎÏ ÐÒÁ× ÎÁ ÔÁËÂÌÉÃÙ ÚÁÐÒÏÓÁ"
ukr "EXPLAIN/SHOW ÎÅ ÍÏÖÅ ÂÕÔÉ ×¦ËÏÎÁÎÏ; ÎÅÍÁ¤ ÐÒÁ× ÎÁ ÔÉÂÌÉæ ÚÁÐÉÔÕ"
ER_FRM_UNKNOWN_TYPE
- eng "File '%-.64s' has unknown type '%-.64s' in its header"
- ger "Datei '%-.64s' hat unbekannten Typ '%-.64s' im Header"
- rus "æÁÊÌ '%-.64s' ÓÏÄÅÒÖÉÔ ÎÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ '%-.64s' × ÚÁÇÏÌÏ×ËÅ"
- ukr "æÁÊÌ '%-.64s' ÍÁ¤ ÎÅצÄÏÍÉÊ ÔÉÐ '%-.64s' Õ ÚÁÇÏÌÏ×ËÕ"
+ eng "File '%-.192s' has unknown type '%-.64s' in its header"
+ ger "Datei '%-.192s' hat unbekannten Typ '%-.64s' im Header"
+ rus "æÁÊÌ '%-.192s' ÓÏÄÅÒÖÉÔ ÎÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ '%-.64s' × ÚÁÇÏÌÏ×ËÅ"
+ ukr "æÁÊÌ '%-.192s' ÍÁ¤ ÎÅצÄÏÍÉÊ ÔÉÐ '%-.64s' Õ ÚÁÇÏÌÏ×ËÕ"
ER_WRONG_OBJECT
- eng "'%-.64s.%-.64s' is not %s"
- ger "'%-.64s.%-.64s' ist nicht %s"
- rus "'%-.64s.%-.64s' - ÎÅ %s"
- ukr "'%-.64s.%-.64s' ÎÅ ¤ %s"
+ eng "'%-.192s.%-.192s' is not %s"
+ ger "'%-.192s.%-.192s' ist nicht %s"
+ rus "'%-.192s.%-.192s' - ÎÅ %s"
+ ukr "'%-.192s.%-.192s' ÎÅ ¤ %s"
ER_NONUPDATEABLE_COLUMN
- eng "Column '%-.64s' is not updatable"
- ger "Feld '%-.64s' ist nicht aktualisierbar"
- rus "óÔÏÌÂÅà '%-.64s' ÎÅ ÏÂÎÏ×ÌÑÅÍÙÊ"
- ukr "óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÚÍÉÎÅÎÉÊ"
+ eng "Column '%-.192s' is not updatable"
+ ger "Feld '%-.192s' ist nicht aktualisierbar"
+ rus "óÔÏÌÂÅà '%-.192s' ÎÅ ÏÂÎÏ×ÌÑÅÍÙÊ"
+ ukr "óÔÏ×ÂÅÃØ '%-.192s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÚÍÉÎÅÎÉÊ"
ER_VIEW_SELECT_DERIVED
eng "View's SELECT contains a subquery in the FROM clause"
ger "SELECT der View enthält eine Subquery in der FROM-Klausel"
@@ -5269,10 +5269,10 @@ ER_VIEW_SELECT_VARIABLE
rus "View SELECT ÓÏÄÅÒÖÉÔ ÐÅÒÅÍÅÎÎÕÀ ÉÌÉ ÐÁÒÁÍÅÔÒ"
ukr "View SELECT ÍÁ¤ ÚÍÉÎÎÕ ÁÂÏ ÐÁÒÁÍÅÔÅÒ"
ER_VIEW_SELECT_TMPTABLE
- eng "View's SELECT refers to a temporary table '%-.64s'"
- ger "SELECT der View verweist auf eine temporäre Tabelle '%-.64s'"
- rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'"
- ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.64s'"
+ eng "View's SELECT refers to a temporary table '%-.192s'"
+ ger "SELECT der View verweist auf eine temporäre Tabelle '%-.192s'"
+ rus "View SELECT ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.192s'"
+ ukr "View SELECT ×ÉËÏÒÉÓÔÏ×Õ¤ ÔÉÍÞÁÓÏ×Õ ÔÁÂÌÉÃÀ '%-.192s'"
ER_VIEW_WRONG_LIST
eng "View's SELECT and view's field list have different column counts"
ger "SELECT- und Feldliste der Views haben unterschiedliche Anzahlen von Spalten"
@@ -5289,7 +5289,7 @@ ER_WARN_VIEW_WITHOUT_KEY
rus "ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÙÈ(ÏÊ) × ÎÅÍ ÔÁÂÌÉÃ(Ù)"
ukr "View, ÝÏ ÏÎÏ×ÌÀÅÔØÓÑ, ΊͦÓÔÉÔØ ÐÏ×ÎÏÇÏ ËÌÀÞÁ ÔÁÂÌÉæ(Ø), ÝÏ ×ÉËÏÒ¦ÓÔÁÎÁ × ÎØÀÏÍÕ"
ER_VIEW_INVALID
- eng "View '%-.64s.%-.64s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
+ eng "View '%-.192s.%-.192s' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them"
ER_SP_NO_DROP_SP
eng "Can't drop or alter a %s from within another stored routine"
ger "Kann eine %s nicht von innerhalb einer anderen gespeicherten Routine löschen oder ändern"
@@ -5303,39 +5303,39 @@ ER_TRG_DOES_NOT_EXIST
eng "Trigger does not exist"
ger "Trigger existiert nicht"
ER_TRG_ON_VIEW_OR_TEMP_TABLE
- eng "Trigger's '%-.64s' is view or temporary table"
- ger "'%-.64s' des Triggers ist View oder temporäre Tabelle"
+ eng "Trigger's '%-.192s' is view or temporary table"
+ ger "'%-.192s' des Triggers ist View oder temporäre Tabelle"
ER_TRG_CANT_CHANGE_ROW
eng "Updating of %s row is not allowed in %strigger"
- ger "Aktualisieren einer %s-Zeile ist in einem %-Trigger nicht erlaubt"
+ ger "Aktualisieren einer %s-Zeile ist in einem %s-Trigger nicht erlaubt"
ER_TRG_NO_SUCH_ROW_IN_TRG
eng "There is no %s row in %s trigger"
ger "Es gibt keine %s-Zeile im %s-Trigger"
ER_NO_DEFAULT_FOR_FIELD
- eng "Field '%-.64s' doesn't have a default value"
- ger "Feld '%-.64s' hat keinen Vorgabewert"
+ eng "Field '%-.192s' doesn't have a default value"
+ ger "Feld '%-.192s' hat keinen Vorgabewert"
ER_DIVISION_BY_ZERO 22012
eng "Division by 0"
ger "Division durch 0"
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
- eng "Incorrect %-.32s value: '%-.128s' for column '%.64s' at row %ld"
- ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.64s' in Zeile %ld"
+ eng "Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld"
+ ger "Falscher %-.32s-Wert: '%-.128s' für Feld '%.192s' in Zeile %ld"
ER_ILLEGAL_VALUE_FOR_TYPE 22007
- eng "Illegal %s '%-.64s' value found during parsing"
- ger "Nicht zulässiger %s-Wert '%-.64s' beim Parsen gefunden"
+ eng "Illegal %s '%-.192s' value found during parsing"
+ ger "Nicht zulässiger %s-Wert '%-.192s' beim Parsen gefunden"
ER_VIEW_NONUPD_CHECK
- eng "CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
- ger "CHECK OPTION auf nicht-aktualisierbarem View '%-.64s.%-.64s'"
- rus "CHECK OPTION ÄÌÑ ÎÅÏÂÎÏ×ÌÑÅÍÏÇÏ VIEW '%-.64s.%-.64s'"
- ukr "CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÝÏ ÎÅ ÍÏÖÅ ÂÕÔÉ ÏÎÏ×ÌÅÎÎÉÍ"
+ eng "CHECK OPTION on non-updatable view '%-.192s.%-.192s'"
+ ger "CHECK OPTION auf nicht-aktualisierbarem View '%-.192s.%-.192s'"
+ rus "CHECK OPTION ÄÌÑ ÎÅÏÂÎÏ×ÌÑÅÍÏÇÏ VIEW '%-.192s.%-.192s'"
+ ukr "CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÝÏ ÎÅ ÍÏÖÅ ÂÕÔÉ ÏÎÏ×ÌÅÎÎÉÍ"
ER_VIEW_CHECK_FAILED
- eng "CHECK OPTION failed '%-.64s.%-.64s'"
- ger "CHECK OPTION fehlgeschlagen: '%-.64s.%-.64s'"
- rus "ÐÒÏ×ÅÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÐÒÏ×ÁÌÉÌÁÓØ"
- ukr "ðÅÒÅצÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÎÅ ÐÒÏÊÛÌÁ"
+ eng "CHECK OPTION failed '%-.192s.%-.192s'"
+ ger "CHECK OPTION fehlgeschlagen: '%-.192s.%-.192s'"
+ rus "ÐÒÏ×ÅÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÐÒÏ×ÁÌÉÌÁÓØ"
+ ukr "ðÅÒÅצÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.192s.%-.192s' ÎÅ ÐÒÏÊÛÌÁ"
ER_PROCACCESS_DENIED_ERROR 42000
- eng "%-.16s command denied to user '%-.32s'@'%-.64s' for routine '%-.64s'"
- ger "Befehl %-.16s nicht zulässig für Benutzer '%-.32s'@'%-.64s' in Routine '%-.64s'"
+ eng "%-.16s command denied to user '%-.48s'@'%-.64s' for routine '%-.192s'"
+ ger "Befehl %-.16s nicht zulässig für Benutzer '%-.48s'@'%-.64s' in Routine '%-.192s'"
ER_RELAY_LOG_FAIL
eng "Failed purging old relay logs: %s"
ger "Bereinigen alter Relais-Logs fehlgeschlagen: %s"
@@ -5389,7 +5389,7 @@ ER_LOGGING_PROHIBIT_CHANGING_OF
ger "Binärlogs und Replikation verhindern Wechsel des globalen Servers %s"
ER_NO_FILE_MAPPING
eng "Can't map file: %-.200s, errno: %d"
- ger "Kann Datei nicht abbilden: %-.64s, Fehler: %d"
+ ger "Kann Datei nicht abbilden: %-.200s, Fehler: %d"
ER_WRONG_MAGIC
eng "Wrong magic in %-.64s"
ger "Falsche magische Zahlen in %-.64s"
@@ -5397,28 +5397,28 @@ ER_PS_MANY_PARAM
eng "Prepared statement contains too many placeholders"
ger "Vorbereitete Anweisung enthält zu viele Platzhalter"
ER_KEY_PART_0
- eng "Key part '%-.64s' length cannot be 0"
- ger "Länge des Schlüsselteils '%-.64s' kann nicht 0 sein"
+ eng "Key part '%-.192s' length cannot be 0"
+ ger "Länge des Schlüsselteils '%-.192s' kann nicht 0 sein"
ER_VIEW_CHECKSUM
eng "View text checksum failed"
ger "View-Text-Prüfsumme fehlgeschlagen"
rus "ðÒÏ×ÅÒËÁ ËÏÎÔÒÏÌØÎÏÊ ÓÕÍÍÙ ÔÅËÓÔÁ VIEW ÐÒÏ×ÁÌÉÌÁÓØ"
ukr "ðÅÒÅצÒËÁ ËÏÎÔÒÏÌØÎϧ ÓÕÍÉ ÔÅËÓÔÕ VIEW ÎÅ ÐÒÏÊÛÌÁ"
ER_VIEW_MULTIUPDATE
- eng "Can not modify more than one base table through a join view '%-.64s.%-.64s'"
- ger "Kann nicht mehr als eine Basistabelle über Join-View '%-.64s.%-.64s' ändern"
- rus "îÅÌØÚÑ ÉÚÍÅÎÉÔØ ÂÏÌØÛÅ ÞÅÍ ÏÄÎÕ ÂÁÚÏ×ÕÀ ÔÁÂÌÉÃÕ ÉÓÐÏÌØÚÕÑ ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s'"
- ukr "îÅÍÏÖÌÉ×Ï ÏÎÏ×ÉÔÉ Â¦ÌØÛ ÎÉÖ ÏÄÎÕ ÂÁÚÏ×Õ ÔÁÂÌÉÃÀ ×ÙËÏÒÉÓÔÏ×ÕÀÞÉ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔ¦ÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ"
+ eng "Can not modify more than one base table through a join view '%-.192s.%-.192s'"
+ ger "Kann nicht mehr als eine Basistabelle über Join-View '%-.192s.%-.192s' ändern"
+ rus "îÅÌØÚÑ ÉÚÍÅÎÉÔØ ÂÏÌØÛÅ ÞÅÍ ÏÄÎÕ ÂÁÚÏ×ÕÀ ÔÁÂÌÉÃÕ ÉÓÐÏÌØÚÕÑ ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.192s.%-.192s'"
+ ukr "îÅÍÏÖÌÉ×Ï ÏÎÏ×ÉÔÉ Â¦ÌØÛ ÎÉÖ ÏÄÎÕ ÂÁÚÏ×Õ ÔÁÂÌÉÃÀ ×ÙËÏÒÉÓÔÏ×ÕÀÞÉ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔ¦ÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ"
ER_VIEW_NO_INSERT_FIELD_LIST
- eng "Can not insert into join view '%-.64s.%-.64s' without fields list"
- ger "Kann nicht ohne Feldliste in Join-View '%-.64s.%-.64s' einfügen"
- rus "îÅÌØÚÑ ×ÓÔÁ×ÌÑÔØ ÚÁÐÉÓÉ × ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.64s.%-.64s' ÂÅÚ ÓÐÉÓËÁ ÐÏÌÅÊ"
- ukr "îÅÍÏÖÌÉ×Ï ÕÓÔÁ×ÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ, ÂÅÚ ÓÐÉÓËÕ ÓÔÏ×Âæ×"
+ eng "Can not insert into join view '%-.192s.%-.192s' without fields list"
+ ger "Kann nicht ohne Feldliste in Join-View '%-.192s.%-.192s' einfügen"
+ rus "îÅÌØÚÑ ×ÓÔÁ×ÌÑÔØ ÚÁÐÉÓÉ × ÍÎÏÇÏÔÁÂÌÉÞÎÙÊ VIEW '%-.192s.%-.192s' ÂÅÚ ÓÐÉÓËÁ ÐÏÌÅÊ"
+ ukr "îÅÍÏÖÌÉ×Ï ÕÓÔÁ×ÉÔÉ ÒÑÄËÉ Õ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔÉÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ, ÂÅÚ ÓÐÉÓËÕ ÓÔÏ×Âæ×"
ER_VIEW_DELETE_MERGE_VIEW
- eng "Can not delete from join view '%-.64s.%-.64s'"
- ger "Kann nicht aus Join-View '%-.64s.%-.64s' löschen"
- rus "îÅÌØÚÑ ÕÄÁÌÑÔØ ÉÚ ÍÎÏÇÏÔÁÂÌÉÞÎÏÇÏ VIEW '%-.64s.%-.64s'"
- ukr "îÅÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÑÄËÉ Õ VIEW '%-.64s.%-.64s', ÝÏ Í¦ÓÔÉÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ"
+ eng "Can not delete from join view '%-.192s.%-.192s'"
+ ger "Kann nicht aus Join-View '%-.192s.%-.192s' löschen"
+ rus "îÅÌØÚÑ ÕÄÁÌÑÔØ ÉÚ ÍÎÏÇÏÔÁÂÌÉÞÎÏÇÏ VIEW '%-.192s.%-.192s'"
+ ukr "îÅÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ÒÑÄËÉ Õ VIEW '%-.192s.%-.192s', ÝÏ Í¦ÓÔÉÔØ ÄÅË¦ÌØËÁ ÔÁÂÌÉÃØ"
ER_CANNOT_USER
eng "Operation %s failed for %.256s"
ger "Operation %s schlug fehl für %.256s"
@@ -5443,8 +5443,8 @@ ER_XA_RBROLLBACK XA100
eng "XA_RBROLLBACK: Transaction branch was rolled back"
ger "XA_RBROLLBACK: Transaktionszweig wurde zurückgerollt"
ER_NONEXISTING_PROC_GRANT 42000
- eng "There is no such grant defined for user '%-.32s' on host '%-.64s' on routine '%-.64s'"
- ger "Es gibt diese Berechtigung für Benutzer '%-.32s' auf Host '%-.64s' für Routine '%-.64s' nicht"
+ eng "There is no such grant defined for user '%-.48s' on host '%-.64s' on routine '%-.192s'"
+ ger "Es gibt diese Berechtigung für Benutzer '%-.48s' auf Host '%-.64s' für Routine '%-.192s' nicht"
ER_PROC_AUTO_GRANT_FAIL
eng "Failed to grant EXECUTE and ALTER ROUTINE privileges"
ger "Gewährung von EXECUTE- und ALTER-ROUTINE-Rechten fehlgeschlagen"
@@ -5503,28 +5503,27 @@ ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG
eng "Explicit or implicit commit is not allowed in stored function or trigger."
ger "Explizites oder implizites Commit ist in gespeicherten Funktionen und in Triggern nicht erlaubt"
ER_NO_DEFAULT_FOR_VIEW_FIELD
- eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value"
- ger "Ein Feld der dem View '%-.64s.%-.64s' zugrundeliegenden Tabelle hat keinen Vorgabewert"
+ eng "Field of view '%-.192s.%-.192s' underlying table doesn't have a default value"
+ ger "Ein Feld der dem View '%-.192s.%-.192s' zugrundeliegenden Tabelle hat keinen Vorgabewert"
ER_SP_NO_RECURSION
eng "Recursive stored functions and triggers are not allowed."
ger "Rekursive gespeicherte Routinen und Triggers sind nicht erlaubt"
ER_TOO_BIG_SCALE 42000 S1009
- eng "Too big scale %d specified for column '%-.64s'. Maximum is %d."
- ger "Zu großer Skalierungsfaktor %d für Feld '%-.64s' angegeben. Maximum ist %d"
+ eng "Too big scale %d specified for column '%-.192s'. Maximum is %d."
+ ger "Zu großer Skalierungsfaktor %d für Feld '%-.192s' angegeben. Maximum ist %d"
ER_TOO_BIG_PRECISION 42000 S1009
- eng "Too big precision %d specified for column '%-.64s'. Maximum is %d."
- ger "Zu große Genauigkeit %d für Feld '%-.64s' angegeben. Maximum ist %d"
+ eng "Too big precision %d specified for column '%-.192s'. Maximum is %d."
+ ger "Zu große Genauigkeit %d für Feld '%-.192s' angegeben. Maximum ist %d"
ER_M_BIGGER_THAN_D 42000 S1009
- eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')."
- ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.64s')"
+ eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')."
+ ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')"
ER_WRONG_LOCK_OF_SYSTEM_TABLE
- eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
- ger "Sie können Schreibsperren auf der Systemtabelle '%-.64s.%-.64s' nicht mit anderen Tabellen kombinieren"
+ eng "You can't combine write-locking of system tables with other tables or lock types"
ER_CONNECT_TO_FOREIGN_DATA_SOURCE
eng "Unable to connect to foreign data source: %.64s"
ger "Kann nicht mit Fremddatenquelle verbinden: %.64s"
ER_QUERY_ON_FOREIGN_DATA_SOURCE
- eng "There was a problem processing the query on the foreign data source. Data source error: %-.64"
+ eng "There was a problem processing the query on the foreign data source. Data source error: %-.64s"
ger "Bei der Verarbeitung der Abfrage ist in der Fremddatenquelle ein Problem aufgetreten. Datenquellenfehlermeldung: %-.64s"
ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST
eng "The foreign data source you are trying to reference does not exist. Data source error: %-.64s"
@@ -5551,8 +5550,8 @@ ER_WARN_CANT_DROP_DEFAULT_KEYCACHE
eng "Cannot drop default keycache"
ger "Der vorgabemäßige Schlüssel-Cache kann nicht gelöscht werden"
ER_TOO_BIG_DISPLAYWIDTH 42000 S1009
- eng "Display width out of range for column '%-.64s' (max = %d)"
- ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.64s' (Maximum: %d)"
+ eng "Display width out of range for column '%-.192s' (max = %d)"
+ ger "Anzeigebreite außerhalb des zulässigen Bereichs für Spalte '%-.192s' (Maximum: %d)"
ER_XAER_DUPID XAE08
eng "XAER_DUPID: The XID already exists"
ger "XAER_DUPID: Die XID existiert bereits"
@@ -5560,11 +5559,11 @@ ER_DATETIME_FUNCTION_OVERFLOW 22008
eng "Datetime function: %-.32s field overflow"
ger "Datetime-Funktion: %-.32s Feldüberlauf"
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG
- eng "Can't update table '%-.64s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
- ger "Kann Tabelle '%-.64s' in gespeicherter Funktion oder Trigger nicht aktualisieren, weil sie bereits von der Anweisung verwendet wird, die diese gespeicherte Funktion oder den Trigger aufrief"
+ eng "Can't update table '%-.192s' in stored function/trigger because it is already used by statement which invoked this stored function/trigger."
+ ger "Kann Tabelle '%-.192s' in gespeicherter Funktion oder Trigger nicht aktualisieren, weil sie bereits von der Anweisung verwendet wird, die diese gespeicherte Funktion oder den Trigger aufrief"
ER_VIEW_PREVENT_UPDATE
- eng "The definition of table '%-.64s' prevents operation %.64s on table '%-.64s'."
- ger "Die Definition der Tabelle '%-.64s' verhindert die Operation %.64s auf Tabelle '%-.64s'"
+ eng "The definition of table '%-.192s' prevents operation %.192s on table '%-.192s'."
+ ger "Die Definition der Tabelle '%-.192s' verhindert die Operation %.192s auf Tabelle '%-.192s'"
ER_PS_NO_RECURSION
eng "The prepared statement contains a stored routine call that refers to that same statement. It's not allowed to execute a prepared statement in such a recursive manner"
ger "Die vorbereitete Anweisung enthält einen Aufruf einer gespeicherten Routine, die auf eben dieselbe Anweisung verweist. Es ist nicht erlaubt, eine vorbereitete Anweisung in solch rekursiver Weise auszuführen"
@@ -5575,17 +5574,17 @@ ER_MALFORMED_DEFINER
eng "Definer is not fully qualified"
ger "Definierer des View ist nicht vollständig spezifiziert"
ER_VIEW_FRM_NO_USER
- eng "View '%-.64s'.'%-.64s' has no definer information (old table format). Current user is used as definer. Please recreate the view!"
- ger "View '%-.64s'.'%-.64s' hat keine Definierer-Information (altes Tabellenformat). Der aktuelle Benutzer wird als Definierer verwendet. Bitte erstellen Sie den View neu"
+ eng "View '%-.192s'.'%-.192s' has no definer information (old table format). Current user is used as definer. Please recreate the view!"
+ ger "View '%-.192s'.'%-.192s' hat keine Definierer-Information (altes Tabellenformat). Der aktuelle Benutzer wird als Definierer verwendet. Bitte erstellen Sie den View neu"
ER_VIEW_OTHER_USER
- eng "You need the SUPER privilege for creation view with '%-.64s'@'%-.64s' definer"
- ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.64s'@'%-.64s' zu erzeugen"
+ eng "You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer"
+ ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.192s'@'%-.192s' zu erzeugen"
ER_NO_SUCH_USER
eng "There is no '%-.64s'@'%-.64s' registered"
ger "'%-.64s'@'%-.64s' ist nicht registriert"
ER_FORBID_SCHEMA_CHANGE
- eng "Changing schema from '%-.64s' to '%-.64s' is not allowed."
- ger "Wechsel des Schemas von '%-.64s' auf '%-.64s' ist nicht erlaubt"
+ eng "Changing schema from '%-.192s' to '%-.192s' is not allowed."
+ ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt"
ER_ROW_IS_REFERENCED_2 23000
eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
ger "Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
@@ -5596,20 +5595,22 @@ ER_SP_BAD_VAR_SHADOW 42000
eng "Variable '%-.64s' must be quoted with `...`, or renamed"
ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"
ER_TRG_NO_DEFINER
- eng "No definer attribute for trigger '%-.64s'.'%-.64s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
- ger "Kein Definierer-Attribut für Trigger '%-.64s'.'%-.64s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
+ eng "No definer attribute for trigger '%-.192s'.'%-.192s'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger."
+ ger "Kein Definierer-Attribut für Trigger '%-.192s'.'%-.192s'. Der Trigger wird mit der Autorisierung des Aufrufers aktiviert, der möglicherweise keine zureichenden Berechtigungen hat. Bitte legen Sie den Trigger neu an."
ER_OLD_FILE_FORMAT
- eng "'%-.64s' has an old format, you should re-create the '%s' object(s)"
- ger "'%-.64s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
+ eng "'%-.192s' has an old format, you should re-create the '%s' object(s)"
+ ger "'%-.192s' hat altes Format, Sie sollten die '%s'-Objekt(e) neu erzeugen"
ER_SP_RECURSION_LIMIT
- eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s"
- ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.64s überschritten"
+ eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s"
+ ger "Rekursionsgrenze %d (durch Variable max_sp_recursion_depth gegeben) wurde für Routine %.192s überschritten"
ER_SP_PROC_TABLE_CORRUPT
- eng "Failed to load routine %-.64s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
- ger "Routine %-64s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
+ eng "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)"
+ ger "Routine %-.192s konnte nicht geladen werden. Die Tabelle mysql.proc fehlt, ist beschädigt, oder enthält fehlerhaften Daten (interner Code: %d)"
+ER_FOREIGN_SERVER_EXISTS
+ eng "The foreign server, %s, you are trying to create already exists."
ER_SP_WRONG_NAME 42000
- eng "Incorrect routine name '%-.64s'"
- ger "Ungültiger Routinenname '%-.64s'"
+ eng "Incorrect routine name '%-.192s'"
+ ger "Ungültiger Routinenname '%-.192s'"
ER_TABLE_NEEDS_UPGRADE
eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" to fix it!"
ger "Tabellenaktualisierung erforderlich. Bitte zum Reparieren \"REPAIR TABLE `%-.32s`\" eingeben!"
@@ -5620,11 +5621,11 @@ ER_MAX_PREPARED_STMT_COUNT_REACHED 42000
eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)"
ger "Kann nicht mehr Anweisungen als max_prepared_stmt_count erzeugen (aktueller Wert: %lu)"
ER_VIEW_RECURSIVE
- eng "`%-.64s`.`%-.64s` contains view recursion"
- ger "`%-.64s`.`%-.64s` enthält View-Rekursion"
+ eng "`%-.192s`.`%-.192s` contains view recursion"
+ ger "`%-.192s`.`%-.192s` enthält View-Rekursion"
ER_NON_GROUPING_FIELD_USED 42000
- eng "non-grouping field '%-.64s' is used in %-.64s clause"
- ger "In der %-.64s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet"
+ eng "non-grouping field '%-.192s' is used in %-.64s clause"
+ ger "In der %-.192s-Klausel wird das die Nicht-Gruppierungsspalte '%-.64s' verwendet"
ER_TABLE_CANT_HANDLE_SPKEYS
eng "The used table type doesn't support SPATIAL indexes"
ger "Der verwendete Tabellentyp unterstützt keine SPATIAL-Indizes"
@@ -5680,9 +5681,9 @@ ER_INCONSISTENT_PARTITION_INFO_ERROR
ger "Die Partitionierungsinformationen in der frm-Datei stimmen nicht mit dem überein, was in die frm-Datei geschrieben werden kann"
swe "Partitioneringsinformationen i frm-filen är inte konsistent med vad som kan skrivas i frm-filen"
ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
- eng "The %-.64s function returns the wrong type"
- ger "Die %-.64s-Funktion gibt einen falschen Typ zurück"
- swe "%-.64s-funktionen returnerar felaktig typ"
+ eng "The %-.192s function returns the wrong type"
+ ger "Die %-.192s-Funktion gibt einen falschen Typ zurück"
+ swe "%-.192s-funktionen returnerar felaktig typ"
ER_PARTITIONS_MUST_BE_DEFINED_ERROR
eng "For %-.64s partitions each partition must be defined"
ger "Für %-.64s-Partitionen muss jede Partition definiert sein"
@@ -5728,7 +5729,7 @@ ER_BLOB_FIELD_IN_PART_FUNC_ERROR
ger "In der Partitionierungsfunktion sind BLOB-Spalten nicht erlaubt"
swe "Ett BLOB-fält är inte tillåtet i partitioneringsfunktioner"
ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF
- eng "A %-.64s must include all columns in the table's partitioning function"
+ eng "A %-.192s must include all columns in the table's partitioning function"
ER_NO_PARTS_ERROR
eng "Number of %-.64s = 0 is not an allowed value"
ger "Eine Anzahl von %-.64s = 0 ist kein erlaubter Wert"
@@ -5782,9 +5783,9 @@ ER_REORG_PARTITION_NOT_EXIST
ger "Es wurde versucht, mehr Partitionen als vorhanden zu reorganisieren"
swe "Fler partitioner att reorganisera än det finns partitioner"
ER_SAME_NAME_PARTITION
- eng "Duplicate partition name %-.64s"
- ger "Doppelter Partitionsname: %-.64s"
- swe "Duplicerat partitionsnamn %-.64s"
+ eng "Duplicate partition name %-.192s"
+ ger "Doppelter Partitionsname: %-.192s"
+ swe "Duplicerat partitionsnamn %-.192s"
ER_NO_BINLOG_ERROR
eng "It is not allowed to shut off binlog on this command"
ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten"
@@ -5809,8 +5810,8 @@ ER_LIMITED_PART_RANGE
ger "Der Handler %-.64s unterstützt in VALUES nur 32-Bit-Integers"
swe "%-.64s stödjer endast 32 bitar i integers i VALUES"
ER_PLUGIN_IS_NOT_LOADED
- eng "Plugin '%-.64s' is not loaded"
- ger "Plugin '%-.64s' ist nicht geladen"
+ eng "Plugin '%-.192s' is not loaded"
+ ger "Plugin '%-.192s' ist nicht geladen"
ER_WRONG_VALUE
eng "Incorrect %-.32s value: '%-.128s'"
ger "Falscher %-.32s-Wert: '%-.128s'"
@@ -5847,18 +5848,21 @@ ER_BINLOG_ROW_WRONG_TABLE_DEF
ER_BINLOG_ROW_RBR_TO_SBR
eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events"
ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können"
+ER_FOREIGN_SERVER_DOESNT_EXIST
+ eng "The foreign server name you are trying to reference does not exist. Data source error: %-.64s"
+ ger "Die externe Verbindung, auf die Sie zugreifen wollen, existiert nicht. Datenquellenfehlermeldung: %-.64s"
ER_EVENT_ALREADY_EXISTS
- eng "Event '%-.64s' already exists"
- ger "Event '%-.64s' existiert bereits"
+ eng "Event '%-.192s' already exists"
+ ger "Event '%-.192s' existiert bereits"
ER_EVENT_STORE_FAILED
eng "Failed to store event %s. Error code %d from storage engine."
ger "Speichern von Event %s fehlgeschlagen. Fehlercode der Speicher-Engine: %d"
ER_EVENT_DOES_NOT_EXIST
- eng "Unknown event '%-.64s'"
- ger "Unbekanntes Event '%-.64s'"
+ eng "Unknown event '%-.192s'"
+ ger "Unbekanntes Event '%-.192s'"
ER_EVENT_CANT_ALTER
- eng "Failed to alter event '%-.64s'"
- ger "Ändern des Events '%-.64s' fehlgeschlagen"
+ eng "Failed to alter event '%-.192s'"
+ ger "Ändern des Events '%-.192s' fehlgeschlagen"
ER_EVENT_DROP_FAILED
eng "Failed to drop %s"
ger "Löschen von %s fehlgeschlagen"
@@ -5869,8 +5873,7 @@ ER_EVENT_ENDS_BEFORE_STARTS
eng "ENDS is either invalid or before STARTS"
ger "ENDS ist entweder ungültig oder liegt vor STARTS"
ER_EVENT_EXEC_TIME_IN_THE_PAST
- eng "Activation (AT) time is in the past"
- ger "Aktivierungszeit (AT) liegt in der Vergangenheit"
+ eng "Event execution time is in the past. Event has been disabled"
ER_EVENT_OPEN_TABLE_FAILED
eng "Failed to open mysql.event"
ger "Öffnen von mysql.event fehlgeschlagen"
@@ -5878,11 +5881,11 @@ ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
eng "No datetime expression provided"
ger "Kein DATETIME-Ausdruck angegeben"
ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
- eng "Column count of mysql.%s is wrong. Expected %d, found %d. Table probably corrupted"
+ eng "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted"
ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d gefunden. Tabelle ist wahrscheinlich beschädigt"
ER_CANNOT_LOAD_FROM_TABLE
- eng "Cannot load from mysql.%s. Table probably corrupted. See error log."
- ger "Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt, siehe Fehlerlog"
+ eng "Cannot load from mysql.%s. The table is probably corrupted"
+ ger "Kann mysql.%s nicht einlesen. Tabelle ist wahrscheinlich beschädigt"
ER_EVENT_CANNOT_DELETE
eng "Failed to delete the event from mysql.event"
ger "Löschen des Events aus mysql.event fehlgeschlagen"
@@ -5896,8 +5899,8 @@ ER_EVENT_DATA_TOO_LONG
eng "Data for column '%s' too long"
ger "Daten der Spalte '%s' zu lang"
ER_DROP_INDEX_FK
- eng "Cannot drop index '%-.64s': needed in a foreign key constraint"
- ger "Kann Index '%-.64s' nicht löschen: wird für einen Fremdschlüssel benötigt"
+ eng "Cannot drop index '%-.192s': needed in a foreign key constraint"
+ ger "Kann Index '%-.192s' nicht löschen: wird für einen Fremdschlüssel benötigt"
ER_WARN_DEPRECATED_SYNTAX
eng "The syntax '%s' is deprecated and will be removed in MySQL %s. Please use %s instead"
ger "Die Syntax '%s' ist veraltet und wird in MySQL %s entfernt. Bitte benutzen Sie statt dessen %s"
@@ -5908,11 +5911,11 @@ ER_CANT_READ_LOCK_LOG_TABLE
eng "You can't use usual read lock with log tables. Try READ LOCAL instead"
ger "Log-Tabellen können nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL"
ER_FOREIGN_DUPLICATE_KEY 23000 S1009
- eng "Upholding foreign key constraints for table '%.64s', entry '%-.64s', key %d would lead to a duplicate entry"
- ger "Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%.64s', Eintrag '%-.64s', Schlüssel %d würde zu einem doppelten Eintrag führen"
+ eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry"
+ ger "Aufrechterhalten der Fremdschlüssel-Constraints für Tabelle '%.192s', Eintrag '%-.192s', Schlüssel %d würde zu einem doppelten Eintrag führen"
ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
- eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use scripts/mysql_fix_privilege_tables"
- ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie scripts/mysql_fix_privilege_tables, um den Fehler zu beheben"
+ eng "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error."
+ ger "Spaltenanzahl von mysql.%s falsch. %d erwartet, aber %d erhalten. Erzeugt mit MySQL %d, jetzt unter %d. Bitte benutzen Sie mysql_upgrade, um den Fehler zu beheben"
ER_REMOVED_SPACES
eng "Leading spaces are removed from name '%s'"
ger "Führende Leerzeichen werden aus dem Namen '%s' entfernt"
@@ -5951,8 +5954,8 @@ ER_CANT_CHANGE_TX_ISOLATION 25001
eng "Transaction isolation level can't be changed while a transaction is in progress"
ger "Transaktionsisolationsebene kann während einer laufenden Transaktion nicht geändert werden"
ER_DUP_ENTRY_AUTOINCREMENT_CASE
- eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
- ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.64s' für Schlüssel '%-.64s' auftritt"
+ eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.192s' for key '%-.192s'"
+ ger "ALTER TABLE führt zur Neusequenzierung von auto_increment, wodurch der doppelte Eintrag '%-.192s' für Schlüssel '%-.192s' auftritt"
ER_EVENT_MODIFY_QUEUE_ERROR
eng "Internal scheduler error %d"
ger "Interner Scheduler-Fehler %d"
@@ -5975,11 +5978,11 @@ ER_BASE64_DECODE_ERROR
ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
eng "Triggers can not be created on system tables"
ger "Trigger können nicht auf Systemtabellen erzeugt werden"
-ER_EVENT_RECURSIVITY_FORBIDDEN
- eng "Recursivity of EVENT DDL statements is forbidden when body is present"
+ER_EVENT_RECURSION_FORBIDDEN
+ eng "Recursion of EVENT DDL statements is forbidden when body is present"
ger "Rekursivität von EVENT-DDL-Anweisungen ist unzulässig wenn ein Hauptteil (Body) existiert"
ER_EVENTS_DB_ERROR
- eng "Cannot proceed because the tables used by events were found damaged at server start"
+ eng "Cannot proceed because system tables used by Event Scheduler were found damaged at server start"
ger "Kann nicht weitermachen, weil die Tabellen, die von Events verwendet werden, beim Serverstart als beschädigt markiert wurden"
ER_ONLY_INTEGERS_ALLOWED
eng "Only integers allowed as number here"
@@ -6004,18 +6007,61 @@ ER_BAD_LOG_STATEMENT
ger "Sie können eine Logtabelle nicht '%s', wenn Loggen angeschaltet ist"
ER_NON_INSERTABLE_TABLE
eng "The target table %-.100s of the %s is not insertable-into"
+ ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar"
ER_CANT_RENAME_LOG_TABLE
eng "Cannot rename '%s'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to '%s'"
+ ger "Kann '%s' nicht umbenennen. Wenn Loggen angeschaltet ist, müssen beim Umbenennen zu/von einer Logtabelle zwei Tabellen angegeben werden: die Logtabelle zu einer Archivtabelle und eine weitere Tabelle zurück zu '%s'"
ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000
- eng "Incorrect parameter count in the call to native function '%-.64s'"
+ eng "Incorrect parameter count in the call to native function '%-.192s'"
+ ger "Falsche Anzahl von Parametern beim Aufruf der nativen Funktion '%-.192s'"
ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000
- eng "Incorrect parameters in the call to native function '%-.64s'"
+ eng "Incorrect parameters in the call to native function '%-.192s'"
+ ger "Falscher Parameter beim Aufruf der nativen Funktion '%-.192s'"
ER_WRONG_PARAMETERS_TO_STORED_FCT 42000
- eng "Incorrect parameters in the call to stored function '%-.64s'"
+ eng "Incorrect parameters in the call to stored function '%-.192s'"
+ ger "Falsche Parameter beim Aufruf der gespeicherten Funktion '%-.192s'"
ER_NATIVE_FCT_NAME_COLLISION
- eng "This function '%-.64s' has the same name as a native function."
+ eng "This function '%-.192s' has the same name as a native function"
+ ger "Die Funktion '%-.192s' hat denselben Namen wie eine native Funktion"
+ER_DUP_ENTRY_WITH_KEY_NAME 23000 S1009
+ cze "Zvojen-Bý klíè '%-.64s' (èíslo klíèe '%-.192s')"
+ dan "Ens værdier '%-.64s' for indeks '%-.192s'"
+ nla "Dubbele ingang '%-.64s' voor zoeksleutel '%-.192s'"
+ eng "Duplicate entry '%-.64s' for key '%-.192s'"
+ jps "'%-.64s' ‚Í key '%-.192s' ‚É‚¨‚¢‚Äd•¡‚µ‚Ä‚¢‚Ü‚·",
+ est "Kattuv väärtus '%-.64s' võtmele '%-.192s'"
+ fre "Duplicata du champ '%-.64s' pour la clef '%-.192s'"
+ ger "Doppelter Eintrag '%-.64s' für Schlüssel '%-.192s'"
+ greek "ÄéðëÞ åããñáöÞ '%-.64s' ãéá ôï êëåéäß '%-.192s'"
+ hun "Duplikalt bejegyzes '%-.64s' a '%-.192s' kulcs szerint."
+ ita "Valore duplicato '%-.64s' per la chiave '%-.192s'"
+ jpn "'%-.64s' ¤Ï key '%-.192s' ¤Ë¤ª¤¤¤Æ½ÅÊ£¤·¤Æ¤¤¤Þ¤¹"
+ kor "Áߺ¹µÈ ÀÔ·Â °ª '%-.64s': key '%-.192s'"
+ nor "Like verdier '%-.64s' for nøkkel '%-.192s'"
+ norwegian-ny "Like verdiar '%-.64s' for nykkel '%-.192s'"
+ pol "Powtórzone wyst?pienie '%-.64s' dla klucza '%-.192s'"
+ por "Entrada '%-.64s' duplicada para a chave '%-.192s'"
+ rum "Cimpul '%-.64s' e duplicat pentru cheia '%-.192s'"
+ rus "äÕÂÌÉÒÕÀÝÁÑÓÑ ÚÁÐÉÓØ '%-.64s' ÐÏ ËÌÀÞÕ '%-.192s'"
+ serbian "Dupliran unos '%-.64s' za kljuè '%-.192s'"
+ slo "Opakovaný kµúè '%-.64s' (èíslo kµúèa '%-.192s')"
+ spa "Entrada duplicada '%-.64s' para la clave '%-.192s'"
+ swe "Dubbel nyckel '%-.64s' för nyckel '%-.192s'"
+ ukr "äÕÂÌÀÀÞÉÊ ÚÁÐÉÓ '%-.64s' ÄÌÑ ËÌÀÞÁ '%-.192s'"
ER_BINLOG_PURGE_EMFILE
eng "Too many files opened, please execute the command again"
+ ger "Zu viele offene Dateien, bitte führen Sie den Befehl noch einmal aus"
+ER_EVENT_CANNOT_CREATE_IN_THE_PAST
+ eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created"
+ER_EVENT_CANNOT_ALTER_IN_THE_PAST
+ eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been altered"
+ER_SLAVE_INCIDENT
+ eng "The incident %s occured on the master. Message: %-.64s"
+ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
+ eng "Table has no partition for some existing values"
+ER_BINLOG_UNSAFE_STATEMENT
+ eng "Statement is not safe to log in statement format."
+ swe "Detta är inte säkert att logga i statement-format."
ER_SLAVE_FATAL_ERROR
eng "Fatal error: %s"
ER_SLAVE_RELAY_LOG_READ_FAILURE
diff --git a/sql/slave.cc b/sql/slave.cc
index 2eb3557641c..f8b81ad8833 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,21 +17,26 @@
#include <mysql.h>
#include <myisam.h>
-#include "rpl_rli.h"
#include "slave.h"
+#include "rpl_mi.h"
+#include "rpl_rli.h"
#include "sql_repl.h"
#include "rpl_filter.h"
#include "repl_failsafe.h"
#include <thr_alarm.h>
#include <my_dir.h>
#include <sql_common.h>
+#include <errmsg.h>
#ifdef HAVE_REPLICATION
#include "rpl_tblmap.h"
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
+static Log_event* next_event(RELAY_LOG_INFO* rli);
+
+#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
#define MAX_SLAVE_RETRY_PAUSE 5
bool use_slave_mask = 0;
@@ -53,6 +57,7 @@ ulonglong relay_log_space_limit = 0;
*/
int disconnect_slave_event_count = 0, abort_slave_event_count = 0;
+int events_till_abort = -1;
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
@@ -73,6 +78,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
+static Log_event* next_event(RELAY_LOG_INFO* rli);
/*
Find out which replications threads are running
@@ -444,7 +450,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
#ifdef NOT_USED_YET
-static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
+static int end_slave_on_walk(MASTER_INFO* mi, uchar* /*unused*/)
{
DBUG_ENTER("end_slave_on_walk");
@@ -517,11 +523,11 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
really one minute of idleness, we don't timeout if the slave SQL thread
is actively working.
*/
- if (!rli->unsafe_to_stop_at)
+ if (rli->last_event_start_time == 0)
DBUG_RETURN(1);
DBUG_PRINT("info", ("Slave SQL thread is in an unsafe situation, giving "
"it some grace period"));
- if (difftime(time(0), rli->unsafe_to_stop_at) > 60)
+ if (difftime(time(0), rli->last_event_start_time) > 60)
{
rli->report(ERROR_LEVEL, 0,
"SQL thread had to stop in an unsafe situation, in "
@@ -550,7 +556,7 @@ void skip_load_data_infile(NET *net)
(void)net_request_file(net, "/dev/null");
(void)my_net_read(net); // discard response
- (void)net_write_command(net, 0, "", 0, "", 0); // Send ok
+ (void)net_write_command(net, 0, (uchar*) "", 0, (uchar*) "", 0); // ok
DBUG_VOID_RETURN;
}
@@ -558,7 +564,8 @@ void skip_load_data_infile(NET *net)
bool net_request_file(NET* net, const char* fname)
{
DBUG_ENTER("net_request_file");
- DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0));
+ DBUG_RETURN(net_write_command(net, 251, (uchar*) fname, strlen(fname),
+ (uchar*) "", 0));
}
/*
@@ -727,8 +734,10 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
else
{
mi->clock_diff_with_master= 0; /* The "most sensible" value */
- sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, \
-do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS");
+ sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, "
+ "do not trust column Seconds_Behind_Master of SHOW "
+ "SLAVE STATUS. Error: %s (%d)",
+ mysql_error(mysql), mysql_errno(mysql));
}
if (master_res)
mysql_free_result(master_res);
@@ -749,7 +758,7 @@ do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS");
{
if ((master_row= mysql_fetch_row(master_res)) &&
(::server_id == strtoul(master_row[1], 0, 10)) &&
- !replicate_same_server_id)
+ !mi->rli.replicate_same_server_id)
errmsg= "The slave I/O thread stops because master and slave have equal \
MySQL server ids; these ids must be different for replication to work (or \
the --replicate-same-server-id option must be used on slave but this does \
@@ -853,6 +862,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
handler *file;
ulonglong save_options;
NET *net= &mysql->net;
+ const char *found_semicolon= NULL;
DBUG_ENTER("create_table_from_dump");
packet_len= my_net_read(net); // read create table statement
@@ -904,7 +914,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
thd->db = (char*)db;
DBUG_ASSERT(thd->db != 0);
thd->db_length= strlen(thd->db);
- mysql_parse(thd, thd->query, packet_len); // run create table
+ mysql_parse(thd, thd->query, packet_len, &found_semicolon); // run create table
thd->db = save_db; // leave things the way the were before
thd->db_length= save_db_length;
thd->options = save_options;
@@ -1090,7 +1100,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi)
int register_slave_on_master(MYSQL* mysql, MASTER_INFO *mi)
{
- char buf[1024], *pos= buf;
+ uchar buf[1024], *pos= buf;
uint report_host_len, report_user_len=0, report_password_len=0;
DBUG_ENTER("register_slave_on_master");
@@ -1107,16 +1117,15 @@ int register_slave_on_master(MYSQL* mysql, MASTER_INFO *mi)
DBUG_RETURN(0); // safety
int4store(pos, server_id); pos+= 4;
- pos= net_store_data(pos, report_host, report_host_len);
- pos= net_store_data(pos, report_user, report_user_len);
- pos= net_store_data(pos, report_password, report_password_len);
+ pos= net_store_data(pos, (uchar*) report_host, report_host_len);
+ pos= net_store_data(pos, (uchar*) report_user, report_user_len);
+ pos= net_store_data(pos, (uchar*) report_password, report_password_len);
int2store(pos, (uint16) report_port); pos+= 2;
int4store(pos, rpl_recovery_rank); pos+= 4;
/* The master will fill in master_id */
int4store(pos, 0); pos+= 4;
- if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
- (uint) (pos- buf), 0))
+ if (simple_command(mysql, COM_REGISTER_SLAVE, buf, (size_t) (pos- buf), 0))
{
char buf[256];
my_snprintf(buf, sizeof(buf),
@@ -1190,6 +1199,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
sizeof(mi->ssl_key)));
field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10,
MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_empty_string("Master_SSL_Verify_Server_Cert",
+ 3));
field_list.push_back(new Item_return_int("Last_IO_Errno", 4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Last_IO_Error", 20));
field_list.push_back(new Item_return_int("Last_SQL_Errno", 4, MYSQL_TYPE_LONG));
@@ -1273,12 +1284,11 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
mi->rli.slave_running)
{
- long tmp= (long)((time_t)time((time_t*) 0)
- - mi->rli.last_master_timestamp)
- - mi->clock_diff_with_master;
+ long time_diff= ((long)(time(0) - mi->rli.last_master_timestamp)
+ - mi->clock_diff_with_master);
/*
- Apparently on some systems tmp can be <0. Here are possible reasons
- related to MySQL:
+ Apparently on some systems time_diff can be <0. Here are possible
+ reasons related to MySQL:
- the master is itself a slave of another master whose time is ahead.
- somebody used an explicit SET TIMESTAMP on the master.
Possible reason related to granularity-to-second of time functions
@@ -1296,11 +1306,14 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
special marker to say "consider we have caught up".
*/
- protocol->store((longlong)(mi->rli.last_master_timestamp ? max(0, tmp)
- : 0));
+ protocol->store((longlong)(mi->rli.last_master_timestamp ?
+ max(0, time_diff) : 0));
}
else
+ {
protocol->store_null();
+ }
+ protocol->store(mi->ssl_verify_server_cert? "Yes":"No", &my_charset_bin);
// Last_IO_Errno
protocol->store(mi->last_error.number);
@@ -1314,7 +1327,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
+ if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length()))
DBUG_RETURN(TRUE);
}
send_eof(thd);
@@ -1344,7 +1357,7 @@ void set_slave_thread_options(THD* thd)
DBUG_VOID_RETURN;
}
-void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO const *rli)
{
DBUG_ENTER("set_slave_thread_default_charset");
@@ -1355,7 +1368,14 @@ void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
thd->variables.collation_server=
global_system_variables.collation_server;
thd->update_charset();
- rli->cached_charset_invalidate();
+
+ /*
+ We use a const cast here since the conceptual (and externally
+ visible) behavior of the function is to set the default charset of
+ the thread. That the cache has to be invalidated is a secondary
+ effect.
+ */
+ const_cast<RELAY_LOG_INFO*>(rli)->cached_charset_invalidate();
DBUG_VOID_RETURN;
}
@@ -1377,13 +1397,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
*/
thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
+ MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */
- thd->net.read_timeout = slave_net_timeout;
thd->slave_thread = 1;
set_slave_thread_options(thd);
thd->client_capabilities = CLIENT_LOCAL_FILES;
- thd->real_id=pthread_self();
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id = thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
if (init_thr_lock() || thd->store_globals())
@@ -1393,12 +1411,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
DBUG_RETURN(-1);
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
if (thd_type == SLAVE_THD_SQL)
thd->proc_info= "Waiting for the next event in relay log";
else
@@ -1443,7 +1455,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
bool *suppress_warnings)
{
- char buf[FN_REFLEN + 10];
+ uchar buf[FN_REFLEN + 10];
int len;
int binlog_flags = 0; // for now
char* logname = mi->master_log_name;
@@ -1477,10 +1489,9 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
{
- char buf[1024];
+ uchar buf[1024], *p = buf;
DBUG_ENTER("request_table_dump");
- char * p = buf;
uint table_len = (uint) strlen(table);
uint db_len = (uint) strlen(db);
if (table_len + db_len > sizeof(buf) - 2)
@@ -1571,13 +1582,15 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
}
-int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
+int check_expected_error(THD* thd, RELAY_LOG_INFO const *rli,
+ int expected_error)
{
DBUG_ENTER("check_expected_error");
switch (expected_error) {
case ER_NET_READ_ERROR:
case ER_NET_ERROR_ON_WRITE:
+ case ER_QUERY_INTERRUPTED:
case ER_SERVER_SHUTDOWN:
case ER_NEW_ABORTING_CONNECTION:
DBUG_RETURN(1);
@@ -1676,78 +1689,44 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
}
if (ev)
{
- int type_code = ev->get_type_code();
- int exec_res;
+ int const type_code= ev->get_type_code();
+ int exec_res= 0;
/*
- Queries originating from this server must be skipped.
- Low-level events (Format_desc, Rotate, Stop) from this server
- must also be skipped. But for those we don't want to modify
- group_master_log_pos, because these events did not exist on the master.
- Format_desc is not completely skipped.
- Skip queries specified by the user in slave_skip_counter.
- We can't however skip events that has something to do with the
- log files themselves.
- Filtering on own server id is extremely important, to ignore execution of
- events created by the creation/rotation of the relay log (remember that
- now the relay log starts with its Format_desc, has a Rotate etc).
*/
- DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id));
+ DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
+ ev->get_type_str(), type_code, ev->server_id));
+ DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
+ FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
+ FLAGSTR(thd->options, OPTION_BEGIN),
+ rli->last_event_start_time));
- if ((ev->server_id == (uint32) ::server_id &&
- !replicate_same_server_id &&
- type_code != FORMAT_DESCRIPTION_EVENT) ||
- (rli->slave_skip_counter &&
- type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
- type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
- {
- DBUG_PRINT("info", ("event skipped"));
- /*
- We only skip the event here and do not increase the group log
- position. In the event that we have to restart, this means
- that we might have to skip the event again, but that is a
- minor issue.
-
- If we were to increase the group log position when skipping an
- event, it might be that we are restarting at the wrong
- position and have events before that we should have executed,
- so not increasing the group log position is a sure bet in this
- case.
-
- In this way, we just step the group log position when we
- *know* that we are at the end of a group.
- */
- rli->inc_event_relay_log_pos();
- /*
- Protect against common user error of setting the counter to 1
- instead of 2 while recovering from an insert which used auto_increment,
- rand or user var.
- */
- if (rli->slave_skip_counter &&
- !((type_code == INTVAR_EVENT ||
- type_code == RAND_EVENT ||
- type_code == USER_VAR_EVENT) &&
- rli->slave_skip_counter == 1) &&
- /*
- The events from ourselves which have something to do with the relay
- log itself must be skipped, true, but they mustn't decrement
- rli->slave_skip_counter, because the user is supposed to not see
- these events (they are not in the master's binlog) and if we
- decremented, START SLAVE would for example decrement when it sees
- the Rotate, so the event which the user probably wanted to skip
- would not be skipped.
- */
- !(ev->server_id == (uint32) ::server_id &&
- (type_code == ROTATE_EVENT || type_code == STOP_EVENT ||
- type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT)))
- --rli->slave_skip_counter;
- pthread_mutex_unlock(&rli->data_lock);
- delete ev;
- DBUG_RETURN(0); // avoid infinite update loops
- }
- pthread_mutex_unlock(&rli->data_lock);
+
+ /*
+ Execute the event to change the database and update the binary
+ log coordinates, but first we set some data that is needed for
+ the thread.
+
+ The event will be executed unless it is supposed to be skipped.
+
+ Queries originating from this server must be skipped. Low-level
+ events (Format_description_log_event, Rotate_log_event,
+ Stop_log_event) from this server must also be skipped. But for
+ those we don't want to modify 'group_master_log_pos', because
+ these events did not exist on the master.
+ Format_description_log_event is not completely skipped.
+
+ Skip queries specified by the user in 'slave_skip_counter'. We
+ can't however skip events that has something to do with the log
+ files themselves.
+
+ Filtering on own server id is extremely important, to ignore
+ execution of events created by the creation/rotation of the relay
+ log (remember that now the relay log starts with its Format_desc,
+ has a Rotate etc).
+ */
thd->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query
@@ -1755,15 +1734,69 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (!ev->when)
ev->when = time(NULL);
ev->thd = thd; // because up to this point, ev->thd == 0
- exec_res = ev->exec_event(rli);
- DBUG_PRINT("info", ("exec_event result: %d", exec_res));
- DBUG_ASSERT(rli->sql_thd==thd);
+
+ int reason= ev->shall_skip(rli);
+ if (reason == Log_event::EVENT_SKIP_COUNT)
+ --rli->slave_skip_counter;
+ pthread_mutex_unlock(&rli->data_lock);
+ if (reason == Log_event::EVENT_SKIP_NOT)
+ exec_res= ev->apply_event(rli);
+#ifndef DBUG_OFF
+ /*
+ This only prints information to the debug trace.
+
+ TODO: Print an informational message to the error log?
+ */
+ static const char *const explain[] = {
+ // EVENT_SKIP_NOT,
+ "not skipped",
+ // EVENT_SKIP_IGNORE,
+ "skipped because event originated from this server",
+ // EVENT_SKIP_COUNT
+ "skipped because event skip counter was non-zero"
+ };
+ DBUG_PRINT("skip_event", ("%s event was %s",
+ ev->get_type_str(), explain[reason]));
+#endif
+
+ DBUG_PRINT("info", ("apply_event error = %d", exec_res));
+ if (exec_res == 0)
+ {
+ int error= ev->update_pos(rli);
+ char buf[22];
+ DBUG_PRINT("info", ("update_pos error = %d", error));
+ DBUG_PRINT("info", ("group %s %s",
+ llstr(rli->group_relay_log_pos, buf),
+ rli->group_relay_log_name));
+ DBUG_PRINT("info", ("event %s %s",
+ llstr(rli->event_relay_log_pos, buf),
+ rli->event_relay_log_name));
+ /*
+ The update should not fail, so print an error message and
+ return an error code.
+
+ TODO: Replace this with a decent error message when merged
+ with BUG#24954 (which adds several new error message).
+ */
+ if (error)
+ {
+ slave_print_msg(ERROR_LEVEL, rli, ER_UNKNOWN_ERROR,
+ "It was not possible to update the positions"
+ " of the relay log information: the slave may"
+ " be in an inconsistent state."
+ " Stopped in %s position %s",
+ rli->group_relay_log_name,
+ llstr(rli->group_relay_log_pos, buf));
+ DBUG_RETURN(1);
+ }
+ }
+
/*
Format_description_log_event should not be deleted because it will be
used to read info about the relay log's format; it will be deleted when
the SQL thread does not need it, i.e. when this thread terminates.
*/
- if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
+ if (type_code != FORMAT_DESCRIPTION_EVENT)
{
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
delete ev;
@@ -1940,12 +1973,13 @@ connected:
{
/*
Register ourselves with the master.
- If fails, this is not fatal - we just print the error message and go
- on with life.
*/
thd->proc_info = "Registering slave on master";
- if (register_slave_on_master(mysql, mi) || update_slave_list(mysql, mi))
+ if (register_slave_on_master(mysql, mi))
+ {
+ sql_print_error("Slave I/O thread couldn't register on master");
goto err;
+ }
}
DBUG_PRINT("info",("Starting reading binary log from master"));
@@ -2012,15 +2046,16 @@ after reconnect");
while (!io_slave_killed(thd,mi))
{
- bool suppress_warnings= 0;
+ ulong event_len;
+ suppress_warnings= 0;
/*
We say "waiting" because read_event() will wait if there's nothing to
read. But if there's something to read, it will not wait. The
important thing is to not confuse users by saying "reading" whereas
we're in fact receiving nothing.
*/
- thd->proc_info = "Waiting for master to send event";
- ulong event_len = read_event(mysql, mi, &suppress_warnings);
+ thd->proc_info= "Waiting for master to send event";
+ event_len= read_event(mysql, mi, &suppress_warnings);
if (io_slave_killed(thd,mi))
{
if (global_system_variables.log_warnings)
@@ -2031,7 +2066,7 @@ after reconnect");
if (event_len == packet_error)
{
uint mysql_error_number= mysql_errno(mysql);
- if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
+ if (mysql_error_number == CR_NET_PACKET_TOO_LARGE)
{
sql_print_error("\
Log entry on master is longer than max_allowed_packet (%ld) on \
@@ -2173,11 +2208,16 @@ err:
THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
- mi->abort_slave = 0;
- mi->slave_running = 0;
- mi->io_thd = 0;
- pthread_mutex_unlock(&mi->run_lock);
+ mi->abort_slave= 0;
+ mi->slave_running= 0;
+ mi->io_thd= 0;
+ /*
+ Note: the order of the two following calls (first broadcast, then unlock)
+ is important. Otherwise a killer_thread can execute between the calls and
+ delete the mi structure leading to a crash! (see BUG#25306 for details)
+ */
pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
+ pthread_mutex_unlock(&mi->run_lock);
my_thread_end();
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
@@ -2328,6 +2368,7 @@ Slave SQL thread aborted. Can't execute init_slave query");
THD_CHECK_SENTRY(thd);
if (exec_relay_log_event(thd,rli))
{
+ DBUG_PRINT("info", ("exec_relay_log_event() failed"));
// do not scare the user if SQL thread was simply killed or stopped
if (!sql_slave_killed(thd,rli))
{
@@ -2338,6 +2379,8 @@ Slave SQL thread aborted. Can't execute init_slave query");
*/
uint32 const last_errno= rli->last_error.number;
+ DBUG_PRINT("info", ("thd->net.last_errno=%d; rli->last_error.number=%d",
+ thd->net.last_errno, last_errno));
if (thd->net.last_errno != 0)
{
char const *const errmsg=
@@ -2356,10 +2399,25 @@ Slave SQL thread aborted. Can't execute init_slave query");
/* Print any warnings issued */
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
MYSQL_ERROR *err;
+ /*
+ Added controlled slave thread cancel for replication
+ of user-defined variables.
+ */
+ bool udf_error = false;
while ((err= it++))
+ {
+ if (err->code == ER_CANT_OPEN_LIBRARY)
+ udf_error = true;
sql_print_warning("Slave: %s Error_code: %d",err->msg, err->code);
-
- sql_print_error("\
+ }
+ if (udf_error)
+ sql_print_error("Error loading user-defined library, slave SQL "
+ "thread aborted. Install the missing library, and restart the "
+ "slave SQL thread with \"SLAVE START\". We stopped at log '%s' "
+ "position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos,
+ llbuff));
+ else
+ sql_print_error("\
Error running query, slave SQL thread aborted. Fix the problem, and restart \
the slave SQL thread with \"SLAVE START\". We stopped at log \
'%s' position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
@@ -2424,9 +2482,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
+ /*
+ Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
+ is important. Otherwise a killer_thread can execute between the calls and
+ delete the mi structure leading to a crash! (see BUG#25306 for details)
+ */
pthread_cond_broadcast(&rli->stop_cond);
- // tell the world we are done
- pthread_mutex_unlock(&rli->run_lock);
+ pthread_mutex_unlock(&rli->run_lock); // tell the world we are done
+
my_thread_end();
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
@@ -2484,7 +2547,8 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
}
if (unlikely(!num_bytes)) /* eof */
{
- net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
+ /* 3.23 master wants it */
+ net_write_command(net, 0, (uchar*) "", 0, (uchar*) "", 0);
/*
If we wrote Create_file_log_event, then we need to write
Execute_load_log_event. If we did not write Create_file_log_event,
@@ -2661,6 +2725,7 @@ static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf,
my_free((char*) tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN(1);
}
+
pthread_mutex_lock(&mi->data_lock);
ev->log_pos= mi->master_log_pos; /* 3.23 events don't contain log_pos */
switch (ev->get_type_code()) {
@@ -2828,6 +2893,8 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
DBUG_ENTER("queue_event");
+ LINT_INIT(inc_pos);
+
if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
DBUG_RETURN(queue_old_event(mi,buf,event_len));
@@ -2922,7 +2989,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
pthread_mutex_lock(log_lock);
if ((uint4korr(buf + SERVER_ID_OFFSET) == ::server_id) &&
- !replicate_same_server_id)
+ !mi->rli.replicate_same_server_id)
{
/*
Do not write it to the relay log.
@@ -2969,7 +3036,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
err:
pthread_mutex_unlock(&mi->data_lock);
- DBUG_PRINT("info", ("error=%d", error));
+ DBUG_PRINT("info", ("error: %d", error));
DBUG_RETURN(error);
}
@@ -3056,12 +3123,16 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
#ifdef HAVE_OPENSSL
if (mi->ssl)
+ {
mysql_ssl_set(mysql,
mi->ssl_key[0]?mi->ssl_key:0,
mi->ssl_cert[0]?mi->ssl_cert:0,
mi->ssl_ca[0]?mi->ssl_ca:0,
mi->ssl_capath[0]?mi->ssl_capath:0,
mi->ssl_cipher[0]?mi->ssl_cipher:0);
+ mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ &mi->ssl_verify_server_cert);
+ }
#endif
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
@@ -3194,7 +3265,7 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
*pos++='\n';
pos=longlong2str(rli->group_master_log_pos, pos, 10);
*pos='\n';
- if (my_b_write(file, (byte*) buff, (ulong) (pos-buff)+1))
+ if (my_b_write(file, (uchar*) buff, (size_t) (pos-buff)+1))
error=1;
if (flush_io_cache(file))
error=1;
@@ -3287,7 +3358,13 @@ static Log_event* next_event(RELAY_LOG_INFO* rli)
hot_log=0; // Using old binary log
}
}
-
+ /*
+ As there is no guarantee that the relay is open (for example, an I/O
+ error during a write by the slave I/O thread may have closed it), we
+ have to test it.
+ */
+ if (!my_b_inited(cur_log))
+ goto err;
#ifndef DBUG_OFF
{
/* This is an assertion which sometimes fails, let's try to track it */
@@ -3616,6 +3693,70 @@ end:
}
+/**
+ Detects, based on master's version (as found in the relay log), if master
+ has a certain bug.
+ @param rli RELAY_LOG_INFO which tells the master's version
+ @param bug_id Number of the bug as found in bugs.mysql.com
+ @return TRUE if master has the bug, FALSE if it does not.
+*/
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id)
+{
+ struct st_version_range_for_one_bug {
+ uint bug_id;
+ const uchar introduced_in[3]; // first version with bug
+ const uchar fixed_in[3]; // first version with fix
+ };
+ static struct st_version_range_for_one_bug versions_for_all_bugs[]=
+ {
+ {24432, { 5, 0, 24 }, { 5, 0, 38 } },
+ {24432, { 5, 1, 12 }, { 5, 1, 17 } }
+ };
+ const uchar *master_ver=
+ rli->relay_log.description_event_for_exec->server_version_split;
+
+ DBUG_ASSERT(sizeof(rli->relay_log.description_event_for_exec->server_version_split) == 3);
+
+ for (uint i= 0;
+ i < sizeof(versions_for_all_bugs)/sizeof(*versions_for_all_bugs);i++)
+ {
+ const uchar *introduced_in= versions_for_all_bugs[i].introduced_in,
+ *fixed_in= versions_for_all_bugs[i].fixed_in;
+ if ((versions_for_all_bugs[i].bug_id == bug_id) &&
+ (memcmp(introduced_in, master_ver, 3) <= 0) &&
+ (memcmp(fixed_in, master_ver, 3) > 0))
+ {
+ // a short message for SHOW SLAVE STATUS (message length constraints)
+ my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " so slave stops; check error log on slave"
+ " for more info", MYF(0), bug_id);
+ // a verbose message for the error log
+ slave_print_msg(ERROR_LEVEL, rli, ER_UNKNOWN_ERROR,
+ "According to the master's version ('%s'),"
+ " it is probable that master suffers from this bug:"
+ " http://bugs.mysql.com/bug.php?id=%u"
+ " and thus replicating the current binary log event"
+ " may make the slave's data become different from the"
+ " master's data."
+ " To take no risk, slave refuses to replicate"
+ " this event and stops."
+ " We recommend that all updates be stopped on the"
+ " master and slave, that the data of both be"
+ " manually synchronized,"
+ " that master's binary logs be deleted,"
+ " that master be upgraded to a version at least"
+ " equal to '%d.%d.%d'. Then replication can be"
+ " restarted.",
+ rli->relay_log.description_event_for_exec->server_version,
+ bug_id,
+ fixed_in[0], fixed_in[1], fixed_in[2]);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
diff --git a/sql/slave.h b/sql/slave.h
index 078a98735ef..731728bde4f 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,13 +22,18 @@
#include "my_list.h"
#include "rpl_filter.h"
#include "rpl_tblmap.h"
-#include "rpl_rli.h"
-#include "rpl_mi.h"
#define SLAVE_NET_TIMEOUT 3600
#define MAX_SLAVE_ERROR 2000
+
+// Forward declarations
+struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
+
+class MASTER_INFO;
+
/*****************************************************************************
MySQL Replication
@@ -90,9 +94,9 @@
extern ulong master_retry_count;
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
-extern char* slave_load_tmpdir;
-extern my_string master_info_file,relay_log_info_file;
-extern my_string opt_relay_logname, opt_relaylog_index_name;
+extern char *slave_load_tmpdir;
+extern char *master_info_file, *relay_log_info_file;
+extern char *opt_relay_logname, *opt_relaylog_index_name;
extern my_bool opt_skip_slave_start, opt_reckless_slave;
extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
@@ -112,8 +116,6 @@ extern ulonglong relay_log_space_limit;
#define MYSQL_SLAVE_RUN_NOT_CONNECT 1
#define MYSQL_SLAVE_RUN_CONNECT 2
-static Log_event* next_event(RELAY_LOG_INFO* rli);
-
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
@@ -162,9 +164,10 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
bool show_master_info(THD* thd, MASTER_INFO* mi);
bool show_binlog_info(THD* thd);
+bool rpl_master_has_bug(RELAY_LOG_INFO *rli, uint bug_id);
const char *print_slave_db_safe(const char *db);
-int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
+int check_expected_error(THD* thd, RELAY_LOG_INFO const *rli, int error_code);
void skip_load_data_infile(NET* net);
void end_slave(); /* clean up */
@@ -181,7 +184,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg);
void set_slave_thread_options(THD* thd);
-void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli);
+void set_slave_thread_default_charset(THD *thd, RELAY_LOG_INFO const *rli);
void rotate_relay_log(MASTER_INFO* mi);
pthread_handler_t handle_slave_io(void *arg);
@@ -195,13 +198,13 @@ extern int disconnect_slave_event_count, abort_slave_event_count ;
/* the master variables are defaults read from my.cnf or command line */
extern uint master_port, master_connect_retry, report_port;
-extern my_string master_user, master_password, master_host,
- master_info_file, relay_log_info_file, report_user, report_host,
- report_password;
+extern char * master_user, *master_password, *master_host;
+extern char *master_info_file, *relay_log_info_file, *report_user;
+extern char *report_host, *report_password;
extern my_bool master_ssl;
-extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert,
- master_ssl_cipher, master_ssl_key;
+extern char *master_ssl_ca, *master_ssl_capath, *master_ssl_cert;
+extern char *master_ssl_cipher, *master_ssl_key;
extern I_List<THD> threads;
diff --git a/sql/sp.cc b/sql/sp.cc
index 9e53aff742e..49e86f9d07e 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -48,7 +47,7 @@ enum
{
MYSQL_PROC_FIELD_DB = 0,
MYSQL_PROC_FIELD_NAME,
- MYSQL_PROC_FIELD_TYPE,
+ MYSQL_PROC_MYSQL_TYPE,
MYSQL_PROC_FIELD_SPECIFIC_NAME,
MYSQL_PROC_FIELD_LANGUAGE,
MYSQL_PROC_FIELD_ACCESS,
@@ -70,24 +69,6 @@ enum
/*
- Close mysql.proc, opened with open_proc_table_for_read().
-
- SYNOPSIS
- close_proc_table()
- thd Thread context
- backup Pointer to Open_tables_state instance which holds
- information about tables which were open before we
- decided to access mysql.proc.
-*/
-
-void close_proc_table(THD *thd, Open_tables_state *backup)
-{
- close_thread_tables(thd);
- thd->restore_backup_open_tables_state(backup);
-}
-
-
-/*
Open the mysql.proc table for read.
SYNOPSIS
@@ -97,13 +78,6 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
currently open tables will be saved, and from which will be
restored when we will end work with mysql.proc.
- NOTES
- Thanks to restrictions which we put on opening and locking of
- this table for writing, we can open and lock it for reading
- even when we already have some other tables open and locked.
- One must call close_proc_table() to close table opened with
- this call.
-
RETURN
0 Error
# Pointer to TABLE object of mysql.proc
@@ -111,38 +85,18 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
{
- TABLE_LIST tables;
- TABLE *table;
- bool not_used;
- DBUG_ENTER("open_proc_table");
+ DBUG_ENTER("open_proc_table_for_read");
- thd->reset_n_backup_open_tables_state(backup);
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
- if (!(table= open_table(thd, &tables, thd->mem_root, &not_used,
- MYSQL_LOCK_IGNORE_FLUSH)))
- {
- thd->restore_backup_open_tables_state(backup);
- DBUG_RETURN(0);
- }
- table->use_all_columns();
-
- DBUG_ASSERT(table->s->system_table);
+ TABLE_LIST table;
+ bzero((char*) &table, sizeof(table));
+ table.db= (char*) "mysql";
+ table.table_name= table.alias= (char*)"proc";
+ table.lock_type= TL_READ;
- table->reginfo.lock_type= TL_READ;
- /*
- We have to ensure we are not blocked by a flush tables, as this
- could lead to a deadlock if we have other tables opened.
- */
- if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
- MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
- {
- close_proc_table(thd, backup);
+ if (!open_system_tables_for_read(thd, &table, backup))
+ DBUG_RETURN(table.table);
+ else
DBUG_RETURN(0);
- }
- DBUG_RETURN(table);
}
@@ -163,20 +117,15 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
static TABLE *open_proc_table_for_update(THD *thd)
{
- TABLE_LIST tables;
- TABLE *table;
- DBUG_ENTER("open_proc_table");
+ DBUG_ENTER("open_proc_table_for_update");
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
- tables.lock_type= TL_WRITE;
-
- table= open_ltable(thd, &tables, TL_WRITE);
- if (table)
- table->use_all_columns();
+ TABLE_LIST table;
+ bzero((char*) &table, sizeof(table));
+ table.db= (char*) "mysql";
+ table.table_name= table.alias= (char*)"proc";
+ table.lock_type= TL_WRITE;
- DBUG_RETURN(table);
+ DBUG_RETURN(open_system_table_for_update(thd, &table));
}
@@ -198,10 +147,10 @@ static TABLE *open_proc_table_for_update(THD *thd)
static int
db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
{
- byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
+ uchar key[MAX_KEY_LENGTH]; // db, name, optional key length type
DBUG_ENTER("db_find_routine_aux");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
+ type, (int) name->m_name.length, name->m_name.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -219,8 +168,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0], 0,
- key, table->key_info->key_length,
+ if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
DBUG_RETURN(SP_KEY_NOT_FOUND);
@@ -267,7 +215,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
Open_tables_state open_tables_state_backup;
DBUG_ENTER("db_find_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ type, (int) name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors
if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
@@ -365,7 +313,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
chistics.comment.str= ptr;
chistics.comment.length= length;
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
table= 0;
ret= db_load_routine(thd, type, name, sphp,
@@ -374,7 +322,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
done:
if (table)
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
DBUG_RETURN(ret);
}
@@ -436,21 +384,26 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
if ((ret= sp_use_new_db(thd, name->m_db, &old_db, 1, &dbchanged)))
goto end;
- lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
+ {
+ Lex_input_stream lip(thd, defstr.c_ptr(), defstr.length());
+ thd->m_lip= &lip;
+ lex_start(thd);
+ ret= MYSQLparse(thd);
+ }
thd->spcont= 0;
- if (MYSQLparse(thd) || thd->is_fatal_error || newlex.sphead == NULL)
+ if (ret || thd->is_fatal_error || newlex.sphead == NULL)
{
sp_head *sp= newlex.sphead;
- if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
goto end;
delete sp;
ret= SP_PARSE_ERROR;
}
else
{
- if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
goto end;
*sphp= newlex.sphead;
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
@@ -489,18 +442,43 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
delete field;
}
-static int
-db_create_routine(THD *thd, int type, sp_head *sp)
+
+/**
+ Write stored-routine object into mysql.proc.
+
+ This operation stores attributes of the stored procedure/function into
+ the mysql.proc.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION).
+ @param sp Stored routine object to store.
+
+ @return Error code. SP_OK is returned on success. Other SP_ constants are
+ used to indicate about errors.
+*/
+
+int
+sp_create_routine(THD *thd, int type, sp_head *sp)
{
int ret;
TABLE *table;
char definer[USER_HOST_BUFF_SIZE];
- char old_db_buf[NAME_LEN+1];
- LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
- DBUG_ENTER("db_create_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length,
+
+ DBUG_ENTER("sp_create_routine");
+ DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length,
sp->m_name.str));
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if (!(table= open_proc_table_for_update(thd)))
ret= SP_OPEN_TABLE_FAILED;
else
@@ -534,7 +512,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
store(sp->m_db.str, sp->m_db.length, system_charset_info);
table->field[MYSQL_PROC_FIELD_NAME]->
store(sp->m_name.str, sp->m_name.length, system_charset_info);
- table->field[MYSQL_PROC_FIELD_TYPE]->
+ table->field[MYSQL_PROC_MYSQL_TYPE]->
store((longlong)type, TRUE);
table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]->
store(sp->m_name.str, sp->m_name.length, system_charset_info);
@@ -628,14 +606,39 @@ done:
}
-static int
-db_drop_routine(THD *thd, int type, sp_name *name)
+/**
+ Delete the record for the stored routine object from mysql.proc.
+
+ The operation deletes the record for the stored routine specified by name
+ from the mysql.proc table and invalidates the stored-routine cache.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param name Stored routine name.
+
+ @return Error code. SP_OK is returned on success. Other SP_ constants are
+ used to indicate about errors.
+*/
+
+int
+sp_drop_routine(THD *thd, int type, sp_name *name)
{
TABLE *table;
int ret;
- DBUG_ENTER("db_drop_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ DBUG_ENTER("sp_drop_routine");
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
+ type, (int) name->m_name.length, name->m_name.str));
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
@@ -653,6 +656,8 @@ db_drop_routine(THD *thd, int type, sp_name *name)
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
thd->query, thd->query_length, FALSE, FALSE);
}
+
+ sp_cache_invalidate();
}
close_thread_tables(thd);
@@ -660,14 +665,40 @@ db_drop_routine(THD *thd, int type, sp_name *name)
}
-static int
-db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
+/**
+ Find and updated the record for the stored routine object in mysql.proc.
+
+ The operation finds the record for the stored routine specified by name
+ in the mysql.proc table and updates it with new attributes. After
+ successful update, the cache is invalidated.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param name Stored routine name.
+ @param chistics New values of stored routine attributes to write.
+
+ @return Error code. SP_OK is returned on success. Other SP_ constants are
+ used to indicate about errors.
+*/
+
+int
+sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
{
TABLE *table;
int ret;
- DBUG_ENTER("db_update_routine");
- DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ DBUG_ENTER("sp_update_routine");
+ DBUG_PRINT("enter", ("type: %d name: %.*s",
+ type, (int) name->m_name.length, name->m_name.str));
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
if (!(table= open_proc_table_for_update(thd)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
@@ -698,6 +729,8 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
thd->query, thd->query_length, FALSE, FALSE);
}
+
+ sp_cache_invalidate();
}
close_thread_tables(thd);
@@ -715,15 +748,15 @@ struct st_used_field
static struct st_used_field init_fields[]=
{
- { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { "Type", 9, MYSQL_TYPE_STRING, 0},
- { "Definer", 77, MYSQL_TYPE_STRING, 0},
- { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0},
- { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0},
- { "Security_type", 1, MYSQL_TYPE_STRING, 0},
- { "Comment", NAME_LEN, MYSQL_TYPE_STRING, 0},
- { 0, 0, MYSQL_TYPE_STRING, 0}
+ { "Db", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0},
+ { "Name", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0},
+ { "Type", 9, MYSQL_TYPE_STRING, 0},
+ { "Definer", 77, MYSQL_TYPE_STRING, 0},
+ { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0},
+ { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0},
+ { "Security_type", 1, MYSQL_TYPE_STRING, 0},
+ { "Comment", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0},
+ { 0, 0, MYSQL_TYPE_STRING, 0}
};
@@ -734,7 +767,7 @@ print_field_values(THD *thd, TABLE *table,
{
Protocol *protocol= thd->protocol;
- if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type)
+ if (table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == type)
{
String db_string;
String name_string;
@@ -757,7 +790,7 @@ print_field_values(THD *thd, TABLE *table,
switch (used_field->field_type) {
case MYSQL_TYPE_TIMESTAMP:
{
- TIME tmp_time;
+ MYSQL_TIME tmp_time;
bzero((char *)&tmp_time, sizeof(tmp_time));
((Field_timestamp *) used_field->field)->get_time(&tmp_time);
@@ -783,13 +816,28 @@ print_field_values(THD *thd, TABLE *table,
}
-static int
-db_show_routine_status(THD *thd, int type, const char *wild)
+/**
+ Implement SHOW STATUS statement for stored routines.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param name_pattern Stored routine name pattern.
+
+ @return Error code. SP_OK is returned on success. Other SP_ constants are
+ used to indicate about errors.
+*/
+
+int
+sp_show_status_routine(THD *thd, int type, const char *name_pattern)
{
TABLE *table;
TABLE_LIST tables;
int res;
- DBUG_ENTER("db_show_routine_status");
+ DBUG_ENTER("sp_show_status_routine");
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
@@ -817,12 +865,14 @@ db_show_routine_status(THD *thd, int type, const char *wild)
{
switch (used_field->field_type) {
case MYSQL_TYPE_TIMESTAMP:
- field_list.push_back(item=new Item_datetime(used_field->field_name));
+ item= new Item_return_date_time(used_field->field_name,
+ MYSQL_TYPE_DATETIME);
+ field_list.push_back(item);
break;
default:
- field_list.push_back(item=new Item_empty_string(used_field->field_name,
- used_field->
- field_length));
+ item= new Item_empty_string(used_field->field_name,
+ used_field->field_length);
+ field_list.push_back(item);
break;
}
}
@@ -866,13 +916,16 @@ db_show_routine_status(THD *thd, int type, const char *wild)
res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR;
goto err_case1;
}
- if ((res= print_field_values(thd, table, used_fields, type, wild)))
- goto err_case1;
- while (!table->file->index_next(table->record[0]))
+
+ do
{
- if ((res= print_field_values(thd, table, used_fields, type, wild)))
+ res= print_field_values(thd, table, used_fields, type, name_pattern);
+
+ if (res)
goto err_case1;
}
+ while (!table->file->index_next(table->record[0]));
+
res= SP_OK;
}
@@ -906,8 +959,8 @@ sp_drop_db_routines(THD *thd, char *db)
ret= SP_OK;
table->file->ha_index_init(0, 1);
if (! table->file->index_read(table->record[0],
- (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
- key_len, HA_READ_KEY_EXACT))
+ (uchar *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ (key_part_map)1, HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;
@@ -923,7 +976,7 @@ sp_drop_db_routines(THD *thd, char *db)
break;
}
} while (! (nxtres= table->file->index_next_same(table->record[0],
- (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
+ (uchar *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
key_len)));
if (nxtres != HA_ERR_END_OF_FILE)
ret= SP_KEY_NOT_FOUND;
@@ -939,9 +992,62 @@ err:
}
-/*****************************************************************************
- PROCEDURE
-******************************************************************************/
+/**
+ Implement SHOW CREATE statement for stored routines.
+
+ The operation finds the stored routine object specified by name and then
+ calls sp_head::show_create_routine() for the object.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+ @param name Stored routine name.
+
+ @return Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+
+bool
+sp_show_create_routine(THD *thd, int type, sp_name *name)
+{
+ bool err_status= TRUE;
+ sp_head *sp;
+ sp_cache **cache = type == TYPE_ENUM_PROCEDURE ?
+ &thd->sp_proc_cache : &thd->sp_func_cache;
+
+ DBUG_ENTER("sp_show_create_routine");
+ DBUG_PRINT("enter", ("name: %.*s",
+ (int) name->m_name.length,
+ name->m_name.str));
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
+
+ if (type == TYPE_ENUM_PROCEDURE)
+ {
+ /*
+ SHOW CREATE PROCEDURE may require two instances of one sp_head
+ object when SHOW CREATE PROCEDURE is called for the procedure that
+ is being executed. Basically, there is no actual recursion, so we
+ increase the recursion limit for this statement (kind of hack).
+
+ SHOW CREATE FUNCTION does not require this because SHOW CREATE
+ statements are prohibitted within stored functions.
+ */
+
+ thd->variables.max_sp_recursion_depth++;
+ }
+
+ if ((sp= sp_find_routine(thd, type, name, cache, FALSE)))
+ err_status= sp->show_create_routine(thd, type);
+
+ if (type == TYPE_ENUM_PROCEDURE)
+ thd->variables.max_sp_recursion_depth--;
+
+ DBUG_RETURN(err_status);
+}
+
/*
Obtain object representing stored procedure/function by its name from
@@ -970,9 +1076,9 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
thd->variables.max_sp_recursion_depth :
0);
DBUG_ENTER("sp_find_routine");
- DBUG_PRINT("enter", ("name: %.*s.%.*s, type: %d, cache only %d",
- name->m_db.length, name->m_db.str,
- name->m_name.length, name->m_name.str,
+ DBUG_PRINT("enter", ("name: %.*s.%.*s type: %d cache only %d",
+ (int) name->m_db.length, name->m_db.str,
+ (int) name->m_name.length, name->m_name.str,
type, cache_only));
if ((sp= sp_cache_lookup(cp, name)))
@@ -991,7 +1097,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
if (sp->m_first_free_instance)
{
- DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x",
+ DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x",
(ulong)sp->m_first_free_instance,
sp->m_first_free_instance->m_recursion_level,
sp->m_first_free_instance->m_flags));
@@ -1074,7 +1180,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
lex_name.length= strlen(routine->table_name);
lex_db.str= thd->strmake(routine->db, lex_db.length);
lex_name.str= thd->strmake(routine->table_name, lex_name.length);
- name= new sp_name(lex_db, lex_name);
+ name= new sp_name(lex_db, lex_name, true);
name->init_qname(thd);
sp_object_found= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name,
&thd->sp_proc_cache, FALSE) != NULL ||
@@ -1129,157 +1235,12 @@ sp_routine_exists_in_table(THD *thd, int type, sp_name *name)
{
if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
ret= SP_KEY_NOT_FOUND;
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
}
return ret;
}
-int
-sp_create_procedure(THD *thd, sp_head *sp)
-{
- int ret;
- DBUG_ENTER("sp_create_procedure");
- DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
-
- ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp);
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_drop_procedure(THD *thd, sp_name *name)
-{
- int ret;
- DBUG_ENTER("sp_drop_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
-{
- int ret;
- DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_create_procedure(THD *thd, sp_name *name)
-{
- int ret= SP_KEY_NOT_FOUND;
- sp_head *sp;
- DBUG_ENTER("sp_show_create_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- /*
- Increase the recursion limit for this statement. SHOW CREATE PROCEDURE
- does not do actual recursion.
- */
- thd->variables.max_sp_recursion_depth++;
- if ((sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name,
- &thd->sp_proc_cache, FALSE)))
- ret= sp->show_create_procedure(thd);
-
- thd->variables.max_sp_recursion_depth--;
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_status_procedure(THD *thd, const char *wild)
-{
- int ret;
- DBUG_ENTER("sp_show_status_procedure");
-
- ret= db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild);
- DBUG_RETURN(ret);
-}
-
-
-/*****************************************************************************
- FUNCTION
-******************************************************************************/
-
-int
-sp_create_function(THD *thd, sp_head *sp)
-{
- int ret;
- DBUG_ENTER("sp_create_function");
- DBUG_PRINT("enter", ("name: %.*s", sp->m_name.length, sp->m_name.str));
-
- ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp);
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_drop_function(THD *thd, sp_name *name)
-{
- int ret;
- DBUG_ENTER("sp_drop_function");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics)
-{
- int ret;
- DBUG_ENTER("sp_update_procedure");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics);
- if (!ret)
- sp_cache_invalidate();
- DBUG_RETURN(ret);
-}
-
-
-int
-sp_show_create_function(THD *thd, sp_name *name)
-{
- sp_head *sp;
- DBUG_ENTER("sp_show_create_function");
- DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
-
- if ((sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, name,
- &thd->sp_func_cache, FALSE)))
- {
- int ret= sp->show_create_function(thd);
-
- DBUG_RETURN(ret);
- }
- DBUG_RETURN(SP_KEY_NOT_FOUND);
-}
-
-
-int
-sp_show_status_function(THD *thd, const char *wild)
-{
- int ret;
- DBUG_ENTER("sp_show_status_function");
- ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild);
- DBUG_RETURN(ret);
-}
-
-
/*
Structure that represents element in the set of stored routines
used by statement or routine.
@@ -1304,11 +1265,12 @@ struct Sroutine_hash_entry
};
-extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first)
+extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
+ my_bool first)
{
Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr;
*plen= rn->key.length;
- return (byte *)rn->key.str;
+ return (uchar *)rn->key.str;
}
@@ -1389,7 +1351,7 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
Query_tables_list::START_SROUTINES_HASH_SIZE,
0, 0, sp_sroutine_key, 0, 0);
- if (!hash_search(&lex->sroutines, (byte *)key->str, key->length))
+ if (!hash_search(&lex->sroutines, (uchar *)key->str, key->length))
{
Sroutine_hash_entry *rn=
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
@@ -1399,8 +1361,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
rn->key.length= key->length;
rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
memcpy(rn->key.str, key->str, key->length);
- my_hash_insert(&lex->sroutines, (byte *)rn);
- lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
+ my_hash_insert(&lex->sroutines, (uchar *)rn);
+ lex->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next);
rn->belong_to_view= belong_to_view;
return TRUE;
}
@@ -1458,7 +1420,7 @@ void sp_remove_not_own_routines(LEX *lex)
but we want to be more future-proof.
*/
next_rt= not_own_rt->next;
- hash_delete(&lex->sroutines, (byte *)not_own_rt);
+ hash_delete(&lex->sroutines, (uchar *)not_own_rt);
}
*(Sroutine_hash_entry **)lex->sroutines_list_own_last= NULL;
@@ -1490,8 +1452,8 @@ void sp_update_sp_used_routines(HASH *dst, HASH *src)
for (uint i=0 ; i < src->records ; i++)
{
Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i);
- if (!hash_search(dst, (byte *)rt->key.str, rt->key.length))
- my_hash_insert(dst, (byte *)rt);
+ if (!hash_search(dst, (uchar *)rt->key.str, rt->key.length))
+ my_hash_insert(dst, (uchar *)rt);
}
}
@@ -1631,10 +1593,8 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
rest of the server checks agains NAME_LEN bytes and not chars.
Hence, the overrun happens only if the name is in length > 32 and
uses multibyte (cyrillic, greek, etc.)
-
- !! Change 3 with SYSTEM_CHARSET_MBMAXLEN when it's defined.
*/
- char n[NAME_LEN*3*2+2];
+ char n[NAME_LEN*2+2];
/* m_qname.str is not always \0 terminated */
memcpy(n, name.m_qname.str, name.m_qname.length);
@@ -1840,9 +1800,7 @@ create_string(THD *thd, String *buf,
SYNOPSIS
sp_use_new_db()
thd thread handle
-
new_db new database name (a string and its length)
-
old_db [IN] str points to a buffer where to store the old
database, length contains the size of the buffer
[OUT] if old db was not NULL, its name is copied
@@ -1850,7 +1808,6 @@ create_string(THD *thd, String *buf,
accordingly. Otherwise str[0] is set to '\0' and length
is set to 0. The out parameter should be used only if
the database name has been changed (see dbchangedp).
-
dbchangedp [OUT] is set to TRUE if the current database is changed,
FALSE otherwise. A database is not changed if the old
name is the same as the new one, both names are empty,
@@ -1899,7 +1856,7 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
DBUG_RETURN(0);
}
- ret= mysql_change_db(thd, new_db.str, no_access_check);
+ ret= mysql_change_db(thd, &new_db, no_access_check);
*dbchangedp= ret == 0;
DBUG_RETURN(ret);
diff --git a/sql/sp.h b/sql/sp.h
index 80430791a5a..52b0344a2e2 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -45,37 +44,20 @@ sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
int
sp_routine_exists_in_table(THD *thd, int type, sp_name *name);
-int
-sp_create_procedure(THD *thd, sp_head *sp);
-
-int
-sp_drop_procedure(THD *thd, sp_name *name);
-
+bool
+sp_show_create_routine(THD *thd, int type, sp_name *name);
int
-sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics);
+sp_show_status_routine(THD *thd, int type, const char *wild);
int
-sp_show_create_procedure(THD *thd, sp_name *name);
+sp_create_routine(THD *thd, int type, sp_head *sp);
int
-sp_show_status_procedure(THD *thd, const char *wild);
+sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics);
int
-sp_create_function(THD *thd, sp_head *sp);
-
-int
-sp_drop_function(THD *thd, sp_name *name);
-
-int
-sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics);
-
-int
-sp_show_create_function(THD *thd, sp_name *name);
-
-int
-sp_show_status_function(THD *thd, const char *wild);
-
+sp_drop_routine(THD *thd, int type, sp_name *name);
/*
Procedures for pre-caching of stored routines and building table list
@@ -94,14 +76,14 @@ int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex,
int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
TABLE_LIST *table);
-extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
+extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
+ my_bool first);
/*
Routines which allow open/lock and close mysql.proc table even when
we already have some tables open and locked.
*/
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
-void close_proc_table(THD *thd, Open_tables_state *backup);
/*
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index f5912caddaf..84b15ee15c4 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -40,12 +39,12 @@ public:
inline void insert(sp_head *sp)
{
/* TODO: why don't we check return value? */
- my_hash_insert(&m_hashtable, (const byte *)sp);
+ my_hash_insert(&m_hashtable, (const uchar *)sp);
}
inline sp_head *lookup(char *name, uint namelen)
{
- return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
+ return (sp_head *)hash_search(&m_hashtable, (const uchar *)name, namelen);
}
#ifdef NOT_USED
@@ -54,7 +53,7 @@ public:
sp_head *sp= lookup(name, namelen);
if (sp)
{
- hash_delete(&m_hashtable, (byte *)sp);
+ hash_delete(&m_hashtable, (uchar *)sp);
return TRUE;
}
return FALSE;
@@ -131,7 +130,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp)
return; // End of memory error
c->version= Cversion; // No need to lock when reading long variable
}
- DBUG_PRINT("info",("sp_cache: inserting: %.*s", sp->m_qname.length,
+ DBUG_PRINT("info",("sp_cache: inserting: %.*s", (int) sp->m_qname.length,
sp->m_qname.str));
c->insert(sp);
*cp= c; // Update *cp if it was NULL
@@ -215,12 +214,12 @@ void sp_cache_flush_obsolete(sp_cache **cp)
Internal functions
*************************************************************************/
-static byte *hash_get_key_for_sp_head(const byte *ptr, uint *plen,
- my_bool first)
+static uchar *hash_get_key_for_sp_head(const uchar *ptr, size_t *plen,
+ my_bool first)
{
sp_head *sp= (sp_head *)ptr;
*plen= sp->m_qname.length;
- return (byte*) sp->m_qname.str;
+ return (uchar*) sp->m_qname.str;
}
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
index 1021d17b9e2..9d34c9a2fb5 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 7fbabdbaac9..f918862de23 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,6 +36,7 @@ Item_result
sp_map_result_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -59,6 +59,7 @@ Item::Type
sp_map_item_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -95,8 +96,6 @@ sp_map_item_type(enum enum_field_types type)
static String *
sp_get_item_value(THD *thd, Item *item, String *str)
{
- Item_result result_type= item->result_type();
-
switch (item->result_type()) {
case REAL_RESULT:
case INT_RESULT:
@@ -350,13 +349,13 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
bool save_abort_on_warning= thd->abort_on_warning;
- bool save_no_trans_update= thd->no_trans_update;
+ bool save_no_trans_update_stmt= thd->no_trans_update.stmt;
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
thd->abort_on_warning=
thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
/* Save the value in the field. Convert the value if needed. */
@@ -364,7 +363,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
thd->count_cuted_fields= save_count_cuted_fields;
thd->abort_on_warning= save_abort_on_warning;
- thd->no_trans_update= save_no_trans_update;
+ thd->no_trans_update.stmt= save_no_trans_update_stmt;
if (thd->net.report_error)
{
@@ -386,13 +385,13 @@ void
sp_name::init_qname(THD *thd)
{
m_sroutines_key.length= m_db.length + m_name.length + 2;
- if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
+ if (!(m_sroutines_key.str= (char*) thd->alloc(m_sroutines_key.length + 1)))
return;
m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1;
sprintf(m_qname.str, "%.*s.%.*s",
- m_db.length, (m_db.length ? m_db.str : ""),
- m_name.length, m_name.str);
+ (int) m_db.length, (m_db.length ? m_db.str : ""),
+ (int) m_name.length, m_name.str);
}
@@ -409,9 +408,22 @@ sp_name::init_qname(THD *thd)
*/
bool
-check_routine_name(LEX_STRING ident)
+check_routine_name(LEX_STRING *ident)
{
- return (!ident.str || !ident.str[0] || ident.str[ident.length-1] == ' ');
+ if (!ident || !ident->str || !ident->str[0] ||
+ ident->str[ident->length-1] == ' ')
+ {
+ my_error(ER_SP_WRONG_NAME, MYF(0), ident->str);
+ return TRUE;
+ }
+ if (check_string_char_length(ident, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str);
+ return TRUE;
+ }
+
+ return FALSE;
}
/* ------------------------------------------------------------------ */
@@ -473,8 +485,7 @@ sp_head::sp_head()
*/
m_db= m_name= m_qname= str_reset;
- extern byte *
- sp_table_key(const byte *ptr, uint *plen, my_bool first);
+ extern uchar *sp_table_key(const uchar *ptr, size_t *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
m_backpatch.empty();
@@ -491,7 +502,7 @@ sp_head::init(LEX *lex)
{
DBUG_ENTER("sp_head::init");
- lex->spcont= m_pcont= new sp_pcontext(NULL);
+ lex->spcont= m_pcont= new sp_pcontext();
/*
Altough trg_table_fields list is used only in triggers we init for all
@@ -542,29 +553,29 @@ void
sp_head::init_strings(THD *thd, LEX *lex)
{
DBUG_ENTER("sp_head::init_strings");
- const uchar *endp; /* Used to trim the end */
+ const char *endp; /* Used to trim the end */
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= thd->mem_root;
+ Lex_input_stream *lip=thd->m_lip;
if (m_param_begin && m_param_end)
{
m_params.length= m_param_end - m_param_begin;
- m_params.str= strmake_root(root,
- (char *)m_param_begin, m_params.length);
+ m_params.str= strmake_root(root, m_param_begin, m_params.length);
}
/* If ptr has overrun end_of_query then end_of_query is the end */
- endp= (lex->ptr > lex->end_of_query ? lex->end_of_query : lex->ptr);
+ endp= (lip->ptr > lip->end_of_query ? lip->end_of_query : lip->ptr);
/*
Trim "garbage" at the end. This is sometimes needed with the
"/ * ! VERSION... * /" wrapper in dump files.
*/
- endp= skip_rear_comments(m_body_begin, endp);
+ endp= skip_rear_comments(thd->charset(), m_body_begin, endp);
m_body.length= endp - m_body_begin;
- m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length);
- m_defstr.length= endp - lex->buf;
- m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length);
+ m_body.str= strmake_root(root, m_body_begin, m_body.length);
+ m_defstr.length= endp - lip->buf;
+ m_defstr.str= strmake_root(root, lip->buf, m_defstr.length);
DBUG_VOID_RETURN;
}
@@ -625,38 +636,10 @@ int
sp_head::create(THD *thd)
{
DBUG_ENTER("sp_head::create");
- int ret;
-
DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s",
m_type, m_name.str, m_params.str, m_body.str));
-#ifndef DBUG_OFF
- optimize();
- {
- String s;
- sp_instr *i;
- uint ip= 0;
- while ((i = get_instr(ip)))
- {
- char buf[8];
-
- sprintf(buf, "%4u: ", ip);
- s.append(buf);
- i->print(&s);
- s.append('\n');
- ip+= 1;
- }
- s.append('\0');
- DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr()));
- }
-#endif
-
- if (m_type == TYPE_ENUM_FUNCTION)
- ret= sp_create_function(thd, this);
- else
- ret= sp_create_procedure(thd, this);
-
- DBUG_RETURN(ret);
+ DBUG_RETURN(sp_create_routine(thd, m_type, this));
}
sp_head::~sp_head()
@@ -723,7 +706,7 @@ sp_head::create_result_field(uint field_max_length, const char *field_name,
field_max_length : m_return_field_def.length;
field= ::make_field(table->s, /* TABLE_SHARE ptr */
- (char*) 0, /* field ptr */
+ (uchar*) 0, /* field ptr */
field_length, /* field [max] length */
(uchar*) "", /* null ptr */
0, /* null bit */
@@ -987,7 +970,7 @@ sp_head::execute(THD *thd)
String old_packet;
/* Use some extra margin for possible SP recursion and functions */
- if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet))
+ if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
/* init per-instruction memroot */
@@ -1015,6 +998,12 @@ sp_head::execute(THD *thd)
m_first_instance->m_last_cached_sp == this) ||
(m_recursion_level + 1 == m_next_cached_sp->m_recursion_level));
+ /*
+ NOTE: The SQL Standard does not specify the context that should be
+ preserved for stored routines. However, at SAP/Walldorf meeting it was
+ decided that current database should be preserved.
+ */
+
if (m_db.length &&
(err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged)))
goto done;
@@ -1139,7 +1128,7 @@ sp_head::execute(THD *thd)
case SP_HANDLER_CONTINUE:
thd->restore_active_arena(&execute_arena, &backup_arena);
thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
- ctx->push_hstack(ip);
+ ctx->push_hstack(i->get_cont_dest());
// Fall through
default:
ip= hip;
@@ -1149,6 +1138,7 @@ sp_head::execute(THD *thd)
thd->clear_error();
thd->is_fatal_error= 0;
thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
continue;
}
}
@@ -1192,7 +1182,7 @@ sp_head::execute(THD *thd)
(It would generate an error from mysql_change_db() when old_db=="")
*/
if (! thd->killed)
- err_status|= mysql_change_db(thd, old_db.str, 1);
+ err_status|= mysql_change_db(thd, &old_db, TRUE);
}
m_flags&= ~IS_INVOKED;
DBUG_PRINT("info",
@@ -1248,7 +1238,11 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
Security_context **save_ctx)
{
*save_ctx= 0;
- if (sp_change_security_context(thd, sp, save_ctx))
+ if (sp->m_chistics->suid != SP_IS_NOT_SUID &&
+ sp->m_security_ctx.change_security_context(thd, &sp->m_definer_user,
+ &sp->m_definer_host,
+ &sp->m_db,
+ save_ctx))
return TRUE;
/*
@@ -1265,7 +1259,7 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, is_proc, FALSE))
{
- sp_restore_security_context(thd, *save_ctx);
+ sp->m_security_ctx.restore_security_context(thd, *save_ctx);
*save_ctx= 0;
return TRUE;
}
@@ -1348,6 +1342,9 @@ err_with_cleanup:
free_root(&call_mem_root, MYF(0));
thd->spcont= octx;
+ if (thd->killed)
+ thd->send_kill_message();
+
DBUG_RETURN(err_status);
}
@@ -1391,7 +1388,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
MEM_ROOT call_mem_root;
Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
Query_arena backup_arena;
-
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
@@ -1472,6 +1468,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
{
binlog_buf.length(0);
binlog_buf.append(STRING_WITH_LEN("SELECT "));
+ append_identifier(thd, &binlog_buf, m_db.str, m_db.length);
+ binlog_buf.append('.');
append_identifier(thd, &binlog_buf, m_name.str, m_name.length);
binlog_buf.append('(');
for (arg_no= 0; arg_no < argcount; arg_no++)
@@ -1505,8 +1503,24 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (need_binlog_call)
{
+ query_id_t q;
reset_dynamic(&thd->user_var_events);
- mysql_bin_log.start_union_events(thd);
+ /*
+ In case of artificially constructed events for function calls
+ we have separate union for each such event and hence can't use
+ query_id of real calling statement as the start of all these
+ unions (this will break logic of replication of user-defined
+ variables). So we use artifical value which is guaranteed to
+ be greater than all query_id's of all statements belonging
+ to previous events/unions.
+ Possible alternative to this is logging of all function invocations
+ as one select and not resetting THD::user_var_events before
+ each invocation.
+ */
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ q= global_query_id;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_bin_log.start_union_events(thd, q + 1);
binlog_save_options= thd->options;
thd->options&= ~OPTION_BIN_LOG;
}
@@ -1559,7 +1573,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, save_security_ctx);
+ m_security_ctx.restore_security_context(thd, save_security_ctx);
#endif
err_with_cleanup:
@@ -1646,7 +1660,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
{
List_iterator<Item> it_args(*args);
- DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str));
+ DBUG_PRINT("info",(" %.*s: eval args", (int) m_name.length, m_name.str));
for (uint i= 0 ; i < params ; i++)
{
@@ -1704,7 +1718,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!thd->in_sub_stmt)
close_thread_tables(thd, 0, 0);
- DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str));
+ DBUG_PRINT("info",(" %.*s: eval args done",
+ (int) m_name.length, m_name.str));
}
if (!(m_flags & LOG_SLOW_STATEMENTS) && thd->enable_slow_log)
{
@@ -1777,7 +1792,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (save_security_ctx)
- sp_restore_security_context(thd, save_security_ctx);
+ m_security_ctx.restore_security_context(thd, save_security_ctx);
#endif
if (!save_spcont)
@@ -1797,25 +1812,13 @@ sp_head::reset_lex(THD *thd)
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
- my_lex_states state= oldlex->next_state; // Keep original next_state
(void)m_lex.push_front(oldlex);
thd->lex= sublex= new st_lex;
- /* Reset most stuff. The length arguments doesn't matter here. */
- lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr));
+ /* Reset most stuff. */
+ lex_start(thd);
- /*
- * next_state is normally the same (0), but it happens that we swap lex in
- * "mid-sentence", so we must restore it.
- */
- sublex->next_state= state;
- /* We must reset ptr and end_of_query again */
- sublex->ptr= oldlex->ptr;
- sublex->end_of_query= oldlex->end_of_query;
- sublex->tok_start= oldlex->tok_start;
- sublex->tok_end= oldlex->tok_end;
- sublex->yylineno= oldlex->yylineno;
/* And keep the SP stuff too */
sublex->sphead= oldlex->sphead;
sublex->spcont= oldlex->spcont;
@@ -1848,10 +1851,6 @@ sp_head::restore_lex(THD *thd)
if (! oldlex)
return; // Nothing to restore
- // Update some state in the old one first
- oldlex->ptr= sublex->ptr;
- oldlex->tok_end= sublex->tok_end;
- oldlex->next_state= sublex->next_state;
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
/*
@@ -1859,7 +1858,7 @@ sp_head::restore_lex(THD *thd)
cannot switch from statement-based to row-based only for this
substatement).
*/
- if (sublex->binlog_row_based_if_mixed)
+ if (sublex->is_stmt_unsafe())
m_flags|= BINLOG_ROW_BASED_IF_MIXED;
/*
@@ -2101,55 +2100,97 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
}
-int
-sp_head::show_create_procedure(THD *thd)
+/**
+ Implement SHOW CREATE statement for stored routines.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+
+ @return Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+
+bool
+sp_head::show_create_routine(THD *thd, int type)
{
+ const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
+ "Procedure" : "Function";
+
+ const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
+ "Create Procedure" : "Create Function";
+
+ bool err_status;
+
Protocol *protocol= thd->protocol;
- char buff[2048];
- String buffer(buff, sizeof(buff), system_charset_info);
- int res;
- List<Item> field_list;
- byte *sql_mode_str;
- ulong sql_mode_len;
+ List<Item> fields;
+
+ LEX_STRING sql_mode;
+
bool full_access;
- DBUG_ENTER("sp_head::show_create_procedure");
- DBUG_PRINT("info", ("procedure %s", m_name.str));
- LINT_INIT(sql_mode_str);
- LINT_INIT(sql_mode_len);
+ DBUG_ENTER("sp_head::show_create_routine");
+ DBUG_PRINT("info", ("routine %s", m_name.str));
+
+ DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
+ type == TYPE_ENUM_FUNCTION);
if (check_show_routine_access(thd, this, &full_access))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
- sql_mode_str=
- sys_var_thd_sql_mode::symbolic_mode_representation(thd,
- m_sql_mode,
- &sql_mode_len);
- field_list.push_back(new Item_empty_string("Procedure", NAME_LEN));
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
- // 1024 is for not to confuse old clients
- Item_empty_string *definition=
- new Item_empty_string("Create Procedure", max(buffer.length(),1024));
- definition->maybe_null= TRUE;
- field_list.push_back(definition);
+ sys_var_thd_sql_mode::symbolic_mode_representation(
+ thd, m_sql_mode, &sql_mode);
+
+ /* Send header. */
+
+ fields.push_back(new Item_empty_string(col1_caption, NAME_CHAR_LEN));
+ fields.push_back(new Item_empty_string("sql_mode", sql_mode.length));
+
+ {
+ /*
+ NOTE: SQL statement field must be not less than 1024 in order not to
+ confuse old clients.
+ */
+
+ Item_empty_string *stmt_fld=
+ new Item_empty_string(col3_caption,
+ max(m_defstr.length, 1024));
+
+ stmt_fld->maybe_null= TRUE;
+
+ fields.push_back(stmt_fld);
+ }
+
+ if (protocol->send_fields(&fields,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ {
+ DBUG_RETURN(TRUE);
+ }
+
+ /* Send data. */
- if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
- Protocol::SEND_EOF))
- DBUG_RETURN(1);
protocol->prepare_for_resend();
+
protocol->store(m_name.str, m_name.length, system_charset_info);
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
+
if (full_access)
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ protocol->store(m_defstr.str, m_defstr.length, &my_charset_bin);
else
protocol->store_null();
- res= protocol->write();
- send_eof(thd);
- DBUG_RETURN(res);
+ err_status= protocol->write();
+
+ if (!err_status)
+ send_eof(thd);
+
+ DBUG_RETURN(err_status);
}
+
+
/*
Add instruction to SP
@@ -2169,54 +2210,7 @@ void sp_head::add_instr(sp_instr *instr)
entire stored procedure, as their life span is equal.
*/
instr->mem_root= &main_mem_root;
- insert_dynamic(&m_instr, (gptr)&instr);
-}
-
-
-int
-sp_head::show_create_function(THD *thd)
-{
- Protocol *protocol= thd->protocol;
- char buff[2048];
- String buffer(buff, sizeof(buff), system_charset_info);
- int res;
- List<Item> field_list;
- byte *sql_mode_str;
- ulong sql_mode_len;
- bool full_access;
- DBUG_ENTER("sp_head::show_create_function");
- DBUG_PRINT("info", ("procedure %s", m_name.str));
- LINT_INIT(sql_mode_str);
- LINT_INIT(sql_mode_len);
-
- if (check_show_routine_access(thd, this, &full_access))
- DBUG_RETURN(1);
-
- sql_mode_str=
- sys_var_thd_sql_mode::symbolic_mode_representation(thd,
- m_sql_mode,
- &sql_mode_len);
- field_list.push_back(new Item_empty_string("Function",NAME_LEN));
- field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
- Item_empty_string *definition=
- new Item_empty_string("Create Function", max(buffer.length(),1024));
- definition->maybe_null= TRUE;
- field_list.push_back(definition);
-
- if (protocol->send_fields(&field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(1);
- protocol->prepare_for_resend();
- protocol->store(m_name.str, m_name.length, system_charset_info);
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- if (full_access)
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
- else
- protocol->store_null();
- res= protocol->write();
- send_eof(thd);
-
- DBUG_RETURN(res);
+ insert_dynamic(&m_instr, (uchar*)&instr);
}
@@ -2229,7 +2223,7 @@ sp_head::show_create_function(THD *thd)
This is the main mark and move loop; it relies on the following methods
in sp_instr and its subclasses:
- opt_mark() Mark instruction as reachable (will recurse for jumps)
+ opt_mark() Mark instruction as reachable
opt_shortcut_jump() Shortcut jumps to the final destination;
used by opt_mark().
opt_move() Update moved instruction
@@ -2242,7 +2236,7 @@ void sp_head::optimize()
sp_instr *i;
uint src, dst;
- opt_mark(0);
+ opt_mark();
bp.empty();
src= dst= 0;
@@ -2260,7 +2254,7 @@ void sp_head::optimize()
sp_instr *ibp;
List_iterator_fast<sp_instr> li(bp);
- set_dynamic(&m_instr, (gptr)&i, dst);
+ set_dynamic(&m_instr, (uchar*)&i, dst);
while ((ibp= li++))
{
sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp);
@@ -2276,13 +2270,50 @@ void sp_head::optimize()
bp.empty();
}
+void sp_head::add_mark_lead(uint ip, List<sp_instr> *leads)
+{
+ sp_instr *i= get_instr(ip);
+
+ if (i && ! i->marked)
+ leads->push_front(i);
+}
+
void
-sp_head::opt_mark(uint ip)
+sp_head::opt_mark()
{
+ uint ip;
sp_instr *i;
+ List<sp_instr> leads;
- while ((i= get_instr(ip)) && !i->marked)
- ip= i->opt_mark(this);
+ /*
+ Forward flow analysis algorithm in the instruction graph:
+ - first, add the entry point in the graph (the first instruction) to the
+ 'leads' list of paths to explore.
+ - while there are still leads to explore:
+ - pick one lead, and follow the path forward. Mark instruction reached.
+ Stop only if the end of the routine is reached, or the path converge
+ to code already explored (marked).
+ - while following a path, collect in the 'leads' list any fork to
+ another path (caused by conditional jumps instructions), so that these
+ paths can be explored as well.
+ */
+
+ /* Add the entry point */
+ i= get_instr(0);
+ leads.push_front(i);
+
+ /* For each path of code ... */
+ while (leads.elements != 0)
+ {
+ i= leads.pop();
+
+ /* Mark the entire path, collecting new leads. */
+ while (i && ! i->marked)
+ {
+ ip= i->opt_mark(this, & leads);
+ i= get_instr(ip);
+ }
+ }
}
@@ -2412,16 +2443,11 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last);
}
}
-
+
reinit_stmt_before_use(thd, m_lex);
- /*
- If requested check whenever we have access to tables in LEX's table list
- and open and lock them before executing instructtions core function.
- */
- if (open_tables &&
- (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) ||
- open_and_lock_tables(thd, m_lex->query_tables)))
- res= -1;
+
+ if (open_tables)
+ res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
if (!res)
{
@@ -2473,6 +2499,29 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
sp_instr class functions
*/
+int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+{
+ int result;
+
+ /*
+ Check whenever we have access to tables for this statement
+ and open and lock them before executing instructions core function.
+ */
+ if (check_table_access(thd, SELECT_ACL, tables, 0)
+ || open_and_lock_tables(thd, tables))
+ result= -1;
+ else
+ result= 0;
+
+ return result;
+}
+
+uint sp_instr::get_cont_dest()
+{
+ return (m_ip+1);
+}
+
+
int sp_instr::exec_core(THD *thd, uint *nextp)
{
DBUG_ASSERT(0);
@@ -2658,6 +2707,15 @@ sp_instr_set_trigger_field::print(String *str)
value->print(str);
}
+/*
+ sp_instr_opt_meta
+*/
+
+uint sp_instr_opt_meta::get_cont_dest()
+{
+ return m_cont_dest;
+}
+
/*
sp_instr_jump class functions
@@ -2684,7 +2742,7 @@ sp_instr_jump::print(String *str)
}
uint
-sp_instr_jump::opt_mark(sp_head *sp)
+sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
m_dest= opt_shortcut_jump(sp, this);
if (m_dest != m_ip+1) /* Jumping to following instruction? */
@@ -2747,7 +2805,6 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
if (! it)
{
res= -1;
- *nextp = m_cont_dest;
}
else
{
@@ -2778,7 +2835,7 @@ sp_instr_jump_if_not::print(String *str)
uint
-sp_instr_jump_if_not::opt_mark(sp_head *sp)
+sp_instr_jump_if_not::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
sp_instr *i;
@@ -2788,13 +2845,13 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp)
m_dest= i->opt_shortcut_jump(sp, this);
m_optdest= sp->get_instr(m_dest);
}
- sp->opt_mark(m_dest);
+ sp->add_mark_lead(m_dest, leads);
if ((i= sp->get_instr(m_cont_dest)))
{
m_cont_dest= i->opt_shortcut_jump(sp, this);
m_cont_optdest= sp->get_instr(m_cont_dest);
}
- sp->opt_mark(m_cont_dest);
+ sp->add_mark_lead(m_cont_dest, leads);
return m_ip+1;
}
@@ -2915,7 +2972,7 @@ sp_instr_hpush_jump::print(String *str)
uint
-sp_instr_hpush_jump::opt_mark(sp_head *sp)
+sp_instr_hpush_jump::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
sp_instr *i;
@@ -2925,7 +2982,7 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp)
m_dest= i->opt_shortcut_jump(sp, this);
m_optdest= sp->get_instr(m_dest);
}
- sp->opt_mark(m_dest);
+ sp->add_mark_lead(m_dest, leads);
return m_ip+1;
}
@@ -2990,15 +3047,23 @@ sp_instr_hreturn::print(String *str)
uint
-sp_instr_hreturn::opt_mark(sp_head *sp)
+sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
+ marked= 1;
+
if (m_dest)
- return sp_instr_jump::opt_mark(sp);
- else
{
- marked= 1;
- return UINT_MAX;
+ /*
+ This is an EXIT handler; next instruction step is in m_dest.
+ */
+ return m_dest;
}
+
+ /*
+ This is a CONTINUE handler; next instruction step will come from
+ the handler stack and not from opt_mark.
+ */
+ return UINT_MAX;
}
@@ -3318,7 +3383,6 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
spcont->clear_handler();
thd->spcont= spcont;
}
- *nextp= m_cont_dest; /* For continue handler */
}
else
*nextp= m_ip+1;
@@ -3341,7 +3405,7 @@ sp_instr_set_case_expr::print(String *str)
}
uint
-sp_instr_set_case_expr::opt_mark(sp_head *sp)
+sp_instr_set_case_expr::opt_mark(sp_head *sp, List<sp_instr> *leads)
{
sp_instr *i;
@@ -3351,7 +3415,7 @@ sp_instr_set_case_expr::opt_mark(sp_head *sp)
m_cont_dest= i->opt_shortcut_jump(sp, this);
m_cont_optdest= sp->get_instr(m_cont_dest);
}
- sp->opt_mark(m_cont_dest);
+ sp->add_mark_lead(m_cont_dest, leads);
return m_ip+1;
}
@@ -3368,44 +3432,6 @@ sp_instr_set_case_expr::opt_move(uint dst, List<sp_instr> *bp)
/* ------------------------------------------------------------------ */
-/*
- Security context swapping
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-bool
-sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup)
-{
- *backup= 0;
- if (sp->m_chistics->suid != SP_IS_NOT_SUID &&
- (strcmp(sp->m_definer_user.str,
- thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info, sp->m_definer_host.str,
- thd->security_ctx->priv_host)))
- {
- if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str,
- sp->m_definer_host.str,
- sp->m_definer_host.str,
- sp->m_db.str))
- {
- my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
- sp->m_definer_host.str);
- return TRUE;
- }
- *backup= thd->security_ctx;
- thd->security_ctx= &sp->m_security_ctx;
- }
- return FALSE;
-}
-
-void
-sp_restore_security_context(THD *thd, Security_context *backup)
-{
- if (backup)
- thd->security_ctx= backup;
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
/*
Structure that represent all instances of one table
@@ -3429,12 +3455,12 @@ typedef struct st_sp_table
uint query_lock_count;
} SP_TABLE;
-byte *
-sp_table_key(const byte *ptr, uint *plen, my_bool first)
+uchar *
+sp_table_key(const uchar *ptr, size_t *plen, my_bool first)
{
SP_TABLE *tab= (SP_TABLE *)ptr;
*plen= tab->qname.length;
- return (byte *)tab->qname.str;
+ return (uchar *)tab->qname.str;
}
@@ -3491,12 +3517,20 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tname[tlen]= '\0';
/*
+ Upgrade the lock type because this table list will be used
+ only in pre-locked mode, in which DELAYED inserts are always
+ converted to normal inserts.
+ */
+ if (table->lock_type == TL_WRITE_DELAYED)
+ table->lock_type= TL_WRITE;
+
+ /*
We ignore alias when we check if table was already marked as temporary
(and therefore should not be prelocked). Otherwise we will erroneously
treat table with same name but with different alias as non-temporary.
*/
- if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) ||
- ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname,
+ if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (uchar *)tname, tlen)) ||
+ ((tab= (SP_TABLE *)hash_search(&m_sptabs, (uchar *)tname,
tlen - alen - 1)) &&
tab->temp))
{
@@ -3526,7 +3560,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
tab->db_length= table->db_length;
tab->lock_type= table->lock_type;
tab->lock_count= tab->query_lock_count= 1;
- my_hash_insert(&m_sptabs, (byte *)tab);
+ my_hash_insert(&m_sptabs, (uchar *)tab);
}
}
return TRUE;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index f1efb1d195e..985d74393ff 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -60,9 +59,10 @@ public:
calling set_routine_type().
*/
LEX_STRING m_sroutines_key;
+ bool m_explicit_name; /**< Prepend the db name? */
- sp_name(LEX_STRING db, LEX_STRING name)
- : m_db(db), m_name(name)
+ sp_name(LEX_STRING db, LEX_STRING name, bool use_explicit_name)
+ : m_db(db), m_name(name), m_explicit_name(use_explicit_name)
{
m_qname.str= m_sroutines_key.str= 0;
m_qname.length= m_sroutines_key.length= 0;
@@ -80,6 +80,7 @@ public:
m_name.length= m_qname.length= key_len - 1;
m_db.str= 0;
m_db.length= 0;
+ m_explicit_name= false;
}
// Init. the qualified name from the db and name.
@@ -96,7 +97,7 @@ public:
bool
-check_routine_name(LEX_STRING name);
+check_routine_name(LEX_STRING *ident);
class sp_head :private Query_arena
{
@@ -108,8 +109,6 @@ public:
/* Possible values of m_flags */
enum {
HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN
- IN_SIMPLE_CASE= 2, // Is set if parsing a simple CASE
- IN_HANDLER= 4, // Is set if the parser is in a handler body
MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s)
CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE
IS_INVOKED= 32, // Is set if this sp_head is being used
@@ -129,7 +128,7 @@ public:
create_field m_return_field_def; /* This is used for FUNCTIONs only. */
- const uchar *m_tmp_query; // Temporary pointer to sub query string
+ const char *m_tmp_query; // Temporary pointer to sub query string
st_sp_chistics *m_chistics;
ulong m_sql_mode; // For SHOW CREATE and execution
LEX_STRING m_qname; // db.name
@@ -177,7 +176,9 @@ public:
*/
HASH m_sroutines;
// Pointers set during parsing
- const uchar *m_param_begin, *m_param_end, *m_body_begin;
+ const char *m_param_begin;
+ const char *m_param_end;
+ const char *m_body_begin;
/*
Security context for stored routine which should be run under
@@ -224,11 +225,8 @@ public:
bool
execute_procedure(THD *thd, List<Item> *args);
- int
- show_create_procedure(THD *thd);
-
- int
- show_create_function(THD *thd);
+ bool
+ show_create_routine(THD *thd, int type);
void
add_instr(sp_instr *instr);
@@ -244,7 +242,7 @@ public:
{
sp_instr *i;
- get_dynamic(&m_instr, (gptr)&i, m_instr.elements-1);
+ get_dynamic(&m_instr, (uchar*)&i, m_instr.elements-1);
return i;
}
@@ -304,8 +302,19 @@ public:
void restore_thd_mem_root(THD *thd);
+ /**
+ Optimize the code.
+ */
void optimize();
- void opt_mark(uint ip);
+
+ /**
+ Helper used during flow analysis during code optimization.
+ See the implementation of <code>opt_mark()</code>.
+ @param ip the instruction to add to the leads list
+ @param leads the list of remaining paths to explore in the graph that
+ represents the code, during flow analysis.
+ */
+ void add_mark_lead(uint ip, List<sp_instr> *leads);
void recursion_level_error(THD *thd);
@@ -315,7 +324,7 @@ public:
sp_instr *ip;
if (i < m_instr.elements)
- get_dynamic(&m_instr, (gptr)&ip, i);
+ get_dynamic(&m_instr, (uchar*)&ip, i);
else
ip= NULL;
return ip;
@@ -369,7 +378,7 @@ public:
the substatements not).
*/
if (m_flags & BINLOG_ROW_BASED_IF_MIXED)
- lex->binlog_row_based_if_mixed= TRUE;
+ lex->set_stmt_unsafe();
}
@@ -412,6 +421,12 @@ private:
bool
execute(THD *thd);
+ /**
+ Perform a forward flow analysis in the generated code.
+ Mark reachable instructions, for the optimizer.
+ */
+ void opt_mark();
+
/*
Merge the list of tables used by query into the multi-set of tables used
by routine.
@@ -452,15 +467,34 @@ public:
thd Thread handle
nextp OUT index of the next instruction to execute. (For most
instructions this will be the instruction following this
- one).
-
- RETURN
- 0 on success,
- other if some error occured
+ one). Note that this parameter is undefined in case of
+ errors, use get_cont_dest() to find the continuation
+ instruction for CONTINUE error handlers.
+
+ RETURN
+ 0 on success,
+ other if some error occurred
*/
-
+
virtual int execute(THD *thd, uint *nextp) = 0;
+ /**
+ Execute <code>open_and_lock_tables()</code> for this statement.
+ Open and lock the tables used by this statement, as a pre-requisite
+ to execute the core logic of this instruction with
+ <code>exec_core()</code>.
+ @param thd the current thread
+ @param tables the list of tables to open and lock
+ @return zero on success, non zero on failure.
+ */
+ int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
+
+ /**
+ Get the continuation destination of this instruction.
+ @return the continuation destination
+ */
+ virtual uint get_cont_dest();
+
/*
Execute core function of instruction after all preparations (e.g.
setting of proper LEX, saving part of the thread context have been
@@ -479,10 +513,10 @@ public:
/*
Mark this instruction as reachable during optimization and return the
- index to the next instruction. Jump instruction will mark their
- destination too recursively.
+ index to the next instruction. Jump instruction will add their
+ destination to the leads list.
*/
- virtual uint opt_mark(sp_head *sp)
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
{
marked= 1;
return m_ip+1;
@@ -637,9 +671,9 @@ class sp_instr_set : public sp_instr
public:
sp_instr_set(uint ip, sp_pcontext *ctx,
- uint offset, Item *val, enum enum_field_types type,
+ uint offset, Item *val, enum enum_field_types type_arg,
LEX *lex, bool lex_resp)
- : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type),
+ : sp_instr(ip, ctx), m_offset(offset), m_value(val), m_type(type_arg),
m_lex_keeper(lex, lex_resp)
{}
@@ -725,6 +759,8 @@ public:
virtual void set_destination(uint old_dest, uint new_dest)
= 0;
+ virtual uint get_cont_dest();
+
protected:
sp_instr *m_optdest; // Used during optimization
@@ -754,7 +790,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp);
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start);
@@ -804,7 +840,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp);
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
/* Override sp_instr_jump's shortcut; we stop here */
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
@@ -837,8 +873,9 @@ class sp_instr_freturn : public sp_instr
public:
sp_instr_freturn(uint ip, sp_pcontext *ctx,
- Item *val, enum enum_field_types type, LEX *lex)
- : sp_instr(ip, ctx), m_value(val), m_type(type), m_lex_keeper(lex, TRUE)
+ Item *val, enum enum_field_types type_arg, LEX *lex)
+ : sp_instr(ip, ctx), m_value(val), m_type(type_arg),
+ m_lex_keeper(lex, TRUE)
{}
virtual ~sp_instr_freturn()
@@ -850,7 +887,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp)
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
{
marked= 1;
return UINT_MAX;
@@ -887,7 +924,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp);
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
/* Override sp_instr_jump's shortcut; we stop here. */
virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
@@ -952,7 +989,13 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp);
+ /* This instruction will not be short cut optimized. */
+ virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start)
+ {
+ return m_ip;
+ }
+
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
private:
@@ -1122,7 +1165,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp)
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads)
{
marked= 1;
return UINT_MAX;
@@ -1155,7 +1198,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp);
+ virtual uint opt_mark(sp_head *sp, List<sp_instr> *leads);
virtual void opt_move(uint dst, List<sp_instr> *ibp);
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index b0b65d5313b..9c96485b8ec 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,6 +25,11 @@
#include "sp_pcontext.h"
#include "sp_head.h"
+/* Initial size for the dynamic arrays in sp_pcontext */
+#define PCONTEXT_ARRAY_INIT_ALLOC 16
+/* Increment size for the dynamic arrays in sp_pcontext */
+#define PCONTEXT_ARRAY_INCREMENT_ALLOC 8
+
/*
Sanity check for SQLSTATEs. Will not check if it's really an existing
state (there are just too many), but will check length and bad characters.
@@ -50,28 +54,61 @@ sp_cond_check(LEX_STRING *sqlstate)
return TRUE;
}
-sp_pcontext::sp_pcontext(sp_pcontext *prev)
- :Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
- m_context_handlers(0), m_parent(prev), m_pboundary(0)
+sp_pcontext::sp_pcontext()
+ : Sql_alloc(),
+ m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
+ m_context_handlers(0), m_parent(NULL), m_pboundary(0),
+ m_label_scope(LABEL_DEFAULT_SCOPE)
{
- VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *), 16, 8));
- VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8));
- VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *), 16, 8));
- VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING), 16, 8));
- VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *), 16, 8));
+ VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
m_label.empty();
m_children.empty();
- if (!prev)
- {
- m_var_offset= m_cursor_offset= 0;
- m_num_case_exprs= 0;
- }
- else
- {
- m_var_offset= prev->m_var_offset + prev->m_max_var_index;
- m_cursor_offset= prev->current_cursor_count();
- m_num_case_exprs= prev->get_num_case_exprs();
- }
+
+ m_var_offset= m_cursor_offset= 0;
+ m_num_case_exprs= 0;
+}
+
+sp_pcontext::sp_pcontext(sp_pcontext *prev, label_scope_type label_scope)
+ : Sql_alloc(),
+ m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
+ m_context_handlers(0), m_parent(prev), m_pboundary(0),
+ m_label_scope(label_scope)
+{
+ VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ m_label.empty();
+ m_children.empty();
+
+ m_var_offset= prev->m_var_offset + prev->m_max_var_index;
+ m_cursor_offset= prev->current_cursor_count();
+ m_num_case_exprs= prev->get_num_case_exprs();
}
void
@@ -93,9 +130,9 @@ sp_pcontext::destroy()
}
sp_pcontext *
-sp_pcontext::push_context()
+sp_pcontext::push_context(label_scope_type label_scope)
{
- sp_pcontext *child= new sp_pcontext(this);
+ sp_pcontext *child= new sp_pcontext(this, label_scope);
if (child)
m_children.push_back(child);
@@ -174,7 +211,7 @@ sp_pcontext::find_variable(LEX_STRING *name, my_bool scoped)
{
sp_variable_t *p;
- get_dynamic(&m_vars, (gptr)&p, i);
+ get_dynamic(&m_vars, (uchar*)&p, i);
if (my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)p->name.str, p->name.length) == 0)
@@ -201,7 +238,7 @@ sp_pcontext::find_variable(uint offset)
{ // This frame
sp_variable_t *p;
- get_dynamic(&m_vars, (gptr)&p, offset - m_var_offset);
+ get_dynamic(&m_vars, (uchar*)&p, offset - m_var_offset);
return p;
}
if (m_parent)
@@ -226,7 +263,7 @@ sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type,
p->mode= mode;
p->offset= current_var_count();
p->dflt= NULL;
- insert_dynamic(&m_vars, (gptr)&p);
+ insert_dynamic(&m_vars, (uchar*)&p);
return p;
}
@@ -258,7 +295,15 @@ sp_pcontext::find_label(char *name)
if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
return lab;
- if (m_parent)
+ /*
+ Note about exception handlers.
+ See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
+ section 13.1 <compound statement>,
+ syntax rule 4.
+ In short, a DECLARE HANDLER block can not refer
+ to labels from the parent context, as they are out of scope.
+ */
+ if (m_parent && (m_label_scope == LABEL_DEFAULT_SCOPE))
return m_parent->find_label(name);
return NULL;
}
@@ -273,7 +318,7 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
p->name.str= name->str;
p->name.length= name->length;
p->val= val;
- insert_dynamic(&m_conds, (gptr)&p);
+ insert_dynamic(&m_conds, (uchar*)&p);
}
}
@@ -289,7 +334,7 @@ sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped)
{
sp_cond_t *p;
- get_dynamic(&m_conds, (gptr)&p, i);
+ get_dynamic(&m_conds, (uchar*)&p, i);
if (my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)p->name.str, p->name.length) == 0)
@@ -316,7 +361,7 @@ sp_pcontext::find_handler(sp_cond_type_t *cond)
{
sp_cond_type_t *p;
- get_dynamic(&m_handlers, (gptr)&p, i);
+ get_dynamic(&m_handlers, (uchar*)&p, i);
if (cond->type == p->type)
{
switch (p->type)
@@ -346,7 +391,7 @@ sp_pcontext::push_cursor(LEX_STRING *name)
m_max_cursor_index+= 1;
n.str= name->str;
n.length= name->length;
- insert_dynamic(&m_cursors, (gptr)&n);
+ insert_dynamic(&m_cursors, (uchar*)&n);
}
/*
@@ -361,7 +406,7 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
{
LEX_STRING n;
- get_dynamic(&m_cursors, (gptr)&n, i);
+ get_dynamic(&m_cursors, (uchar*)&n, i);
if (my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)n.str, n.length) == 0)
@@ -384,7 +429,7 @@ sp_pcontext::retrieve_field_definitions(List<create_field> *field_def_lst)
for (uint i = 0; i < m_vars.elements; ++i)
{
sp_variable_t *var_def;
- get_dynamic(&m_vars, (gptr) &var_def, i);
+ get_dynamic(&m_vars, (uchar*) &var_def, i);
field_def_lst->push_back(&var_def->field_def);
}
@@ -408,7 +453,7 @@ sp_pcontext::find_cursor(uint offset, LEX_STRING *n)
if (m_cursor_offset <= offset &&
offset < m_cursor_offset + m_cursors.elements)
{ // This frame
- get_dynamic(&m_cursors, (gptr)n, offset - m_cursor_offset);
+ get_dynamic(&m_cursors, (uchar*)n, offset - m_cursor_offset);
return TRUE;
}
if (m_parent)
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 2ee77696efb..3b8b165a6e0 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -89,16 +88,33 @@ typedef struct sp_cond
sp_cond_type_t *val;
} sp_cond_t;
+/**
+ The scope of a label in Stored Procedures,
+ for name resolution of labels in a parsing context.
+*/
+enum label_scope_type
+{
+ /**
+ The labels declared in a parent context are in scope.
+ */
+ LABEL_DEFAULT_SCOPE,
+ /**
+ The labels declared in a parent context are not in scope.
+ */
+ LABEL_HANDLER_SCOPE
+};
-/*
- The parse-time context, used to keep track on declared variables/parameters,
+/**
+ The parse-time context, used to keep track of declared variables/parameters,
conditions, handlers, cursors and labels, during parsing.
sp_contexts are organized as a tree, with one object for each begin-end
- block, plus a root-context for the parameters.
+ block, one object for each exception handler,
+ plus a root-context for the parameters.
This is used during parsing for looking up defined names (e.g. declared
variables and visible labels), for error checking, and to calculate offsets
to be used at runtime. (During execution variable values, active handlers
and cursors, etc, are referred to by an index in a stack.)
+ Parsing contexts for exception handlers limit the visibility of labels.
The pcontext tree is also kept during execution and is used for error
checking (e.g. correct number of parameters), and in the future, used by
the debugger.
@@ -106,21 +122,30 @@ typedef struct sp_cond
class sp_pcontext : public Sql_alloc
{
- sp_pcontext(const sp_pcontext &); /* Prevent use of these */
- void operator=(sp_pcontext &);
+public:
- public:
-
- sp_pcontext(sp_pcontext *prev);
+ /**
+ Constructor.
+ Builds a parsing context root node.
+ */
+ sp_pcontext();
// Free memory
void
destroy();
+ /**
+ Create and push a new context in the tree.
+ @param label_scope label scope for the new parsing context
+ @return the node created
+ */
sp_pcontext *
- push_context();
+ push_context(label_scope_type label_scope);
- // Returns the previous context, not the one we pop
+ /**
+ Pop a node from the parsing context tree.
+ @return the parent node
+ */
sp_pcontext *
pop_context();
@@ -248,7 +273,7 @@ class sp_pcontext : public Sql_alloc
inline bool
push_case_expr_id(int case_expr_id)
{
- return insert_dynamic(&m_case_expr_id_lst, (gptr) &case_expr_id);
+ return insert_dynamic(&m_case_expr_id_lst, (uchar*) &case_expr_id);
}
inline void
@@ -262,7 +287,7 @@ class sp_pcontext : public Sql_alloc
{
int case_expr_id;
- get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (gptr) &case_expr_id,
+ get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (uchar*) &case_expr_id,
m_case_expr_id_lst.elements - 1);
return case_expr_id;
@@ -318,7 +343,7 @@ class sp_pcontext : public Sql_alloc
inline void
push_handler(sp_cond_type_t *cond)
{
- insert_dynamic(&m_handlers, (gptr)&cond);
+ insert_dynamic(&m_handlers, (uchar*)&cond);
}
bool
@@ -364,6 +389,13 @@ class sp_pcontext : public Sql_alloc
protected:
+ /**
+ Constructor for a tree node.
+ @param prev the parent parsing context
+ @param label_scope label_scope for this parsing context
+ */
+ sp_pcontext(sp_pcontext *prev, label_scope_type label_scope);
+
/*
m_max_var_index -- number of variables (including all types of arguments)
in this context including all children contexts.
@@ -417,6 +449,14 @@ private:
List<sp_pcontext> m_children; // Children contexts, used for destruction
+ /**
+ Scope of labels for this parsing context.
+ */
+ label_scope_type m_label_scope;
+
+private:
+ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
+ void operator=(sp_pcontext &);
}; // class sp_pcontext : public Sql_alloc
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 67ee5459bb4..e49c4eb1240 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 5e03aa60d23..fbf479f52aa 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 02f1525f2ad..e0680ed182c 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,13 +23,13 @@
String Geometry::bad_geometry_data("Bad object", &my_charset_bin);
-Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]=
+Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_last+1]=
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static Geometry::Class_info **ci_collection_end=
- Geometry::ci_collection+Geometry::wkb_end + 1;
+ Geometry::ci_collection+Geometry::wkb_last + 1;
Geometry::Class_info::Class_info(const char *name, int type_id,
void(*create_func)(void *)):
@@ -217,23 +216,24 @@ static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
}
-int Geometry::create_from_wkb(Geometry_buffer *buffer,
- const char *wkb, uint32 len, String *res)
+Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
+ const char *wkb, uint32 len, String *res)
{
uint32 geom_type;
Geometry *geom;
if (len < WKB_HEADER_SIZE)
- return 1;
+ return NULL;
geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
res->reserve(WKB_HEADER_SIZE, 512))
- return 1;
+ return NULL;
res->q_append((char) wkb_ndr);
res->q_append(geom_type);
- return geom->init_from_wkb(wkb+WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
- (wkbByteOrder) wkb[0], res);
+
+ return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
+ (wkbByteOrder) wkb[0], res) ? geom : NULL;
}
@@ -553,7 +553,7 @@ bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
}
-int Gis_line_string::length(double *len) const
+int Gis_line_string::geom_length(double *len) const
{
uint32 n_points;
double prev_x, prev_y;
@@ -929,6 +929,8 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
n_linear_rings= uint4korr(data);
data+= 4;
+ DBUG_ASSERT(n_linear_rings > 0);
+
while (n_linear_rings--)
{
uint32 n_points, org_n_points;
@@ -948,14 +950,14 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
while (--n_points) // One point is already read
{
- double x, y;
- get_point(&x, &y, data);
+ double tmp_x, tmp_y;
+ get_point(&tmp_x, &tmp_y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
- cur_area+= (prev_x + x) * (prev_y - y);
- cur_cx+= x;
- cur_cy+= y;
- prev_x= x;
- prev_y= y;
+ cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y);
+ cur_cx+= tmp_x;
+ cur_cy+= tmp_y;
+ prev_x= tmp_x;
+ prev_y= tmp_y;
}
cur_area= fabs(cur_area) / 2;
cur_cx= cur_cx / (org_n_points - 1);
@@ -1299,7 +1301,7 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const
}
-int Gis_multi_line_string::length(double *len) const
+int Gis_multi_line_string::geom_length(double *len) const
{
uint32 n_line_strings;
const char *data= m_data;
@@ -1316,7 +1318,7 @@ int Gis_multi_line_string::length(double *len) const
Gis_line_string ls;
data+= WKB_HEADER_SIZE;
ls.set_data_ptr(data, (uint32) (m_data_end - data));
- if (ls.length(&ls_len))
+ if (ls.geom_length(&ls_len))
return 1;
*len+= ls_len;
/*
diff --git a/sql/spatial.h b/sql/spatial.h
index 36949ff5014..f806861290e 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2002-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -145,15 +144,46 @@ struct MBR
return (xmin<x) && (xmax>x) && (ymin<y) && (ymax>y);
}
+ /**
+ The dimension maps to an integer as:
+ - Polygon -> 2
+ - Horizontal or vertical line -> 1
+ - Point -> 0
+ - Invalid MBR -> -1
+ */
+ int dimension() const
+ {
+ int d= 0;
+
+ if (xmin > xmax)
+ return -1;
+ else if (xmin < xmax)
+ d++;
+
+ if (ymin > ymax)
+ return -1;
+ else if (ymin < ymax)
+ d++;
+
+ return d;
+ }
+
int overlaps(const MBR *mbr)
{
- int lb= mbr->inner_point(xmin, ymin);
- int rb= mbr->inner_point(xmax, ymin);
- int rt= mbr->inner_point(xmax, ymax);
- int lt= mbr->inner_point(xmin, ymax);
+ /*
+ overlaps() requires that some point inside *this is also inside
+ *mbr, and that both geometries and their intersection are of the
+ same dimension.
+ */
+ int d = dimension();
+
+ if (d != mbr->dimension() || d <= 0 || contains(mbr) || within(mbr))
+ return 0;
+
+ MBR intersection(max(xmin, mbr->xmin), max(ymin, mbr->ymin),
+ min(xmax, mbr->xmax), min(ymax, mbr->ymax));
- int a = lb+rb+rt+lt;
- return (a>0) && (a<4) && (!within(mbr));
+ return (d == intersection.dimension());
}
};
@@ -189,7 +219,7 @@ public:
wkb_multilinestring= 5,
wkb_multipolygon= 6,
wkb_geometrycollection= 7,
- wkb_end=7
+ wkb_last=7
};
enum wkbByteOrder
{
@@ -218,7 +248,7 @@ public:
virtual bool dimension(uint32 *dim, const char **end) const=0;
virtual int get_x(double *x) const { return -1; }
virtual int get_y(double *y) const { return -1; }
- virtual int length(double *len) const { return -1; }
+ virtual int geom_length(double *len) const { return -1; }
virtual int area(double *ar, const char **end) const { return -1;}
virtual int is_closed(int *closed) const { return -1; }
virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; }
@@ -247,8 +277,8 @@ public:
static Geometry *create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt,
bool init_stream=1);
- static int create_from_wkb(Geometry_buffer *buffer,
- const char *wkb, uint32 len, String *res);
+ static Geometry *create_from_wkb(Geometry_buffer *buffer, const char *wkb,
+ uint32 len, String *res);
int as_wkt(String *wkt, const char **end)
{
uint32 len= get_class_info()->m_name.length;
@@ -274,12 +304,12 @@ public:
}
bool envelope(String *result) const;
- static Class_info *ci_collection[wkb_end+1];
+ static Class_info *ci_collection[wkb_last+1];
protected:
static Class_info *find_class(int type_id)
{
- return ((type_id < wkb_point) || (type_id > wkb_end)) ?
+ return ((type_id < wkb_point) || (type_id > wkb_last)) ?
NULL : ci_collection[type_id];
}
static Class_info *find_class(const char *name, uint32 len);
@@ -360,7 +390,7 @@ public:
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
bool get_data_as_wkt(String *txt, const char **end) const;
bool get_mbr(MBR *mbr, const char **end) const;
- int length(double *len) const;
+ int geom_length(double *len) const;
int is_closed(int *closed) const;
int num_points(uint32 *n_points) const;
int start_point(String *point) const;
@@ -442,7 +472,7 @@ public:
bool get_mbr(MBR *mbr, const char **end) const;
int num_geometries(uint32 *num) const;
int geometry_n(uint32 num, String *result) const;
- int length(double *len) const;
+ int geom_length(double *len) const;
int is_closed(int *closed) const;
bool dimension(uint32 *dim, const char **end) const
{
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 3da00695b35..59e3c0a7dd4 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -161,11 +160,11 @@ public:
};
-static byte* acl_entry_get_key(acl_entry *entry,uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length=(uint) entry->length;
- return (byte*) entry->key;
+ return (uchar*) entry->key;
}
#define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
@@ -363,9 +362,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
}
#endif
- VOID(push_dynamic(&acl_hosts,(gptr) &host));
+ VOID(push_dynamic(&acl_hosts,(uchar*) &host));
}
- qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
+ qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
sizeof(ACL_HOST),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_hosts);
@@ -547,13 +546,13 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user.access|= SUPER_ACL | EXECUTE_ACL;
#endif
}
- VOID(push_dynamic(&acl_users,(gptr) &user));
+ VOID(push_dynamic(&acl_users,(uchar*) &user));
if (!user.host.hostname ||
(user.host.hostname[0] == wild_many && !user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect
}
}
- qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_users);
@@ -610,9 +609,9 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
#endif
- VOID(push_dynamic(&acl_dbs,(gptr) &db));
+ VOID(push_dynamic(&acl_dbs,(uchar*) &db));
}
- qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_dbs);
@@ -761,7 +760,7 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
Field **pos;
for (pos=form->field+fieldnr, bit=1;
- *pos && (*pos)->real_type() == FIELD_TYPE_ENUM &&
+ *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
((Field_enum*) (*pos))->typelib->count == 2 ;
pos++, fieldnr++, bit<<=1)
{
@@ -1153,11 +1152,11 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
DBUG_RETURN(res);
}
-static byte* check_get_key(ACL_USER *buff,uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* check_get_key(ACL_USER *buff, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length=buff->hostname_length;
- return (byte*) buff->host.hostname;
+ return (uchar*) buff->host.hostname;
}
@@ -1238,11 +1237,11 @@ static void acl_insert_user(const char *user, const char *host,
set_user_salt(&acl_user, password, password_len);
- VOID(push_dynamic(&acl_users,(gptr) &acl_user));
+ VOID(push_dynamic(&acl_users,(uchar*) &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 */
- qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
@@ -1304,8 +1303,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
acl_db.db=strdup_root(&mem,db);
acl_db.access=privileges;
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
- VOID(push_dynamic(&acl_dbs,(gptr) &acl_db));
- qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ VOID(push_dynamic(&acl_dbs,(uchar*) &acl_db));
+ qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
sizeof(ACL_DB),(qsort_cmp) acl_compare);
}
@@ -1322,7 +1321,8 @@ ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern)
{
ulong host_access= ~(ulong)0, db_access= 0;
- uint i,key_length;
+ uint i;
+ size_t key_length;
char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
DBUG_ENTER("acl_get");
@@ -1334,8 +1334,9 @@ ulong acl_get(const char *host, const char *ip,
my_casedn_str(files_charset_info, tmp_db);
db=tmp_db;
}
- key_length=(uint) (end-key);
- if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search(key,key_length)))
+ key_length= (size_t) (end-key);
+ if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
+ key_length)))
{
db_access=entry->access;
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1389,7 +1390,7 @@ exit:
{
entry->access=(db_access & host_access);
entry->length=key_length;
- memcpy((gptr) entry->key,key,key_length);
+ memcpy((uchar*) entry->key,key,key_length);
acl_cache->add(entry);
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1431,12 +1432,12 @@ static void init_check_host(void)
break; // already stored
}
if (j == acl_wild_hosts.elements) // If new
- (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
+ (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
}
- else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname,
- (uint) strlen(acl_user->host.hostname)))
+ else if (!hash_search(&acl_check_hosts,(uchar*) acl_user->host.hostname,
+ strlen(acl_user->host.hostname)))
{
- if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
+ if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
{ // End of memory
allow_all_hosts=1; // Should never happen
DBUG_VOID_RETURN;
@@ -1474,8 +1475,8 @@ bool acl_check_host(const char *host, const char *ip)
return 0;
VOID(pthread_mutex_lock(&acl_cache->lock));
- if (host && hash_search(&acl_check_hosts,(byte*) host,(uint) strlen(host)) ||
- ip && hash_search(&acl_check_hosts,(byte*) ip,(uint) strlen(ip)))
+ if (host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host)) ||
+ ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
return 0; // Found host
@@ -1534,7 +1535,7 @@ bool check_change_password(THD *thd, const char *host, const char *user,
MYF(0));
return(1);
}
- uint len=strlen(new_password);
+ size_t len= strlen(new_password);
if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
@@ -1568,7 +1569,7 @@ bool change_password(THD *thd, const char *host, const char *user,
/* Buffer should be extended when password length is extended. */
char buff[512];
ulong query_length;
- uint new_password_len= strlen(new_password);
+ uint new_password_len= (uint) strlen(new_password);
bool result= 1;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
@@ -1769,8 +1770,8 @@ bool hostname_requires_resolving(const char *hostname)
char cur;
if (!hostname)
return FALSE;
- int namelen= strlen(hostname);
- int lhlen= strlen(my_localhost);
+ size_t namelen= strlen(hostname);
+ size_t lhlen= strlen(my_localhost);
if ((namelen == lhlen) &&
!my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
(const uchar *)my_localhost, strlen(my_localhost)))
@@ -1810,12 +1811,11 @@ static bool update_user_table(THD *thd, TABLE *table,
table->use_all_columns();
table->field[0]->store(host,(uint) strlen(host), system_charset_info);
table->field[1]->store(user,(uint) strlen(user), system_charset_info);
- key_copy((byte *) user_key, table->record[0], table->key_info,
+ key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
- (byte *) user_key,
- table->key_info->key_length,
+ (uchar *) user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
@@ -1880,7 +1880,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
const char *password= "";
uint password_len= 0;
char what= (revoke_grant) ? 'N' : 'Y';
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
LEX *lex= thd->lex;
DBUG_ENTER("replace_user_table");
@@ -1906,8 +1906,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0], 0,
- user_key, table->key_info->key_length,
+ if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/* what == 'N' means revoke */
@@ -1969,7 +1968,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
ulong priv;
uint next_field;
for (tmp_field= table->field+3, priv = SELECT_ACL;
- *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM &&
+ *tmp_field && (*tmp_field)->real_type() == MYSQL_TYPE_ENUM &&
((Field_enum*) (*tmp_field))->typelib->count == 2 ;
tmp_field++, priv <<= 1)
{
@@ -2099,7 +2098,7 @@ static int replace_db_table(TABLE *table, const char *db,
bool old_row_exists=0;
int error;
char what= (revoke_grant) ? 'N' : 'Y';
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_db_table");
if (!initialized)
@@ -2124,8 +2123,7 @@ static int replace_db_table(TABLE *table, const char *db,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0],0,
- user_key, table->key_info->key_length,
+ if (table->file->index_read_idx(table->record[0],0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
if (what == 'N')
@@ -2202,16 +2200,16 @@ public:
uint key_length;
GRANT_COLUMN(String &c, ulong y) :rights (y)
{
- column= memdup_root(&memex,c.ptr(), key_length=c.length());
+ column= (char*) memdup_root(&memex,c.ptr(), key_length=c.length());
}
};
-static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
+static uchar* get_key_column(GRANT_COLUMN *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->key_length;
- return (byte*) buff->column;
+ return (uchar*) buff->column;
}
@@ -2222,7 +2220,7 @@ public:
char *db, *user, *tname, *hash_key;
ulong privs;
ulong sort;
- uint key_length;
+ size_t key_length;
GRANT_NAME(const char *h, const char *d,const char *u,
const char *t, ulong p);
GRANT_NAME (TABLE *form);
@@ -2261,8 +2259,8 @@ GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
my_casedn_str(files_charset_info, db);
my_casedn_str(files_charset_info, tname);
}
- key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
- hash_key = (char*) alloc_root(&memex,key_length);
+ key_length= strlen(d) + strlen(u)+ strlen(t)+3;
+ hash_key= (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
}
@@ -2296,9 +2294,8 @@ GRANT_NAME::GRANT_NAME(TABLE *form)
my_casedn_str(files_charset_info, db);
my_casedn_str(files_charset_info, tname);
}
- key_length = ((uint) strlen(db) + (uint) strlen(user) +
- (uint) strlen(tname) + 3);
- hash_key = (char*) alloc_root(&memex,key_length);
+ key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
+ hash_key= (char*) alloc_root(&memex, key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (ulong) form->field[6]->val_int();
privs = fix_rights_for_table(privs);
@@ -2308,7 +2305,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form)
GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
:GRANT_NAME(form)
{
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
if (!db || !tname)
{
@@ -2342,9 +2339,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->ha_index_init(0, 1);
- if (col_privs->file->index_read(col_privs->record[0],
- (byte*) key,
- key_prefix_len, HA_READ_KEY_EXACT))
+ if (col_privs->file->index_read(col_privs->record[0], (uchar*) key,
+ (key_part_map)15, HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@@ -2364,7 +2360,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
privs = cols = 0; /* purecov: deadcode */
return; /* purecov: deadcode */
}
- my_hash_insert(&hash_columns, (byte *) mem_check);
+ my_hash_insert(&hash_columns, (uchar *) mem_check);
} while (!col_privs->file->index_next(col_privs->record[0]) &&
!key_cmp_if_same(col_privs,key,0,key_prefix_len));
col_privs->file->ha_index_end();
@@ -2378,11 +2374,11 @@ GRANT_TABLE::~GRANT_TABLE()
}
-static byte* get_grant_table(GRANT_NAME *buff,uint *length,
+static uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->key_length;
- return (byte*) buff->hash_key;
+ return (uchar*) buff->hash_key;
}
@@ -2406,10 +2402,10 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
HASH_SEARCH_STATE state;
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
- for (grant_name= (GRANT_NAME*) hash_first(name_hash, (byte*) helping,
+ for (grant_name= (GRANT_NAME*) hash_first(name_hash, (uchar*) helping,
len, &state);
grant_name ;
- grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping,
+ grant_name= (GRANT_NAME*) hash_next(name_hash,(uchar*) helping,
len, &state))
{
if (exact)
@@ -2454,7 +2450,7 @@ table_hash_search(const char *host, const char *ip, const char *db,
inline GRANT_COLUMN *
column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
{
- return (GRANT_COLUMN*) hash_search(&t->hash_columns, (byte*) cname,length);
+ return (GRANT_COLUMN*) hash_search(&t->hash_columns, (uchar*) cname,length);
}
@@ -2465,7 +2461,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
ulong rights, bool revoke_grant)
{
int error=0,result=0;
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
uint key_prefix_length;
KEY_PART_INFO *key_part= table->key_info->key_part;
DBUG_ENTER("replace_column_table");
@@ -2480,7 +2476,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
table->field[3]->store(table_name,(uint) strlen(table_name),
system_charset_info);
- /* Get length of 3 first key parts */
+ /* Get length of 4 first key parts */
key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
key_part[2].store_length + key_part[3].store_length);
key_copy(key, table->record[0], table->key_info, key_prefix_length);
@@ -2496,7 +2492,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
ulong privileges= column->rights;
bool old_row_exists=0;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
key_restore(table->record[0],key,table->key_info,
key_prefix_length);
@@ -2506,8 +2502,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read(table->record[0], user_key,
- table->key_info->key_length,
+ if (table->file->index_read(table->record[0], user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
if (revoke_grant)
@@ -2568,7 +2563,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
goto end; /* purecov: inspected */
}
grant_column= new GRANT_COLUMN(column->column,privileges);
- my_hash_insert(&g_t->hash_columns,(byte*) grant_column);
+ my_hash_insert(&g_t->hash_columns,(uchar*) grant_column);
}
}
@@ -2579,12 +2574,11 @@ static int replace_column_table(GRANT_TABLE *g_t,
if (revoke_grant)
{
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
- if (table->file->index_read(table->record[0], user_key,
- key_prefix_length,
+ if (table->file->index_read(table->record[0], user_key, (key_part_map)15,
HA_READ_KEY_EXACT))
goto end;
@@ -2632,7 +2626,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
goto end; /* purecov: deadcode */
}
if (grant_column)
- hash_delete(&g_t->hash_columns,(byte*) grant_column);
+ hash_delete(&g_t->hash_columns,(uchar*) grant_column);
}
}
} while (!table->file->index_next(table->record[0]) &&
@@ -2655,7 +2649,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
int old_row_exists = 1;
int error=0;
ulong store_table_rights, store_col_rights;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
strxmov(grantor, thd->security_ctx->user, "@",
@@ -2685,8 +2679,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx(table->record[0], 0,
- user_key, table->key_info->key_length,
+ if (table->file->index_read_idx(table->record[0], 0, user_key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/*
@@ -2756,7 +2749,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
else
{
- hash_delete(&column_priv_hash,(byte*) grant_table);
+ hash_delete(&column_priv_hash,(uchar*) grant_table);
}
DBUG_RETURN(0);
@@ -2804,13 +2797,13 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
- table->field[4]->store((longlong)(is_proc ?
+ table->field[4]->store((longlong)(is_proc ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
TRUE);
store_record(table,record[1]); // store at pos 1
- if (table->file->index_read_idx(table->record[0],0,
- (byte*) table->field[0]->ptr,0,
+ if (table->file->index_read_idx(table->record[0], 0,
+ (uchar*) table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
/*
@@ -2873,7 +2866,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
}
else
{
- hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
+ hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name);
}
DBUG_RETURN(0);
@@ -3002,6 +2995,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3082,7 +3082,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
result= TRUE; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
- my_hash_insert(&column_priv_hash,(byte*) grant_table);
+ my_hash_insert(&column_priv_hash,(uchar*) grant_table);
}
/* If revoke_grant, calculate the new column privilege for tables_priv */
@@ -3137,7 +3137,6 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
}
}
- grant_option=TRUE;
thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock);
@@ -3219,6 +3218,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3294,7 +3300,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
result= TRUE;
continue;
}
- my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
+ my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name);
}
if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
@@ -3304,7 +3310,6 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
continue;
}
}
- grant_option=TRUE;
thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock);
if (!result && !no_error)
@@ -3358,6 +3363,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3445,7 +3457,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
void grant_free(void)
{
DBUG_ENTER("grant_free");
- grant_option = FALSE;
hash_free(&column_priv_hash);
hash_free(&proc_priv_hash);
hash_free(&func_priv_hash);
@@ -3509,7 +3520,6 @@ static my_bool grant_load(TABLE_LIST *tables)
THR_MALLOC);
DBUG_ENTER("grant_load");
- grant_option = FALSE;
(void) hash_init(&column_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
@@ -3539,7 +3549,6 @@ static my_bool grant_load(TABLE_LIST *tables)
if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table)))
{
/* This could only happen if we are out memory */
- grant_option= FALSE;
goto end_unlock;
}
@@ -3559,10 +3568,9 @@ static my_bool grant_load(TABLE_LIST *tables)
if (! mem_check->ok())
delete mem_check;
- else if (my_hash_insert(&column_priv_hash,(byte*) mem_check))
+ else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check))
{
delete mem_check;
- grant_option= FALSE;
goto end_unlock;
}
}
@@ -3579,7 +3587,6 @@ static my_bool grant_load(TABLE_LIST *tables)
if (!(mem_check=new (&memex) GRANT_NAME(p_table)))
{
/* This could only happen if we are out memory */
- grant_option= FALSE;
goto end_unlock;
}
@@ -3615,16 +3622,14 @@ static my_bool grant_load(TABLE_LIST *tables)
mem_check->privs= fix_rights_for_procedure(mem_check->privs);
if (! mem_check->ok())
delete mem_check;
- else if (my_hash_insert(hash, (byte*) mem_check))
+ else if (my_hash_insert(hash, (uchar*) mem_check))
{
delete mem_check;
- grant_option= FALSE;
goto end_unlock;
}
}
while (!p_table->file->index_next(p_table->record[0]));
}
- grant_option= TRUE;
return_val=0; // Return ok
end_unlock:
@@ -3657,7 +3662,6 @@ my_bool grant_reload(THD *thd)
{
TABLE_LIST tables[3];
HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
- bool old_grant_option;
MEM_ROOT old_mem;
my_bool return_val= 1;
DBUG_ENTER("grant_reload");
@@ -3687,7 +3691,6 @@ my_bool grant_reload(THD *thd)
old_column_priv_hash= column_priv_hash;
old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash;
- old_grant_option= grant_option;
old_mem= memex;
if ((return_val= grant_load(tables)))
@@ -3697,7 +3700,6 @@ my_bool grant_reload(THD *thd)
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
proc_priv_hash= old_proc_priv_hash;
func_priv_hash= old_func_priv_hash;
- grant_option= old_grant_option; /* purecov: deadcode */
memex= old_mem; /* purecov: deadcode */
}
else
@@ -3994,8 +3996,6 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
want_access &= ~grant->privilege;
if (!want_access)
return 0; // Already checked
- if (!grant_option)
- goto err2;
rw_rdlock(&LOCK_grant);
@@ -4026,7 +4026,6 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
err:
rw_unlock(&LOCK_grant);
-err2:
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
@@ -4039,6 +4038,26 @@ err2:
}
+static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
+{
+ Security_context *sctx= thd->security_ctx;
+
+ for (uint idx= 0; idx < hash->records; ++idx)
+ {
+ GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx);
+
+ if (strcmp(item->user, sctx->priv_user) == 0 &&
+ strcmp(item->db, db) == 0 &&
+ compare_hostname(&item->host, sctx->host, sctx->ip))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
/*
Check if a user has the right to access a database
Access is accepted if he has a grant for any table/routine in the database
@@ -4050,9 +4069,10 @@ bool check_grant_db(THD *thd,const char *db)
Security_context *sctx= thd->security_ctx;
char helping [NAME_LEN+USERNAME_LENGTH+2];
uint len;
- bool error= 1;
+ bool error= TRUE;
len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
+
rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
@@ -4063,11 +4083,17 @@ bool check_grant_db(THD *thd,const char *db)
!memcmp(grant_table->hash_key,helping,len) &&
compare_hostname(&grant_table->host, sctx->host, sctx->ip))
{
- error=0; // Found match
+ error= FALSE; /* Found match. */
break;
}
}
+
+ if (error)
+ error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
+ check_grant_db_routine(thd, db, &func_priv_hash);
+
rw_unlock(&LOCK_grant);
+
return error;
}
@@ -4158,18 +4184,15 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc)
{
bool no_routine_acl= 1;
- if (grant_option)
- {
- GRANT_NAME *grant_proc;
- Security_context *sctx= thd->security_ctx;
- rw_rdlock(&LOCK_grant);
- if ((grant_proc= routine_hash_search(sctx->priv_host,
- sctx->ip, db,
- sctx->priv_user,
- name, is_proc, 0)))
- no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
- rw_unlock(&LOCK_grant);
- }
+ GRANT_NAME *grant_proc;
+ Security_context *sctx= thd->security_ctx;
+ rw_rdlock(&LOCK_grant);
+ if ((grant_proc= routine_hash_search(sctx->priv_host,
+ sctx->ip, db,
+ sctx->priv_user,
+ name, is_proc, 0)))
+ no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
+ rw_unlock(&LOCK_grant);
return no_routine_acl;
}
@@ -4962,7 +4985,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
char *user_str= user_from->user.str;
const char *host;
const char *user;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
uint key_prefix_length;
DBUG_ENTER("handle_grant_table");
@@ -4988,7 +5011,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
if ((error= table->file->index_read_idx(table->record[0], 0,
- user_key, key_prefix_length,
+ user_key, (key_part_map)3,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@@ -5170,6 +5193,8 @@ static int handle_grant_struct(uint struct_no, bool drop,
user= grant_name->user;
host= grant_name->host.hostname;
break;
+ default:
+ assert(0);
}
if (! user)
user= "";
@@ -5197,11 +5222,11 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- hash_delete(&column_priv_hash, (byte*) grant_name);
+ hash_delete(&column_priv_hash, (uchar*) grant_name);
break;
case 3:
- hash_delete(&proc_priv_hash, (byte*) grant_name);
+ hash_delete(&proc_priv_hash, (uchar*) grant_name);
break;
}
elements--;
@@ -5400,6 +5425,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_create_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* CREATE USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5472,6 +5504,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_drop_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* DROP USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5536,6 +5575,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_rename_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* RENAME USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5611,6 +5657,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_revoke_all");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5801,6 +5854,13 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* Remove procedure access */
do
{
@@ -6004,15 +6064,15 @@ void update_schema_privilege(TABLE *table, char *buff, const char* db,
int i= 2;
CHARSET_INFO *cs= system_charset_info;
restore_record(table, s->default_values);
- table->field[0]->store(buff, strlen(buff), cs);
+ table->field[0]->store(buff, (uint) strlen(buff), cs);
if (db)
- table->field[i++]->store(db, strlen(db), cs);
+ table->field[i++]->store(db, (uint) strlen(db), cs);
if (t_name)
- table->field[i++]->store(t_name, strlen(t_name), cs);
+ table->field[i++]->store(t_name, (uint) strlen(t_name), cs);
if (column)
table->field[i++]->store(column, col_length, cs);
table->field[i++]->store(priv, priv_length, cs);
- table->field[i]->store(is_grantable, strlen(is_grantable), cs);
+ table->field[i]->store(is_grantable, (uint) strlen(is_grantable), cs);
table->file->ha_write_row(table->record[0]);
}
@@ -6029,6 +6089,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_user_privileges");
+ if (!initialized)
+ DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_users.elements ; counter++)
@@ -6088,6 +6150,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_schema_privileges");
+ if (!initialized)
+ DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_dbs.elements ; counter++)
@@ -6322,12 +6386,6 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
/* db privileges */
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
- if (!grant_option)
- {
- DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
- DBUG_VOID_RETURN;
- }
-
/* table privileges */
rw_rdlock(&LOCK_grant);
if (grant->version != grant_version)
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index e1153522ed5..cba283ec65b 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -48,8 +47,7 @@
don't forget to update
1. static struct show_privileges_st sys_privileges[]
2. static const char *command_array[] and static uint command_lengths[]
- 3. mysql_create_system_tables.sh, mysql_fix_privilege_tables.sql
- and mysql-test/lib/init_db.sql
+ 3. mysql_system_tables.sql and mysql_system_tables_fix.sql
4. acl_init() or whatever - to define behaviour for old privilege tables
5. sql_yacc.yy - for GRANT/REVOKE to work
*/
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 264e3e2b988..6b4aaa26236 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -87,6 +86,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
else if (param->next)
{
// first parameter
+ if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item))
+ {
+ DBUG_PRINT("info", ("fix_fields() for the first parameter failed"));
+ goto err;
+ }
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val_real() < 0)
{
@@ -101,6 +105,11 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
goto err;
}
// second parameter
+ if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item))
+ {
+ DBUG_PRINT("info", ("fix_fields() for the second parameter failed"));
+ goto err;
+ }
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val_real() < 0)
{
@@ -140,7 +149,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
case INT_RESULT:
// Check if fieldtype is ulonglong
if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG &&
+ ((Item_field*) item)->field->type() == MYSQL_TYPE_LONGLONG &&
((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
new_field= new field_ulonglong(item, pc);
else
@@ -489,7 +498,7 @@ void field_decimal::add()
if (room_in_tree)
{
- char buf[DECIMAL_MAX_FIELD_SIZE];
+ uchar buf[DECIMAL_MAX_FIELD_SIZE];
my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
item->max_length, item->decimals);
if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
@@ -755,26 +764,26 @@ bool analyse::end_of_records()
{
switch (((Item_field*) (*f)->item)->field->real_type())
{
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
ans.append(STRING_WITH_LEN("TIMESTAMP"));
break;
- case FIELD_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME:
ans.append(STRING_WITH_LEN("DATETIME"));
break;
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
ans.append(STRING_WITH_LEN("DATE"));
break;
- case FIELD_TYPE_SET:
+ case MYSQL_TYPE_SET:
ans.append(STRING_WITH_LEN("SET"));
break;
- case FIELD_TYPE_YEAR:
+ case MYSQL_TYPE_YEAR:
ans.append(STRING_WITH_LEN("YEAR"));
break;
- case FIELD_TYPE_TIME:
+ case MYSQL_TYPE_TIME:
ans.append(STRING_WITH_LEN("TIME"));
break;
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
ans.append(STRING_WITH_LEN("DECIMAL"));
// if item is FIELD_ITEM, it _must_be_ Field_num in this case
if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill)
@@ -1099,7 +1108,7 @@ int collect_real(double *element, element_count count __attribute__((unused)),
} // collect_real
-int collect_decimal(char *element, element_count count,
+int collect_decimal(uchar *element, element_count count,
TREE_INFO *info)
{
char buff[DECIMAL_MAX_STR_LENGTH];
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 0e7bd1b722a..ae5d88bf93e 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -144,7 +143,7 @@ public:
};
-int collect_decimal(char *element, element_count count,
+int collect_decimal(uchar *element, element_count count,
TREE_INFO *info);
class field_decimal :public field_info
@@ -166,7 +165,7 @@ public:
String *get_min_arg(String *);
String *get_max_arg(String *);
String *avg(String *s, ha_rows rows);
- friend int collect_decimal(char *element, element_count count,
+ friend int collect_decimal(uchar *element, element_count count,
TREE_INFO *info);
tree_walk_action collect_enum()
{ return (tree_walk_action) collect_decimal; }
diff --git a/sql/sql_array.h b/sql/sql_array.h
index c68caf74b25..ab6fdd0c5c0 100644
--- a/sql/sql_array.h
+++ b/sql/sql_array.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -46,7 +45,7 @@ public:
bool append(Elem &el)
{
- return (insert_dynamic(&array, (gptr)&el));
+ return (insert_dynamic(&array, (uchar*)&el));
}
int elements()
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index db652d5aebe..7c8b1f724d8 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -29,6 +28,59 @@
#include <io.h>
#endif
+/**
+ This internal handler is used to trap internally
+ errors that can occur when executing open table
+ during the prelocking phase.
+*/
+class Prelock_error_handler : public Internal_error_handler
+{
+public:
+ Prelock_error_handler()
+ : m_handled_errors(0), m_unhandled_errors(0)
+ {}
+
+ virtual ~Prelock_error_handler() {}
+
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+
+ bool safely_trapped_errors();
+
+private:
+ int m_handled_errors;
+ int m_unhandled_errors;
+};
+
+
+bool
+Prelock_error_handler::handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level /* level */,
+ THD * /* thd */)
+{
+ if (sql_errno == ER_NO_SUCH_TABLE)
+ {
+ m_handled_errors++;
+ return TRUE; // 'TRUE', as per coding style
+ }
+
+ m_unhandled_errors++;
+ return FALSE; // 'FALSE', as per coding style
+}
+
+
+bool Prelock_error_handler::safely_trapped_errors()
+{
+ /*
+ If m_unhandled_errors != 0, something else, unanticipated, happened,
+ so the error is not trapped but returned to the caller.
+ Multiple ER_NO_SUCH_TABLE can be raised in case of views.
+ */
+ return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
+}
+
+
TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
static HASH table_def_cache;
@@ -41,32 +93,29 @@ static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
char *cache_key, uint cache_key_length,
MEM_ROOT *mem_root, uint flags);
static void free_cache_entry(TABLE *entry);
-static void mysql_rm_tmp_tables(void);
static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
-static void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
+static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
bool send_refresh);
-static bool reopen_table(TABLE *table);
static bool
has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables);
-extern "C" byte *table_cache_key(const byte *record,uint *length,
+extern "C" uchar *table_cache_key(const uchar *record, size_t *length,
my_bool not_used __attribute__((unused)))
{
TABLE *entry=(TABLE*) record;
*length= entry->s->table_cache_key.length;
- return (byte*) entry->s->table_cache_key.str;
+ return (uchar*) entry->s->table_cache_key.str;
}
bool table_cache_init(void)
{
- mysql_rm_tmp_tables();
return hash_init(&open_cache, &my_charset_bin, table_cache_size+16,
- 0, 0,table_cache_key,
+ 0, 0, table_cache_key,
(hash_free_key) free_cache_entry, 0) != 0;
}
@@ -193,12 +242,12 @@ uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
Functions to handle table definition cach (TABLE_SHARE)
*****************************************************************************/
-extern "C" byte *table_def_key(const byte *record, uint *length,
+extern "C" uchar *table_def_key(const uchar *record, size_t *length,
my_bool not_used __attribute__((unused)))
{
TABLE_SHARE *entry=(TABLE_SHARE*) record;
*length= entry->table_cache_key.length;
- return (byte*) entry->table_cache_key.str;
+ return (uchar*) entry->table_cache_key.str;
}
@@ -284,7 +333,7 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
*error= 0;
/* Read table definition from cache */
- if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(byte*) key,
+ if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key,
key_length)))
goto found;
@@ -301,7 +350,7 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
pthread_mutex_unlock(&LOCK_open);
pthread_mutex_lock(&LOCK_open);
/* Check that another thread didn't insert the same table in between */
- if ((old_share= hash_search(&table_def_cache, (byte*) key, key_length)))
+ if ((old_share= hash_search(&table_def_cache, (uchar*) key, key_length)))
{
(void) pthread_mutex_lock(&share->mutex);
free_table_share(share);
@@ -331,7 +380,7 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
*/
assign_new_table_id(share);
- if (my_hash_insert(&table_def_cache, (byte*) share))
+ if (my_hash_insert(&table_def_cache, (uchar*) share))
{
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
pthread_mutex_unlock(&LOCK_open);
@@ -357,7 +406,7 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
(void) pthread_mutex_lock(&share->mutex);
#endif
*error= share->error;
- (void) hash_delete(&table_def_cache, (byte*) share);
+ (void) hash_delete(&table_def_cache, (uchar*) share);
DBUG_RETURN(0);
}
share->ref_count++; // Mark in use
@@ -412,7 +461,7 @@ found:
oldest_unused_share->next)
{
pthread_mutex_lock(&oldest_unused_share->mutex);
- VOID(hash_delete(&table_def_cache, (byte*) oldest_unused_share));
+ VOID(hash_delete(&table_def_cache, (uchar*) oldest_unused_share));
}
DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u",
@@ -535,7 +584,7 @@ void release_table_share(TABLE_SHARE *share, enum release_type type)
if (to_be_deleted)
{
DBUG_PRINT("info", ("Deleting share"));
- hash_delete(&table_def_cache, (byte*) share);
+ hash_delete(&table_def_cache, (uchar*) share);
DBUG_VOID_RETURN;
}
pthread_mutex_unlock(&share->mutex);
@@ -561,13 +610,13 @@ void release_table_share(TABLE_SHARE *share, enum release_type type)
This code is execured when someone does FLUSH TABLES while on has
locked tables.
*/
- (void) hash_search(&def_cache,(byte*) key,key_length);
- hash_replace(&def_cache, def_cache.current_record,(byte*) name_lock);
+ (void) hash_search(&def_cache,(uchar*) key,key_length);
+ hash_replace(&def_cache, def_cache.current_record,(uchar*) name_lock);
}
else
{
/* Remove table definition */
- hash_delete(&def_cache,(byte*) share);
+ hash_delete(&def_cache,(uchar*) share);
}
pthread_mutex_unlock(&LOCK_open);
free_table_share(share);
@@ -612,7 +661,7 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
key_length= create_table_def_key((THD*) 0, key, &table_list, 0);
- return (TABLE_SHARE*) hash_search(&table_def_cache,(byte*) key, key_length);
+ return (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key, key_length);
}
@@ -631,13 +680,15 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
*/
-static void close_handle_and_leave_table_as_lock(TABLE *table)
+void close_handle_and_leave_table_as_lock(TABLE *table)
{
TABLE_SHARE *share, *old_share= table->s;
char *key_buff;
MEM_ROOT *mem_root= &table->mem_root;
DBUG_ENTER("close_handle_and_leave_table_as_lock");
+ DBUG_ASSERT(table->db_stat);
+
/*
Make a local copy of the table share and free the current one.
This has to be done to ensure that the table share is removed from
@@ -790,7 +841,7 @@ static void free_cache_entry(TABLE *table)
}
check_unused(); // consisty check
}
- my_free((gptr) table,MYF(0));
+ my_free((uchar*) table,MYF(0));
DBUG_VOID_RETURN;
}
@@ -802,12 +853,13 @@ void free_io_cache(TABLE *table)
if (table->sort.io_cache)
{
close_cached_file(table->sort.io_cache);
- my_free((gptr) table->sort.io_cache,MYF(0));
+ my_free((uchar*) table->sort.io_cache,MYF(0));
table->sort.io_cache=0;
}
DBUG_VOID_RETURN;
}
+
/*
Close all tables which aren't in use by any thread
@@ -830,17 +882,17 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
while (unused_tables)
{
#ifdef EXTRA_DEBUG
- if (hash_delete(&open_cache,(byte*) unused_tables))
+ if (hash_delete(&open_cache,(uchar*) unused_tables))
printf("Warning: Couldn't delete open table from hash\n");
#else
- VOID(hash_delete(&open_cache,(byte*) unused_tables));
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables));
#endif
}
/* Free table shares */
while (oldest_unused_share->next)
{
pthread_mutex_lock(&oldest_unused_share->mutex);
- VOID(hash_delete(&table_def_cache, (byte*) oldest_unused_share));
+ VOID(hash_delete(&table_def_cache, (uchar*) oldest_unused_share));
}
}
else
@@ -883,8 +935,22 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
+ /*
+ Note that we wait here only for tables which are actually open, and
+ not for placeholders with TABLE::open_placeholder set. Waiting for
+ latter will cause deadlock in the following scenario, for example:
+
+ conn1: lock table t1 write;
+ conn2: lock table t2 write;
+ conn1: flush tables;
+ conn2: flush tables;
+
+ It also does not make sense to wait for those of placeholders that
+ are employed by CREATE TABLE as in this case table simply does not
+ exist yet.
+ */
if (!table->s->log_table &&
- ((table->s->version) < refresh_version && table->db_stat))
+ (table->needs_reopen_or_name_lock() && table->db_stat))
{
found=1;
DBUG_PRINT("signal", ("Waiting for COND_refresh"));
@@ -920,6 +986,71 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
/*
+ Close all tables which match specified connection string or
+ if specified string is NULL, then any table with a connection string.
+*/
+
+bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh,
+ LEX_STRING *connection, bool have_lock)
+{
+ uint idx;
+ TABLE_LIST tmp, *tables= NULL;
+ bool result= FALSE;
+ DBUG_ENTER("close_cached_connections");
+ DBUG_ASSERT(thd);
+
+ bzero(&tmp, sizeof(TABLE_LIST));
+
+ if (!have_lock)
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ for (idx= 0; idx < table_def_cache.records; idx++)
+ {
+ TABLE_SHARE *share= (TABLE_SHARE *) hash_element(&table_def_cache, idx);
+
+ /* Ignore if table is not open or does not have a connect_string */
+ if (!share->connect_string.length || !share->ref_count)
+ continue;
+
+ /* Compare the connection string */
+ if (connection &&
+ (connection->length > share->connect_string.length ||
+ (connection->length < share->connect_string.length &&
+ (share->connect_string.str[connection->length] != '/' &&
+ share->connect_string.str[connection->length] != '\\')) ||
+ strncasecmp(connection->str, share->connect_string.str,
+ connection->length)))
+ continue;
+
+ /* close_cached_tables() only uses these elements */
+ tmp.db= share->db.str;
+ tmp.table_name= share->table_name.str;
+ tmp.next_local= tables;
+
+ tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp,
+ sizeof(TABLE_LIST));
+ }
+
+ if (tables)
+ result= close_cached_tables(thd, FALSE, tables, TRUE);
+
+ if (!have_lock)
+ VOID(pthread_mutex_unlock(&LOCK_open));
+
+ if (if_wait_for_refresh)
+ {
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ thd->proc_info=0;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ }
+
+ DBUG_RETURN(result);
+}
+
+
+/*
Mark all tables in the list which were used by current substatement
as free for reuse.
@@ -1081,7 +1212,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
if (!thd->active_transaction())
thd->transaction.xid_state.xid.null();
- /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
if (!lock_in_use)
VOID(pthread_mutex_lock(&LOCK_open));
@@ -1101,7 +1231,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
/* Free tables to hold down open files */
while (open_cache.records > table_cache_size && unused_tables)
- VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
check_unused();
if (found_old_table)
{
@@ -1134,23 +1264,24 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
TABLE *table= *table_ptr;
DBUG_ENTER("close_thread_table");
DBUG_ASSERT(table->key_read == 0);
- DBUG_ASSERT(table->file->inited == handler::NONE);
+ DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
*table_ptr=table->next;
- if (table->s->version != refresh_version ||
+ if (table->needs_reopen_or_name_lock() ||
thd->version != refresh_version || !table->db_stat)
{
- VOID(hash_delete(&open_cache,(byte*) table));
+ VOID(hash_delete(&open_cache,(uchar*) table));
found_old_table=1;
}
else
{
- if (table->s->flush_version != flush_version)
- {
- table->s->flush_version= flush_version;
- table->file->extra(HA_EXTRA_FLUSH);
- }
- // Free memory and reset for next loop
+ /*
+ Open placeholders have TABLE::db_stat set to 0, so they should be
+ handled by the first alternative.
+ */
+ DBUG_ASSERT(!table->open_placeholder);
+
+ /* Free memory and reset for next loop */
table->file->ha_reset();
table->in_use=0;
if (unused_tables)
@@ -1211,11 +1342,12 @@ void close_temporary_tables(THD *thd)
const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
uint stub_len= sizeof(stub) - 1;
char buf[256];
- memcpy(buf, stub, stub_len);
String s_query= String(buf, sizeof(buf), system_charset_info);
- bool found_user_tables= false;
+ bool found_user_tables= FALSE;
LINT_INIT(next);
+ memcpy(buf, stub, stub_len);
+
/*
insertion sort of temp tables by pseudo_thread_id to build ordered list
of sublists of equal pseudo_thread_id
@@ -1266,10 +1398,13 @@ void close_temporary_tables(THD *thd)
{
if (is_user_table(table))
{
+ my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
/* Set pseudo_thread_id to be that of the processed table */
thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
- /* Loop forward through all tables within the sublist of
- common pseudo_thread_id to create single DROP query */
+ /*
+ Loop forward through all tables within the sublist of
+ common pseudo_thread_id to create single DROP query.
+ */
for (s_query.length(stub_len);
table && is_user_table(table) &&
tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
@@ -1280,10 +1415,10 @@ void close_temporary_tables(THD *thd)
due to special characters in the names
*/
append_identifier(thd, &s_query, table->s->db.str, strlen(table->s->db.str));
- s_query.q_append('.');
+ s_query.append('.');
append_identifier(thd, &s_query, table->s->table_name.str,
strlen(table->s->table_name.str));
- s_query.q_append(',');
+ s_query.append(',');
next= table->next;
close_temporary(table, 1, 1);
}
@@ -1295,16 +1430,18 @@ void close_temporary_tables(THD *thd)
0, FALSE);
thd->variables.character_set_client= cs_save;
/*
- Imagine the thread had created a temp table, then was doing a SELECT, and
- the SELECT was killed. Then it's not clever to mark the statement above as
- "killed", because it's not really a statement updating data, and there
- are 99.99% chances it will succeed on slave.
- If a real update (one updating a persistent table) was killed on the
- master, then this real update will be logged with error_code=killed,
- rightfully causing the slave to stop.
+ Imagine the thread had created a temp table, then was doing a
+ SELECT, and the SELECT was killed. Then it's not clever to
+ mark the statement above as "killed", because it's not really
+ a statement updating data, and there are 99.99% chances it
+ will succeed on slave. If a real update (one updating a
+ persistent table) was killed on the master, then this real
+ update will be logged with error_code=killed, rightfully
+ causing the slave to stop.
*/
qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
+ thd->variables.pseudo_thread_id= save_pseudo_thread_id;
}
else
{
@@ -1360,6 +1497,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
thd thread handle
table table which should be checked
table_list list of tables
+ check_alias whether to check tables' aliases
NOTE: to exclude derived tables from check we use following mechanism:
a) during derived table processing set THD::derived_tables_processing
@@ -1387,10 +1525,11 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
0 if table is unique
*/
-TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
+TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias)
{
TABLE_LIST *res;
- const char *d_name, *t_name;
+ const char *d_name, *t_name, *t_alias;
DBUG_ENTER("unique_table");
DBUG_PRINT("enter", ("table alias: %s", table->alias));
@@ -1418,6 +1557,7 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
}
d_name= table->db;
t_name= table->table_name;
+ t_alias= table->alias;
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;)
@@ -1425,6 +1565,9 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
((!res->table || res->table != table->table) &&
+ (!check_alias || !(lower_case_table_names ?
+ my_strcasecmp(files_charset_info, t_alias, res->alias) :
+ strcmp(t_alias, res->alias))) &&
res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
!res->prelocking_placeholder))
break;
@@ -1522,9 +1665,15 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list)
{
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
+ {
+ DBUG_PRINT("info",
+ ("Found table. server_id: %u pseudo_thread_id: %lu",
+ (uint) thd->server_id,
+ (ulong) thd->variables.pseudo_thread_id));
DBUG_RETURN(table);
+ }
}
- DBUG_RETURN(0); // Not a temporary table
+ DBUG_RETURN(0); // Not a temporary table
}
@@ -1588,7 +1737,7 @@ void close_temporary_table(THD *thd, TABLE *table,
void close_temporary(TABLE *table, bool free_share, bool delete_table)
{
- handlerton *table_type= table->s->db_type;
+ handlerton *table_type= table->s->db_type();
DBUG_ENTER("close_temporary");
free_io_cache(table);
@@ -1650,18 +1799,32 @@ static void relink_unused(TABLE *table)
}
-/*
- Remove all instances of table from the current open list
- Free all locks on tables that are done with LOCK TABLES
- */
+/**
+ @brief Remove all instances of table from thread's open list and
+ table cache.
+
+ @param thd Thread context
+ @param find Table to remove
+ @param unlock TRUE - free all locks on tables removed that are
+ done with LOCK TABLES
+ FALSE - otherwise
+
+ @note When unlock parameter is FALSE or current thread doesn't have
+ any tables locked with LOCK TABLES tables are assumed to be
+ not locked (for example already unlocked).
+*/
-TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
+void unlink_open_table(THD *thd, TABLE *find, bool unlock)
{
char key[MAX_DBKEY_LENGTH];
uint key_length= find->s->table_cache_key.length;
- TABLE *start=list,**prev,*next;
- prev= &start;
+ TABLE *list, **prev, *next;
+ DBUG_ENTER("unlink_open_table");
+ safe_mutex_assert_owner(&LOCK_open);
+
+ list= thd->open_tables;
+ prev= &thd->open_tables;
memcpy(key, find->s->table_cache_key.str, key_length);
for (; list ; list=next)
{
@@ -1669,9 +1832,9 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
if (list->s->table_cache_key.length == key_length &&
!memcmp(list->s->table_cache_key.str, key, key_length))
{
- if (thd->locked_tables)
+ if (unlock && thd->locked_tables)
mysql_lock_remove(thd, thd->locked_tables,list);
- VOID(hash_delete(&open_cache,(byte*) list)); // Close table
+ VOID(hash_delete(&open_cache,(uchar*) list)); // Close table
}
else
{
@@ -1682,7 +1845,41 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
*prev=0;
// Notify any 'refresh' threads
broadcast_refresh();
- return start;
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Auxiliary routine which closes and drops open table.
+
+ @param thd Thread handle
+ @param table TABLE object for table to be dropped
+ @param db_name Name of database for this table
+ @param table_name Name of this table
+
+ @note This routine assumes that table to be closed is open only
+ by calling thread so we needn't wait until other threads
+ will close the table. It also assumes that table to be
+ dropped is already unlocked.
+*/
+
+void drop_open_table(THD *thd, TABLE *table, const char *db_name,
+ const char *table_name)
+{
+ if (table->s->tmp_table)
+ close_temporary_table(thd, table, 1, 1);
+ else
+ {
+ handlerton *table_type= table->s->db_type();
+ VOID(pthread_mutex_lock(&LOCK_open));
+ /*
+ unlink_open_table() also tells threads waiting for refresh or close
+ that something has happened.
+ */
+ unlink_open_table(thd, table, FALSE);
+ quick_rm_table(table_type, db_name, table_name, 0);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
}
@@ -1739,6 +1936,11 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
table_list TABLE_LIST object for table to be open, TABLE_LIST::table
member should point to TABLE object which was used for
name-locking.
+ link_in TRUE - if TABLE object for table to be opened should be
+ linked into THD::open_tables list.
+ FALSE - placeholder used for name-locking is already in
+ this list so we only need to preserve TABLE::next
+ pointer.
NOTE
This function assumes that its caller already acquired LOCK_open mutex.
@@ -1748,7 +1950,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
TRUE - Error
*/
-bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
+bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in)
{
TABLE *table= table_list->table;
TABLE_SHARE *share;
@@ -1779,23 +1981,208 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
}
share= table->s;
+ /*
+ We want to prevent other connections from opening this table until end
+ of statement as it is likely that modifications of table's metadata are
+ not yet finished (for example CREATE TRIGGER have to change .TRG file,
+ or we might want to drop table if CREATE TABLE ... SELECT fails).
+ This also allows us to assume that no other connection will sneak in
+ before we will get table-level lock on this table.
+ */
share->version=0;
- share->flush_version=0;
table->in_use = thd;
check_unused();
- table->next = thd->open_tables;
- thd->open_tables = table;
+
+ if (link_in)
+ {
+ table->next= thd->open_tables;
+ thd->open_tables= table;
+ }
+ else
+ {
+ /*
+ TABLE object should be already in THD::open_tables list so we just
+ need to set TABLE::next correctly.
+ */
+ table->next= orig_table.next;
+ }
+
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= share->keys_in_use;
- table->used_keys= share->keys_for_keyread;
DBUG_RETURN(FALSE);
}
+/**
+ @brief Create and insert into table cache placeholder for table
+ which will prevent its opening (or creation) (a.k.a lock
+ table name).
+
+ @param thd Thread context
+ @param key Table cache key for name to be locked
+ @param key_length Table cache key length
+
+ @return Pointer to TABLE object used for name locking or 0 in
+ case of failure.
+*/
+
+TABLE *table_cache_insert_placeholder(THD *thd, const char *key,
+ uint key_length)
+{
+ TABLE *table;
+ TABLE_SHARE *share;
+ char *key_buff;
+ DBUG_ENTER("table_cache_insert_placeholder");
+
+ safe_mutex_assert_owner(&LOCK_open);
+
+ /*
+ Create a table entry with the right key and with an old refresh version
+ Note that we must use my_multi_malloc() here as this is freed by the
+ table cache
+ */
+ if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &table, sizeof(*table),
+ &share, sizeof(*share),
+ &key_buff, key_length,
+ NULL))
+ DBUG_RETURN(NULL);
+
+ table->s= share;
+ share->set_table_cache_key(key_buff, key, key_length);
+ share->tmp_table= INTERNAL_TMP_TABLE; // for intern_close_table
+ table->in_use= thd;
+ table->locked_by_name=1;
+
+ if (my_hash_insert(&open_cache, (uchar*)table))
+ {
+ my_free((uchar*) table, MYF(0));
+ DBUG_RETURN(NULL);
+ }
+
+ DBUG_RETURN(table);
+}
+
+
+/**
+ @brief Obtain an exclusive name lock on the table if it is not cached
+ in the table cache.
+
+ @param thd Thread context
+ @param db Name of database
+ @param table_name Name of table
+ @param[out] table Out parameter which is either:
+ - set to NULL if table cache contains record for
+ the table or
+ - set to point to the TABLE instance used for
+ name-locking.
+
+ @note This function takes into account all records for table in table
+ cache, even placeholders used for name-locking. This means that
+ 'table' parameter can be set to NULL for some situations when
+ table does not really exist.
+
+ @retval TRUE Error occured (OOM)
+ @retval FALSE Success. 'table' parameter set according to above rules.
+*/
+
+bool lock_table_name_if_not_cached(THD *thd, const char *db,
+ const char *table_name, TABLE **table)
+{
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ DBUG_ENTER("lock_table_name_if_not_cached");
+
+ key_length= (uint)(strmov(strmov(key, db) + 1, table_name) - key) + 1;
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ if (hash_search(&open_cache, (uchar *)key, key_length))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_PRINT("info", ("Table is cached, name-lock is not obtained"));
+ *table= 0;
+ DBUG_RETURN(FALSE);
+ }
+ if (!(*table= table_cache_insert_placeholder(thd, key, key_length)))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(TRUE);
+ }
+ (*table)->open_placeholder= 1;
+ (*table)->next= thd->open_tables;
+ thd->open_tables= *table;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ @brief Check that table exists in table definition cache, on disk
+ or in some storage engine.
+
+ @param thd Thread context
+ @param table Table list element
+ @param exists[out] Out parameter which is set to TRUE if table
+ exists and to FALSE otherwise.
+
+ @note This function assumes that caller owns LOCK_open mutex.
+ It also assumes that the fact that there are no name-locks
+ on the table was checked beforehand.
+
+ @note If there is no .FRM file for the table but it exists in one
+ of engines (e.g. it was created on another node of NDB cluster)
+ this function will fetch and create proper .FRM file for it.
+
+ @retval TRUE Some error occured
+ @retval FALSE No error. 'exists' out parameter set accordingly.
+*/
+
+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
+{
+ char path[FN_REFLEN];
+ int rc;
+ DBUG_ENTER("check_if_table_exists");
+
+ safe_mutex_assert_owner(&LOCK_open);
+
+ *exists= TRUE;
+
+ if (get_cached_table_share(table->db, table->table_name))
+ DBUG_RETURN(FALSE);
+
+ build_table_filename(path, sizeof(path) - 1, table->db, table->table_name,
+ reg_ext, 0);
+
+ if (!access(path, F_OK))
+ DBUG_RETURN(FALSE);
+
+ /* .FRM file doesn't exist. Check if some engine can provide it. */
+
+ rc= ha_create_table_from_engine(thd, table->db, table->table_name);
+
+ if (rc < 0)
+ {
+ /* Table does not exists in engines as well. */
+ *exists= FALSE;
+ DBUG_RETURN(FALSE);
+ }
+ else if (!rc)
+ {
+ /* Table exists in some engine and .FRM for it was created. */
+ DBUG_RETURN(FALSE);
+ }
+ else /* (rc > 0) */
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Failed to open '%-.64s', error while "
+ "unpacking from engine", MYF(0), table->table_name);
+ DBUG_RETURN(TRUE);
+ }
+}
+
+
/*
Open a table.
@@ -1811,12 +2198,17 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
MYSQL_LOCK_IGNORE_FLUSH - Open table even if
someone has done a flush or namelock on it.
No version number checking is done.
- MYSQL_OPEN_IGNORE_LOCKED_TABLES - Open table
- ignoring set of locked tables and prelocked mode.
+ MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
+ table not the base table or view.
IMPLEMENTATION
Uses a cache of open tables to find a table not in use.
+ If table list element for the table to be opened has "create" flag
+ set and table does not exist, this function will automatically insert
+ a placeholder for exclusive name lock into the open tables cache and
+ will return the TABLE instance that corresponds to this placeholder.
+
RETURN
NULL Open failed. If refresh is set then one should close
all other tables and retry the open.
@@ -1834,12 +2226,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
HASH_SEARCH_STATE state;
DBUG_ENTER("open_table");
+ DBUG_ASSERT (table_list->lock_type != TL_WRITE_DEFAULT);
/* find a unused table in the open table cache */
if (refresh)
*refresh=0;
/* an open table operation needs a lot of the stack space */
- if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (char *)&alias))
+ if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
DBUG_RETURN(0);
if (thd->killed)
@@ -1848,6 +2241,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
key_length= (create_table_def_key(thd, key, table_list, 1) -
TMP_TABLE_KEY_EXTRA);
+ /*
+ Unless requested otherwise, try to resolve this table in the list
+ of temporary tables of this thread. In MySQL temporary tables
+ are always thread-local and "shadow" possible base tables with the
+ same name. This block implements the behaviour.
+ TODO: move this block into a separate function.
+ */
if (!table_list->skip_temporary)
{
for (table= thd->temporary_tables; table ; table=table->next)
@@ -1857,9 +2257,19 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
!memcmp(table->s->table_cache_key.str, key,
key_length + TMP_TABLE_KEY_EXTRA))
{
+ /*
+ We're trying to use the same temporary table twice in a query.
+ Right now we don't support this because a temporary table
+ is always represented by only one TABLE object in THD, and
+ it can not be cloned. Emit an error for an unsupported behaviour.
+ */
if (table->query_id == thd->query_id ||
thd->prelocked_mode && table->query_id)
{
+ DBUG_PRINT("error",
+ ("query_id: %lu server_id: %u pseudo_thread_id: %lu",
+ (ulong) table->query_id, (uint) thd->server_id,
+ (ulong) thd->variables.pseudo_thread_id));
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
DBUG_RETURN(0);
}
@@ -1872,8 +2282,20 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
}
- if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
- (thd->locked_tables || thd->prelocked_mode))
+ if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
+ {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
+ DBUG_RETURN(0);
+ }
+
+ /*
+ The table is not temporary - if we're in pre-locked or LOCK TABLES
+ mode, let's try to find the requested table in the list of pre-opened
+ and locked tables. If the table is not there, return an error - we can't
+ open not pre-opened tables in pre-locked/LOCK TABLES mode.
+ TODO: move this block into a separate function.
+ */
+ if (thd->locked_tables || thd->prelocked_mode)
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
@@ -1943,7 +2365,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
goto reset;
}
/*
- is it view?
+ Is this table a view and not a base table?
(it is work around to allow to open view with locked tables,
real fix will be made after definition cache will be made)
*/
@@ -1971,12 +2393,46 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
VOID(pthread_mutex_unlock(&LOCK_open));
}
}
- my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+ /*
+ No table in the locked tables list. In case of explicit LOCK TABLES
+ this can happen if a user did not include the able into the list.
+ In case of pre-locked mode locked tables list is generated automatically,
+ so we may only end up here if the table did not exist when
+ locked tables list was created.
+ */
+ if (thd->prelocked_mode == PRELOCKED)
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
+ else
+ my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
DBUG_RETURN(0);
}
+ /*
+ Non pre-locked/LOCK TABLES mode, and the table is not temporary:
+ this is the normal use case.
+ Now we should:
+ - try to find the table in the table cache.
+ - if one of the discovered TABLE instances is name-locked
+ (table->s->version == 0) or some thread has started FLUSH TABLES
+ (refresh_version > table->s->version), back off -- we have to wait
+ until no one holds a name lock on the table.
+ - if there is no such TABLE in the name cache, read the table definition
+ and insert it into the cache.
+ We perform all of the above under LOCK_open which currently protects
+ the open cache (also known as table cache) and table definitions stored
+ on disk.
+ */
+
VOID(pthread_mutex_lock(&LOCK_open));
+ /*
+ If it's the first table from a list of tables used in a query,
+ remember refresh_version (the version of open_cache state).
+ If the version changes while we're opening the remaining tables,
+ we will have to back off, close all the tables opened-so-far,
+ and try to reopen them.
+ Note: refresh_version is currently changed only during FLUSH TABLES.
+ */
if (!thd->open_tables)
thd->version=refresh_version;
else if ((thd->version != refresh_version) &&
@@ -1993,17 +2449,42 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
- for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ /*
+ Actually try to find the table in the open_cache.
+ The cache may contain several "TABLE" instances for the same
+ physical table. The instances that are currently "in use" by
+ some thread have their "in_use" member != NULL.
+ There is no good reason for having more than one entry in the
+ hash for the same physical table, except that we use this as
+ an implicit "pending locks queue" - see
+ wait_for_locked_table_names for details.
+ */
+ for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length,
&state);
table && table->in_use ;
- table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,
&state))
{
/*
Here we flush tables marked for flush. However we never flush log
tables here. They are flushed only on FLUSH LOGS.
+ Normally, table->s->version contains the value of
+ refresh_version from the moment when this table was
+ (re-)opened and added to the cache.
+ If since then we did (or just started) FLUSH TABLES
+ statement, refresh_version has been increased.
+ For "name-locked" TABLE instances, table->s->version is set
+ to 0 (see lock_table_name for details).
+ In case there is a pending FLUSH TABLES or a name lock, we
+ need to back off and re-start opening tables.
+ If we do not back off now, we may dead lock in case of lock
+ order mismatch with some other thread:
+ c1: name lock t1; -- sort of exclusive lock
+ c2: open t2; -- sort of shared lock
+ c1: name lock t2; -- blocks
+ c2: open t1; -- blocks
*/
- if (table->s->version != refresh_version && !table->s->log_table)
+ if (table->needs_reopen_or_name_lock() && !table->s->log_table)
{
DBUG_PRINT("note",
("Found table '%s.%s' with different refresh version",
@@ -2016,17 +2497,52 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
continue;
}
+ /* Avoid self-deadlocks by detecting self-dependencies. */
+ if (table->open_placeholder && table->in_use == thd)
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table->s->table_name.str);
+ DBUG_RETURN(0);
+ }
+
/*
- There is a refresh in progress for this table
- Wait until the table is freed or the thread is killed.
+ Back off, part 1: mark the table as "unused" for the
+ purpose of name-locking by setting table->db_stat to 0. Do
+ that only for the tables in this thread that have an old
+ table->s->version (this is an optimization (?)).
+ table->db_stat == 0 signals wait_for_locked_table_names
+ that the tables in question are not used any more. See
+ table_is_used call for details.
*/
close_old_data_files(thd,thd->open_tables,0,0);
+ /*
+ Back-off part 2: try to avoid "busy waiting" on the table:
+ if the table is in use by some other thread, we suspend
+ and wait till the operation is complete: when any
+ operation that juggles with table->s->version completes,
+ it broadcasts COND_refresh condition variable.
+ If 'old' table we met is in use by current thread we return
+ without waiting since in this situation it's this thread
+ which is responsible for broadcasting on COND_refresh
+ (and this was done already in close_old_data_files()).
+ Good example of such situation is when we have statement
+ that needs two instances of table and FLUSH TABLES comes
+ after we open first instance but before we open second
+ instance.
+ */
if (table->in_use != thd)
+ {
+ /* wait_for_conditionwill unlock LOCK_open for us */
wait_for_condition(thd, &LOCK_open, &COND_refresh);
+ }
else
{
VOID(pthread_mutex_unlock(&LOCK_open));
}
+ /*
+ There is a refresh in progress for this table.
+ Signal the caller that it has to try again.
+ */
if (refresh)
*refresh=1;
DBUG_RETURN(0);
@@ -2034,6 +2550,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
if (table)
{
+ /* Unlink the table from "unused_tables" list. */
if (table == unused_tables)
{ // First unused
unused_tables=unused_tables->next; // Remove from link
@@ -2046,10 +2563,45 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
}
else
{
+ /* Insert a new TABLE instance into the open cache */
int error;
/* Free cache if too big */
while (open_cache.records > table_cache_size && unused_tables)
- VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
+
+ if (table_list->create)
+ {
+ bool exists;
+
+ if (check_if_table_exists(thd, table_list, &exists))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(NULL);
+ }
+
+ if (!exists)
+ {
+ /*
+ Table to be created, so we need to create placeholder in table-cache.
+ */
+ if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(NULL);
+ }
+ /*
+ Link placeholder to the open tables list so it will be automatically
+ removed once tables are closed. Also mark it so it won't be ignored
+ by other trying to take name-lock.
+ */
+ table->open_placeholder= 1;
+ table->next= thd->open_tables;
+ thd->open_tables= table;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(table);
+ }
+ /* Table exists. Let us try to open it. */
+ }
/* make a new table */
if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
@@ -2062,7 +2614,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
mem_root, (flags & OPEN_VIEW_NO_PARSE));
if (error > 0)
{
- my_free((gptr)table, MYF(0));
+ my_free((uchar*)table, MYF(0));
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
@@ -2075,12 +2627,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (error < 0)
table_list->view= (st_lex*)1;
- my_free((gptr)table, MYF(0));
+ my_free((uchar*)table, MYF(0));
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(0); // VIEW
}
DBUG_PRINT("info", ("inserting table 0x%lx into the cache", (long) table));
- VOID(my_hash_insert(&open_cache,(byte*) table));
+ VOID(my_hash_insert(&open_cache,(uchar*) table));
}
check_unused(); // Debugging call
@@ -2113,11 +2665,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->const_table=0;
table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->s->keys_in_use;
table->insert_values= 0;
- table->used_keys= table->s->keys_for_keyread;
table->fulltext_searched= 0;
table->file->ft_handler= 0;
+ /* Catch wrong handling of the auto_increment_field_not_null. */
+ DBUG_ASSERT(!table->auto_increment_field_not_null);
+ table->auto_increment_field_not_null= FALSE;
if (table->timestamp_field)
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
table->pos_in_table_list= table_list;
@@ -2159,7 +2712,7 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
1 error. The old table object is not changed.
*/
-static bool reopen_table(TABLE *table)
+bool reopen_table(TABLE *table)
{
TABLE tmp;
bool error= 1;
@@ -2200,8 +2753,6 @@ static bool reopen_table(TABLE *table)
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
- tmp.keys_in_use_for_query= tmp.s->keys_in_use;
- tmp.used_keys= tmp.s->keys_for_keyread;
tmp.s->table_map_id= table->s->table_map_id;
@@ -2244,33 +2795,76 @@ static bool reopen_table(TABLE *table)
}
-/*
- Used with ALTER TABLE:
- Close all instanses of table when LOCK TABLES is in used;
- Close first all instances of table and then reopen them
+/**
+ @brief Close all instances of a table open by this thread and replace
+ them with exclusive name-locks.
+
+ @param thd Thread context
+ @param db Database name for the table to be closed
+ @param table_name Name of the table to be closed
+
+ @note This function assumes that if we are not under LOCK TABLES,
+ then there is only one table open and locked. This means that
+ the function probably has to be adjusted before it can be used
+ anywhere outside ALTER TABLE.
*/
-bool close_data_tables(THD *thd,const char *db, const char *table_name)
+void close_data_files_and_morph_locks(THD *thd, const char *db,
+ const char *table_name)
{
TABLE *table;
- DBUG_ENTER("close_data_tables");
+ DBUG_ENTER("close_data_files_and_morph_locks");
+
+ safe_mutex_assert_owner(&LOCK_open);
+
+ if (thd->lock)
+ {
+ /*
+ If we are not under LOCK TABLES we should have only one table
+ open and locked so it makes sense to remove the lock at once.
+ */
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ }
+ /*
+ Note that open table list may contain a name-lock placeholder
+ for target table name if we process ALTER TABLE ... RENAME.
+ So loop below makes sense even if we are not under LOCK TABLES.
+ */
for (table=thd->open_tables; table ; table=table->next)
{
if (!strcmp(table->s->table_name.str, table_name) &&
!strcmp(table->s->db.str, db))
{
- mysql_lock_remove(thd, thd->locked_tables,table);
+ if (thd->locked_tables)
+ mysql_lock_remove(thd, thd->locked_tables, table);
+ table->open_placeholder= 1;
close_handle_and_leave_table_as_lock(table);
}
}
- DBUG_RETURN(0); // For the future
+ DBUG_VOID_RETURN;
}
-/*
- Reopen all tables with closed data files
- One should have lock on LOCK_open when calling this
+/**
+ @brief Reopen all tables with closed data files.
+
+ @param thd Thread context
+ @param get_locks Should we get locks after reopening tables ?
+ @param in_refresh Are we in FLUSH TABLES ? TODO: It seems that
+ we can remove this parameter.
+
+ @note Since this function can't properly handle prelocking and
+ create placeholders it should be used in very special
+ situations like FLUSH TABLES or ALTER TABLE. In general
+ case one should just repeat open_tables()/lock_tables()
+ combination when one needs tables to be reopened (for
+ example see open_and_lock_tables()).
+
+ @note One should have lock on LOCK_open when calling this.
+
+ @return FALSE in case of success, TRUE - otherwise.
*/
bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
@@ -2304,7 +2898,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
if (!tables || (!db_stat && reopen_table(table)))
{
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- VOID(hash_delete(&open_cache,(byte*) table));
+ VOID(hash_delete(&open_cache,(uchar*) table));
error=1;
}
else
@@ -2316,7 +2910,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
if (in_refresh)
{
table->s->version=0;
- table->locked_by_flush=0;
+ table->open_placeholder= 0;
}
}
}
@@ -2335,7 +2929,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
}
if (get_locks && tables)
{
- my_afree((gptr) tables);
+ my_afree((uchar*) tables);
}
broadcast_refresh();
*prev=0;
@@ -2343,13 +2937,21 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
}
-/*
- Close handlers for tables in list, but leave the TABLE structure
- intact so that we can re-open these quickly
- abort_locks is set if called from flush_tables.
+/**
+ @brief Close handlers for tables in list, but leave the TABLE structure
+ intact so that we can re-open these quickly.
+
+ @param thd Thread context
+ @param table Head of the list of TABLE objects
+ @param morph_locks TRUE - remove locks which we have on tables being closed
+ but ensure that no DML or DDL will sneak in before
+ we will re-open the table (i.e. temporarily morph
+ our table-level locks into name-locks).
+ FALSE - otherwise
+ @param send_refresh Should we awake waiters even if we didn't close any tables?
*/
-void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
+void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
bool send_refresh)
{
bool found= send_refresh;
@@ -2361,19 +2963,41 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
Reopen marked for flush. But close log tables. They are flushed only
explicitly on FLUSH LOGS
*/
- if (table->s->version != refresh_version && !table->s->log_table)
+ if (table->needs_reopen_or_name_lock() && !table->s->log_table)
{
found=1;
if (table->db_stat)
{
- if (abort_locks)
+ if (morph_locks)
{
- mysql_lock_abort(thd,table, TRUE); // Close waiting threads
- mysql_lock_remove(thd, thd->locked_tables,table);
- table->locked_by_flush=1; // Will be reopened with locks
+ /*
+ Wake up threads waiting for table-level lock on this table
+ so they won't sneak in when we will temporarily remove our
+ lock on it. This will also give them a chance to close their
+ instances of this table.
+ */
+ mysql_lock_abort(thd, table, TRUE);
+ mysql_lock_remove(thd, thd->locked_tables, table);
+ /*
+ We want to protect the table from concurrent DDL operations
+ (like RENAME TABLE) until we will re-open and re-lock it.
+ */
+ table->open_placeholder= 1;
}
close_handle_and_leave_table_as_lock(table);
}
+ else if (table->open_placeholder)
+ {
+ /*
+ We come here only in close-for-back-off scenario. So we have to
+ "close" create placeholder here to avoid deadlocks (for example,
+ in case of concurrent execution of CREATE TABLE t1 SELECT * FROM t2
+ and RENAME TABLE t2 TO t1). In close-for-re-open scenario we will
+ probably want to let it stay.
+ */
+ DBUG_ASSERT(!morph_locks);
+ table->open_placeholder= 0;
+ }
}
}
if (found)
@@ -2402,17 +3026,17 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
DBUG_PRINT("loop", ("table_name: %s", table->alias));
HASH_SEARCH_STATE state;
- for (TABLE *search= (TABLE*) hash_first(&open_cache, (byte*) key,
+ for (TABLE *search= (TABLE*) hash_first(&open_cache, (uchar*) key,
key_length, &state);
search ;
- search= (TABLE*) hash_next(&open_cache, (byte*) key,
+ search= (TABLE*) hash_next(&open_cache, (uchar*) key,
key_length, &state))
{
DBUG_PRINT("info", ("share: 0x%lx locked_by_logger: %d "
- "locked_by_flush: %d locked_by_name: %d "
+ "open_placeholder: %d locked_by_name: %d "
"db_stat: %u version: %lu",
(ulong) search->s, search->locked_by_logger,
- search->locked_by_flush, search->locked_by_name,
+ search->open_placeholder, search->locked_by_name,
search->db_stat,
search->s->version));
if (search->in_use == table->in_use)
@@ -2428,8 +3052,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
*/
if (!search->locked_by_logger &&
(search->locked_by_name && wait_for_name_lock ||
- search->locked_by_flush ||
- (search->db_stat && search->s->version < refresh_version)))
+ (search->is_name_opened() && search->needs_reopen_or_name_lock())))
DBUG_RETURN(1);
}
} while ((table=table->next));
@@ -2520,7 +3143,7 @@ TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name)
else
{
/* We already have a name lock, remove copy */
- VOID(hash_delete(&open_cache,(byte*) table));
+ VOID(hash_delete(&open_cache,(uchar*) table));
}
}
else
@@ -2534,7 +3157,7 @@ TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name)
broadcast_refresh();
if (thd->locked_tables && thd->locked_tables->table_count == 0)
{
- my_free((gptr) thd->locked_tables,MYF(0));
+ my_free((uchar*) thd->locked_tables,MYF(0));
thd->locked_tables=0;
}
DBUG_RETURN(found);
@@ -2854,6 +3477,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
MEM_ROOT new_frm_mem;
/* Also used for indicating that prelocking is need */
TABLE_LIST **query_tables_last_own;
+ bool safe_to_ignore_table;
+
DBUG_ENTER("open_tables");
/*
temporary mem_root for new .frm parsing.
@@ -2875,7 +3500,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
- thd->lex->sroutines_list.elements)
+ thd->lex->uses_stored_routines())
{
bool first_no_prelocking, need_prelocking;
TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
@@ -2900,8 +3525,19 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
}
}
+ /*
+ For every table in the list of tables to open, try to find or open
+ a table.
+ */
for (tables= *start; tables ;tables= tables->next_global)
{
+ safe_to_ignore_table= FALSE; // 'FALSE', as per coding style
+
+ if (tables->lock_type == TL_WRITE_DEFAULT)
+ {
+ tables->lock_type= thd->update_lock_default;
+ DBUG_ASSERT (tables->lock_type >= TL_WRITE_ALLOW_WRITE);
+ }
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
@@ -2914,6 +3550,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
goto process_view_routines;
continue;
}
+ /*
+ If this TABLE_LIST object is a placeholder for an information_schema
+ table, create a temporary table to represent the information_schema
+ table in the query. Do not fill it yet - will be filled during
+ execution.
+ */
if (tables->schema_table)
{
if (!mysql_schema_table(thd, thd->lex, tables))
@@ -2921,9 +3563,32 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
DBUG_RETURN(-1);
}
(*counter)++;
-
- if (!tables->table &&
- !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
+
+ /*
+ Not a placeholder: must be a base table or a view, and the table is
+ not opened yet. Try to open the table.
+ */
+ if (!tables->table)
+ {
+ if (tables->prelocking_placeholder)
+ {
+ /*
+ For the tables added by the pre-locking code, attempt to open
+ the table but fail silently if the table does not exist.
+ The real failure will occur when/if a statement attempts to use
+ that table.
+ */
+ Prelock_error_handler prelock_handler;
+ thd->push_internal_handler(& prelock_handler);
+ tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+ thd->pop_internal_handler();
+ safe_to_ignore_table= prelock_handler.safely_trapped_errors();
+ }
+ else
+ tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags);
+ }
+
+ if (!tables->table)
{
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
@@ -2974,6 +3639,14 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
close_tables_for_reopen(thd, start);
goto restart;
}
+
+ if (safe_to_ignore_table)
+ {
+ DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
+ tables->db, tables->alias));
+ continue;
+ }
+
result= -1; // Fatal error
break;
}
@@ -3019,7 +3692,7 @@ process_view_routines:
*/
if (tables->view && !thd->prelocked_mode &&
!thd->lex->requires_prelocking() &&
- tables->view->sroutines_list.elements)
+ tables->view->uses_stored_routines())
{
/* We have at least one table in TL here. */
if (!query_tables_last_own)
@@ -3028,7 +3701,7 @@ process_view_routines:
{
/*
Serious error during reading stored routines from mysql.proc table.
- Something's wrong with the table or its contents, and an error has
+ Something is wrong with the table or its contents, and an error has
been emitted; we must abort.
*/
result= -1;
@@ -3277,7 +3950,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
{
for (; table; table= table->next_global)
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
table->table->query_id= 0;
}
@@ -3326,7 +3999,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
/*
CREATE ... SELECT UUID() locks no tables, we have to test here.
*/
- if (thd->lex->binlog_row_based_if_mixed)
+ if (thd->lex->is_stmt_unsafe())
thd->set_current_stmt_binlog_row_based_if_mixed();
if (!tables && !thd->lex->requires_prelocking())
@@ -3350,7 +4023,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
DBUG_RETURN(-1);
for (table= tables; table; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
*(ptr++)= table->table;
}
@@ -3367,7 +4040,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
has_two_write_locked_tables_with_auto_increment(tables))
{
- thd->lex->binlog_row_based_if_mixed= TRUE;
+ thd->lex->set_stmt_unsafe();
thd->set_current_stmt_binlog_row_based_if_mixed();
}
}
@@ -3403,7 +4076,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table)
+ if (!table->placeholder())
{
table->table->query_id= thd->query_id;
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
@@ -3430,7 +4103,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() && !table->schema_table &&
+ if (!table->placeholder() &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
@@ -3510,8 +4183,11 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
uint key_length;
TABLE_LIST table_list;
DBUG_ENTER("open_temporary_table");
- DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'",
- db, table_name, path));
+ DBUG_PRINT("enter",
+ ("table: '%s'.'%s' path: '%s' server_id: %u "
+ "pseudo_thread_id: %lu",
+ db, table_name, path,
+ (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id));
table_list.db= (char*) db;
table_list.table_name= (char*) table_name;
@@ -3547,7 +4223,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
tmp_table->reginfo.lock_type= TL_WRITE; // Simulate locked
share->tmp_table= (tmp_table->file->has_transactions() ?
- TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
+ TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
if (link_in_list)
{
@@ -3615,7 +4291,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
been set for all fields (for example for view).
*/
- table->used_keys.intersect(field->part_of_key);
+ table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
if (thd->mark_used_columns == MARK_COLUMNS_READ)
@@ -3767,7 +4443,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
{
List_iterator_fast<Natural_join_column>
field_it(*(table_ref->join_columns));
- Natural_join_column *nj_col;
+ Natural_join_column *nj_col, *curr_nj_col;
Field *found_field;
Query_arena *arena, backup;
DBUG_ENTER("find_field_in_natural_join");
@@ -3779,18 +4455,26 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
LINT_INIT(arena);
LINT_INIT(found_field);
- for (;;)
+ for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col;
+ curr_nj_col= field_it++)
{
- if (!(nj_col= field_it++))
- DBUG_RETURN(NULL);
-
- if (!my_strcasecmp(system_charset_info, nj_col->name(), name))
- break;
+ if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name))
+ {
+ if (nj_col)
+ {
+ my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
+ DBUG_RETURN(NULL);
+ }
+ nj_col= curr_nj_col;
+ }
}
+ if (!nj_col)
+ DBUG_RETURN(NULL);
if (nj_col->view_field)
{
Item *item;
+ LINT_INIT(arena);
if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup);
/*
@@ -3798,6 +4482,19 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
column reference. See create_view_field() for details.
*/
item= nj_col->create_item(thd);
+ /*
+ *ref != NULL means that *ref contains the item that we need to
+ replace. If the item was aliased by the user, set the alias to
+ the replacing item.
+ We need to set alias on both ref itself and on ref real item.
+ */
+ if (*ref && !(*ref)->is_autogenerated_name)
+ {
+ item->set_name((*ref)->name, (*ref)->name_length,
+ system_charset_info);
+ item->real_item()->set_name((*ref)->name, (*ref)->name_length,
+ system_charset_info);
+ }
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -3868,7 +4565,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
field_ptr= table->field + cached_field_index;
else if (table->s->name_hash.records)
{
- field_ptr= (Field**) hash_search(&table->s->name_hash, (byte*) name,
+ field_ptr= (Field**) hash_search(&table->s->name_hash, (uchar*) name,
length);
if (field_ptr)
{
@@ -3961,6 +4658,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
{
Field *fld;
DBUG_ENTER("find_field_in_table_ref");
+ DBUG_ASSERT(table_list->alias);
+ DBUG_ASSERT(name);
+ DBUG_ASSERT(item_name);
DBUG_PRINT("enter",
("table: '%s' field name: '%s' item name: '%s' ref 0x%lx",
table_list->alias, name, item_name, (ulong) ref));
@@ -4073,7 +4773,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
else
{
if (thd->mark_used_columns == MARK_COLUMNS_READ)
- it->walk(&Item::register_field_in_read_map, 1, (byte *) 0);
+ it->walk(&Item::register_field_in_read_map, 1, (uchar *) 0);
}
}
else
@@ -4112,7 +4812,7 @@ Field *find_field_in_table_sef(TABLE *table, const char *name)
Field **field_ptr;
if (table->s->name_hash.records)
{
- field_ptr= (Field**)hash_search(&table->s->name_hash,(byte*) name,
+ field_ptr= (Field**)hash_search(&table->s->name_hash,(uchar*) name,
strlen(name));
if (field_ptr)
{
@@ -4267,14 +4967,35 @@ find_field_in_tables(THD *thd, Item_ident *item,
{
Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
item->name, db, table_name, ref,
- check_privileges, allow_rowid,
+ check_privileges,
+ allow_rowid,
&(item->cached_field_index),
register_tree_change,
&actual_table);
if (cur_field)
{
if (cur_field == WRONG_GRANT)
- return (Field*) 0;
+ {
+ if (thd->lex->sql_command != SQLCOM_SHOW_FIELDS)
+ return (Field*) 0;
+
+ thd->clear_error();
+ cur_field= find_field_in_table_ref(thd, cur_table, name, length,
+ item->name, db, table_name, ref,
+ false,
+ allow_rowid,
+ &(item->cached_field_index),
+ register_tree_change,
+ &actual_table);
+ if (cur_field)
+ {
+ Field *nf=new Field_null(NULL,0,Field::NONE,
+ cur_field->field_name,
+ &my_charset_bin);
+ nf->init(cur_table->table);
+ cur_field= nf;
+ }
+ }
/*
Store the original table of the field, which may be different from
@@ -4297,7 +5018,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
report_error == IGNORE_EXCEPT_NON_UNIQUE)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
table_name ? item->full_name() : name, thd->where);
- return (Field*) 0;
+ return (Field*) 0;
}
found= cur_field;
}
@@ -4354,10 +5075,13 @@ find_field_in_tables(THD *thd, Item_ident *item,
return not_found_item, report other errors,
return 0
IGNORE_ERRORS Do not report errors, return 0 if error
- unaliased Set to true if item is field which was found
- by original field name and not by its alias
- in item list. Set to false otherwise.
-
+ resolution Set to the resolution type if the item is found
+ (it says whether the item is resolved
+ against an alias name,
+ or as a field name without alias,
+ or as a field hidden by alias,
+ or ignoring alias)
+
RETURN VALUES
0 Item is not found or item is not unique,
error message is reported
@@ -4373,7 +5097,8 @@ Item **not_found_item= (Item**) 0x1;
Item **
find_item_in_list(Item *find, List<Item> &items, uint *counter,
- find_item_error_report_type report_error, bool *unaliased)
+ find_item_error_report_type report_error,
+ enum_resolution_type *resolution)
{
List_iterator<Item> li(items);
Item **found=0, **found_unaliased= 0, *item;
@@ -4387,10 +5112,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
*/
bool is_ref_by_name= 0;
uint unaliased_counter;
-
LINT_INIT(unaliased_counter); // Dependent on found_unaliased
- *unaliased= FALSE;
+ *resolution= NOT_RESOLVED;
is_ref_by_name= (find->type() == Item::FIELD_ITEM ||
find->type() == Item::REF_ITEM);
@@ -4457,63 +5181,77 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
}
found_unaliased= li.ref();
unaliased_counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
if (db_name)
break; // Perfect match
}
}
- else if (!my_strcasecmp(system_charset_info, item_field->name,
- field_name))
- {
- /*
- If table name was not given we should scan through aliases
- (or non-aliased fields) first. We are also checking unaliased
- name of the field in then next else-if, to be able to find
- instantly field (hidden by alias) if no suitable alias (or
- non-aliased field) was found.
- */
- if (found)
- {
- if ((*found)->eq(item, 0))
- continue; // Same field twice
- if (report_error != IGNORE_ERRORS)
- my_error(ER_NON_UNIQ_ERROR, MYF(0),
- find->full_name(), current_thd->where);
- return (Item**) 0;
- }
- found= li.ref();
- *counter= i;
- }
- else if (!my_strcasecmp(system_charset_info, item_field->field_name,
- field_name))
+ else
{
- /*
- We will use un-aliased field or react on such ambiguities only if
- we won't be able to find aliased field.
- Again if we have ambiguity with field outside of select list
- we should prefer fields from select list.
- */
- if (found_unaliased)
+ int fname_cmp= my_strcasecmp(system_charset_info,
+ item_field->field_name,
+ field_name);
+ if (!my_strcasecmp(system_charset_info,
+ item_field->name,field_name))
{
- if ((*found_unaliased)->eq(item, 0))
- continue; // Same field twice
- found_unaliased_non_uniq= 1;
+ /*
+ If table name was not given we should scan through aliases
+ and non-aliased fields first. We are also checking unaliased
+ name of the field in then next else-if, to be able to find
+ instantly field (hidden by alias) if no suitable alias or
+ non-aliased field was found.
+ */
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ *resolution= fname_cmp ? RESOLVED_AGAINST_ALIAS:
+ RESOLVED_WITH_NO_ALIAS;
}
- else
+ else if (!fname_cmp)
{
+ /*
+ We will use non-aliased field or react on such ambiguities only if
+ we won't be able to find aliased field.
+ Again if we have ambiguity with field outside of select list
+ we should prefer fields from select list.
+ */
+ if (found_unaliased)
+ {
+ if ((*found_unaliased)->eq(item, 0))
+ continue; // Same field twice
+ found_unaliased_non_uniq= 1;
+ }
found_unaliased= li.ref();
unaliased_counter= i;
}
}
}
- else if (!table_name && (find->eq(item,0) ||
- is_ref_by_name && find->name && item->name &&
- !my_strcasecmp(system_charset_info,
- item->name,find->name)))
- {
- found= li.ref();
- *counter= i;
- break;
- }
+ else if (!table_name)
+ {
+ if (is_ref_by_name && find->name && item->name &&
+ !my_strcasecmp(system_charset_info,item->name,find->name))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_AGAINST_ALIAS;
+ break;
+ }
+ else if (find->eq(item,0))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
+ break;
+ }
+ }
}
if (!found)
{
@@ -4528,7 +5266,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
found= found_unaliased;
*counter= unaliased_counter;
- *unaliased= TRUE;
+ *resolution= RESOLVED_BEHIND_ALIAS;
}
}
if (found)
@@ -4674,9 +5412,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
{
bool found= FALSE;
const char *field_name_1;
+ /* true if field_name_1 is a member of using_fields */
+ bool is_using_column_1;
if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1)))
goto err;
field_name_1= nj_col_1->name();
+ is_using_column_1= using_fields &&
+ test_if_string_in_list(field_name_1, using_fields);
+ DBUG_PRINT ("info", ("field_name_1=%s.%s",
+ nj_col_1->table_name() ? nj_col_1->table_name() : "",
+ field_name_1));
/*
Find a field with the same name in table_ref_2.
@@ -4693,6 +5438,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2)))
goto err;
cur_field_name_2= cur_nj_col_2->name();
+ DBUG_PRINT ("info", ("cur_field_name_2=%s.%s",
+ cur_nj_col_2->table_name() ?
+ cur_nj_col_2->table_name() : "",
+ cur_field_name_2));
/*
Compare the two columns and check for duplicate common fields.
@@ -4700,10 +5449,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
table_ref_2 (then found == TRUE), or if a field in table_ref_2
was already matched by some previous field in table_ref_1
(then cur_nj_col_2->is_common == TRUE).
+ Note that it is too early to check the columns outside of the
+ USING list for ambiguity because they are not actually "referenced"
+ here. These columns must be checked only on unqualified reference
+ by name (e.g. in SELECT list).
*/
if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2))
{
- if (found || cur_nj_col_2->is_common)
+ DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common));
+ if (cur_nj_col_2->is_common ||
+ (found && (!using_fields || is_using_column_1)))
{
my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where);
goto err;
@@ -4729,9 +5484,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
clause (if present), mark them as common fields, and add a new
equi-join condition to the ON clause.
*/
- if (nj_col_2 &&
- (!using_fields ||
- test_if_string_in_list(field_name_1, using_fields)))
+ if (nj_col_2 && (!using_fields ||is_using_column_1))
{
Item *item_1= nj_col_1->create_item(thd);
Item *item_2= nj_col_2->create_item(thd);
@@ -4786,13 +5539,20 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
eq_cond);
nj_col_1->is_common= nj_col_2->is_common= TRUE;
+ DBUG_PRINT ("info", ("%s.%s and %s.%s are common",
+ nj_col_1->table_name() ?
+ nj_col_1->table_name() : "",
+ nj_col_1->name(),
+ nj_col_2->table_name() ?
+ nj_col_2->table_name() : "",
+ nj_col_2->name()));
if (field_1)
{
TABLE *table_1= nj_col_1->table_ref->table;
/* Mark field_1 used for table cache. */
bitmap_set_bit(table_1->read_set, field_1->field_index);
- table_1->used_keys.intersect(field_1->part_of_key);
+ table_1->covering_keys.intersect(field_1->part_of_key);
table_1->merge_keys.merge(field_1->part_of_key);
}
if (field_2)
@@ -4800,7 +5560,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
TABLE *table_2= nj_col_2->table_ref->table;
/* Mark field_2 used for table cache. */
bitmap_set_bit(table_2->read_set, field_2->field_index);
- table_2->used_keys.intersect(field_2->part_of_key);
+ table_2->covering_keys.intersect(field_2->part_of_key);
table_2->merge_keys.merge(field_2->part_of_key);
}
@@ -5223,6 +5983,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
arena= thd->activate_stmt_arena_if_needed(&backup);
+ thd->lex->current_select->cur_pos_in_select_list= 0;
while (wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM &&
@@ -5241,7 +6002,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Item_int do not need fix_fields() because it is basic constant.
*/
- it.replace(new Item_int("Not_used", (longlong) 1, 21));
+ it.replace(new Item_int("Not_used", (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
}
else if (insert_fields(thd, ((Item_field*) item)->context,
((Item_field*) item)->db_name,
@@ -5263,7 +6025,10 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
wild_num--;
}
+ else
+ thd->lex->current_select->cur_pos_in_select_list++;
}
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
if (arena)
{
/* make * substituting permanent */
@@ -5288,6 +6053,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
+ bool save_is_item_list_lookup;
DBUG_ENTER("setup_fields");
thd->mark_used_columns= mark_used_columns;
@@ -5295,6 +6061,8 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (allow_sum_func)
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
thd->where= THD::DEFAULT_WHERE;
+ save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup;
+ thd->lex->current_select->is_item_list_lookup= 0;
/*
To prevent fail on forward lookup we fill it with zerows,
@@ -5311,11 +6079,13 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
Item **ref= ref_pointer_array;
+ thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
thd->lex->allow_sum_func= save_allow_sum_func;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
@@ -5327,7 +6097,11 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
thd->used_tables|= item->used_tables();
+ thd->lex->current_select->cur_pos_in_select_list++;
}
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
+
thd->lex->allow_sum_func= save_allow_sum_func;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
@@ -5400,21 +6174,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
uint tablenr= 0;
DBUG_ENTER("setup_tables");
- /*
- Due to the various call paths that lead to setup_tables() it may happen
- that context->table_list and context->first_name_resolution_table can be
- NULL (this is typically done when creating TABLE_LISTs internally).
- TODO:
- Investigate all cases when this my happen, initialize the name resolution
- context correctly in all those places, and remove the context reset below.
- */
- if (!context->table_list || !context->first_name_resolution_table)
- {
- /* Test whether the context is in a consistent state. */
- DBUG_ASSERT(!context->first_name_resolution_table && !context->table_list);
- context->table_list= context->first_name_resolution_table= tables;
- }
-
+ DBUG_ASSERT ((select_insert && !tables->next_name_resolution_table) || !tables ||
+ (context->table_list && context->first_name_resolution_table));
/*
this is used for INSERT ... SELECT.
For select we setup tables except first (and its underlying tables)
@@ -5440,25 +6201,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
tablenr= 0;
}
setup_table_map(table, table_list, tablenr);
- table->used_keys= table->s->keys_for_keyread;
- table->merge_keys.clear_all();
- if (table_list->use_index)
- {
- key_map map;
- get_key_map_from_key_list(&map, table, table_list->use_index);
- if (map.is_set_all())
- DBUG_RETURN(1);
- table->keys_in_use_for_query=map;
- }
- if (table_list->ignore_index)
- {
- key_map map;
- get_key_map_from_key_list(&map, table, table_list->ignore_index);
- if (map.is_set_all())
- DBUG_RETURN(1);
- table->keys_in_use_for_query.subtract(map);
- }
- table->used_keys.intersect(table->keys_in_use_for_query);
+ if (table_list->process_index_hints(table))
+ DBUG_RETURN(1);
}
if (tablenr > MAX_TABLES)
{
@@ -5534,13 +6278,14 @@ bool setup_tables_and_check_access(THD *thd,
&leaves_tmp, select_insert))
return TRUE;
- *leaves= leaves_tmp;
+ if (leaves)
+ *leaves= leaves_tmp;
for (; leaves_tmp; leaves_tmp= leaves_tmp->next_leaf)
{
if (leaves_tmp->belong_to_view &&
check_single_table_access(thd, first_table ? want_access_first :
- want_access, leaves_tmp))
+ want_access, leaves_tmp, FALSE))
{
tables->hide_view_error(thd);
return TRUE;
@@ -5740,7 +6485,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
bitmap_set_bit(field->table->read_set, field->field_index);
if (table)
{
- table->used_keys.intersect(field->part_of_key);
+ table->covering_keys.intersect(field->part_of_key);
table->merge_keys.merge(field->part_of_key);
}
if (tables->is_natural_join)
@@ -5758,7 +6503,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (field_table)
{
thd->used_tables|= field_table->map;
- field_table->used_keys.intersect(field->part_of_key);
+ field_table->covering_keys.intersect(field->part_of_key);
field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
}
@@ -5766,6 +6511,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
}
else
thd->used_tables|= item->used_tables();
+ thd->lex->current_select->cur_pos_in_select_list++;
}
/*
In case of stored tables, all fields are considered as used,
@@ -5827,6 +6573,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
*/
bool it_is_update= (select_lex == &thd->lex->select_lex) &&
thd->lex->which_check_option_applicable();
+ bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
+ select_lex->is_item_list_lookup= 0;
DBUG_ENTER("setup_conds");
if (select_lex->conds_processed_with_permanent_arena ||
@@ -5902,9 +6650,11 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
select_lex->where= *conds;
select_lex->conds_processed_with_permanent_arena= 1;
}
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
DBUG_RETURN(test(thd->net.report_error));
err_no_arena:
+ select_lex->is_item_list_lookup= save_is_item_list_lookup;
DBUG_RETURN(1);
}
@@ -5925,6 +6675,11 @@ err_no_arena:
values values to fill with
ignore_errors TRUE if we should ignore errors
+ NOTE
+ fill_record() may set table->auto_increment_field_not_null and a
+ caller should make sure that it is reset after their last call to this
+ function.
+
RETURN
FALSE OK
TRUE error occured
@@ -5937,27 +6692,52 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
List_iterator_fast<Item> f(fields),v(values);
Item *value, *fld;
Item_field *field;
+ TABLE *table= 0;
DBUG_ENTER("fill_record");
+ /*
+ Reset the table->auto_increment_field_not_null as it is valid for
+ only one row.
+ */
+ if (fields.elements)
+ {
+ /*
+ On INSERT or UPDATE fields are checked to be from the same table,
+ thus we safely can take table from the first field.
+ */
+ fld= (Item_field*)f++;
+ if (!(field= fld->filed_for_view_update()))
+ {
+ my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
+ goto err;
+ }
+ table= field->field->table;
+ table->auto_increment_field_not_null= FALSE;
+ f.rewind();
+ }
while ((fld= f++))
{
if (!(field= fld->filed_for_view_update()))
{
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
- DBUG_RETURN(TRUE);
+ goto err;
}
value=v++;
Field *rfield= field->field;
- TABLE *table= rfield->table;
+ table= rfield->table;
if (rfield == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
{
my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
- DBUG_RETURN(TRUE);
+ goto err;
}
}
DBUG_RETURN(thd->net.report_error);
+err:
+ if (table)
+ table->auto_increment_field_not_null= FALSE;
+ DBUG_RETURN(TRUE);
}
@@ -6006,6 +6786,11 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
values list of fields
ignore_errors TRUE if we should ignore errors
+ NOTE
+ fill_record() may set table->auto_increment_field_not_null and a
+ caller should make sure that it is reset after their last call to this
+ function.
+
RETURN
FALSE OK
TRUE error occured
@@ -6016,19 +6801,38 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
{
List_iterator_fast<Item> v(values);
Item *value;
+ TABLE *table= 0;
DBUG_ENTER("fill_record");
Field *field;
- while ((field = *ptr++))
+ /*
+ Reset the table->auto_increment_field_not_null as it is valid for
+ only one row.
+ */
+ if (*ptr)
+ {
+ /*
+ On INSERT or UPDATE fields are checked to be from the same table,
+ thus we safely can take table from the first field.
+ */
+ table= (*ptr)->table;
+ table->auto_increment_field_not_null= FALSE;
+ }
+ while ((field = *ptr++) && !thd->net.report_error)
{
value=v++;
- TABLE *table= field->table;
+ table= field->table;
if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
- if (value->save_in_field(field, 0) == -1)
- DBUG_RETURN(TRUE);
+ if (value->save_in_field(field, 0) < 0)
+ goto err;
}
DBUG_RETURN(thd->net.report_error);
+
+err:
+ if (table)
+ table->auto_increment_field_not_null= FALSE;
+ DBUG_RETURN(TRUE);
}
@@ -6067,14 +6871,21 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
}
-static void mysql_rm_tmp_tables(void)
+my_bool mysql_rm_tmp_tables(void)
{
uint i, idx;
- char filePath[FN_REFLEN], *tmpdir;
+ char filePath[FN_REFLEN], *tmpdir, filePathCopy[FN_REFLEN];
MY_DIR *dirp;
FILEINFO *file;
+ TABLE_SHARE share;
+ THD *thd;
DBUG_ENTER("mysql_rm_tmp_tables");
+ if (!(thd= new THD))
+ DBUG_RETURN(1);
+ thd->thread_stack= (char*) &thd;
+ thd->store_globals();
+
for (i=0; i<=mysql_tmpdir_list.max; i++)
{
tmpdir=mysql_tmpdir_list.list[i];
@@ -6093,15 +6904,43 @@ static void mysql_rm_tmp_tables(void)
(file->name[1] == '.' && !file->name[2])))
continue;
- if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length))
+ if (!bcmp((uchar*) file->name, (uchar*) tmp_file_prefix,
+ tmp_file_prefix_length))
{
- sprintf(filePath,"%s%c%s",tmpdir,FN_LIBCHAR,file->name);
- VOID(my_delete(filePath,MYF(MY_WME)));
+ char *ext= fn_ext(file->name);
+ uint ext_len= strlen(ext);
+ uint filePath_len= my_snprintf(filePath, sizeof(filePath),
+ "%s%c%s", tmpdir, FN_LIBCHAR,
+ file->name);
+ if (!bcmp((uchar*) reg_ext, (uchar*) ext, ext_len))
+ {
+ handler *handler_file= 0;
+ /* We should cut file extention before deleting of table */
+ memcpy(filePathCopy, filePath, filePath_len - ext_len);
+ filePathCopy[filePath_len - ext_len]= 0;
+ init_tmp_table_share(&share, "", 0, "", filePathCopy);
+ if (!open_table_def(thd, &share, 0) &&
+ ((handler_file= get_new_handler(&share, thd->mem_root,
+ share.db_type()))))
+ {
+ handler_file->delete_table(filePathCopy);
+ delete handler_file;
+ }
+ free_table_share(&share);
+ }
+ /*
+ File can be already deleted by tmp_table.file->delete_table().
+ So we hide error messages which happnes during deleting of these
+ files(MYF(0)).
+ */
+ VOID(my_delete(filePath, MYF(0)));
}
}
my_dirend(dirp);
}
- DBUG_VOID_RETURN;
+ delete thd;
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ DBUG_RETURN(0);
}
@@ -6136,7 +6975,7 @@ void remove_db_from_cache(const char *db)
}
}
while (unused_tables && !unused_tables->s->version)
- VOID(hash_delete(&open_cache,(byte*) unused_tables));
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables));
}
@@ -6152,7 +6991,7 @@ void flush_tables()
{
(void) pthread_mutex_lock(&LOCK_open);
while (unused_tables)
- hash_delete(&open_cache,(byte*) unused_tables);
+ hash_delete(&open_cache,(uchar*) unused_tables);
(void) pthread_mutex_unlock(&LOCK_open);
}
@@ -6189,10 +7028,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
HASH_SEARCH_STATE state;
result= signalled= 0;
- for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
+ for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length,
&state);
table;
- table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
+ table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length,
&state))
{
THD *in_use;
@@ -6207,7 +7046,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
{
DBUG_PRINT("info", ("Table was in use by other thread"));
in_use->some_tables_deleted=1;
- if (table->db_stat)
+ if (table->is_name_opened())
{
DBUG_PRINT("info", ("Found another active instance of the table"));
result=1;
@@ -6247,11 +7086,11 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
}
}
while (unused_tables && !unused_tables->s->version)
- VOID(hash_delete(&open_cache,(byte*) unused_tables));
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables));
DBUG_PRINT("info", ("Removing table from table_def_cache"));
/* Remove table from table definition cache if it's not in use */
- if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(byte*) key,
+ if ((share= (TABLE_SHARE*) hash_search(&table_def_cache,(uchar*) key,
key_length)))
{
DBUG_PRINT("info", ("share version: %lu ref_count: %u",
@@ -6260,7 +7099,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
if (share->ref_count == 0)
{
pthread_mutex_lock(&share->mutex);
- VOID(hash_delete(&table_def_cache, (byte*) share));
+ VOID(hash_delete(&table_def_cache, (uchar*) share));
}
}
@@ -6502,10 +7341,10 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table
key_length=(uint) (strmov(strmov(key,lpt->db)+1,lpt->table_name)-key)+1;
VOID(pthread_mutex_lock(&LOCK_open));
HASH_SEARCH_STATE state;
- for (table= (TABLE*) hash_first(&open_cache,(byte*) key,key_length,
+ for (table= (TABLE*) hash_first(&open_cache,(uchar*) key,key_length,
&state) ;
table;
- table= (TABLE*) hash_next(&open_cache,(byte*) key,key_length,
+ table= (TABLE*) hash_next(&open_cache,(uchar*) key,key_length,
&state))
{
THD *in_use= table->in_use;
@@ -6582,7 +7421,7 @@ has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables)
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
- if (!table->placeholder() && !table->schema_table &&
+ if (!table->placeholder() &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
{
@@ -6599,3 +7438,122 @@ has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables)
}
return 0;
}
+
+
+/*
+ Open and lock system tables for read.
+
+ SYNOPSIS
+ open_system_tables_for_read()
+ thd Thread context.
+ table_list List of tables to open.
+ backup Pointer to Open_tables_state instance where
+ information about currently open tables will be
+ saved, and from which will be restored when we will
+ end work with system tables.
+
+ NOTES
+ Thanks to restrictions which we put on opening and locking of
+ system tables for writing, we can open and lock them for reading
+ even when we already have some other tables open and locked. One
+ must call close_system_tables() to close systems tables opened
+ with this call.
+
+ RETURN
+ FALSE Success
+ TRUE Error
+*/
+
+bool
+open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
+ Open_tables_state *backup)
+{
+ DBUG_ENTER("open_system_tables_for_read");
+
+ thd->reset_n_backup_open_tables_state(backup);
+
+ uint count= 0;
+ bool not_used;
+ for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
+ {
+ TABLE *table= open_table(thd, tables, thd->mem_root, &not_used,
+ MYSQL_LOCK_IGNORE_FLUSH);
+ if (!table)
+ goto error;
+
+ DBUG_ASSERT(table->s->system_table);
+
+ table->use_all_columns();
+ table->reginfo.lock_type= tables->lock_type;
+ tables->table= table;
+ count++;
+ }
+
+ {
+ TABLE **list= (TABLE**) thd->alloc(sizeof(TABLE*) * count);
+ TABLE **ptr= list;
+ for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
+ *(ptr++)= tables->table;
+
+ thd->lock= mysql_lock_tables(thd, list, count,
+ MYSQL_LOCK_IGNORE_FLUSH, &not_used);
+ }
+ if (thd->lock)
+ DBUG_RETURN(FALSE);
+
+error:
+ close_system_tables(thd, backup);
+
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Close system tables, opened with open_system_tables_for_read().
+
+ SYNOPSIS
+ close_system_tables()
+ thd Thread context
+ backup Pointer to Open_tables_state instance which holds
+ information about tables which were open before we
+ decided to access system tables.
+*/
+
+void
+close_system_tables(THD *thd, Open_tables_state *backup)
+{
+ close_thread_tables(thd);
+ thd->restore_backup_open_tables_state(backup);
+}
+
+
+/*
+ Open and lock one system table for update.
+
+ SYNOPSIS
+ open_system_table_for_update()
+ thd Thread context.
+ one_table Table to open.
+
+ NOTES
+ Table opened with this call should closed using close_thread_tables().
+
+ RETURN
+ 0 Error
+ # Pointer to TABLE object of system table
+*/
+
+TABLE *
+open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
+{
+ DBUG_ENTER("open_system_table_for_update");
+
+ TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
+ if (table)
+ {
+ DBUG_ASSERT(table->s->system_table);
+ table->use_all_columns();
+ }
+
+ DBUG_RETURN(table);
+}
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 37094b992e5..77432ce518e 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,9 +11,10 @@
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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "mysql_priv.h"
+#include "rpl_rli.h"
#include "base64.h"
/*
@@ -33,8 +33,8 @@ void mysql_client_binlog_statement(THD* thd)
{
DBUG_ENTER("mysql_client_binlog_statement");
DBUG_PRINT("info",("binlog base64: '%*s'",
- (thd->lex->comment.length < 2048 ?
- thd->lex->comment.length : 2048),
+ (int) (thd->lex->comment.length < 2048 ?
+ thd->lex->comment.length : 2048),
thd->lex->comment.str));
/*
@@ -44,8 +44,8 @@ void mysql_client_binlog_statement(THD* thd)
my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE;
- my_size_t coded_len= thd->lex->comment.length + 1;
- my_size_t decoded_len= base64_needed_decoded_length(coded_len);
+ size_t coded_len= thd->lex->comment.length + 1;
+ size_t decoded_len= base64_needed_decoded_length(coded_len);
DBUG_ASSERT(coded_len > 0);
/*
@@ -164,9 +164,17 @@ void mysql_client_binlog_statement(THD* thd)
(ulong) uint4korr(bufptr+EVENT_LEN_OFFSET)));
#endif
ev->thd= thd;
- if (int err= ev->exec_event(thd->rli_fake))
+ /*
+ We go directly to the application phase, since we don't need
+ to check if the event shall be skipped or not.
+
+ Neither do we have to update the log positions, since that is
+ not used at all: the rli_fake instance is used only for error
+ reporting.
+ */
+ if (IF_DBUG(int err= ) ev->apply_event(thd->rli_fake))
{
- DBUG_PRINT("error", ("exec_event() returned: %d", err));
+ DBUG_PRINT("info", ("apply_event() returned: %d", err));
/*
TODO: Maybe a better error message since the BINLOG statement
now contains several events.
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index 3a7fa4b661a..9a765120895 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
index 18705aa3dfb..3becdbaccfe 100644
--- a/sql/sql_builtin.cc.in
+++ b/sql/sql_builtin.cc.in
@@ -1,3 +1,17 @@
+/* Copyright (C) 2006 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; version 2 of the License.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <mysql/plugin.h>
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 1b9af26530e..04f142c5dfb 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -366,7 +365,7 @@ TYPELIB query_cache_type_typelib=
inline Query_cache_block * Query_cache_block_table::block()
{
- return (Query_cache_block *)(((byte*)this) -
+ return (Query_cache_block *)(((uchar*)this) -
ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
ALIGN_SIZE(sizeof(Query_cache_block)));
}
@@ -378,7 +377,7 @@ inline Query_cache_block * Query_cache_block_table::block()
void Query_cache_block::init(ulong block_length)
{
DBUG_ENTER("Query_cache_block::init");
- DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this,
+ DBUG_PRINT("qcache", ("init block: 0x%lx length: %lu", (ulong) this,
block_length));
length = block_length;
used = 0;
@@ -402,9 +401,9 @@ inline uint Query_cache_block::headers_len()
ALIGN_SIZE(sizeof(Query_cache_block)));
}
-inline gptr Query_cache_block::data(void)
+inline uchar* Query_cache_block::data(void)
{
- return (gptr)( ((byte*)this) + headers_len() );
+ return (uchar*)( ((uchar*)this) + headers_len() );
}
inline Query_cache_query * Query_cache_block::query()
@@ -438,7 +437,7 @@ inline Query_cache_result * Query_cache_block::result()
inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
{
return ((Query_cache_block_table *)
- (((byte*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
+ (((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
n*sizeof(Query_cache_block_table)));
}
@@ -449,13 +448,13 @@ inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
extern "C"
{
-byte *query_cache_table_get_key(const byte *record, uint *length,
+uchar *query_cache_table_get_key(const uchar *record, size_t *length,
my_bool not_used __attribute__((unused)))
{
Query_cache_block* table_block = (Query_cache_block*) record;
*length = (table_block->used - table_block->headers_len() -
ALIGN_SIZE(sizeof(Query_cache_table)));
- return (((byte *) table_block->data()) +
+ return (((uchar *) table_block->data()) +
ALIGN_SIZE(sizeof(Query_cache_table)));
}
}
@@ -523,7 +522,7 @@ void Query_cache_query::init_n_lock()
my_rwlock_init(&lock, NULL);
lock_writing();
DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
- (long) (((byte*) this) -
+ (long) (((uchar*) this) -
ALIGN_SIZE(sizeof(Query_cache_block)))));
DBUG_VOID_RETURN;
}
@@ -533,7 +532,7 @@ void Query_cache_query::unlock_n_destroy()
{
DBUG_ENTER("Query_cache_query::unlock_n_destroy");
DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
- (long) (((byte*) this) -
+ (long) (((uchar*) this) -
ALIGN_SIZE(sizeof(Query_cache_block)))));
/*
The following call is not needed on system where one can destroy an
@@ -547,13 +546,13 @@ void Query_cache_query::unlock_n_destroy()
extern "C"
{
-byte *query_cache_query_get_key(const byte *record, uint *length,
+uchar *query_cache_query_get_key(const uchar *record, size_t *length,
my_bool not_used)
{
Query_cache_block *query_block = (Query_cache_block*) record;
*length = (query_block->used - query_block->headers_len() -
ALIGN_SIZE(sizeof(Query_cache_query)));
- return (((byte *) query_block->data()) +
+ return (((uchar *) query_block->data()) +
ALIGN_SIZE(sizeof(Query_cache_query)));
}
}
@@ -640,7 +639,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
done by query_cache.append_result_data if success (if not we need
query_cache.structure_guard_mutex locked to free query)
*/
- if (!query_cache.append_result_data(&result, length, (gptr) packet,
+ if (!query_cache.append_result_data(&result, length, (uchar*) packet,
query_block))
{
DBUG_PRINT("warning", ("Can't append data"));
@@ -800,12 +799,26 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size,
query_cache_size_arg));
DBUG_ASSERT(initialized);
+
STRUCT_LOCK(&structure_guard_mutex);
+ while (flush_in_progress)
+ pthread_cond_wait(&COND_flush_finished, &structure_guard_mutex);
+ flush_in_progress= TRUE;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
free_cache();
+
query_cache_size= query_cache_size_arg;
- ::query_cache_size= init_cache();
+ ulong new_query_cache_size= init_cache();
+
+ DBUG_EXECUTE("check_querycache",check_integrity(0););
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ flush_in_progress= FALSE;
+ pthread_cond_signal(&COND_flush_finished);
STRUCT_UNLOCK(&structure_guard_mutex);
- DBUG_RETURN(::query_cache_size);
+
+ DBUG_RETURN(new_query_cache_size);
}
@@ -845,6 +858,12 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
flags.client_protocol_41= test(thd->client_capabilities &
CLIENT_PROTOCOL_41);
+ /*
+ Protocol influences result format, so statement results in the binary
+ protocol (COM_EXECUTE) cannot be served to statements asking for results
+ in the text protocol (COM_QUERY) and vice-versa.
+ */
+ flags.result_in_binary_protocol= (unsigned int) thd->protocol->type();
flags.more_results_exists= test(thd->server_status &
SERVER_MORE_RESULTS_EXISTS);
flags.pkt_nr= net->pkt_nr;
@@ -862,11 +881,16 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
flags.max_sort_length= thd->variables.max_sort_length;
flags.lc_time_names= thd->variables.lc_time_names;
flags.group_concat_max_len= thd->variables.group_concat_max_len;
- DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
+ flags.div_precision_increment= thd->variables.div_precincrement;
+ flags.default_week_format= thd->variables.default_week_format;
+ DBUG_PRINT("qcache", ("\
+long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
-sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
+sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
+def_week_frmt: %lu",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
+ (int)flags.result_in_binary_protocol,
(int)flags.more_results_exists,
flags.pkt_nr,
flags.character_set_client_num,
@@ -876,7 +900,9 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
(ulong) flags.time_zone,
flags.sql_mode,
flags.max_sort_length,
- flags.group_concat_max_len));
+ flags.group_concat_max_len,
+ flags.div_precision_increment,
+ flags.default_week_format));
/*
Make InnoDB to release the adaptive hash index latch before
acquiring the query cache mutex.
@@ -920,13 +946,13 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
/* Check if another thread is processing the same query? */
Query_cache_block *competitor = (Query_cache_block *)
- hash_search(&queries, (byte*) thd->query, tot_length);
+ hash_search(&queries, (uchar*) thd->query, tot_length);
DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor));
if (competitor == 0)
{
/* Query is not in cache and no one is working with it; Store it */
Query_cache_block *query_block;
- query_block= write_block_data(tot_length, (gptr) thd->query,
+ query_block= write_block_data(tot_length, (uchar*) thd->query,
ALIGN_SIZE(sizeof(Query_cache_query)),
Query_cache_block::QUERY, local_tables, 1);
if (query_block != 0)
@@ -936,7 +962,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
Query_cache_query *header = query_block->query();
header->init_n_lock();
- if (my_hash_insert(&queries, (byte*) query_block))
+ if (my_hash_insert(&queries, (uchar*) query_block))
{
refused++;
DBUG_PRINT("qcache", ("insertion in query hash"));
@@ -949,7 +975,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
{
refused++;
DBUG_PRINT("warning", ("tables list including failed"));
- hash_delete(&queries, (byte *) query_block);
+ hash_delete(&queries, (uchar *) query_block);
header->unlock_n_destroy();
free_memory_block(query_block);
STRUCT_UNLOCK(&structure_guard_mutex);
@@ -958,7 +984,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
double_linked_list_simple_include(query_block, &queries_blocks);
inserts++;
queries_in_cache++;
- net->query_cache_query= (gptr) query_block;
+ net->query_cache_query= (uchar*) query_block;
header->writer(net);
header->tables_type(tables_type);
@@ -1090,6 +1116,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
flags.client_protocol_41= test(thd->client_capabilities &
CLIENT_PROTOCOL_41);
+ flags.result_in_binary_protocol= (unsigned int)thd->protocol->type();
flags.more_results_exists= test(thd->server_status &
SERVER_MORE_RESULTS_EXISTS);
flags.pkt_nr= thd->net.pkt_nr;
@@ -1104,12 +1131,17 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
flags.sql_mode= thd->variables.sql_mode;
flags.max_sort_length= thd->variables.max_sort_length;
flags.group_concat_max_len= thd->variables.group_concat_max_len;
+ flags.div_precision_increment= thd->variables.div_precincrement;
+ flags.default_week_format= thd->variables.default_week_format;
flags.lc_time_names= thd->variables.lc_time_names;
- DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
+ DBUG_PRINT("qcache", ("\
+long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
-sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
+sql mode: 0x%lx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
+def_week_frmt: %lu",
(int)flags.client_long_flag,
(int)flags.client_protocol_41,
+ (int)flags.result_in_binary_protocol,
(int)flags.more_results_exists,
flags.pkt_nr,
flags.character_set_client_num,
@@ -1119,10 +1151,12 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
(ulong) flags.time_zone,
flags.sql_mode,
flags.max_sort_length,
- flags.group_concat_max_len));
- memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
- &flags, QUERY_CACHE_FLAGS_SIZE);
- query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql,
+ flags.group_concat_max_len,
+ flags.div_precision_increment,
+ flags.default_week_format));
+ memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
+ (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
+ query_block = (Query_cache_block *) hash_search(&queries, (uchar*) sql,
tot_length);
/* Quick abort on unlocked data */
if (query_block == 0 ||
@@ -1233,7 +1267,7 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
("Handler require invalidation queries of %s.%s %lu-%lu",
table_list.db, table_list.alias,
(ulong) engine_data, (ulong) table->engine_data()));
- invalidate_table((byte *) table->db(), table->key_length());
+ invalidate_table((uchar *) table->db(), table->key_length());
}
else
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
@@ -1337,7 +1371,7 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
DUMP(this);
for (; tables_used; tables_used= tables_used->next)
{
- invalidate_table((byte*) tables_used->key, tables_used->key_length);
+ invalidate_table((uchar*) tables_used->key, tables_used->key_length);
DBUG_PRINT("qcache", ("db: %s table: %s", tables_used->key,
tables_used->key+
strlen(tables_used->key)+1));
@@ -1418,7 +1452,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
if (using_transactions) // used for innodb => has_transactions() is TRUE
thd->add_changed_table(key, key_length);
else
- invalidate_table((byte*)key, key_length);
+ invalidate_table((uchar*)key, key_length);
}
STRUCT_UNLOCK(&structure_guard_mutex);
@@ -1479,8 +1513,8 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
uint key_length= filename_2_table_key(key, filename, &db_length);
Query_cache_block *table_block;
if ((table_block = (Query_cache_block*) hash_search(&tables,
- (byte*) key,
- key_length)))
+ (uchar*) key,
+ key_length)))
invalidate_table(table_block);
}
STRUCT_UNLOCK(&structure_guard_mutex);
@@ -1565,8 +1599,9 @@ ulong Query_cache::init_cache()
int align;
DBUG_ENTER("Query_cache::init_cache");
+
approx_additional_data_size = (sizeof(Query_cache) +
- sizeof(gptr)*(def_query_hash_size+
+ sizeof(uchar*)*(def_query_hash_size+
def_table_hash_size));
if (query_cache_size < approx_additional_data_size)
goto err;
@@ -1622,7 +1657,7 @@ ulong Query_cache::init_cache()
goto err;
query_cache_size -= additional_data_size;
- if (!(cache= (byte *)
+ if (!(cache= (uchar *)
my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
goto err;
@@ -1743,48 +1778,28 @@ void Query_cache::make_disabled()
mem_bin_num= mem_bin_steps= 0;
queries_in_cache= 0;
first_block= 0;
+ total_blocks= 0;
+ tables_blocks= 0;
DBUG_VOID_RETURN;
}
-/*
- free_cache() - free all resources allocated by the cache.
-
- SYNOPSIS
- free_cache()
-
- DESCRIPTION
- This function frees all resources allocated by the cache. You
- have to call init_cache() before using the cache again.
+/**
+ @class Query_cache
+ @brief Free all resources allocated by the cache.
+ @details This function frees all resources allocated by the cache. You
+ have to call init_cache() before using the cache again. This function requires
+ the structure_guard_mutex to be locked.
*/
void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
- if (query_cache_size > 0)
- {
- flush_cache();
-#ifndef DBUG_OFF
- if (bins[0].free_blocks == 0)
- {
- wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
- DBUG_VOID_RETURN;
- }
-#endif
- /* Becasue we did a flush, all cache memory must be in one this block */
- bins[0].free_blocks->destroy();
- total_blocks--;
-#ifndef DBUG_OFF
- if (free_memory != query_cache_size)
- DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
- free_memory , query_cache_size));
-#endif
- my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR));
- make_disabled();
- hash_free(&queries);
- hash_free(&tables);
- }
+ my_free((uchar*) cache, MYF(MY_ALLOW_ZERO_PTR));
+ make_disabled();
+ hash_free(&queries);
+ hash_free(&tables);
DBUG_VOID_RETURN;
}
@@ -1805,6 +1820,12 @@ void Query_cache::free_cache()
flush_in_progress flag and releases the lock, so other threads may
proceed skipping the cache as if it is disabled. Concurrent
flushes are performed in turn.
+
+ After flush_cache() call, the cache is flushed, all the freed
+ memory is accumulated in bin[0], and the 'structure_guard_mutex'
+ is locked. However, since we could release the mutex during
+ execution, the rest of the cache state could have been changed,
+ and should not be relied on.
*/
void Query_cache::flush_cache()
@@ -1978,7 +1999,7 @@ void Query_cache::free_query(Query_cache_block *query_block)
(ulong) query_block,
query_block->query()->length() ));
- hash_delete(&queries,(byte *) query_block);
+ hash_delete(&queries,(uchar *) query_block);
free_query_internal(query_block);
DBUG_VOID_RETURN;
@@ -1989,7 +2010,7 @@ void Query_cache::free_query(Query_cache_block *query_block)
*****************************************************************************/
Query_cache_block *
-Query_cache::write_block_data(ulong data_len, gptr data,
+Query_cache::write_block_data(ulong data_len, uchar* data,
ulong header_len,
Query_cache_block::block_type type,
TABLE_COUNTER_TYPE ntab,
@@ -2012,8 +2033,7 @@ Query_cache::write_block_data(ulong data_len, gptr data,
block->n_tables = ntab;
block->used = len;
- memcpy((void*) (((byte *) block)+ all_headers_len),
- (void*) data, data_len);
+ memcpy((uchar *) block+ all_headers_len, data, data_len);
}
DBUG_RETURN(block);
}
@@ -2025,7 +2045,7 @@ Query_cache::write_block_data(ulong data_len, gptr data,
my_bool
Query_cache::append_result_data(Query_cache_block **current_block,
- ulong data_len, gptr data,
+ ulong data_len, uchar* data,
Query_cache_block *query_block)
{
DBUG_ENTER("Query_cache::append_result_data");
@@ -2081,7 +2101,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
by the next call
*/
success = write_result_data(&new_block, data_len-last_block_free_space,
- (gptr)(((byte*)data)+last_block_free_space),
+ (uchar*)(((uchar*)data)+last_block_free_space),
query_block,
Query_cache_block::RES_CONT);
/*
@@ -2103,8 +2123,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
ulong to_copy = min(data_len,last_block_free_space);
DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
last_block_free_space, (ulong)last_block, to_copy));
- memcpy((void*) (((byte*) last_block) + last_block->used), (void*) data,
- to_copy);
+ memcpy((uchar*) last_block + last_block->used, data, to_copy);
last_block->used+=to_copy;
}
DBUG_RETURN(success);
@@ -2112,7 +2131,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
my_bool Query_cache::write_result_data(Query_cache_block **result_block,
- ulong data_len, gptr data,
+ ulong data_len, uchar* data,
Query_cache_block *query_block,
Query_cache_block::block_type type)
{
@@ -2138,7 +2157,7 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
ALIGN_SIZE(sizeof(Query_cache_result)));
#ifndef EMBEDDED_LIBRARY
Query_cache_block *block= *result_block;
- byte *rest= (byte*) data;
+ uchar *rest= data;
// Now fill list of blocks that created by allocate_data_chain
do
{
@@ -2146,7 +2165,7 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
ulong length = block->used - headers_len;
DBUG_PRINT("qcache", ("write %lu byte in block 0x%lx",length,
(ulong)block));
- memcpy((void*)(((byte*) block)+headers_len), (void*) rest, length);
+ memcpy((uchar*) block+headers_len, rest, length);
rest += length;
block = block->next;
type = Query_cache_block::RES_CONT;
@@ -2281,18 +2300,18 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list)
// We don't store temporary tables => no key_length+=4 ...
if ((table_block = (Query_cache_block*)
- hash_search(&tables,(byte*) key,key_length)))
+ hash_search(&tables,(uchar*) key,key_length)))
invalidate_table(table_block);
}
}
void Query_cache::invalidate_table(TABLE *table)
{
- invalidate_table((byte*) table->s->table_cache_key.str,
+ invalidate_table((uchar*) table->s->table_cache_key.str,
table->s->table_cache_key.length);
}
-void Query_cache::invalidate_table(byte * key, uint32 key_length)
+void Query_cache::invalidate_table(uchar * key, uint32 key_length)
{
Query_cache_block *table_block;
if ((table_block = ((Query_cache_block*)
@@ -2370,11 +2389,11 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
else
{
DBUG_PRINT("qcache",
- ("table: %s db: %s openinfo: 0x%lx keylen: %u key: 0x%lx",
+ ("table: %s db: %s openinfo: 0x%lx keylen: %lu key: 0x%lx",
tables_used->table->s->table_name.str,
tables_used->table->s->table_cache_key.str,
(ulong) tables_used->table,
- tables_used->table->s->table_cache_key.length,
+ (ulong) tables_used->table->s->table_cache_key.length,
(ulong) tables_used->table->s->table_cache_key.str));
if (!insert_table(tables_used->table->s->table_cache_key.length,
tables_used->table->s->table_cache_key.str,
@@ -2385,7 +2404,12 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
tables_used->engine_data))
DBUG_RETURN(0);
- if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
+#ifdef WITH_MYISAMMRG_STORAGE_ENGINE
+ /*
+ XXX FIXME: Some generic mechanism is required here instead of this
+ MYISAMMRG-specific implementation.
+ */
+ if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
{
ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
MYRG_INFO *file = handler->myrg_info();
@@ -2408,6 +2432,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
DBUG_RETURN(0);
}
}
+#endif
}
}
DBUG_RETURN(n - counter);
@@ -2465,7 +2490,7 @@ Query_cache::insert_table(uint key_len, char *key,
(ulong)node, key_len));
Query_cache_block *table_block = ((Query_cache_block *)
- hash_search(&tables, (byte*) key,
+ hash_search(&tables, (uchar*) key,
key_len));
if (table_block &&
@@ -2489,7 +2514,7 @@ Query_cache::insert_table(uint key_len, char *key,
{
DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
(ulong) key, (int) key_len));
- table_block = write_block_data(key_len, (gptr) key,
+ table_block = write_block_data(key_len, (uchar*) key,
ALIGN_SIZE(sizeof(Query_cache_table)),
Query_cache_block::TABLE,
1, 1);
@@ -2504,7 +2529,7 @@ Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *list_root = table_block->table(0);
list_root->n = 0;
list_root->next = list_root->prev = list_root;
- if (my_hash_insert(&tables, (const byte *) table_block))
+ if (my_hash_insert(&tables, (const uchar *) table_block))
{
DBUG_PRINT("qcache", ("Can't insert table to hash"));
// write_block_data return locked block
@@ -2541,7 +2566,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node)
Query_cache_block *table_block = neighbour->block();
double_linked_list_exclude(table_block,
&tables_blocks);
- hash_delete(&tables,(byte *) table_block);
+ hash_delete(&tables,(uchar *) table_block);
free_memory_block(table_block);
}
DBUG_VOID_RETURN;
@@ -2696,7 +2721,7 @@ void Query_cache::free_memory_block(Query_cache_block *block)
void Query_cache::split_block(Query_cache_block *block, ulong len)
{
DBUG_ENTER("Query_cache::split_block");
- Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len);
+ Query_cache_block *new_block = (Query_cache_block*)(((uchar*) block)+len);
new_block->init(block->length - len);
total_blocks++;
@@ -2984,7 +3009,7 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
DBUG_PRINT("qcache", ("table: %s db: %s type: %u",
tables_used->table->s->table_name.str,
tables_used->table->s->db.str,
- tables_used->table->s->db_type->db_type));
+ tables_used->table->s->db_type()->db_type));
if (tables_used->derived)
{
table_count--;
@@ -3009,12 +3034,18 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
"other non-cacheable table(s)"));
DBUG_RETURN(0);
}
- if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
+#ifdef WITH_MYISAMMRG_STORAGE_ENGINE
+ /*
+ XXX FIXME: Some generic mechanism is required here instead of this
+ MYISAMMRG-specific implementation.
+ */
+ if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
{
ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
MYRG_INFO *file = handler->myrg_info();
table_count+= (file->end_table - file->open_tables);
}
+#endif
}
}
DBUG_RETURN(table_count);
@@ -3033,11 +3064,10 @@ Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
TABLE_COUNTER_TYPE table_count;
DBUG_ENTER("Query_cache::is_cacheable");
- if (lex->sql_command == SQLCOM_SELECT &&
+ if (query_cache_is_cacheable_query(lex) &&
(thd->variables.query_cache_type == 1 ||
(thd->variables.query_cache_type == 2 && (lex->select_lex.options &
- OPTION_TO_QUERY_CACHE))) &&
- lex->safe_to_cache_query)
+ OPTION_TO_QUERY_CACHE))))
{
DBUG_PRINT("qcache", ("options: %lx %lx type: %u",
(long) OPTION_TO_QUERY_CACHE,
@@ -3124,7 +3154,7 @@ void Query_cache::pack_cache()
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
- byte *border = 0;
+ uchar *border = 0;
Query_cache_block *before = 0;
ulong gap = 0;
my_bool ok = 1;
@@ -3160,7 +3190,7 @@ void Query_cache::pack_cache()
}
-my_bool Query_cache::move_by_type(byte **border,
+my_bool Query_cache::move_by_type(uchar **border,
Query_cache_block **before, ulong *gap,
Query_cache_block *block)
{
@@ -3173,7 +3203,7 @@ my_bool Query_cache::move_by_type(byte **border,
DBUG_PRINT("qcache", ("block 0x%lx FREE", (ulong) block));
if (*border == 0)
{
- *border = (byte *) block;
+ *border = (uchar *) block;
*before = block->pprev;
DBUG_PRINT("qcache", ("gap beginning here"));
}
@@ -3203,10 +3233,10 @@ my_bool Query_cache::move_by_type(byte **border,
*new_block =(Query_cache_block *) *border;
uint tablename_offset = block->table()->table() - block->table()->db();
char *data = (char*) block->data();
- byte *key;
- uint key_length;
- key=query_cache_table_get_key((byte*) block, &key_length, 0);
- hash_first(&tables, (byte*) key, key_length, &record_idx);
+ uchar *key;
+ size_t key_length;
+ key=query_cache_table_get_key((uchar*) block, &key_length, 0);
+ hash_first(&tables, (uchar*) key, key_length, &record_idx);
block->destroy();
new_block->init(len);
@@ -3240,7 +3270,7 @@ my_bool Query_cache::move_by_type(byte **border,
/* Fix pointer to table name */
new_block->table()->table(new_block->table()->db() + tablename_offset);
/* Fix hash to point at moved block */
- hash_replace(&tables, &record_idx, (byte*) new_block);
+ hash_replace(&tables, &record_idx, (uchar*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
@@ -3263,10 +3293,10 @@ my_bool Query_cache::move_by_type(byte **border,
char *data = (char*) block->data();
Query_cache_block *first_result_block = ((Query_cache_query *)
block->data())->result();
- byte *key;
- uint key_length;
- key=query_cache_query_get_key((byte*) block, &key_length, 0);
- hash_first(&queries, (byte*) key, key_length, &record_idx);
+ uchar *key;
+ size_t key_length;
+ key=query_cache_query_get_key((uchar*) block, &key_length, 0);
+ hash_first(&queries, (uchar*) key, key_length, &record_idx);
// Move table of used tables
memmove((char*) new_block->table(0), (char*) block->table(0),
ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
@@ -3282,7 +3312,7 @@ my_bool Query_cache::move_by_type(byte **border,
queries_blocks = new_block;
Query_cache_block_table *beg_of_table_table= block->table(0),
*end_of_table_table= block->table(n_tables);
- byte *beg_of_new_table_table= (byte*) new_block->table(0);
+ uchar *beg_of_new_table_table= (uchar*) new_block->table(0);
for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++)
{
@@ -3292,8 +3322,8 @@ my_bool Query_cache::move_by_type(byte **border,
if ((beg_of_table_table <= block_table->next) &&
(block_table->next < end_of_table_table))
((Query_cache_block_table *)(beg_of_new_table_table +
- (((byte*)block_table->next) -
- ((byte*)beg_of_table_table))))->prev=
+ (((uchar*)block_table->next) -
+ ((uchar*)beg_of_table_table))))->prev=
block_table;
else
block_table->next->prev= block_table;
@@ -3302,8 +3332,8 @@ my_bool Query_cache::move_by_type(byte **border,
if ((beg_of_table_table <= block_table->prev) &&
(block_table->prev < end_of_table_table))
((Query_cache_block_table *)(beg_of_new_table_table +
- (((byte*)block_table->prev) -
- ((byte*)beg_of_table_table))))->next=
+ (((uchar*)block_table->prev) -
+ ((uchar*)beg_of_table_table))))->next=
block_table;
else
block_table->prev->next = block_table;
@@ -3331,10 +3361,10 @@ my_bool Query_cache::move_by_type(byte **border,
NET *net = new_block->query()->writer();
if (net != 0)
{
- net->query_cache_query= (gptr) new_block;
+ net->query_cache_query= (uchar*) new_block;
}
/* Fix hash to point at moved block */
- hash_replace(&queries, &record_idx, (byte*) new_block);
+ hash_replace(&queries, &record_idx, (uchar*) new_block);
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
len, (ulong) new_block, (ulong) *border));
break;
@@ -3470,7 +3500,7 @@ my_bool Query_cache::join_results(ulong join_limit)
Query_cache_result *new_result = new_result_block->result();
new_result->parent(block);
- byte *write_to = (byte*) new_result->data();
+ uchar *write_to = (uchar*) new_result->data();
Query_cache_block *result_block = first_result;
do
{
@@ -3654,18 +3684,18 @@ void Query_cache::queries_dump()
Query_cache_block *block = queries_blocks;
do
{
- uint len;
- char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0);
+ size_t len;
+ char *str = (char*) query_cache_query_get_key((uchar*) block, &len, 0);
len-= QUERY_CACHE_FLAGS_SIZE; // Point at flags
Query_cache_query_flags flags;
memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE);
str[len]= 0; // make zero ending DB name
- DBUG_PRINT("qcache", ("F:%u C:%u L:%lu T:'%s' (%u) '%s' '%s'",
+ DBUG_PRINT("qcache", ("F: %u C: %u L: %lu T: '%s' (%lu) '%s' '%s'",
flags.client_long_flag,
flags.character_set_client_num,
(ulong)flags.limit,
flags.time_zone->get_name()->ptr(),
- len, str, strend(str)+1));
+ (ulong) len, str, strend(str)+1));
DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
(ulong) block->next, (ulong) block->prev,
(ulong)block->pnext, (ulong)block->pprev));
@@ -3779,25 +3809,25 @@ my_bool Query_cache::check_integrity(bool locked)
// Check memory allocation
if (block->pnext == first_block) // Is it last block?
{
- if (((byte*)block) + block->length !=
- ((byte*)first_block) + query_cache_size)
+ if (((uchar*)block) + block->length !=
+ ((uchar*)first_block) + query_cache_size)
{
DBUG_PRINT("error",
("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
(ulong) block, (uint) block->type,
- (ulong) (((byte*)block) + block->length),
- (ulong) (((byte*)first_block) + query_cache_size)));
+ (ulong) (((uchar*)block) + block->length),
+ (ulong) (((uchar*)first_block) + query_cache_size)));
result = 1;
}
}
else
- if (((byte*)block) + block->length != ((byte*)block->pnext))
+ if (((uchar*)block) + block->length != ((uchar*)block->pnext))
{
DBUG_PRINT("error",
("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
(ulong) block, (uint) block->type,
- (ulong) (((byte*)block) + block->length),
- (ulong) ((byte*)block->pnext)));
+ (ulong) (((uchar*)block) + block->length),
+ (ulong) ((uchar*)block->pnext)));
}
if (block->type == Query_cache_block::FREE)
free+= block->length;
@@ -3809,8 +3839,8 @@ my_bool Query_cache::check_integrity(bool locked)
Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
block->data());
//is it correct pointer?
- if (((byte*)bin) < ((byte*)bins) ||
- ((byte*)bin) >= ((byte*)first_block))
+ if (((uchar*)bin) < ((uchar*)bins) ||
+ ((uchar*)bin) >= ((uchar*)first_block))
{
DBUG_PRINT("error",
("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
@@ -3822,7 +3852,7 @@ my_bool Query_cache::check_integrity(bool locked)
}
else
{
- int idx = (((byte*)bin) - ((byte*)bins)) /
+ int idx = (((uchar*)bin) - ((uchar*)bins)) /
sizeof(Query_cache_memory_bin);
if (in_list(bins[idx].free_blocks, block, "free memory"))
result = 1;
@@ -3844,7 +3874,7 @@ my_bool Query_cache::check_integrity(bool locked)
Query_cache_block_table *block_table = block->table(j);
Query_cache_block_table *block_table_root =
(Query_cache_block_table *)
- (((byte*)block_table->parent) -
+ (((uchar*)block_table->parent) -
ALIGN_SIZE(sizeof(Query_cache_block_table)));
if (in_table_list(block_table, block_table_root, "table list"))
@@ -3860,15 +3890,15 @@ my_bool Query_cache::check_integrity(bool locked)
case Query_cache_block::RESULT:
{
Query_cache_block * query_block = block->result()->parent();
- if (((byte*)query_block) < ((byte*)first_block) ||
- ((byte*)query_block) >= (((byte*)first_block) + query_cache_size))
+ if (((uchar*)query_block) < ((uchar*)first_block) ||
+ ((uchar*)query_block) >= (((uchar*)first_block) + query_cache_size))
{
DBUG_PRINT("error",
("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
(ulong) block,
(ulong) query_block,
(ulong) first_block,
- (ulong) (((byte*)first_block) + query_cache_size)));
+ (ulong) (((uchar*)first_block) + query_cache_size)));
result = 1;
}
else
@@ -3915,10 +3945,10 @@ my_bool Query_cache::check_integrity(bool locked)
{
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
(ulong) block, (uint) block->type));
- uint length;
- byte *key = query_cache_query_get_key((byte*) block, &length, 0);
- gptr val = hash_search(&queries, key, length);
- if (((gptr)block) != val)
+ size_t length;
+ uchar *key = query_cache_query_get_key((uchar*) block, &length, 0);
+ uchar* val = hash_search(&queries, key, length);
+ if (((uchar*)block) != val)
{
DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
(ulong) block, (ulong) val));
@@ -3950,10 +3980,10 @@ my_bool Query_cache::check_integrity(bool locked)
{
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
(ulong) block, (uint) block->type));
- uint length;
- byte *key = query_cache_table_get_key((byte*) block, &length, 0);
- gptr val = hash_search(&tables, key, length);
- if (((gptr)block) != val)
+ size_t length;
+ uchar *key = query_cache_table_get_key((uchar*) block, &length, 0);
+ uchar* val = hash_search(&tables, key, length);
+ if (((uchar*)block) != val)
{
DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
(ulong) block, (ulong) val));
@@ -3983,7 +4013,7 @@ my_bool Query_cache::check_integrity(bool locked)
} while (block != bins[i].free_blocks);
if (count != bins[i].number)
{
- DBUG_PRINT("error", ("bins[%d].number = %d, but bin have %d blocks",
+ DBUG_PRINT("error", ("bins[%d].number= %d, but bin have %d blocks",
i, bins[i].number, count));
result = 1;
}
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index a66067159e2..3c5d784ce94 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2001-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -99,7 +98,7 @@ struct Query_cache_block
void init(ulong length);
void destroy();
inline uint headers_len();
- inline gptr data(void);
+ inline uchar* data(void);
inline Query_cache_query *query();
inline Query_cache_table *table();
inline Query_cache_result *result();
@@ -128,18 +127,16 @@ struct Query_cache_query
inline void tables_type(uint8 type) { tbls_type= type; }
inline ulong length() { return len; }
inline ulong add(ulong packet_len) { return(len+= packet_len); }
- inline void length(ulong length) { len= length; }
- inline gptr query()
+ inline void length(ulong length_arg) { len= length_arg; }
+ inline uchar* query()
{
- return (gptr)(((byte*)this)+
- ALIGN_SIZE(sizeof(Query_cache_query)));
+ return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query)));
}
void lock_writing();
void lock_reading();
my_bool try_lock_writing();
void unlock_writing();
void unlock_reading();
- static byte *cache_key(const byte *record, uint *length, my_bool not_used);
};
@@ -156,7 +153,7 @@ struct Query_cache_table
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
- inline void table(char *table) { tbl= table; }
+ inline void table(char *table_arg) { tbl= table_arg; }
inline uint32 key_length() { return key_len; }
inline void key_length(uint32 len) { key_len= len; }
inline uint8 type() { return table_type; }
@@ -164,10 +161,10 @@ struct Query_cache_table
inline qc_engine_callback callback() { return callback_func; }
inline void callback(qc_engine_callback fn){ callback_func= fn; }
inline ulonglong engine_data() { return engine_data_buff; }
- inline void engine_data(ulonglong data) { engine_data_buff= data; }
- inline gptr data()
+ inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; }
+ inline uchar* data()
{
- return (gptr)(((byte*)this)+
+ return (uchar*)(((uchar*)this)+
ALIGN_SIZE(sizeof(Query_cache_table)));
}
};
@@ -177,9 +174,9 @@ struct Query_cache_result
Query_cache_result() {} /* Remove gcc warning */
Query_cache_block *query;
- inline gptr data()
+ inline uchar* data()
{
- return (gptr)(((byte*) this)+
+ return (uchar*)(((uchar*) this)+
ALIGN_SIZE(sizeof(Query_cache_result)));
}
/* data_continue (if not whole packet contained by this block) */
@@ -190,10 +187,10 @@ struct Query_cache_result
extern "C"
{
- byte *query_cache_query_get_key(const byte *record, uint *length,
- my_bool not_used);
- byte *query_cache_table_get_key(const byte *record, uint *length,
- my_bool not_used);
+ uchar *query_cache_query_get_key(const uchar *record, size_t *length,
+ my_bool not_used);
+ uchar *query_cache_table_get_key(const uchar *record, size_t *length,
+ my_bool not_used);
}
extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
@@ -262,7 +259,7 @@ protected:
till the end of a flush operation.
*/
pthread_mutex_t structure_guard_mutex;
- byte *cache; // cache memory
+ uchar *cache; // cache memory
Query_cache_block *first_block; // physical location block list
Query_cache_block *queries_blocks; // query list (LIFO)
Query_cache_block *tables_blocks;
@@ -300,7 +297,7 @@ protected:
my_bool first_block);
void invalidate_table(TABLE_LIST *table);
void invalidate_table(TABLE *table);
- void invalidate_table(byte *key, uint32 key_length);
+ void invalidate_table(uchar *key, uint32 key_length);
void invalidate_table(Query_cache_block *table_block);
TABLE_COUNTER_TYPE
register_tables_from_list(TABLE_LIST *tables_used,
@@ -325,7 +322,7 @@ protected:
ulong add_size);
void exclude_from_free_memory_list(Query_cache_block *free_block);
void insert_into_free_memory_list(Query_cache_block *new_block);
- my_bool move_by_type(byte **border, Query_cache_block **before,
+ my_bool move_by_type(uchar **border, Query_cache_block **before,
ulong *gap, Query_cache_block *i);
uint find_bin(ulong size);
void move_to_query_list_end(Query_cache_block *block);
@@ -347,16 +344,16 @@ protected:
ulong init_cache();
void make_disabled();
void free_cache();
- Query_cache_block *write_block_data(ulong data_len, gptr data,
+ Query_cache_block *write_block_data(ulong data_len, uchar* data,
ulong header_len,
Query_cache_block::block_type type,
TABLE_COUNTER_TYPE ntab = 0,
my_bool under_guard=0);
my_bool append_result_data(Query_cache_block **result,
- ulong data_len, gptr data,
+ ulong data_len, uchar* data,
Query_cache_block *parent);
my_bool write_result_data(Query_cache_block **result,
- ulong data_len, gptr data,
+ ulong data_len, uchar* data,
Query_cache_block *parent,
Query_cache_block::block_type
type=Query_cache_block::RESULT);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 25fa4a70bd0..68a5ada71f6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,6 +26,8 @@
#endif
#include "mysql_priv.h"
+#include "rpl_rli.h"
+#include "rpl_record.h"
#include <my_bitmap.h>
#include "log_event.h"
#include <m_ctype.h>
@@ -70,11 +71,11 @@ template class List_iterator<Alter_column>;
** User variables
****************************************************************************/
-extern "C" byte *get_var_key(user_var_entry *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" uchar *get_var_key(user_var_entry *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
- *length=(uint) entry->name.length;
- return (byte*) entry->name.str;
+ *length= entry->name.length;
+ return (uchar*) entry->name.str;
}
extern "C" void free_user_var(user_var_entry *entry)
@@ -90,6 +91,40 @@ bool key_part_spec::operator==(const key_part_spec& other) const
return length == other.length && !strcmp(field_name, other.field_name);
}
+/**
+ Construct an (almost) deep copy of this key. Only those
+ elements that are known to never change are not copied.
+ If out of memory, a partial copy is returned and an error is set
+ in THD.
+*/
+
+Key::Key(const Key &rhs, MEM_ROOT *mem_root)
+ :type(rhs.type),
+ key_create_info(rhs.key_create_info),
+ columns(rhs.columns, mem_root),
+ name(rhs.name),
+ generated(rhs.generated)
+{
+ list_copy_and_replace_each_value(columns, mem_root);
+}
+
+/**
+ Construct an (almost) deep copy of this foreign key. Only those
+ elements that are known to never change are not copied.
+ If out of memory, a partial copy is returned and an error is set
+ in THD.
+*/
+
+foreign_key::foreign_key(const foreign_key &rhs, MEM_ROOT *mem_root)
+ :Key(rhs),
+ ref_table(rhs.ref_table),
+ ref_columns(rhs.ref_columns),
+ delete_opt(rhs.delete_opt),
+ update_opt(rhs.update_opt),
+ match_opt(rhs.match_opt)
+{
+ list_copy_and_replace_each_value(ref_columns, mem_root);
+}
/*
Test if a foreign key (= generated key) is a prefix of the given key
@@ -168,18 +203,25 @@ Open_tables_state::Open_tables_state(ulong version_arg)
reset_open_tables_state();
}
-my_bool thd_in_lock_tables(const THD *thd)
+/*
+ The following functions form part of the C plugin API
+*/
+
+extern "C"
+int thd_in_lock_tables(const THD *thd)
{
- return thd->in_lock_tables;
+ return test(thd->in_lock_tables);
}
-my_bool thd_tablespace_op(const THD *thd)
+extern "C"
+int thd_tablespace_op(const THD *thd)
{
- return thd->tablespace_op;
+ return test(thd->tablespace_op);
}
+extern "C"
const char *thd_proc_info(THD *thd, const char *info)
{
const char *old_info= thd->proc_info;
@@ -187,34 +229,129 @@ const char *thd_proc_info(THD *thd, const char *info)
return old_info;
}
+extern "C"
void **thd_ha_data(const THD *thd, const struct handlerton *hton)
{
return (void **) thd->ha_data + hton->slot;
}
+extern "C"
+long long thd_test_options(const THD *thd, long long test_options)
+{
+ return thd->options & test_options;
+}
+
+extern "C"
+int thd_sql_command(const THD *thd)
+{
+ return (int) thd->lex->sql_command;
+}
+
+extern "C"
+int thd_tx_isolation(const THD *thd)
+{
+ return (int) thd->variables.tx_isolation;
+}
+
/*
- Pass nominal parameters to Statement constructor only to ensure that
- the destructor works OK in case of error. The main_mem_root will be
- re-initialized in init().
+ Dumps a text description of a thread, its security context
+ (user, host) and the current query.
+
+ SYNOPSIS
+ thd_security_context()
+ thd current thread context
+ buffer pointer to preferred result buffer
+ length length of buffer
+ max_query_len how many chars of query to copy (0 for all)
+
+ RETURN VALUES
+ pointer to string
*/
+extern "C"
+char *thd_security_context(THD *thd, char *buffer, unsigned int length,
+ unsigned int max_query_len)
+{
+ String str(buffer, length, &my_charset_latin1);
+ const Security_context *sctx= &thd->main_security_ctx;
+ char header[64];
+ int len;
+
+ len= my_snprintf(header, sizeof(header),
+ "MySQL thread id %lu, query id %lu",
+ thd->thread_id, (ulong) thd->query_id);
+ str.length(0);
+ str.append(header, len);
+
+ if (sctx->host)
+ {
+ str.append(' ');
+ str.append(sctx->host);
+ }
+
+ if (sctx->ip)
+ {
+ str.append(' ');
+ str.append(sctx->ip);
+ }
+
+ if (sctx->user)
+ {
+ str.append(' ');
+ str.append(sctx->user);
+ }
+
+ if (thd->proc_info)
+ {
+ str.append(' ');
+ str.append(thd->proc_info);
+ }
+
+ if (thd->query)
+ {
+ if (max_query_len < 1)
+ len= thd->query_length;
+ else
+ len= min(thd->query_length, max_query_len);
+ str.append('\n');
+ str.append(thd->query, len);
+ }
+ if (str.c_ptr_safe() == buffer)
+ return buffer;
+ return thd->strmake(str.ptr(), str.length());
+}
+
+
THD::THD()
- :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
+ :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
+ /* statement id */ 0),
Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
- binlog_table_maps(0),
- global_read_lock(0), is_fatal_error(0),
- rand_used(0), time_zone_used(0),
+ binlog_table_maps(0), binlog_flags(0UL),
arg_of_last_insert_id_function(FALSE),
first_successful_insert_id_in_prev_stmt(0),
first_successful_insert_id_in_prev_stmt_for_binlog(0),
first_successful_insert_id_in_cur_stmt(0),
- in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
+ global_read_lock(0),
+ is_fatal_error(0),
+ rand_used(0),
+ time_zone_used(0),
+ in_lock_tables(0),
+ bootstrap(0),
+ derived_tables_processing(FALSE),
spcont(NULL)
{
+ ulong tmp;
+
+ /*
+ Pass nominal parameters to init_alloc_root only to ensure that
+ the destructor works OK in case of an error. The main_mem_root
+ will be re-initialized in init_for_queries().
+ */
+ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
stmt_arena= this;
thread_stack= 0;
db= 0;
@@ -242,7 +379,8 @@ THD::THD()
time_after_lock=(time_t) 0;
current_linfo = 0;
slave_thread = 0;
- variables.pseudo_thread_id= 0;
+ bzero(&variables, sizeof(variables));
+ thread_id= variables.pseudo_thread_id= 0;
one_shot_set= 0;
file_id = 0;
query_id= 0;
@@ -260,15 +398,14 @@ THD::THD()
#endif
client_capabilities= 0; // minimalistic client
net.last_error[0]=0; // If error on boot
+#ifdef HAVE_QUERY_CACHE
query_cache_init_query(&net); // If error on boot
+#endif
ull=0;
system_thread= NON_SYSTEM_THREAD;
cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
transaction.m_pending_rows_event= 0;
-#ifdef __WIN__
- real_id = 0;
-#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
@@ -301,16 +438,48 @@ THD::THD()
bzero((char*) &user_var_events, sizeof(user_var_events));
/* Protocol */
- protocol= &protocol_simple; // Default protocol
- protocol_simple.init(this);
- protocol_prep.init(this);
+ protocol= &protocol_text; // Default protocol
+ protocol_text.init(this);
+ protocol_binary.init(this);
tablespace_op=FALSE;
- ulong tmp=sql_rnd_with_mutex();
- randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ tmp= sql_rnd_with_mutex();
+ randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
substitute_null_with_insert_id = FALSE;
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
thr_lock_owner_init(&main_lock_id, &lock_info);
+
+ m_internal_handler= NULL;
+}
+
+
+void THD::push_internal_handler(Internal_error_handler *handler)
+{
+ /*
+ TODO: The current implementation is limited to 1 handler at a time only.
+ THD and sp_rcontext need to be modified to use a common handler stack.
+ */
+ DBUG_ASSERT(m_internal_handler == NULL);
+ m_internal_handler= handler;
+}
+
+
+bool THD::handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level)
+{
+ if (m_internal_handler)
+ {
+ return m_internal_handler->handle_error(sql_errno, level, this);
+ }
+
+ return FALSE; // 'FALSE', as per coding style
+}
+
+
+void THD::pop_internal_handler()
+{
+ DBUG_ASSERT(m_internal_handler != NULL);
+ m_internal_handler= NULL;
}
@@ -321,21 +490,19 @@ THD::THD()
void THD::init(void)
{
pthread_mutex_lock(&LOCK_global_system_variables);
- variables= global_system_variables;
+ plugin_thdvar_init(this);
variables.time_format= date_time_format_copy((THD*) 0,
variables.time_format);
variables.date_format= date_time_format_copy((THD*) 0,
variables.date_format);
variables.datetime_format= date_time_format_copy((THD*) 0,
variables.datetime_format);
-#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
- variables.ndb_use_transactions= 1;
-#endif
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
options= thd_startup_options;
+ no_trans_update.stmt= no_trans_update.all= FALSE;
open_options=ha_open_options;
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
@@ -347,7 +514,6 @@ void THD::init(void)
update_charset();
reset_current_stmt_binlog_row_based();
bzero((char *) &status_var, sizeof(status_var));
- variables.lc_time_names = &my_locale_en_US;
}
@@ -359,6 +525,7 @@ void THD::init(void)
void THD::init_for_queries()
{
+ set_time();
ha_enable_transaction(this,TRUE);
reset_root_defaults(mem_root, variables.query_alloc_block_size,
@@ -387,6 +554,7 @@ void THD::init_for_queries()
void THD::change_user(void)
{
cleanup();
+ killed= NOT_KILLED;
cleanup_done= 0;
init();
stmt_map.reset();
@@ -403,6 +571,9 @@ void THD::change_user(void)
void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
+ DBUG_ASSERT(cleanup_done == 0);
+
+ killed= KILL_CONNECTION;
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
if (transaction.xid_state.xa_state == XA_PREPARED)
{
@@ -438,7 +609,6 @@ void THD::cleanup(void)
pthread_mutex_lock(&LOCK_user_locks);
item_user_lock_release(ull);
pthread_mutex_unlock(&LOCK_user_locks);
- ull= 0;
}
cleanup_done=1;
@@ -469,6 +639,7 @@ THD::~THD()
cleanup();
ha_close_connection(this);
+ plugin_thdvar_cleanup(this);
DBUG_PRINT("info", ("freeing security context"));
main_security_ctx.destroy();
@@ -487,6 +658,7 @@ THD::~THD()
delete rli_fake;
#endif
+ free_root(&main_mem_root, MYF(0));
DBUG_VOID_RETURN;
}
@@ -507,7 +679,7 @@ THD::~THD()
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
{
- ulong *end= (ulong*) ((byte*) to_var +
+ ulong *end= (ulong*) ((uchar*) to_var +
offsetof(STATUS_VAR, last_system_status_var) +
sizeof(ulong));
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
@@ -532,7 +704,7 @@ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
STATUS_VAR *dec_var)
{
- ulong *end= (ulong*) ((byte*) to_var + offsetof(STATUS_VAR,
+ ulong *end= (ulong*) ((uchar*) to_var + offsetof(STATUS_VAR,
last_system_status_var) +
sizeof(ulong));
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
@@ -552,7 +724,9 @@ void THD::awake(THD::killed_state state_to_set)
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
{
- thr_alarm_kill(real_id);
+ thr_alarm_kill(thread_id);
+ if (!slave_thread)
+ thread_scheduler.post_kill_notification(this);
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@@ -603,18 +777,19 @@ bool THD::store_globals()
Assert that thread_stack is initialized: it's necessary to be able
to track stack overrun.
*/
- DBUG_ASSERT(this->thread_stack);
+ DBUG_ASSERT(thread_stack);
if (my_pthread_setspecific_ptr(THR_THD, this) ||
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
mysys_var=my_thread_var;
- dbug_thread_id=my_thread_id();
/*
- By default 'slave_proxy_id' is 'thread_id'. They may later become different
- if this is the slave SQL thread.
+ Let mysqld define the thread id (not mysys)
+ This allows us to move THD to different threads if needed.
*/
- variables.pseudo_thread_id= thread_id;
+ mysys_var->id= thread_id;
+ real_id= pthread_self(); // For debugging
+
/*
We have to call thr_lock_info_init() again here as THD may have been
created in another thread
@@ -642,11 +817,22 @@ bool THD::store_globals()
void THD::cleanup_after_query()
{
+ /*
+ Reset rand_used so that detection of calls to rand() will save random
+ seeds if needed by the slave.
+
+ Do not reset rand_used if inside a stored function or trigger because
+ only the call to these operations is logged. Thus only the calling
+ statement needs to detect rand() calls made by its substatements. These
+ substatements must not set rand_used to 0 because it would remove the
+ detection of rand() by the calling statement.
+ */
if (!in_sub_stmt) /* stored functions and triggers are a special case */
{
/* Forget those values, for next binlogger: */
stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
+ rand_used= 0;
}
if (first_successful_insert_id_in_cur_stmt > 0)
{
@@ -689,9 +875,9 @@ bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
CHARSET_INFO *from_cs)
{
DBUG_ENTER("convert_string");
- size_s new_length= to_cs->mbmaxlen * from_length;
+ size_t new_length= to_cs->mbmaxlen * from_length;
uint dummy_errors;
- if (!(to->str= alloc(new_length+1)))
+ if (!(to->str= (char*) alloc(new_length+1)))
{
to->length= 0; // Safety fix
DBUG_RETURN(1); // EOM
@@ -775,7 +961,7 @@ void THD::add_changed_table(TABLE *table)
DBUG_ASSERT((options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
table->file->has_transactions());
add_changed_table(table->s->table_cache_key.str,
- table->s->table_cache_key.length);
+ (long) table->s->table_cache_key.length);
DBUG_VOID_RETURN;
}
@@ -793,7 +979,8 @@ void THD::add_changed_table(const char *key, long key_length)
{
list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
- ("key_length %ld %u", key_length, (*prev_changed)->key_length));
+ ("key_length: %ld %u", key_length,
+ (*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
else if (cmp == 0)
@@ -803,7 +990,7 @@ void THD::add_changed_table(const char *key, long key_length)
{
list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
- ("key_length %ld %u", key_length,
+ ("key_length: %ld %u", key_length,
(*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
@@ -815,7 +1002,7 @@ void THD::add_changed_table(const char *key, long key_length)
}
}
*prev_changed = changed_table_dup(key, key_length);
- DBUG_PRINT("info", ("key_length %ld %u", key_length,
+ DBUG_PRINT("info", ("key_length: %ld %u", key_length,
(*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
@@ -834,8 +1021,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
return 0;
}
- new_table->key = (char *) (((byte*)new_table)+
- ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST)));
+ new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST));
new_table->next = 0;
new_table->key_length = key_length;
::memcpy(new_table->key, key, key_length);
@@ -850,7 +1036,7 @@ int THD::send_explain_fields(select_result *result)
CHARSET_INFO *cs= system_charset_info;
field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_empty_string("select_type", 19, cs));
- field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs));
+ field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
item->maybe_null= 1;
if (lex->describe & DESCRIBE_PARTITIONS)
{
@@ -863,15 +1049,16 @@ int THD::send_explain_fields(select_result *result)
field_list.push_back(item= new Item_empty_string("type", 10, cs));
item->maybe_null= 1;
field_list.push_back(item=new Item_empty_string("possible_keys",
- NAME_LEN*MAX_KEY, cs));
+ NAME_CHAR_LEN*MAX_KEY, cs));
item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("key", NAME_LEN, cs));
+ field_list.push_back(item=new Item_empty_string("key", NAME_CHAR_LEN, cs));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("key_len",
- NAME_LEN*MAX_KEY));
+ NAME_CHAR_LEN*MAX_KEY));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("ref",
- NAME_LEN*MAX_REF_PARTS, cs));
+ NAME_CHAR_LEN*MAX_REF_PARTS,
+ cs));
item->maybe_null=1;
field_list.push_back(item= new Item_return_int("rows", 10,
MYSQL_TYPE_LONGLONG));
@@ -979,6 +1166,13 @@ void select_result::cleanup()
/* do nothing */
}
+bool select_result::check_simple_select() const
+{
+ my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
+ return TRUE;
+}
+
+
static String default_line_term("\n",default_charset_info);
static String default_escaped("\\",default_charset_info);
static String default_field_term("\t",default_charset_info);
@@ -990,6 +1184,7 @@ sql_exchange::sql_exchange(char *name,bool flag)
enclosed= line_start= &my_empty_string;
line_term= &default_line_term;
escaped= &default_escaped;
+ cs= NULL;
}
bool select_send::send_fields(List<Item> &list, uint flags)
@@ -1174,7 +1369,7 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
IO_CACHE *cache)
{
File file;
- uint option= MY_UNPACK_FILENAME;
+ uint option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|= MY_REPLACE_DIR; // Force use of db directory
@@ -1188,7 +1383,15 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
}
else
(void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
-
+
+ if (opt_secure_file_priv &&
+ strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
+ {
+ /* Write only allowed to dir or subdir specified by secure_file_priv */
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
+ return -1;
+ }
+
if (!access(path, F_OK))
{
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
@@ -1253,6 +1456,11 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
+#define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \
+ (int) (uchar) (x) == field_sep_char || \
+ (int) (uchar) (x) == line_sep_char || \
+ !(x))
+
bool select_export::send_data(List<Item> &items)
{
@@ -1269,11 +1477,10 @@ bool select_export::send_data(List<Item> &items)
}
row_count++;
Item *item;
- char *buff_ptr=buff;
uint used_length=0,items_left=items.elements;
List_iterator_fast<Item> li(items);
- if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
+ if (my_b_write(&cache,(uchar*) exchange->line_start->ptr(),
exchange->line_start->length()))
goto err;
while ((item=li++))
@@ -1282,7 +1489,7 @@ bool select_export::send_data(List<Item> &items)
res=item->str_result(&tmp);
if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
{
- if (my_b_write(&cache,(byte*) exchange->enclosed->ptr(),
+ if (my_b_write(&cache,(uchar*) exchange->enclosed->ptr(),
exchange->enclosed->length()))
goto err;
}
@@ -1294,10 +1501,10 @@ bool select_export::send_data(List<Item> &items)
{
null_buff[0]=escape_char;
null_buff[1]='N';
- if (my_b_write(&cache,(byte*) null_buff,2))
+ if (my_b_write(&cache,(uchar*) null_buff,2))
goto err;
}
- else if (my_b_write(&cache,(byte*) "NULL",4))
+ else if (my_b_write(&cache,(uchar*) "NULL",4))
goto err;
}
else
@@ -1313,14 +1520,20 @@ bool select_export::send_data(List<Item> &items)
used_length=res->length();
if (result_type == STRING_RESULT && escape_char != -1)
{
- char *pos,*start,*end;
-
+ char *pos, *start, *end;
+ CHARSET_INFO *res_charset= res->charset();
+ CHARSET_INFO *character_set_client= thd->variables.
+ character_set_client;
+ bool check_second_byte= (res_charset == &my_charset_bin) &&
+ character_set_client->
+ escape_with_backslash_is_dangerous;
+ DBUG_ASSERT(character_set_client->mbmaxlen == 2 ||
+ !character_set_client->escape_with_backslash_is_dangerous);
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
pos != end ;
pos++)
{
#ifdef USE_MB
- CHARSET_INFO *res_charset=res->charset();
if (use_mb(res_charset))
{
int l;
@@ -1331,22 +1544,58 @@ bool select_export::send_data(List<Item> &items)
}
}
#endif
- if ((int) *pos == escape_char || (int) *pos == field_sep_char ||
- (int) *pos == line_sep_char || !*pos)
- {
+
+ /*
+ Special case when dumping BINARY/VARBINARY/BLOB values
+ for the clients with character sets big5, cp932, gbk and sjis,
+ which can have the escape character (0x5C "\" by default)
+ as the second byte of a multi-byte sequence.
+
+ If
+ - pos[0] is a valid multi-byte head (e.g 0xEE) and
+ - pos[1] is 0x00, which will be escaped as "\0",
+
+ then we'll get "0xEE + 0x5C + 0x30" in the output file.
+
+ If this file is later loaded using this sequence of commands:
+
+ mysql> create table t1 (a varchar(128)) character set big5;
+ mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1;
+
+ then 0x5C will be misinterpreted as the second byte
+ of a multi-byte character "0xEE + 0x5C", instead of
+ escape character for 0x00.
+
+ To avoid this confusion, we'll escape the multi-byte
+ head character too, so the sequence "0xEE + 0x00" will be
+ dumped as "0x5C + 0xEE + 0x5C + 0x30".
+
+ Note, in the condition below we only check if
+ mbcharlen is equal to 2, because there are no
+ character sets with mbmaxlen longer than 2
+ and with escape_with_backslash_is_dangerous set.
+ DBUG_ASSERT before the loop makes that sure.
+ */
+
+ if (NEED_ESCAPING(*pos) ||
+ (check_second_byte &&
+ my_mbcharlen(character_set_client, (uchar) *pos) == 2 &&
+ pos + 1 < end &&
+ NEED_ESCAPING(pos[1])))
+ {
char tmp_buff[2];
tmp_buff[0]= escape_char;
tmp_buff[1]= *pos ? *pos : '0';
- if (my_b_write(&cache,(byte*) start,(uint) (pos-start)) ||
- my_b_write(&cache,(byte*) tmp_buff,2))
+ if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)) ||
+ my_b_write(&cache,(uchar*) tmp_buff,2))
goto err;
start=pos+1;
}
}
- if (my_b_write(&cache,(byte*) start,(uint) (pos-start)))
+ if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)))
goto err;
}
- else if (my_b_write(&cache,(byte*) res->ptr(),used_length))
+ else if (my_b_write(&cache,(uchar*) res->ptr(),used_length))
goto err;
}
if (fixed_row_size)
@@ -1362,28 +1611,27 @@ bool select_export::send_data(List<Item> &items)
uint length=item->max_length-used_length;
for (; length > sizeof(space) ; length-=sizeof(space))
{
- if (my_b_write(&cache,(byte*) space,sizeof(space)))
+ if (my_b_write(&cache,(uchar*) space,sizeof(space)))
goto err;
}
- if (my_b_write(&cache,(byte*) space,length))
+ if (my_b_write(&cache,(uchar*) space,length))
goto err;
}
}
- buff_ptr=buff; // Place separators here
if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
{
- memcpy(buff_ptr,exchange->enclosed->ptr(),exchange->enclosed->length());
- buff_ptr+=exchange->enclosed->length();
+ if (my_b_write(&cache, (uchar*) exchange->enclosed->ptr(),
+ exchange->enclosed->length()))
+ goto err;
}
if (--items_left)
{
- memcpy(buff_ptr,exchange->field_term->ptr(),field_term_length);
- buff_ptr+=field_term_length;
+ if (my_b_write(&cache, (uchar*) exchange->field_term->ptr(),
+ field_term_length))
+ goto err;
}
- if (my_b_write(&cache,(byte*) buff,(uint) (buff_ptr-buff)))
- goto err;
}
- if (my_b_write(&cache,(byte*) exchange->line_term->ptr(),
+ if (my_b_write(&cache,(uchar*) exchange->line_term->ptr(),
exchange->line_term->length()))
goto err;
DBUG_RETURN(0);
@@ -1430,10 +1678,10 @@ bool select_dump::send_data(List<Item> &items)
res=item->str_result(&tmp);
if (!res) // If NULL
{
- if (my_b_write(&cache,(byte*) "",1))
+ if (my_b_write(&cache,(uchar*) "",1))
goto err;
}
- else if (my_b_write(&cache,(byte*) res->ptr(),res->length()))
+ else if (my_b_write(&cache,(uchar*) res->ptr(),res->length()))
{
my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
goto err;
@@ -1529,7 +1777,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
bool select_max_min_finder_subselect::cmp_real()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
double val1= cache->val_real(), val2= maxmin->val_real();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
@@ -1542,7 +1790,7 @@ bool select_max_min_finder_subselect::cmp_real()
bool select_max_min_finder_subselect::cmp_int()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
longlong val1= cache->val_int(), val2= maxmin->val_int();
if (fmax)
return (cache->null_value && !maxmin->null_value) ||
@@ -1555,7 +1803,7 @@ bool select_max_min_finder_subselect::cmp_int()
bool select_max_min_finder_subselect::cmp_decimal()
{
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
my_decimal cval, *cvalue= cache->val_decimal(&cval);
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
if (fmax)
@@ -1570,7 +1818,7 @@ bool select_max_min_finder_subselect::cmp_decimal()
bool select_max_min_finder_subselect::cmp_str()
{
String *val1, *val2, buf1, buf2;
- Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
/*
as far as both operand is Item_cache buf1 & buf2 will not be used,
but added for safety
@@ -1619,6 +1867,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
+bool select_dumpvar::check_simple_select() const
+{
+ my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
+ return TRUE;
+}
+
+
void select_dumpvar::cleanup()
{
row_count= 0;
@@ -1661,21 +1916,20 @@ void Query_arena::cleanup_stmt()
}
/*
- Statement functions
+ Statement functions
*/
-Statement::Statement(enum enum_state state_arg, ulong id_arg,
- ulong alloc_block_size, ulong prealloc_size)
- :Query_arena(&main_mem_root, state_arg),
+Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
+ enum enum_state state_arg, ulong id_arg)
+ :Query_arena(mem_root_arg, state_arg),
id(id_arg),
mark_used_columns(MARK_COLUMNS_READ),
- lex(&main_lex),
+ lex(lex_arg),
query(0),
query_length(0),
cursor(0)
{
name.str= NULL;
- init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size);
}
@@ -1717,7 +1971,7 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
void THD::end_statement()
{
- /* Cleanup SQL processing state to resuse this statement in next query. */
+ /* Cleanup SQL processing state to reuse this statement in next query. */
lex_end(lex);
delete lex->result;
lex->result= 0;
@@ -1758,23 +2012,17 @@ void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
Statement::~Statement()
{
- /*
- We must free `main_mem_root', not `mem_root' (pointer), to work
- correctly if this statement is used as a backup statement,
- for which `mem_root' may point to some other statement.
- */
- free_root(&main_mem_root, MYF(0));
}
C_MODE_START
-static byte *
-get_statement_id_as_hash_key(const byte *record, uint *key_length,
+static uchar *
+get_statement_id_as_hash_key(const uchar *record, size_t *key_length,
my_bool not_used __attribute__((unused)))
{
const Statement *statement= (const Statement *) record;
*key_length= sizeof(statement->id);
- return (byte *) &((const Statement *) statement)->id;
+ return (uchar *) &((const Statement *) statement)->id;
}
static void delete_statement_as_hash_key(void *key)
@@ -1782,11 +2030,11 @@ static void delete_statement_as_hash_key(void *key)
delete (Statement *) key;
}
-static byte *get_stmt_name_hash_key(Statement *entry, uint *length,
+static uchar *get_stmt_name_hash_key(Statement *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
- *length=(uint) entry->name.length;
- return (byte*) entry->name.str;
+ *length= entry->name.length;
+ return (uchar*) entry->name.str;
}
C_MODE_END
@@ -1831,7 +2079,7 @@ Statement_map::Statement_map() :
int Statement_map::insert(THD *thd, Statement *statement)
{
- if (my_hash_insert(&st_hash, (byte*) statement))
+ if (my_hash_insert(&st_hash, (uchar*) statement))
{
/*
Delete is needed only in case of an insert failure. In all other
@@ -1841,7 +2089,7 @@ int Statement_map::insert(THD *thd, Statement *statement)
my_error(ER_OUT_OF_RESOURCES, MYF(0));
goto err_st_hash;
}
- if (statement->name.str && my_hash_insert(&names_hash, (byte*) statement))
+ if (statement->name.str && my_hash_insert(&names_hash, (uchar*) statement))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
goto err_names_hash;
@@ -1869,9 +2117,9 @@ int Statement_map::insert(THD *thd, Statement *statement)
err_max:
if (statement->name.str)
- hash_delete(&names_hash, (byte*) statement);
+ hash_delete(&names_hash, (uchar*) statement);
err_names_hash:
- hash_delete(&st_hash, (byte*) statement);
+ hash_delete(&st_hash, (uchar*) statement);
err_st_hash:
return 1;
}
@@ -1892,9 +2140,9 @@ void Statement_map::erase(Statement *statement)
if (statement == last_found_statement)
last_found_statement= 0;
if (statement->name.str)
- hash_delete(&names_hash, (byte *) statement);
+ hash_delete(&names_hash, (uchar *) statement);
- hash_delete(&st_hash, (byte *) statement);
+ hash_delete(&st_hash, (uchar *) statement);
pthread_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count > 0);
prepared_stmt_count--;
@@ -2057,6 +2305,102 @@ bool Security_context::set_user(char *user_arg)
return user == 0;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/**
+ Initialize this security context from the passed in credentials
+ and activate it in the current thread.
+
+ @param[out] backup Save a pointer to the current security context
+ in the thread. In case of success it points to the
+ saved old context, otherwise it points to NULL.
+
+
+ During execution of a statement, multiple security contexts may
+ be needed:
+ - the security context of the authenticated user, used as the
+ default security context for all top-level statements
+ - in case of a view or a stored program, possibly the security
+ context of the definer of the routine, if the object is
+ defined with SQL SECURITY DEFINER option.
+
+ The currently "active" security context is parameterized in THD
+ member security_ctx. By default, after a connection is
+ established, this member points at the "main" security context
+ - the credentials of the authenticated user.
+
+ Later, if we would like to execute some sub-statement or a part
+ of a statement under credentials of a different user, e.g.
+ definer of a procedure, we authenticate this user in a local
+ instance of Security_context by means of this method (and
+ ultimately by means of acl_getroot_no_password), and make the
+ local instance active in the thread by re-setting
+ thd->security_ctx pointer.
+
+ Note, that the life cycle and memory management of the "main" and
+ temporary security contexts are different.
+ For the main security context, the memory for user/host/ip is
+ allocated on system heap, and the THD class frees this memory in
+ its destructor. The only case when contents of the main security
+ context may change during its life time is when someone issued
+ CHANGE USER command.
+ Memory management of a "temporary" security context is
+ responsibility of the module that creates it.
+
+ @retval TRUE there is no user with the given credentials. The erro
+ is reported in the thread.
+ @retval FALSE success
+*/
+
+bool
+Security_context::
+change_security_context(THD *thd,
+ LEX_STRING *definer_user,
+ LEX_STRING *definer_host,
+ LEX_STRING *db,
+ Security_context **backup)
+{
+ bool needs_change;
+
+ DBUG_ENTER("Security_context::change_security_context");
+
+ DBUG_ASSERT(definer_user->str && definer_host->str);
+
+ *backup= NULL;
+ /*
+ The current security context may have NULL members
+ if we have just started the thread and not authenticated
+ any user. This use case is currently in events worker thread.
+ */
+ needs_change= (thd->security_ctx->priv_user == NULL ||
+ strcmp(definer_user->str, thd->security_ctx->priv_user) ||
+ thd->security_ctx->priv_host == NULL ||
+ my_strcasecmp(system_charset_info, definer_host->str,
+ thd->security_ctx->priv_host));
+ if (needs_change)
+ {
+ if (acl_getroot_no_password(this, definer_user->str, definer_host->str,
+ definer_host->str, db->str))
+ {
+ my_error(ER_NO_SUCH_USER, MYF(0), definer_user->str,
+ definer_host->str);
+ DBUG_RETURN(TRUE);
+ }
+ *backup= thd->security_ctx;
+ thd->security_ctx= this;
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+
+void
+Security_context::restore_security_context(THD *thd,
+ Security_context *backup)
+{
+ if (backup)
+ thd->security_ctx= backup;
+}
+#endif
/****************************************************************************
Handling of open and locked tables states.
@@ -2144,7 +2488,12 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
!current_stmt_binlog_row_based)
{
options&= ~OPTION_BIN_LOG;
- }
+ }
+
+ if ((backup->options & OPTION_BIN_LOG) && is_update_query(lex->sql_command)&&
+ !current_stmt_binlog_row_based)
+ mysql_bin_log.start_union_events(this, this->query_id);
+
/* Disable result sets */
client_capabilities &= ~CLIENT_MULTI_RESULTS;
in_sub_stmt|= new_state;
@@ -2188,6 +2537,10 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
sent_row_count= backup->sent_row_count;
client_capabilities= backup->client_capabilities;
+ if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
+ !current_stmt_binlog_row_based)
+ mysql_bin_log.stop_union_events(this);
+
/*
The following is added to the old values as we are interested in the
total complexity of the query
@@ -2204,7 +2557,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
pthread_mutex_t LOCK_xid_cache;
HASH xid_cache;
-static byte *xid_get_hash_key(const byte *ptr,uint *length,
+static uchar *xid_get_hash_key(const uchar *ptr, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=((XID_STATE*)ptr)->xid.key_length();
@@ -2214,7 +2567,7 @@ static byte *xid_get_hash_key(const byte *ptr,uint *length,
static void xid_free_hash (void *ptr)
{
if (!((XID_STATE*)ptr)->in_thd)
- my_free((gptr)ptr, MYF(0));
+ my_free((uchar*)ptr, MYF(0));
}
bool xid_cache_init()
@@ -2256,7 +2609,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
xs->xa_state=xa_state;
xs->xid.set(xid);
xs->in_thd=0;
- res=my_hash_insert(&xid_cache, (byte*)xs);
+ res=my_hash_insert(&xid_cache, (uchar*)xs);
}
pthread_mutex_unlock(&LOCK_xid_cache);
return res;
@@ -2268,7 +2621,7 @@ bool xid_cache_insert(XID_STATE *xid_state)
pthread_mutex_lock(&LOCK_xid_cache);
DBUG_ASSERT(hash_search(&xid_cache, xid_state->xid.key(),
xid_state->xid.key_length())==0);
- my_bool res=my_hash_insert(&xid_cache, (byte*)xid_state);
+ my_bool res=my_hash_insert(&xid_cache, (uchar*)xid_state);
pthread_mutex_unlock(&LOCK_xid_cache);
return res;
}
@@ -2277,7 +2630,7 @@ bool xid_cache_insert(XID_STATE *xid_state)
void xid_cache_delete(XID_STATE *xid_state)
{
pthread_mutex_lock(&LOCK_xid_cache);
- hash_delete(&xid_cache, (byte *)xid_state);
+ hash_delete(&xid_cache, (uchar *)xid_state);
pthread_mutex_unlock(&LOCK_xid_cache);
}
@@ -2313,8 +2666,8 @@ void xid_cache_delete(XID_STATE *xid_state)
template <class RowsEventT> Rows_log_event*
THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
MY_BITMAP const* cols,
- my_size_t colcnt,
- my_size_t needed,
+ size_t colcnt,
+ size_t needed,
bool is_transactional,
RowsEventT *hint __attribute__((unused)))
{
@@ -2384,24 +2737,25 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
*/
template Rows_log_event*
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- my_size_t, my_size_t, bool,
+ size_t, size_t, bool,
Write_rows_log_event*);
template Rows_log_event*
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- my_size_t colcnt, my_size_t, bool,
+ size_t colcnt, size_t, bool,
Delete_rows_log_event *);
template Rows_log_event*
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- my_size_t colcnt, my_size_t, bool,
+ size_t colcnt, size_t, bool,
Update_rows_log_event *);
#endif
+
+#ifdef NOT_USED
static char const*
field_type_name(enum_field_types type)
{
- switch (type)
- {
+ switch (type) {
case MYSQL_TYPE_DECIMAL:
return "MYSQL_TYPE_DECIMAL";
case MYSQL_TYPE_TINY:
@@ -2459,52 +2813,7 @@ field_type_name(enum_field_types type)
}
return "Unknown";
}
-
-
-my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const
-{
- my_size_t length= 0;
- TABLE_SHARE *table_s= table->s;
- uint* const beg= table_s->blob_field;
- uint* const end= beg + table_s->blob_fields;
-
- for (uint *ptr= beg ; ptr != end ; ++ptr)
- {
- Field_blob* const blob= (Field_blob*) table->field[*ptr];
- length+= blob->get_length((const char*) (data +
- blob->offset(table->record[0]))) +
- HA_KEY_BLOB_LENGTH;
- }
-
- return length;
-}
-
-
-my_size_t THD::pack_row(TABLE *table, MY_BITMAP const* cols, byte *row_data,
- const byte *record) const
-{
- Field **p_field= table->field, *field;
- int n_null_bytes= table->s->null_bytes;
- byte *ptr;
- uint i;
- my_ptrdiff_t const rec_offset= record - table->record[0];
- my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
- memcpy(row_data, record, n_null_bytes);
- ptr= row_data+n_null_bytes;
-
- for (i= 0 ; (field= *p_field) ; i++, p_field++)
- {
- if (bitmap_is_set(cols,i))
- {
- my_ptrdiff_t const offset=
- field->is_null(rec_offset) ? def_offset : rec_offset;
- field->move_field_offset(offset);
- ptr= (byte*)field->pack((char *) ptr, field->ptr);
- field->move_field_offset(-offset);
- }
- }
- return (static_cast<my_size_t>(ptr - row_data));
-}
+#endif
namespace {
@@ -2535,22 +2844,22 @@ namespace {
@param length
Length of data that is needed, if the record contain blobs.
*/
- Row_data_memory(TABLE *table, my_size_t const len1)
+ Row_data_memory(TABLE *table, size_t const len1)
: m_memory(0)
{
#ifndef DBUG_OFF
- m_alloc_checked= false;
+ m_alloc_checked= FALSE;
#endif
allocate_memory(table, len1);
m_ptr[0]= has_memory() ? m_memory : 0;
m_ptr[1]= 0;
}
- Row_data_memory(TABLE *table, my_size_t const len1, my_size_t const len2)
+ Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
: m_memory(0)
{
#ifndef DBUG_OFF
- m_alloc_checked= false;
+ m_alloc_checked= FALSE;
#endif
allocate_memory(table, len1 + len2);
m_ptr[0]= has_memory() ? m_memory : 0;
@@ -2560,7 +2869,7 @@ namespace {
~Row_data_memory()
{
if (m_memory != 0 && m_release_memory_on_destruction)
- my_free((gptr) m_memory, MYF(MY_WME));
+ my_free((uchar*) m_memory, MYF(MY_WME));
}
/**
@@ -2571,21 +2880,21 @@ namespace {
*/
bool has_memory() const {
#ifndef DBUG_OFF
- m_alloc_checked= true;
+ m_alloc_checked= TRUE;
#endif
return m_memory != 0;
}
- byte *slot(uint s)
+ uchar *slot(uint s)
{
DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
DBUG_ASSERT(m_ptr[s] != 0);
- DBUG_ASSERT(m_alloc_checked == true);
+ DBUG_ASSERT(m_alloc_checked == TRUE);
return m_ptr[s];
}
private:
- void allocate_memory(TABLE *const table, my_size_t const total_length)
+ void allocate_memory(TABLE *const table, size_t const total_length)
{
if (table->s->blob_fields == 0)
{
@@ -2599,7 +2908,7 @@ namespace {
to add two bytes for each field, which can potentially be
added to hold the length of a packed field.
*/
- my_size_t const maxlen= table->s->reclength + 2 * table->s->fields;
+ size_t const maxlen= table->s->reclength + 2 * table->s->fields;
/*
Allocate memory for two records if memory hasn't been
@@ -2608,14 +2917,14 @@ namespace {
*/
if (table->write_row_record == 0)
table->write_row_record=
- (byte *) alloc_root(&table->mem_root, 2 * maxlen);
+ (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
m_memory= table->write_row_record;
- m_release_memory_on_destruction= false;
+ m_release_memory_on_destruction= FALSE;
}
else
{
- m_memory= (byte *) my_malloc(total_length, MYF(MY_WME));
- m_release_memory_on_destruction= true;
+ m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
+ m_release_memory_on_destruction= TRUE;
}
}
@@ -2623,15 +2932,15 @@ namespace {
mutable bool m_alloc_checked;
#endif
bool m_release_memory_on_destruction;
- byte *m_memory;
- byte *m_ptr[2];
+ uchar *m_memory;
+ uchar *m_ptr[2];
};
}
int THD::binlog_write_row(TABLE* table, bool is_trans,
- MY_BITMAP const* cols, my_size_t colcnt,
- byte const *record)
+ MY_BITMAP const* cols, size_t colcnt,
+ uchar const *record)
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
@@ -2639,15 +2948,13 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- int error= 0;
-
Row_data_memory memory(table, max_row_length(table, record));
if (!memory.has_memory())
return HA_ERR_OUT_OF_MEM;
- byte *row_data= memory.slot(0);
+ uchar *row_data= memory.slot(0);
- my_size_t const len= pack_row(table, cols, row_data, record);
+ size_t const len= pack_row(table, cols, row_data, record);
Rows_log_event* const ev=
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
@@ -2661,26 +2968,25 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
}
int THD::binlog_update_row(TABLE* table, bool is_trans,
- MY_BITMAP const* cols, my_size_t colcnt,
- const byte *before_record,
- const byte *after_record)
+ MY_BITMAP const* cols, size_t colcnt,
+ const uchar *before_record,
+ const uchar *after_record)
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
- int error= 0;
- my_size_t const before_maxlen = max_row_length(table, before_record);
- my_size_t const after_maxlen = max_row_length(table, after_record);
+ size_t const before_maxlen = max_row_length(table, before_record);
+ size_t const after_maxlen = max_row_length(table, after_record);
Row_data_memory row_data(table, before_maxlen, after_maxlen);
if (!row_data.has_memory())
return HA_ERR_OUT_OF_MEM;
- byte *before_row= row_data.slot(0);
- byte *after_row= row_data.slot(1);
+ uchar *before_row= row_data.slot(0);
+ uchar *after_row= row_data.slot(1);
- my_size_t const before_size= pack_row(table, cols, before_row,
+ size_t const before_size= pack_row(table, cols, before_row,
before_record);
- my_size_t const after_size= pack_row(table, cols, after_row,
+ size_t const after_size= pack_row(table, cols, after_row,
after_record);
/*
@@ -2688,10 +2994,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
trigger false warnings.
*/
#ifndef HAVE_purify
- DBUG_DUMP("before_record", (const char *)before_record, table->s->reclength);
- DBUG_DUMP("after_record", (const char *)after_record, table->s->reclength);
- DBUG_DUMP("before_row", (const char *)before_row, before_size);
- DBUG_DUMP("after_row", (const char *)after_row, after_size);
+ DBUG_DUMP("before_record", before_record, table->s->reclength);
+ DBUG_DUMP("after_record", after_record, table->s->reclength);
+ DBUG_DUMP("before_row", before_row, before_size);
+ DBUG_DUMP("after_row", after_row, after_size);
#endif
Rows_log_event* const ev=
@@ -2708,8 +3014,8 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
}
int THD::binlog_delete_row(TABLE* table, bool is_trans,
- MY_BITMAP const* cols, my_size_t colcnt,
- byte const *record)
+ MY_BITMAP const* cols, size_t colcnt,
+ uchar const *record)
{
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
@@ -2717,15 +3023,13 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
Pack records into format for transfer. We are allocating more
memory than needed, but that doesn't matter.
*/
- int error= 0;
-
Row_data_memory memory(table, max_row_length(table, record));
if (unlikely(!memory.has_memory()))
return HA_ERR_OUT_OF_MEM;
- byte *row_data= memory.slot(0);
+ uchar *row_data= memory.slot(0);
- my_size_t const len= pack_row(table, cols, row_data, record);
+ size_t const len= pack_row(table, cols, row_data, record);
Rows_log_event* const ev=
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
@@ -2803,9 +3107,9 @@ void THD::binlog_delete_pending_rows_event()
RETURN VALUE
Error code, or 0 if no error.
*/
-int THD::binlog_query(THD::enum_binlog_query_type qtype,
- char const *query, ulong query_len,
- bool is_trans, bool suppress_use)
+int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query,
+ ulong query_len, bool is_trans, bool suppress_use,
+ THD::killed_state killed_status_arg)
{
DBUG_ENTER("THD::binlog_query");
DBUG_PRINT("enter", ("qtype=%d, query='%s'", qtype, query));
@@ -2824,6 +3128,27 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
if (int error= binlog_flush_pending_rows_event(TRUE))
DBUG_RETURN(error);
+ /*
+ If we are in statement mode and trying to log an unsafe statement,
+ we should print a warning.
+ */
+ if (lex->is_stmt_unsafe() &&
+ variables.binlog_format == BINLOG_FORMAT_STMT)
+ {
+ DBUG_ASSERT(this->query != NULL);
+ push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_BINLOG_UNSAFE_STATEMENT,
+ ER(ER_BINLOG_UNSAFE_STATEMENT));
+ if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
+ {
+ char warn_buf[MYSQL_ERRMSG_SIZE];
+ my_snprintf(warn_buf, MYSQL_ERRMSG_SIZE, "%s Statement: %s",
+ ER(ER_BINLOG_UNSAFE_STATEMENT), this->query);
+ sql_print_warning(warn_buf);
+ binlog_flags|= BINLOG_FLAG_UNSAFE_STMT_PRINTED;
+ }
+ }
+
switch (qtype) {
case THD::ROW_QUERY_TYPE:
if (current_stmt_binlog_row_based)
@@ -2844,7 +3169,8 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
flush the pending rows event if necessary.
*/
{
- Query_log_event qinfo(this, query, query_len, is_trans, suppress_use);
+ Query_log_event qinfo(this, query, query_len, is_trans, suppress_use,
+ killed_status_arg);
qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
/*
Binlog table maps will be irrelevant after a Query_log_event
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a5bdeee9d16..0be437fd5c1 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,14 +21,17 @@
#endif
#include "log.h"
-#include "rpl_rli.h"
#include "rpl_tblmap.h"
+struct st_relay_log_info;
+typedef st_relay_log_info RELAY_LOG_INFO;
+
class Query_log_event;
class Load_log_event;
class Slave_log_event;
class sp_rcontext;
class sp_cache;
+class Lex_input_stream;
class Rows_log_event;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
@@ -88,6 +90,17 @@ public:
uint length;
key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
bool operator==(const key_part_spec& other) const;
+ /**
+ Construct a copy of this key_part_spec. field_name is copied
+ by-pointer as it is known to never change. At the same time
+ 'length' may be reset in mysql_prepare_create_table, and this
+ is why we supply it with a copy.
+
+ @return If out of memory, 0 is returned and an error is set in
+ THD.
+ */
+ key_part_spec *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) key_part_spec(*this); }
};
@@ -98,6 +111,12 @@ public:
enum drop_type type;
Alter_drop(enum drop_type par_type,const char *par_name)
:name(par_name), type(par_type) {}
+ /**
+ Used to make a clone of this object for ALTER/CREATE TABLE
+ @sa comment for key_part_spec::clone
+ */
+ Alter_drop *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Alter_drop(*this); }
};
@@ -107,6 +126,12 @@ public:
Item *def;
Alter_column(const char *par_name,Item *literal)
:name(par_name), def(literal) {}
+ /**
+ Used to make a clone of this object for ALTER/CREATE TABLE
+ @sa comment for key_part_spec::clone
+ */
+ Alter_column *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Alter_column(*this); }
};
@@ -125,9 +150,16 @@ public:
:type(type_par), key_create_info(*key_info_arg), columns(cols),
name(name_arg), generated(generated_arg)
{}
- ~Key() {}
+ Key(const Key &rhs, MEM_ROOT *mem_root);
+ virtual ~Key() {}
/* Equality comparison of keys (ignoring name) */
friend bool foreign_key_prefix(Key *a, Key *b);
+ /**
+ Used to make a clone of this object for ALTER/CREATE TABLE
+ @sa comment for key_part_spec::clone
+ */
+ virtual Key *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Key(*this, mem_root); }
};
class Table_ident;
@@ -150,6 +182,13 @@ public:
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
{}
+ foreign_key(const foreign_key &rhs, MEM_ROOT *mem_root);
+ /**
+ Used to make a clone of this object for ALTER/CREATE TABLE
+ @sa comment for key_part_spec::clone
+ */
+ virtual Key *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) foreign_key(*this, mem_root); }
};
typedef struct st_mysql_lock
@@ -170,7 +209,7 @@ public:
#include "sql_lex.h" /* Must be here */
-class delayed_insert;
+class Delayed_insert;
class select_result;
class Time_zone;
@@ -181,6 +220,20 @@ class Time_zone;
struct system_variables
{
+ /*
+ How dynamically allocated system variables are handled:
+
+ The global_system_variables and max_system_variables are "authoritative"
+ They both should have the same 'version' and 'size'.
+ When attempting to access a dynamic variable, if the session version
+ is out of date, then the session version is updated and realloced if
+ neccessary and bytes copied from global to make up for missing data.
+ */
+ ulong dynamic_variables_version;
+ char* dynamic_variables_ptr;
+ uint dynamic_variables_head; /* largest valid variable offset */
+ uint dynamic_variables_size; /* how many bytes are in use */
+
ulonglong myisam_max_extra_sort_file_size;
ulonglong myisam_max_sort_file_size;
ulonglong max_heap_table_size;
@@ -215,7 +268,7 @@ struct system_variables
ulong read_rnd_buff_size;
ulong div_precincrement;
ulong sortbuff_size;
- handlerton *table_type;
+ ulong thread_handling;
ulong tx_isolation;
ulong completion_type;
/* Determines which non-standard SQL behaviour should be enabled */
@@ -232,31 +285,36 @@ struct system_variables
ulong trans_prealloc_size;
ulong log_warnings;
ulong group_concat_max_len;
+ ulong ndb_autoincrement_prefetch_sz;
+ ulong ndb_index_stat_cache_entries;
+ ulong ndb_index_stat_update_freq;
+ ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
/*
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
*/
- ulong pseudo_thread_id;
+ my_thread_id pseudo_thread_id;
my_bool low_priority_updates;
my_bool new_mode;
+ /*
+ compatibility option:
+ - index usage hints (USE INDEX without a FOR clause) behave as in 5.0
+ */
+ my_bool old_mode;
my_bool query_cache_wlock_invalidate;
my_bool engine_condition_pushdown;
- my_bool innodb_table_locks;
- my_bool innodb_support_xa;
my_bool ndb_force_send;
my_bool ndb_use_copying_alter_table;
my_bool ndb_use_exact_count;
my_bool ndb_use_transactions;
my_bool ndb_index_stat_enable;
- ulong ndb_autoincrement_prefetch_sz;
- ulong ndb_index_stat_cache_entries;
- ulong ndb_index_stat_update_freq;
- ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
my_bool old_alter_table;
my_bool old_passwords;
+ plugin_ref table_plugin;
+
/* Only charset part of these variables is sensible */
CHARSET_INFO *character_set_filesystem;
CHARSET_INFO *character_set_client;
@@ -272,11 +330,12 @@ struct system_variables
Time_zone *time_zone;
- /* DATE, DATETIME and TIME formats */
+ /* DATE, DATETIME and MYSQL_TIME formats */
DATE_TIME_FORMAT *date_format;
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
+
};
@@ -413,30 +472,31 @@ public:
inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; }
- inline gptr alloc(unsigned int size) { return alloc_root(mem_root,size); }
- inline gptr calloc(unsigned int size)
+ inline void* alloc(size_t size) { return alloc_root(mem_root,size); }
+ inline void* calloc(size_t size)
{
- gptr ptr;
+ void *ptr;
if ((ptr=alloc_root(mem_root,size)))
- bzero((char*) ptr,size);
+ bzero(ptr, size);
return ptr;
}
inline char *strdup(const char *str)
{ return strdup_root(mem_root,str); }
- inline char *strmake(const char *str, uint size)
+ inline char *strmake(const char *str, size_t size)
{ return strmake_root(mem_root,str,size); }
- inline bool LEX_STRING_make(LEX_STRING *lex_str, const char *str, uint size)
+ inline bool LEX_STRING_make(LEX_STRING *lex_str, const char *str,
+ size_t size)
{
return ((lex_str->str=
strmake_root(mem_root, str, (lex_str->length= size)))) == 0;
}
- inline char *memdup(const char *str, uint size)
+ inline void *memdup(const void *str, size_t size)
{ return memdup_root(mem_root,str,size); }
- inline char *memdup_w_gap(const char *str, uint size, uint gap)
+ inline void *memdup_w_gap(const void *str, size_t size, uint gap)
{
- gptr ptr;
- if ((ptr=alloc_root(mem_root,size+gap)))
+ void *ptr;
+ if ((ptr= alloc_root(mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
@@ -451,8 +511,10 @@ public:
class Server_side_cursor;
-/*
- State of a single command executed against this connection.
+/**
+ @class Statement
+ @brief State of a single command executed against this connection.
+
One connection can contain a lot of simultaneously running statements,
some of which could be:
- prepared, that is, contain placeholders,
@@ -470,10 +532,6 @@ class Statement: public ilink, public Query_arena
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
public:
- /* FIXME: these must be protected */
- MEM_ROOT main_mem_root;
- LEX main_lex;
-
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const
@@ -524,10 +582,10 @@ public:
public:
/* This constructor is called for backup statements */
- Statement() { clear_alloc_root(&main_mem_root); }
+ Statement() {}
- Statement(enum enum_state state_arg, ulong id_arg,
- ulong alloc_block_size, ulong prealloc_size);
+ Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
+ enum enum_state state_arg, ulong id_arg);
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
@@ -539,7 +597,7 @@ public:
};
-/*
+/**
Container for all statements created/used in a connection.
Statements in Statement_map have unique Statement::id (guaranteed by id
assignment in Statement::Statement)
@@ -560,7 +618,7 @@ public:
Statement *find_by_name(LEX_STRING *name)
{
Statement *stmt;
- stmt= (Statement*)hash_search(&names_hash, (byte*)name->str,
+ stmt= (Statement*)hash_search(&names_hash, (uchar*)name->str,
name->length);
return stmt;
}
@@ -570,7 +628,7 @@ public:
if (last_found_statement == 0 || id != last_found_statement->id)
{
Statement *stmt;
- stmt= (Statement *) hash_search(&st_hash, (byte *) &id, sizeof(id));
+ stmt= (Statement *) hash_search(&st_hash, (uchar *) &id, sizeof(id));
if (stmt && stmt->name.str)
return NULL;
last_found_statement= stmt;
@@ -619,6 +677,10 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state);
bool xid_cache_insert(XID_STATE *xid_state);
void xid_cache_delete(XID_STATE *xid_state);
+/**
+ @class Security_context
+ @brief A set of THD members describing the current authenticated user.
+*/
class Security_context {
public:
@@ -647,10 +709,22 @@ public:
}
bool set_user(char *user_arg);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool
+ change_security_context(THD *thd,
+ LEX_STRING *definer_user,
+ LEX_STRING *definer_host,
+ LEX_STRING *db,
+ Security_context **backup);
+
+ void
+ restore_security_context(THD *thd, Security_context *backup);
+#endif
};
-/*
+/**
A registry for item tree transformations performed during
query optimization. We register only those changes which require
a rollback to re-execute a prepared statement or stored procedure
@@ -661,7 +735,7 @@ struct Item_change_record;
typedef I_List<Item_change_record> Item_change_list;
-/*
+/**
Type of prelocked mode.
See comment for THD::prelocked_mode for complete description.
*/
@@ -670,7 +744,7 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
PRELOCKED_UNDER_LOCK_TABLES= 2};
-/*
+/**
Class that holds information about tables which were opened and locked
by the thread. It is also used to save/restore this information in
push_open_tables_state()/pop_open_tables_state().
@@ -773,14 +847,17 @@ public:
}
};
-
-/* class to save context when executing a function or trigger */
+/**
+ @class Sub_statement_state
+ @brief Used to save context when executing a function or trigger
+*/
/* Defines used for Sub_statement_state::in_sub_stmt */
#define SUB_STMT_TRIGGER 1
#define SUB_STMT_FUNCTION 2
+
class Sub_statement_state
{
public:
@@ -812,7 +889,51 @@ enum enum_thread_type
};
-/*
+/**
+ This class represents the interface for internal error handlers.
+ Internal error handlers are exception handlers used by the server
+ implementation.
+*/
+class Internal_error_handler
+{
+protected:
+ Internal_error_handler() {}
+ virtual ~Internal_error_handler() {}
+
+public:
+ /**
+ Handle an error condition.
+ This method can be implemented by a subclass to achieve any of the
+ following:
+ - mask an error internally, prevent exposing it to the user,
+ - mask an error and throw another one instead.
+ When this method returns true, the error condition is considered
+ 'handled', and will not be propagated to upper layers.
+ It is the responsability of the code installing an internal handler
+ to then check for trapped conditions, and implement logic to recover
+ from the anticipated conditions trapped during runtime.
+
+ This mechanism is similar to C++ try/throw/catch:
+ - 'try' correspond to <code>THD::push_internal_handler()</code>,
+ - 'throw' correspond to <code>my_error()</code>,
+ which invokes <code>my_message_sql()</code>,
+ - 'catch' correspond to checking how/if an internal handler was invoked,
+ before removing it from the exception stack with
+ <code>THD::pop_internal_handler()</code>.
+
+ @param sql_errno the error number
+ @param level the error level
+ @param thd the calling thread
+ @return true if the error is handled
+ */
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd) = 0;
+};
+
+
+/**
+ @class THD
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
*/
@@ -854,8 +975,8 @@ public:
NET net; // client connection descriptor
MEM_ROOT warn_root; // For warnings and errors
Protocol *protocol; // Current protocol
- Protocol_simple protocol_simple; // Normal protocol
- Protocol_prep protocol_prep; // Binary protocol
+ Protocol_text protocol_text; // Normal protocol
+ Protocol_binary protocol_binary; // Binary protocol
HASH user_vars; // hash for user variables
String packet; // dynamic buffer for network I/O
String convert_buffer; // buffer for charset conversions
@@ -931,7 +1052,7 @@ public:
time_t start_time,time_after_lock,user_time;
time_t connect_time,thr_create_time; // track down slow pthread_create
thr_lock_type update_lock_default;
- delayed_insert *di;
+ Delayed_insert *di;
/* <> 0 if we are inside of trigger or stored function. */
uint in_sub_stmt;
@@ -946,16 +1067,18 @@ public:
Public interface to write RBR events to the binlog
*/
void binlog_start_trans_and_stmt();
+ int binlog_flush_transaction_cache();
+ void binlog_set_stmt_begin();
int binlog_write_table_map(TABLE *table, bool is_transactional);
int binlog_write_row(TABLE* table, bool is_transactional,
- MY_BITMAP const* cols, my_size_t colcnt,
- const byte *buf);
+ MY_BITMAP const* cols, size_t colcnt,
+ const uchar *buf);
int binlog_delete_row(TABLE* table, bool is_transactional,
- MY_BITMAP const* cols, my_size_t colcnt,
- const byte *buf);
+ MY_BITMAP const* cols, size_t colcnt,
+ const uchar *buf);
int binlog_update_row(TABLE* table, bool is_transactional,
- MY_BITMAP const* cols, my_size_t colcnt,
- const byte *old_data, const byte *new_data);
+ MY_BITMAP const* cols, size_t colcnt,
+ const uchar *old_data, const uchar *new_data);
void set_server_id(uint32 sid) { server_id = sid; }
@@ -965,64 +1088,34 @@ public:
template <class RowsEventT> Rows_log_event*
binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
MY_BITMAP const* cols,
- my_size_t colcnt,
- my_size_t needed,
+ size_t colcnt,
+ size_t needed,
bool is_transactional,
RowsEventT* hint);
Rows_log_event* binlog_get_pending_rows_event() const;
void binlog_set_pending_rows_event(Rows_log_event* ev);
-
- my_size_t max_row_length_blob(TABLE* table, const byte *data) const;
- my_size_t max_row_length(TABLE* table, const byte *data) const
- {
- TABLE_SHARE *table_s= table->s;
- my_size_t length= table_s->reclength + 2 * table_s->fields;
- if (table_s->blob_fields == 0)
- return length;
-
- return (length+max_row_length_blob(table,data));
- }
-
- my_size_t pack_row(TABLE* table, MY_BITMAP const* cols, byte *row_data,
- const byte *data) const;
-
int binlog_flush_pending_rows_event(bool stmt_end);
void binlog_delete_pending_rows_event();
private:
uint binlog_table_maps; // Number of table maps currently in the binlog
+
+ enum enum_binlog_flag {
+ BINLOG_FLAG_UNSAFE_STMT_PRINTED,
+ BINLOG_FLAG_COUNT
+ };
+
+ /**
+ Flags with per-thread information regarding the status of the
+ binary log.
+ */
+ uint32 binlog_flags;
public:
uint get_binlog_table_maps() const {
return binlog_table_maps;
}
#endif /* MYSQL_CLIENT */
-#ifndef MYSQL_CLIENT
-public:
- enum enum_binlog_query_type {
- /*
- The query can be logged row-based or statement-based
- */
- ROW_QUERY_TYPE,
-
- /*
- The query has to be logged statement-based
- */
- STMT_QUERY_TYPE,
-
- /*
- The query represents a change to a table in the "mysql"
- database and is currently mapped to ROW_QUERY_TYPE.
- */
- MYSQL_QUERY_TYPE,
- QUERY_TYPE_COUNT
- };
-
- int binlog_query(enum_binlog_query_type qtype,
- char const *query, ulong query_len,
- bool is_trans, bool suppress_use);
-#endif
-
public:
struct st_transactions {
@@ -1063,7 +1156,7 @@ public:
} transaction;
Field *dup_field;
#ifndef __WIN__
- sigset_t signals,block_signals;
+ sigset_t signals;
#endif
#ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio;
@@ -1212,7 +1305,7 @@ public:
return first_successful_insert_id_in_prev_stmt;
}
/*
- Used by Intvar_log_event::exec_event() and by "SET INSERT_ID=#"
+ Used by Intvar_log_event::do_apply_event() and by "SET INSERT_ID=#"
(mysqlbinlog). We'll soon add a variant which can take many intervals in
argument.
*/
@@ -1254,7 +1347,7 @@ public:
update auto-updatable fields (like auto_increment and timestamp).
*/
query_id_t query_id, warn_id;
- ulong thread_id, col_access;
+ ulong col_access;
#ifdef ERROR_INJECT_SUPPORT
ulong error_inject_value;
@@ -1263,8 +1356,8 @@ public:
ulong statement_id_counter;
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;
+ pthread_t real_id; /* For debugging */
+ my_thread_id thread_id;
uint tmp_table, global_read_lock;
uint server_status,open_options;
enum enum_thread_type system_thread;
@@ -1277,7 +1370,14 @@ public:
DYNAMIC_ARRAY user_var_events; /* For user variables replication */
MEM_ROOT *user_var_events_alloc; /* Allocate above array elements here */
- enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
+ enum killed_state
+ {
+ NOT_KILLED=0,
+ KILL_BAD_DATA=1,
+ KILL_CONNECTION=ER_SERVER_SHUTDOWN,
+ KILL_QUERY=ER_QUERY_INTERRUPTED,
+ KILLED_NO_VALUE /* means neither of the states */
+ };
killed_state volatile killed;
/* scramble - random string sent to client on handshake */
@@ -1298,7 +1398,11 @@ public:
bool charset_is_system_charset, charset_is_collation_connection;
bool charset_is_character_set_filesystem;
bool enable_slow_log; /* enable slow log for current statement */
- bool no_trans_update, abort_on_warning;
+ struct {
+ bool all:1;
+ bool stmt:1;
+ } no_trans_update;
+ bool abort_on_warning;
bool got_warning; /* Set on call to push_warning() */
bool no_warnings_for_error; /* no warnings on call to my_error() */
/* set during loop of derived table processing */
@@ -1350,10 +1454,20 @@ public:
*/
query_id_t first_query_id;
} binlog_evt_union;
+
+ /**
+ Character input stream consumed by the lexical analyser,
+ used during parsing.
+ Note that since the parser is not re-entrant, we keep only one input
+ stream here. This member is valid only when executing code during parsing,
+ and may point to invalid memory after that.
+ */
+ Lex_input_stream *m_lip;
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *work_part_info;
#endif
-
+
THD();
~THD();
@@ -1388,6 +1502,33 @@ public:
void close_active_vio();
#endif
void awake(THD::killed_state state_to_set);
+
+#ifndef MYSQL_CLIENT
+ enum enum_binlog_query_type {
+ /*
+ The query can be logged row-based or statement-based
+ */
+ ROW_QUERY_TYPE,
+
+ /*
+ The query has to be logged statement-based
+ */
+ STMT_QUERY_TYPE,
+
+ /*
+ The query represents a change to a table in the "mysql"
+ database and is currently mapped to ROW_QUERY_TYPE.
+ */
+ MYSQL_QUERY_TYPE,
+ QUERY_TYPE_COUNT
+ };
+
+ int binlog_query(enum_binlog_query_type qtype,
+ char const *query, ulong query_len,
+ bool is_trans, bool suppress_use,
+ THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
+#endif
+
/*
For enter_cond() / exit_cond() to work the mutex must be got before
enter_cond(); this mutex is then released by exit_cond().
@@ -1443,7 +1584,7 @@ public:
{
return !stmt_arena->is_stmt_prepare();
}
- inline gptr trans_alloc(unsigned int size)
+ inline void* trans_alloc(unsigned int size)
{
return alloc_root(&transaction.mem_root,size);
}
@@ -1514,7 +1655,8 @@ public:
void end_statement();
inline int killed_errno() const
{
- return killed != KILL_BAD_DATA ? killed : 0;
+ killed_state killed_val; /* to cache the volatile 'killed' */
+ return (killed_val= killed) != KILL_BAD_DATA ? killed_val : 0;
}
inline void send_kill_message() const
{
@@ -1526,7 +1668,7 @@ public:
inline bool really_abort_on_warning()
{
return (abort_on_warning &&
- (!no_trans_update ||
+ (!no_trans_update.stmt ||
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
}
void set_status_var_init();
@@ -1538,6 +1680,7 @@ public:
void restore_sub_statement_state(Sub_statement_state *backup);
void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
void restore_active_arena(Query_arena *set, Query_arena *backup);
+
inline void set_current_stmt_binlog_row_based_if_mixed()
{
/*
@@ -1594,7 +1737,7 @@ public:
This way the user will notice the error as there will be no current
database selected (in addition to the error message set by malloc).
*/
- bool set_db(const char *new_db, uint new_db_len)
+ bool set_db(const char *new_db, size_t new_db_len)
{
/* Do not reallocate memory if current chunk is big enough. */
if (db && new_db && db_length >= new_db_len)
@@ -1607,7 +1750,7 @@ public:
db_length= db ? new_db_len : 0;
return new_db && !db;
}
- void reset_db(char *new_db, uint new_db_len)
+ void reset_db(char *new_db, size_t new_db_len)
{
db= new_db;
db_length= new_db_len;
@@ -1617,7 +1760,7 @@ public:
allocate memory for a deep copy: current database may be freed after
a statement is parsed but before it's executed.
*/
- bool copy_db_to(char **p_db, uint *p_db_length)
+ bool copy_db_to(char **p_db, size_t *p_db_length)
{
if (db == NULL)
{
@@ -1628,6 +1771,48 @@ public:
*p_db_length= db_length;
return FALSE;
}
+ thd_scheduler scheduler;
+
+public:
+ /**
+ Add an internal error handler to the thread execution context.
+ @param handler the exception handler to add
+ */
+ void push_internal_handler(Internal_error_handler *handler);
+
+ /**
+ Handle an error condition.
+ @param sql_errno the error number
+ @param level the error level
+ @return true if the error is handled
+ */
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level);
+
+ /**
+ Remove the error handler last pushed.
+ */
+ void pop_internal_handler();
+
+private:
+ /** The current internal error handler for this thread, or NULL. */
+ Internal_error_handler *m_internal_handler;
+ /**
+ The lex to hold the parsed tree of conventional (non-prepared) queries.
+ Whereas for prepared and stored procedure statements we use an own lex
+ instance for each new query, for conventional statements we reuse
+ the same lex. (@see mysql_parse for details).
+ */
+ LEX main_lex;
+ /**
+ This memory root is used for two purposes:
+ - for conventional queries, to allocate structures stored in main_lex
+ during parsing, and allocate runtime data (execution plan, etc.)
+ during execution.
+ - for prepared queries, only to allocate runtime data. The parsed
+ tree itself is reused between executions and thus is stored elsewhere.
+ */
+ MEM_ROOT main_mem_root;
};
@@ -1639,7 +1824,7 @@ public:
/*
- Used to hold information about file and file structure in exchainge
+ Used to hold information about file and file structure in exchange
via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
XXX: We never call destructor for objects of this class.
*/
@@ -1652,6 +1837,7 @@ public:
bool opt_enclosed;
bool dumpfile;
ulong skip_lines;
+ CHARSET_INFO *cs;
sql_exchange(char *name,bool dumpfile_flag);
};
@@ -1688,7 +1874,14 @@ public:
virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err);
virtual bool send_eof()=0;
- virtual bool simple_select() { return 0; }
+ /**
+ Check if this query returns a result set and therefore is allowed in
+ cursors and set an error message if it is not the case.
+
+ @retval FALSE success
+ @retval TRUE error, an error message is set
+ */
+ virtual bool check_simple_select() const;
virtual void abort() {}
/*
Cleanup instance of this class for next execution of a prepared
@@ -1726,7 +1919,7 @@ public:
bool send_fields(List<Item> &list, uint flags);
bool send_data(List<Item> &items);
bool send_eof();
- bool simple_select() { return 1; }
+ virtual bool check_simple_select() const { return FALSE; }
void abort();
};
@@ -1798,20 +1991,20 @@ class select_insert :public select_result_interceptor {
class select_create: public select_insert {
ORDER *group;
TABLE_LIST *create_table;
- List<create_field> *extra_fields;
- List<Key> *keys;
HA_CREATE_INFO *create_info;
+ Alter_info *alter_info;
Field **field;
public:
- select_create (TABLE_LIST *table,
- HA_CREATE_INFO *create_info_par,
- List<create_field> &fields_par,
- List<Key> &keys_par,
- List<Item> &select_fields,enum_duplicates duplic, bool ignore)
- :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore),
- create_table(table), extra_fields(&fields_par),keys(&keys_par),
- create_info(create_info_par)
- {}
+ select_create(TABLE_LIST *table_arg,
+ HA_CREATE_INFO *create_info_arg,
+ Alter_info *alter_info_arg,
+ List<Item> &select_fields,
+ enum_duplicates duplic, bool ignore)
+ :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore),
+ create_table(table_arg),
+ create_info(create_info_arg),
+ alter_info(alter_info_arg)
+ {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void binlog_show_create_table(TABLE **tables, uint count);
@@ -1846,7 +2039,7 @@ public:
List<Item> save_copy_funcs;
Copy_field *copy_field, *copy_field_end;
Copy_field *save_copy_field, *save_copy_field_end;
- byte *group_buff;
+ uchar *group_buff;
Item **items_to_copy; /* Fields in tmp table */
MI_COLUMNDEF *recinfo,*start_recinfo;
KEY *keyinfo;
@@ -1921,7 +2114,9 @@ public:
class select_singlerow_subselect :public select_subselect
{
public:
- select_singlerow_subselect(Item_subselect *item):select_subselect(item){}
+ select_singlerow_subselect(Item_subselect *item_arg)
+ :select_subselect(item_arg)
+ {}
bool send_data(List<Item> &items);
};
@@ -1932,8 +2127,8 @@ class select_max_min_finder_subselect :public select_subselect
bool (select_max_min_finder_subselect::*op)();
bool fmax;
public:
- select_max_min_finder_subselect(Item_subselect *item, bool mx)
- :select_subselect(item), cache(0), fmax(mx)
+ select_max_min_finder_subselect(Item_subselect *item_arg, bool mx)
+ :select_subselect(item_arg), cache(0), fmax(mx)
{}
void cleanup();
bool send_data(List<Item> &items);
@@ -1947,7 +2142,8 @@ public:
class select_exists_subselect :public select_subselect
{
public:
- select_exists_subselect(Item_subselect *item):select_subselect(item){}
+ select_exists_subselect(Item_subselect *item_arg)
+ :select_subselect(item_arg){}
bool send_data(List<Item> &items);
};
@@ -2049,7 +2245,7 @@ class Unique :public Sql_alloc
ulonglong max_in_memory_size;
IO_CACHE file;
TREE tree;
- byte *record_pointers;
+ uchar *record_pointers;
bool flush();
uint size;
@@ -2082,8 +2278,8 @@ public:
void reset();
bool walk(tree_walk_action action, void *walk_action_arg);
- friend int unique_write_to_file(gptr key, element_count count, Unique *unique);
- friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
+ friend int unique_write_to_file(uchar* key, element_count count, Unique *unique);
+ friend int unique_write_to_ptrs(uchar* key, element_count count, Unique *unique);
};
@@ -2124,6 +2320,11 @@ class multi_update :public select_result_interceptor
List <Item> *fields, *values;
List <Item> **fields_for_table, **values_for_table;
uint table_count;
+ /*
+ List of tables referenced in the CHECK OPTION condition of
+ the updated view excluding the updated table.
+ */
+ List <TABLE> unupdated_check_opt_tables;
Copy_field *copy_field;
enum enum_duplicates handle_duplicates;
bool do_update, trans_safe;
@@ -2172,6 +2373,7 @@ public:
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
bool send_eof();
+ virtual bool check_simple_select() const;
void cleanup();
};
diff --git a/sql/sql_client.cc b/sql/sql_client.cc
index 49d0d3087ad..d6f1183806e 100644
--- a/sql/sql_client.cc
+++ b/sql/sql_client.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
new file mode 100644
index 00000000000..d23c9bb3454
--- /dev/null
+++ b/sql/sql_connect.cc
@@ -0,0 +1,1110 @@
+/* Copyright (C) 2007 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; version 2 of the License.
+
+ 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 */
+
+
+/*
+ Functions to autenticate and handle reqests for a connection
+*/
+
+#include "mysql_priv.h"
+
+#ifdef HAVE_OPENSSL
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilites and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilites field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL */
+
+#ifdef __WIN__
+static void test_signal(int sig_ptr)
+{
+#if !defined( DBUG_OFF)
+ MessageBox(NULL,"Test signal","DBUG",MB_OK);
+#endif
+#if defined(OS2)
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
+#endif
+}
+static void init_signals(void)
+{
+ int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
+ for (int i=0 ; i < 7 ; i++)
+ signal( signals[i], test_signal) ;
+}
+#endif
+
+/*
+ Get structure for logging connection data for the current user
+*/
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static HASH hash_user_connections;
+
+static int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ USER_RESOURCES *mqh)
+{
+ int return_val= 0;
+ uint temp_len, user_len;
+ char temp_user[USER_HOST_BUFF_SIZE];
+ struct user_conn *uc;
+
+ DBUG_ASSERT(user != 0);
+ DBUG_ASSERT(host != 0);
+
+ user_len= strlen(user);
+ temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (uchar*) temp_user, temp_len)))
+ {
+ /* First connection for user; Create a user connection object */
+ if (!(uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)))))
+ {
+ net_send_error(thd, 0, NullS); // Out of memory
+ return_val= 1;
+ goto end;
+ }
+ uc->user=(char*) (uc+1);
+ memcpy(uc->user,temp_user,temp_len+1);
+ uc->host= uc->user + user_len + 1;
+ uc->len= temp_len;
+ uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
+ uc->user_resources= *mqh;
+ uc->intime= thd->thr_create_time;
+ if (my_hash_insert(&hash_user_connections, (uchar*) uc))
+ {
+ my_free((char*) uc,0);
+ net_send_error(thd, 0, NullS); // Out of memory
+ return_val= 1;
+ goto end;
+ }
+ }
+ thd->user_connect=uc;
+ uc->connections++;
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return return_val;
+
+}
+
+
+/*
+ check if user has already too many connections
+
+ SYNOPSIS
+ check_for_max_user_connections()
+ thd Thread handle
+ uc User connect object
+
+ NOTES
+ If check fails, we decrease user connection count, which means one
+ shouldn't call decrease_user_connections() after this function.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+int check_for_max_user_connections(THD *thd, USER_CONN *uc)
+{
+ int error=0;
+ DBUG_ENTER("check_for_max_user_connections");
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (max_user_connections && !uc->user_resources.user_conn &&
+ max_user_connections < (uint) uc->connections)
+ {
+ net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ error=1;
+ goto end;
+ }
+ time_out_user_resource_limits(thd, uc);
+ if (uc->user_resources.user_conn &&
+ uc->user_resources.user_conn < uc->connections)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_user_connections",
+ (long) uc->user_resources.user_conn);
+ error= 1;
+ goto end;
+ }
+ if (uc->user_resources.conn_per_hour &&
+ uc->user_resources.conn_per_hour <= uc->conn_per_hour)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
+ "max_connections_per_hour",
+ (long) uc->user_resources.conn_per_hour);
+ error=1;
+ goto end;
+ }
+ uc->conn_per_hour++;
+
+ end:
+ if (error)
+ uc->connections--; // no need for decrease_user_connections() here
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Decrease user connection count
+
+ SYNOPSIS
+ decrease_user_connections()
+ uc User connection object
+
+ NOTES
+ If there is a n user connection object for a connection
+ (which only happens if 'max_user_connections' is defined or
+ if someone has created a resource grant for a user), then
+ the connection count is always incremented on connect.
+
+ The user connect object is not freed if some users has
+ 'max connections per hour' defined as we need to be able to hold
+ count over the lifetime of the connection.
+*/
+
+void decrease_user_connections(USER_CONN *uc)
+{
+ DBUG_ENTER("decrease_user_connections");
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ DBUG_ASSERT(uc->connections);
+ if (!--uc->connections && !mqh_used)
+ {
+ /* Last connection for user; Delete it */
+ (void) hash_delete(&hash_user_connections,(uchar*) uc);
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Reset per-hour user resource limits when it has been more than
+ an hour since they were last checked
+
+ SYNOPSIS:
+ time_out_user_resource_limits()
+ thd Thread handler
+ uc User connection details
+
+ NOTE:
+ This assumes that the LOCK_user_conn mutex has been acquired, so it is
+ safe to test and modify members of the USER_CONN structure.
+*/
+
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
+{
+ time_t check_time = thd->start_time ? thd->start_time : time(NULL);
+ DBUG_ENTER("time_out_user_resource_limits");
+
+ /* If more than a hour since last check, reset resource checking */
+ if (check_time - uc->intime >= 3600)
+ {
+ uc->questions=1;
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ uc->intime=check_time;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Check if maximum queries per hour limit has been reached
+ returns 0 if OK.
+*/
+
+bool check_mqh(THD *thd, uint check_command)
+{
+ bool error= 0;
+ USER_CONN *uc=thd->user_connect;
+ DBUG_ENTER("check_mqh");
+ DBUG_ASSERT(uc != 0);
+
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+
+ time_out_user_resource_limits(thd, uc);
+
+ /* Check that we have not done too many questions / hour */
+ if (uc->user_resources.questions &&
+ uc->questions++ >= uc->user_resources.questions)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ (long) uc->user_resources.questions);
+ error=1;
+ goto end;
+ }
+ if (check_command < (uint) SQLCOM_END)
+ {
+ /* Check that we have not done too many updates / hour */
+ if (uc->user_resources.updates &&
+ (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
+ uc->updates++ >= uc->user_resources.updates)
+ {
+ net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ (long) uc->user_resources.updates);
+ error=1;
+ goto end;
+ }
+ }
+end:
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ DBUG_RETURN(error);
+}
+
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+
+/*
+ Check if user exist and password supplied is correct.
+
+ SYNOPSIS
+ check_user()
+ thd thread handle, thd->security_ctx->{host,user,ip} are used
+ command originator of the check: now check_user is called
+ during connect and change user procedures; used for
+ logging.
+ passwd scrambled password received from client
+ passwd_len length of scrambled password
+ db database name to connect to, may be NULL
+ check_count dont know exactly
+
+ Note, that host, user and passwd may point to communication buffer.
+ Current implementation does not depend on that, but future changes
+ should be done with this in mind; 'thd' is INOUT, all other params
+ are 'IN'.
+
+ RETURN VALUE
+ 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
+ thd->db are updated; OK is sent to client;
+ -1 access denied or handshake error; error is sent to client;
+ >0 error, not sent to client
+*/
+
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count)
+{
+ DBUG_ENTER("check_user");
+ LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
+ /* Change database if necessary */
+ if (db && db[0])
+ {
+ /*
+ thd->db is saved in caller and needs to be freed by caller if this
+ function returns 0
+ */
+ thd->reset_db(NULL, 0);
+ if (mysql_change_db(thd, &db_str, FALSE))
+ {
+ /* Send the error to the client */
+ net_send_error(thd);
+ DBUG_RETURN(-1);
+ }
+ }
+ send_ok(thd);
+ DBUG_RETURN(0);
+#else
+
+ my_bool opt_secure_auth_local;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ opt_secure_auth_local= opt_secure_auth;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+
+ /*
+ If the server is running in secure auth mode, short scrambles are
+ forbidden.
+ */
+ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
+ {
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ if (passwd_len != 0 &&
+ passwd_len != SCRAMBLE_LENGTH &&
+ passwd_len != SCRAMBLE_LENGTH_323)
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
+
+ /*
+ Clear thd->db as it points to something, that will be freed when
+ connection is closed. We don't want to accidentally free a wrong pointer
+ if connect failed. Also in case of 'CHANGE USER' failure, current
+ database will be switched to 'no database selected'.
+ */
+ thd->reset_db(NULL, 0);
+
+ USER_RESOURCES ur;
+ int res= acl_getroot(thd, &ur, passwd, passwd_len);
+#ifndef EMBEDDED_LIBRARY
+ if (res == -1)
+ {
+ /*
+ This happens when client (new) sends password scrambled with
+ scramble(), but database holds old value (scrambled with
+ scramble_323()). Here we please client to send scrambled_password
+ in old format.
+ */
+ NET *net= &thd->net;
+ if (opt_secure_auth_local)
+ {
+ net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip);
+ general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip);
+ DBUG_RETURN(-1);
+ }
+ /* We have to read very specific packet size */
+ if (send_old_password_request(thd) ||
+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
+ }
+ /* Final attempt to check the user based on reply */
+ /* So as passwd is short, errcode is always >= 0 */
+ res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
+ }
+#endif /*EMBEDDED_LIBRARY*/
+ /* here res is always >= 0 */
+ if (res == 0)
+ {
+ if (!(thd->main_security_ctx.master_access &
+ NO_ACCESS)) // authentication is OK
+ {
+ DBUG_PRINT("info",
+ ("Capabilities: %lu packet_length: %ld Host: '%s' "
+ "Login user: '%s' Priv_user: '%s' Using password: %s "
+ "Access: %lu db: '%s'",
+ thd->client_capabilities,
+ thd->max_client_packet_length,
+ thd->main_security_ctx.host_or_ip,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.priv_user,
+ passwd_len ? "yes": "no",
+ thd->main_security_ctx.master_access,
+ (thd->db ? thd->db : "*none*")));
+
+ if (check_count)
+ {
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ bool count_ok= thread_count <= max_connections + delayed_insert_threads
+ || (thd->main_security_ctx.master_access & SUPER_ACL);
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (!count_ok)
+ { // too many connections
+ net_send_error(thd, ER_CON_COUNT_ERROR);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ /*
+ Log the command before authentication checks, so that the user can
+ check the log for the tried login tried and also to detect
+ break-in attempts.
+ */
+ general_log_print(thd, command,
+ (thd->main_security_ctx.priv_user ==
+ thd->main_security_ctx.user ?
+ (char*) "%s@%s on %s" :
+ (char*) "%s@%s as anonymous on %s"),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ db ? db : (char*) "");
+
+ /*
+ This is the default access rights for the current database. It's
+ set to 0 here because we don't have an active database yet (and we
+ may not have an active database to set.
+ */
+ thd->main_security_ctx.db_access=0;
+
+ /* Don't allow user to connect if he has done too many queries */
+ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
+ max_user_connections) &&
+ get_or_create_user_conn(thd,
+ (opt_old_style_user_limits ? thd->main_security_ctx.user :
+ thd->main_security_ctx.priv_user),
+ (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
+ thd->main_security_ctx.priv_host),
+ &ur))
+ DBUG_RETURN(-1);
+ if (thd->user_connect &&
+ (thd->user_connect->user_resources.conn_per_hour ||
+ thd->user_connect->user_resources.user_conn ||
+ max_user_connections) &&
+ check_for_max_user_connections(thd, thd->user_connect))
+ DBUG_RETURN(-1);
+
+ /* Change database if necessary */
+ if (db && db[0])
+ {
+ if (mysql_change_db(thd, &db_str, FALSE))
+ {
+ /* Send error to the client */
+ net_send_error(thd);
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
+ DBUG_RETURN(-1);
+ }
+ }
+ send_ok(thd);
+ thd->password= test(passwd_len); // remember for error messages
+ /* Ready to handle queries */
+ DBUG_RETURN(0);
+ }
+ }
+ else if (res == 2) // client gave short hash, server has long hash
+ {
+ net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
+ thd->main_security_ctx.user,
+ thd->main_security_ctx.host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ DBUG_RETURN(-1);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+/*
+ Check for maximum allowable user connections, if the mysqld server is
+ started with corresponding variable that is greater then 0.
+*/
+
+extern "C" uchar *get_key_conn(user_conn *buff, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length= buff->len;
+ return (uchar*) buff->user;
+}
+
+
+extern "C" void free_user(struct user_conn *uc)
+{
+ my_free((char*) uc,MYF(0));
+}
+
+
+void init_max_user_conn(void)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0,
+ (hash_get_key) get_key_conn, (hash_free_key) free_user,
+ 0);
+#endif
+}
+
+
+void free_max_user_conn(void)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ hash_free(&hash_user_connections);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+void reset_mqh(LEX_USER *lu, bool get_them= 0)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ if (lu) // for GRANT
+ {
+ USER_CONN *uc;
+ uint temp_len=lu->user.length+lu->host.length+2;
+ char temp_user[USER_HOST_BUFF_SIZE];
+
+ memcpy(temp_user,lu->user.str,lu->user.length);
+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
+ temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (uchar*) temp_user, temp_len)))
+ {
+ uc->questions=0;
+ get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ }
+ }
+ else
+ {
+ /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
+ for (uint idx=0;idx < hash_user_connections.records; idx++)
+ {
+ USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
+ idx);
+ if (get_them)
+ get_mqh(uc->user,uc->host,uc);
+ uc->questions=0;
+ uc->updates=0;
+ uc->conn_per_hour=0;
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+}
+
+
+void thd_init_client_charset(THD *thd, uint cs_number)
+{
+ /*
+ Use server character set and collation if
+ - opt_character_set_client_handshake is not set
+ - client has not specified a character set
+ - client character set is the same as the servers
+ - client character set doesn't exists in server
+ */
+ if (!opt_character_set_client_handshake ||
+ !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
+ !my_strcasecmp(&my_charset_latin1,
+ global_system_variables.character_set_client->name,
+ thd->variables.character_set_client->name))
+ {
+ 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;
+ }
+}
+
+
+/*
+ Initialize connection threads
+*/
+
+bool init_new_connection_handler_thread()
+{
+ pthread_detach_this_thread();
+#if defined(__WIN__)
+ init_signals();
+#else
+ /* Win32 calls this in pthread_create */
+ if (my_thread_init())
+ return 1;
+#endif /* __WIN__ */
+ return 0;
+}
+
+/*
+ Perform handshake, authorize client and update thd ACL variables.
+
+ SYNOPSIS
+ check_connection()
+ thd thread handle
+
+ RETURN
+ 0 success, OK is sent to user, thd is updated.
+ -1 error, which is sent to user
+ > 0 error code (not sent to user)
+*/
+
+#ifndef EMBEDDED_LIBRARY
+static int check_connection(THD *thd)
+{
+ uint connect_errors= 0;
+ NET *net= &thd->net;
+ ulong pkt_len= 0;
+ char *end;
+
+ DBUG_PRINT("info",
+ ("New connection received on %s", vio_description(net->vio)));
+#ifdef SIGNAL_WITH_VIO_CLOSE
+ thd->set_active_vio(net->vio);
+#endif
+
+ if (!thd->main_security_ctx.host) // If TCP/IP connection
+ {
+ char ip[30];
+
+ if (vio_peer_addr(net->vio, ip, &thd->peer_port))
+ return (ER_BAD_HOST_ERROR);
+ if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
+ {
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->main_security_ctx.host=
+ ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
+ /* Cut very long hostnames to avoid possible overflows */
+ if (thd->main_security_ctx.host)
+ {
+ if (thd->main_security_ctx.host != my_localhost)
+ thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
+ HOSTNAME_LENGTH)]= 0;
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
+ }
+ if (connect_errors > max_connect_errors)
+ return(ER_HOST_IS_BLOCKED);
+ }
+ DBUG_PRINT("info",("Host: %s ip: %s",
+ (thd->main_security_ctx.host ?
+ thd->main_security_ctx.host : "unknown host"),
+ (thd->main_security_ctx.ip ?
+ thd->main_security_ctx.ip : "unknown ip")));
+ if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
+ return(ER_HOST_NOT_PRIVILEGED);
+ }
+ else /* Hostname given means that the connection was on a socket */
+ {
+ DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
+ thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
+ thd->main_security_ctx.ip= 0;
+ /* Reset sin_addr */
+ bzero((char*) &thd->remote, sizeof(thd->remote));
+ }
+ vio_keepalive(net->vio, TRUE);
+ {
+ /* buff[] needs to big enough to hold the server_version variable */
+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
+ ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
+
+ if (opt_using_transactions)
+ client_flags|=CLIENT_TRANSACTIONS;
+#ifdef HAVE_COMPRESS
+ client_flags |= CLIENT_COMPRESS;
+#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd)
+ client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
+#endif /* HAVE_OPENSSL */
+
+ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
+ int4store((uchar*) end, thd->thread_id);
+ end+= 4;
+ /*
+ So as check_connection is the only entry point to authorization
+ procedure, scramble is set here. This gives us new scramble for
+ each handshake.
+ */
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ /*
+ Old clients does not understand long scrambles, but can ignore packet
+ tail: that's why first part of the scramble is placed here, and second
+ part at the end of packet.
+ */
+ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
+
+ int2store(end, client_flags);
+ /* write server characteristics: up to 16 bytes allowed */
+ end[2]=(char) default_charset_info->number;
+ int2store(end+3, thd->server_status);
+ bzero(end+5, 13);
+ end+= 18;
+ /* write scramble tail */
+ end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
+ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
+
+ /* At this point we write connection message and read reply */
+ if (net_write_command(net, (uchar) protocol_version, (uchar*) "", 0,
+ (uchar*) buff, (size_t) (end-buff)) ||
+ (pkt_len= my_net_read(net)) == packet_error ||
+ pkt_len < MIN_HANDSHAKE_SIZE)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ }
+#ifdef _CUSTOMCONFIG_
+#include "_cust_sql_parse.h"
+#endif
+ if (connect_errors)
+ reset_host_errors(&thd->remote.sin_addr);
+ if (thd->packet.alloc(thd->variables.net_buffer_length))
+ return(ER_OUT_OF_RESOURCES);
+
+ thd->client_capabilities=uint2korr(net->read_pos);
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
+ thd->max_client_packet_length= uint4korr(net->read_pos+4);
+ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
+ thd_init_client_charset(thd, (uint) net->read_pos[8]);
+ thd->update_charset();
+ end= (char*) net->read_pos+32;
+ }
+ else
+ {
+ thd->max_client_packet_length= uint3korr(net->read_pos+2);
+ end= (char*) net->read_pos+5;
+ }
+
+ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
+#ifdef HAVE_OPENSSL
+ DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
+ if (thd->client_capabilities & CLIENT_SSL)
+ {
+ /* Do the SSL layering. */
+ if (!ssl_acceptor_fd)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ DBUG_PRINT("info", ("IO layer change in progress..."));
+ if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
+ {
+ DBUG_PRINT("error", ("Failed to accept new SSL connection"));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ DBUG_PRINT("info", ("Reading user information over SSL layer"));
+ if ((pkt_len= my_net_read(net)) == packet_error ||
+ pkt_len < NORMAL_HANDSHAKE_SIZE)
+ {
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+ }
+#endif /* HAVE_OPENSSL */
+
+ if (end >= (char*) net->read_pos+ pkt_len +2)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
+
+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
+ if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
+ opt_using_transactions)
+ net->return_status= &thd->server_status;
+
+ char *user= end;
+ char *passwd= strend(user)+1;
+ uint user_len= passwd - user - 1;
+ char *db= passwd;
+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
+ uint dummy_errors;
+
+ /*
+ Old clients send null-terminated string as password; new clients send
+ the size (1 byte) + string (not null-terminated). Hence in case of empty
+ password both send '\0'.
+
+ This strlen() can't be easily deleted without changing protocol.
+ */
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ *passwd++ : strlen(passwd);
+ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
+ db + passwd_len + 1 : 0;
+ /* strlen() can't be easily deleted without changing protocol */
+ uint db_len= db ? strlen(db) : 0;
+
+ if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+
+ /* Since 4.1 all database names are stored in utf8 */
+ if (db)
+ {
+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info,
+ db, db_len,
+ thd->charset(), &dummy_errors)]= 0;
+ db= db_buff;
+ }
+
+ user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
+ system_charset_info, user, user_len,
+ thd->charset(), &dummy_errors)]= '\0';
+ user= user_buff;
+
+ /* If username starts and ends in "'", chop them off */
+ if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
+ {
+ user[user_len-1]= 0;
+ user++;
+ user_len-= 2;
+ }
+
+ if (thd->main_security_ctx.user)
+ x_free(thd->main_security_ctx.user);
+ if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
+}
+
+
+/*
+ Setup thread to be used with the current thread
+
+ SYNOPSIS
+ bool setup_connection_thread_globals()
+ thd Thread/connection handler
+
+ RETURN
+ 0 ok
+ 1 Error (out of memory)
+ In this case we will close the connection and increment status
+*/
+
+bool setup_connection_thread_globals(THD *thd)
+{
+ if (thd->store_globals())
+ {
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ statistic_increment(aborted_connects,&LOCK_status);
+ thread_scheduler.end_thread(thd, 0);
+ return 1; // Error
+ }
+ return 0;
+}
+
+
+/*
+ Autenticate user, with error reporting
+
+ SYNOPSIS
+ login_connection()
+ thd Thread handler
+
+ NOTES
+ Connection is not closed in case of errors
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+
+bool login_connection(THD *thd)
+{
+ int error;
+ NET *net= &thd->net;
+ Security_context *sctx= thd->security_ctx;
+ DBUG_ENTER("login_connection");
+ DBUG_PRINT("info", ("handle_one_connection called by thread %lu",
+ thd->thread_id));
+
+ net->no_send_error= 0;
+
+ /* Use "connect_timeout" value during connection phase */
+ net_set_read_timeout(net, connect_timeout);
+ net_set_write_timeout(net, connect_timeout);
+
+ if ((error=check_connection(thd)))
+ { // Wrong permissions
+ if (error > 0)
+ net_printf_error(thd, error, sctx->host_or_ip);
+#ifdef __NT__
+ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
+ my_sleep(1000); /* must wait after eof() */
+#endif
+ statistic_increment(aborted_connects,&LOCK_status);
+ DBUG_RETURN(1);
+ }
+ /* Connect completed, set read/write timeouts back to default */
+ net_set_read_timeout(net, thd->variables.net_read_timeout);
+ net_set_write_timeout(net, thd->variables.net_write_timeout);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Close an established connection
+
+ NOTES
+ This mainly updates status variables
+*/
+
+void end_connection(THD *thd)
+{
+ NET *net= &thd->net;
+ plugin_thdvar_cleanup(thd);
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
+ if (net->error && net->vio != 0 && net->report_error)
+ {
+ Security_context *sctx= thd->security_ctx;
+ if (!thd->killed && thd->variables.log_warnings > 1)
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ sctx->user ? sctx->user : "unauthenticated",
+ sctx->host_or_ip,
+ (net->last_errno ? ER(net->last_errno) :
+ ER(ER_UNKNOWN_ERROR)));
+ net_send_error(thd, net->last_errno, NullS);
+ statistic_increment(aborted_threads,&LOCK_status);
+ }
+ else if (thd->killed)
+ statistic_increment(aborted_threads,&LOCK_status);
+}
+
+
+/*
+ Initialize THD to handle queries
+*/
+
+void prepare_new_connection_state(THD* thd)
+{
+ Security_context *sctx= thd->security_ctx;
+
+#ifdef __NETWARE__
+ netware_reg_user(sctx->ip, sctx->user, "MySQL");
+#endif
+
+ if (thd->variables.max_join_size == HA_POS_ERROR)
+ thd->options |= OPTION_BIG_SELECTS;
+ if (thd->client_capabilities & CLIENT_COMPRESS)
+ thd->net.compress=1; // Use compression
+
+ thd->version= refresh_version;
+ thd->proc_info= 0;
+ thd->command= COM_SLEEP;
+ thd->set_time();
+ thd->init_for_queries();
+
+ if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
+ {
+ execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
+ if (thd->query_error)
+ {
+ thd->killed= THD::KILL_CONNECTION;
+ sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ sctx->user ? sctx->user : "unauthenticated",
+ sctx->host_or_ip, "init_connect command failed");
+ sql_print_warning("%s", thd->net.last_error);
+ }
+ thd->proc_info=0;
+ thd->set_time();
+ thd->init_for_queries();
+ }
+}
+
+
+/*
+ Thread handler for a connection
+
+ SYNOPSIS
+ handle_one_connection()
+ arg Connection object (THD)
+
+ IMPLEMENTATION
+ This function (normally) does the following:
+ - Initialize thread
+ - Initialize THD to be used with this thread
+ - Authenticate user
+ - Execute all queries sent on the connection
+ - Take connection down
+ - End thread / Handle next connection using thread from thread cache
+*/
+
+pthread_handler_t handle_one_connection(void *arg)
+{
+ THD *thd= (THD*) arg;
+ uint launch_time =
+ (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
+
+ if (thread_scheduler.init_new_connection_thread())
+ {
+ close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+ statistic_increment(aborted_connects,&LOCK_status);
+ thread_scheduler.end_thread(thd,0);
+ return 0;
+ }
+ if (launch_time >= slow_launch_time)
+ statistic_increment(slow_launch_threads,&LOCK_status);
+
+ /*
+ handle_one_connection() is normally the only way a thread would
+ start and would always be on the very high end of the stack ,
+ therefore, the thread stack always starts at the address of the
+ first local variable of handle_one_connection, which is thd. We
+ need to know the start of the stack so that we could check for
+ stack overruns.
+ */
+ thd->thread_stack= (char*) &thd;
+ if (setup_connection_thread_globals(thd))
+ return 0;
+
+ for (;;)
+ {
+ NET *net= &thd->net;
+
+ if (login_connection(thd))
+ goto end_thread;
+
+ prepare_new_connection_state(thd);
+
+ while (!net->error && net->vio != 0 &&
+ !(thd->killed == THD::KILL_CONNECTION))
+ {
+ net->no_send_error= 0;
+ if (do_command(thd))
+ break;
+ }
+ end_connection(thd);
+
+end_thread:
+ close_connection(thd, 0, 1);
+ if (thread_scheduler.end_thread(thd,1))
+ return 0; // Probably no-threads
+
+ /*
+ If end_thread() returns, we are either running with
+ thread-handler=no-threads or this thread has been schedule to
+ handle the next connection.
+ */
+ thd= current_thd;
+ thd->thread_stack= (char*) &thd;
+ }
+}
+#endif /* EMBEDDED_LIBRARY */
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 4e73941fb49..ebd424f00f0 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2003, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index 25bc2d29e1d..f3db9adde25 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 46fae3ffb99..d31c0af1163 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h
index d1156dfba8d..6edd6b24b36 100644
--- a/sql/sql_cursor.h
+++ b/sql/sql_cursor.h
@@ -1,11 +1,8 @@
-#ifndef _sql_cursor_h_
-#define _sql_cursor_h_
-/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,6 +13,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#ifndef _sql_cursor_h_
+#define _sql_cursor_h_
+
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class interface */
#endif
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 4f9e19732fd..82938184245 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,6 +22,7 @@
#include "events.h"
#include <my_dir.h>
#include <m_ctype.h>
+#include "log.h"
#ifdef __WIN__
#include <direct.h>
#endif
@@ -59,11 +59,11 @@ typedef struct my_dblock_st
lock_db key.
*/
-static byte* lock_db_get_key(my_dblock_t *ptr, uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* lock_db_get_key(my_dblock_t *ptr, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= ptr->name_length;
- return (byte*) ptr->name;
+ return (uchar*) ptr->name;
}
@@ -73,7 +73,7 @@ static byte* lock_db_get_key(my_dblock_t *ptr, uint *length,
static void lock_db_free_element(void *ptr)
{
- my_free((gptr) ptr, MYF(0));
+ my_free(ptr, MYF(0));
}
@@ -98,12 +98,12 @@ static my_bool lock_db_insert(const char *dbname, uint length)
safe_mutex_assert_owner(&LOCK_lock_db);
if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache,
- (byte*) dbname, length)))
+ (uchar*) dbname, length)))
{
/* Db is not in the hash, insert it */
char *tmp_name;
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &opt, (uint) sizeof(*opt), &tmp_name, length+1,
+ &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
NullS))
{
error= 1;
@@ -114,11 +114,8 @@ static my_bool lock_db_insert(const char *dbname, uint length)
strmov(opt->name, dbname);
opt->name_length= length;
- if ((error= my_hash_insert(&lock_db_cache, (byte*) opt)))
- {
- my_free((gptr) opt, MYF(0));
- goto end;
- }
+ if ((error= my_hash_insert(&lock_db_cache, (uchar*) opt)))
+ my_free(opt, MYF(0));
}
end:
@@ -135,8 +132,8 @@ void lock_db_delete(const char *name, uint length)
my_dblock_t *opt;
safe_mutex_assert_owner(&LOCK_lock_db);
if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
- (const byte*) name, length)))
- hash_delete(&lock_db_cache, (byte*) opt);
+ (const uchar*) name, length)))
+ hash_delete(&lock_db_cache, (uchar*) opt);
}
@@ -158,11 +155,11 @@ typedef struct my_dbopt_st
Function we use in the creation of our hash to get key.
*/
-static byte* dboptions_get_key(my_dbopt_t *opt, uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= opt->name_length;
- return (byte*) opt->name;
+ return (uchar*) opt->name;
}
@@ -187,7 +184,7 @@ static inline void write_to_binlog(THD *thd, char *query, uint q_len,
static void free_dbopt(void *dbopt)
{
- my_free((gptr) dbopt, MYF(0));
+ my_free((uchar*) dbopt, MYF(0));
}
@@ -280,7 +277,7 @@ static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
length= (uint) strlen(dbname);
rw_rdlock(&LOCK_dboptions);
- if ((opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length)))
+ if ((opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
{
create->default_table_charset= opt->charset;
error= 0;
@@ -312,12 +309,12 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
length= (uint) strlen(dbname);
rw_wrlock(&LOCK_dboptions);
- if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length)))
+ if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
{
/* Options are not in the hash, insert them */
char *tmp_name;
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &opt, (uint) sizeof(*opt), &tmp_name, length+1,
+ &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
NullS))
{
error= 1;
@@ -328,9 +325,9 @@ static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
strmov(opt->name, dbname);
opt->name_length= length;
- if ((error= my_hash_insert(&dboptions, (byte*) opt)))
+ if ((error= my_hash_insert(&dboptions, (uchar*) opt)))
{
- my_free((gptr) opt, MYF(0));
+ my_free(opt, MYF(0));
goto end;
}
}
@@ -352,9 +349,9 @@ void del_dbopt(const char *path)
{
my_dbopt_t *opt;
rw_wrlock(&LOCK_dboptions);
- if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const byte*) path,
+ if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const uchar*) path,
strlen(path))))
- hash_delete(&dboptions, (byte*) opt);
+ hash_delete(&dboptions, (uchar*) opt);
rw_unlock(&LOCK_dboptions);
}
@@ -392,7 +389,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
"\n", NullS) - buf);
/* Error is written by my_write */
- if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME)))
+ if (!my_write(file,(uchar*) buf, length, MYF(MY_NABP+MY_WME)))
error=0;
my_close(file,MYF(0));
}
@@ -578,7 +575,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_ENTER("mysql_create_db");
/* do not create 'information_schema' db */
- if (!my_strcasecmp(system_charset_info, db, information_schema_name.str))
+ if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
{
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
@@ -920,7 +917,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
TABLE_LIST *tbl;
uint db_len;
- if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN)))
+ if (!(query= (char*) thd->alloc(MAX_DROP_TABLE_Q_LEN)))
goto exit; /* not much else we can do */
query_pos= query_data_start= strmov(query,"drop table ");
query_end= query + MAX_DROP_TABLE_Q_LEN;
@@ -954,7 +951,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
- Events::get_instance()->drop_schema_events(thd, db);
+ Events::drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently
change the client's selected database to nothing (to have an empty
@@ -1021,7 +1018,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
DBUG_PRINT("my",("New subdir found: %s", newpath));
if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
goto err;
- if (!(copy_of_path= thd->memdup(newpath, length+1)) ||
+ if (!(copy_of_path= (char*) thd->memdup(newpath, length+1)) ||
!(dir= new (thd->mem_root) String(copy_of_path, length,
&my_charset_bin)) ||
raid_dirs.push_back(dir))
@@ -1257,155 +1254,251 @@ err:
}
-/*
- Change the current database.
+/**
+ @brief Internal implementation: switch current database to a valid one.
- SYNOPSIS
- mysql_change_db()
- thd thread handle
- name database name
- no_access_check if TRUE, don't do access check. In this
- case name may be ""
+ @param thd Thread context.
+ @param new_db_name Name of the database to switch to. The function will
+ take ownership of the name (the caller must not free
+ the allocated memory). If the name is NULL, we're
+ going to switch to NULL db.
+ @param new_db_access Privileges of the new database.
+ @param new_db_charset Character set of the new database.
+*/
- DESCRIPTION
- Check that the database name corresponds to a valid and
- existent database, check access rights (unless called with
- no_access_check), and set the current database. This function
- is called to change the current database upon user request
- (COM_CHANGE_DB command) or temporarily, to execute a stored
- routine.
+static void mysql_change_db_impl(THD *thd,
+ LEX_STRING *new_db_name,
+ ulong new_db_access,
+ CHARSET_INFO *new_db_charset)
+{
+ /* 1. Change current database in THD. */
- NOTES
- This function is not the only way to switch the database that
- is currently employed. When the replication slave thread
- switches the database before executing a query, it calls
- thd->set_db directly. However, if the query, in turn, uses
- a stored routine, the stored routine will use this function,
- even if it's run on the slave.
-
- This function allocates the name of the database on the system
- heap: this is necessary to be able to uniformly change the
- database from any module of the server. Up to 5.0 different
- modules were using different memory to store the name of the
- database, and this led to memory corruption: a stack pointer
- set by Stored Procedures was used by replication after the
- stack address was long gone.
-
- This function does not send anything, including error
- messages, to the client. If that should be sent to the client,
- call net_send_error after this function.
+ if (new_db_name == NULL)
+ {
+ /*
+ THD::set_db() does all the job -- it frees previous database name and
+ sets the new one.
+ */
- RETURN VALUES
- 0 OK
- 1 error
+ thd->set_db(NULL, 0);
+ }
+ else if (new_db_name == &INFORMATION_SCHEMA_NAME)
+ {
+ /*
+ Here we must use THD::set_db(), because we want to copy
+ INFORMATION_SCHEMA_NAME constant.
+ */
+
+ thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
+ }
+ else
+ {
+ /*
+ Here we already have a copy of database name to be used in THD. So,
+ we just call THD::reset_db(). Since THD::reset_db() does not releases
+ the previous database name, we should do it explicitly.
+ */
+
+ x_free(thd->db);
+
+ thd->reset_db(new_db_name->str, new_db_name->length);
+ }
+
+ /* 2. Update security context. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ thd->security_ctx->db_access= new_db_access;
+#endif
+
+ /* 3. Update db-charset environment variables. */
+
+ thd->db_charset= new_db_charset;
+ thd->variables.collation_database= new_db_charset;
+}
+
+
+/**
+ @brief Change the current database.
+
+ @param thd thread handle
+ @param name database name
+ @param force_switch if this flag is set (TRUE), mysql_change_db() will
+ switch to NULL db if the specified database is not
+ available anymore. Corresponding warning will be
+ thrown in this case. This flag is used to change
+ database in stored-routine-execution code.
+
+ @details Check that the database name corresponds to a valid and existent
+ database, check access rights (unless called with no_access_check), and
+ set the current database. This function is called to change the current
+ database upon user request (COM_CHANGE_DB command) or temporarily, to
+ execute a stored routine.
+
+ This function is not the only way to switch the database that is
+ currently employed. When the replication slave thread switches the
+ database before executing a query, it calls thd->set_db directly.
+ However, if the query, in turn, uses a stored routine, the stored routine
+ will use this function, even if it's run on the slave.
+
+ This function allocates the name of the database on the system heap: this
+ is necessary to be able to uniformly change the database from any module
+ of the server. Up to 5.0 different modules were using different memory to
+ store the name of the database, and this led to memory corruption:
+ a stack pointer set by Stored Procedures was used by replication after
+ the stack address was long gone.
+
+ @return Operation status
+ @retval FALSE Success
+ @retval TRUE Error
*/
-bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
{
- LEX_STRING db_name;
- bool system_db= 0;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- ulong db_access;
+ LEX_STRING new_db_file_name;
+
Security_context *sctx= thd->security_ctx;
- LINT_INIT(db_access);
-#endif
+ ulong db_access= sctx->db_access;
+
DBUG_ENTER("mysql_change_db");
- DBUG_PRINT("enter",("name: '%s'",name));
+ DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
- if (name == NULL || name[0] == '\0' && no_access_check == FALSE)
+ if (new_db_name == NULL ||
+ new_db_name->length == 0)
{
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- DBUG_RETURN(1); /* purecov: inspected */
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+
+ DBUG_RETURN(TRUE);
+ }
}
- else if (name[0] == '\0')
+
+ if (my_strcasecmp(system_charset_info, new_db_name->str,
+ INFORMATION_SCHEMA_NAME.str) == 0)
{
- /* Called from SP to restore the original database, which was NULL */
- DBUG_ASSERT(no_access_check);
- system_db= 1;
- db_name.str= NULL;
- db_name.length= 0;
- goto end;
+ /* Switch database to INFORMATION_SCHEMA. */
+
+ mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
+ system_charset_info);
+
+ DBUG_RETURN(FALSE);
}
+
/*
Now we need to make a copy because check_db_name requires a
- non-constant argument. TODO: fix check_db_name.
+ non-constant argument. Actually, it takes database file name.
+
+ TODO: fix check_db_name().
+ */
+
+ new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length,
+ MYF(MY_WME));
+ new_db_file_name.length= new_db_name->length;
+
+ if (new_db_file_name.str == NULL)
+ DBUG_RETURN(TRUE); /* the error is set */
+
+ /*
+ NOTE: if check_db_name() fails, we should throw an error in any case,
+ even if we are called from sp_head::execute().
+
+ It's next to impossible however to get this error when we are called
+ from sp_head::execute(). But let's switch database to NULL in this case
+ to be sure.
*/
- if ((db_name.str= my_strdup(name, MYF(MY_WME))) == NULL)
- DBUG_RETURN(1); /* the error is set */
- db_name.length= strlen(db_name.str);
- if (check_db_name(&db_name))
+
+ if (check_db_name(&new_db_file_name))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
+ my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+
+ if (force_switch)
+ {
+ /* Change db to NULL. */
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ }
+ DBUG_RETURN(TRUE);
}
- DBUG_PRINT("info",("Use database: %s", db_name.str));
- if (!my_strcasecmp(system_charset_info, db_name.str,
- information_schema_name.str))
- {
- system_db= 1;
+
+ DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access= SELECT_ACL;
-#endif
- goto end;
+ db_access=
+ test_all_bits(sctx->master_access, DB_ACLS) ?
+ DB_ACLS :
+ acl_get(sctx->host,
+ sctx->ip,
+ sctx->priv_user,
+ new_db_file_name.str,
+ FALSE) | sctx->master_access;
+
+ if (!force_switch &&
+ !(db_access & DB_ACLS) &&
+ check_grant_db(thd, new_db_file_name.str))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ sctx->priv_user,
+ sctx->priv_host,
+ new_db_file_name.str);
+ general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
+ sctx->priv_user, sctx->priv_host, new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
}
+#endif
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
+ if (check_db_dir_existence(new_db_file_name.str))
{
- if (test_all_bits(sctx->master_access, DB_ACLS))
- db_access=DB_ACLS;
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
+ new_db_file_name.str);
+
+ my_free(new_db_file_name.str, MYF(0));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user,
- db_name.str, 0) |
- sctx->master_access);
- if (!(db_access & DB_ACLS) && (!grant_option ||
- check_grant_db(thd, db_name.str)))
{
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user,
- sctx->priv_host,
- db_name.str);
- general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
- sctx->priv_user, sctx->priv_host, db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
+ my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
}
}
-#endif
- if (check_db_dir_existence(db_name.str))
- {
- my_error(ER_BAD_DB_ERROR, MYF(0), db_name.str);
- my_free(db_name.str, MYF(0));
- DBUG_RETURN(1);
- }
+ /*
+ NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
+ attributes and will be freed in THD::~THD().
+ */
-end:
- x_free(thd->db);
- DBUG_ASSERT(db_name.str == NULL || db_name.str[0] != '\0');
- thd->reset_db(db_name.str, db_name.length); // THD::~THD will free this
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
- sctx->db_access= db_access;
-#endif
- if (system_db)
- {
- thd->db_charset= system_charset_info;
- thd->variables.collation_database= system_charset_info;
- }
- else
{
- HA_CREATE_INFO create;
+ HA_CREATE_INFO db_options;
- load_db_opt_by_name(thd, db_name.str, &create);
+ load_db_opt_by_name(thd, new_db_name->str, &db_options);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
+ mysql_change_db_impl(thd, &new_db_file_name, db_access,
+ db_options.default_table_charset ?
+ db_options.default_table_charset :
+ thd->variables.collation_server);
}
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
}
@@ -1415,8 +1508,8 @@ lock_databases(THD *thd, const char *db1, uint length1,
{
pthread_mutex_lock(&LOCK_lock_db);
while (!thd->killed &&
- (hash_search(&lock_db_cache,(byte*) db1, length1) ||
- hash_search(&lock_db_cache,(byte*) db2, length2)))
+ (hash_search(&lock_db_cache,(uchar*) db1, length1) ||
+ hash_search(&lock_db_cache,(uchar*) db2, length2)))
{
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
pthread_mutex_lock(&LOCK_lock_db);
@@ -1558,7 +1651,7 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
table_str.length= filename_to_tablename(file->name,
tname, sizeof(tname)-1);
- table_str.str= sql_memdup(tname, table_str.length + 1);
+ table_str.str= (char*) sql_memdup(tname, table_str.length + 1);
Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
Table_ident *new_ident= new Table_ident(thd, *new_db, table_str, 0);
if (!old_ident || !new_ident ||
@@ -1582,8 +1675,8 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
Failed to move all tables from the old database to the new one.
In the best case mysql_rename_tables() moved all tables back to the old
database. In the worst case mysql_rename_tables() moved some tables
- to the new database, then failed, then started to move the tables back, and
- then failed again. In this situation we have some tables in the
+ to the new database, then failed, then started to move the tables back,
+ and then failed again. In this situation we have some tables in the
old database and some tables in the new database.
Let's delete the option file, and then the new database directory.
If some tables were left in the new directory, rmdir() will fail.
@@ -1704,7 +1797,7 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db)
/* Step9: Let's do "use newdb" if we renamed the current database */
if (change_to_newdb)
- error|= mysql_change_db(thd, new_db->str, 0);
+ error|= mysql_change_db(thd, new_db, 0);
exit:
pthread_mutex_lock(&LOCK_lock_db);
@@ -1719,6 +1812,8 @@ exit:
DBUG_RETURN(error);
}
+
+
/*
Check if there is directory for the database name.
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index df24dad2d4c..fe54a12e4dc 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -55,6 +54,27 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (mysql_prepare_delete(thd, table_list, &conds))
DBUG_RETURN(TRUE);
+ /* check ORDER BY even if it can be ignored */
+ if (order && order->elements)
+ {
+ TABLE_LIST tables;
+ List<Item> fields;
+ List<Item> all_fields;
+
+ bzero((char*) &tables,sizeof(tables));
+ tables.table = table;
+ tables.alias = table_list->alias;
+
+ if (select_lex->setup_ref_array(thd, order->elements) ||
+ setup_order(thd, select_lex->ref_pointer_array, &tables,
+ fields, all_fields, (ORDER*) order->first))
+ {
+ delete select;
+ free_underlaid_joins(thd, &thd->lex->select_lex);
+ DBUG_RETURN(TRUE);
+ }
+ }
+
const_cond= (!conds || conds->const_item());
safe_update=test(thd->options & OPTION_SAFE_UPDATES);
if (safe_update && const_cond)
@@ -70,13 +90,13 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
Test if the user wants to delete all rows and deletion doesn't have
any side-effects (because of triggers), so we can use optimized
handler::delete_all_rows() method.
-
- If row-based replication is used, we also delete the table row by
- row.
+ We implement fast TRUNCATE for InnoDB even if triggers are present.
+ TRUNCATE ignores triggers.
*/
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
- !(table->triggers && table->triggers->has_delete_triggers()) &&
+ (thd->lex->sql_command == SQLCOM_TRUNCATE ||
+ !(table->triggers && table->triggers->has_delete_triggers())) &&
!thd->current_stmt_binlog_row_based)
{
/* Update the table->file->stats.records number */
@@ -117,7 +137,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
/* Update the table->file->stats.records number */
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- table->used_keys.clear_all();
+ table->covering_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table, 0, 0, conds, 0, &error);
if (error)
@@ -154,27 +174,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (order && order->elements)
{
- uint length;
+ uint length= 0;
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;
- tables.alias = table_list->alias;
-
- if (select_lex->setup_ref_array(thd, order->elements) ||
- setup_order(thd, select_lex->ref_pointer_array, &tables,
- fields, all_fields, (ORDER*) order->first))
- {
- delete select;
- free_underlaid_joins(thd, &thd->lex->select_lex);
- DBUG_RETURN(TRUE);
- }
- if (!select && limit != HA_POS_ERROR)
+ if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);
if (usable_index == MAX_KEY)
@@ -217,7 +221,20 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
init_ftfuncs(thd, select_lex, 1);
thd->proc_info="updating";
- will_batch= !table->file->start_bulk_delete();
+ if (table->triggers &&
+ table->triggers->has_triggers(TRG_EVENT_DELETE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER DELETE triggers that might access to subject table
+ and therefore might need delete to be done immediately. So we turn-off
+ the batching.
+ */
+ (void) table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+ will_batch= FALSE;
+ }
+ else
+ will_batch= !table->file->start_bulk_delete();
table->mark_columns_needed_for_delete();
@@ -336,7 +353,7 @@ cleanup:
}
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
free_underlaid_joins(thd, select_lex);
if (transactional_table)
@@ -378,6 +395,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
Item *fake_conds= 0;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
+ List<Item> all_fields;
thd->lex->allow_sum_func= 0;
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
@@ -395,12 +413,17 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
}
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{
update_non_unique_table_error(table_list, "DELETE", duplicate);
DBUG_RETURN(TRUE);
}
}
+
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
}
@@ -415,7 +438,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
{
handler *file= (handler*)arg;
- return file->cmp_ref((const byte*)a, (const byte*)b);
+ return file->cmp_ref((const uchar*)a, (const uchar*)b);
}
/*
@@ -487,7 +510,7 @@ bool mysql_multi_delete_prepare(THD *thd)
{
TABLE_LIST *duplicate;
if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
- lex->query_tables)))
+ lex->query_tables, 0)))
{
update_non_unique_table_error(target_tbl->correspondent_table,
"DELETE", duplicate);
@@ -548,11 +571,22 @@ multi_delete::initialize_tables(JOIN *join)
tbl->no_keyread=1;
/* Don't use record cache */
tbl->no_cache= 1;
- tbl->used_keys.clear_all();
+ tbl->covering_keys.clear_all();
if (tbl->file->has_transactions())
transactional_tables= 1;
else
normal_tables= 1;
+ if (tbl->triggers &&
+ tbl->triggers->has_triggers(TRG_EVENT_DELETE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER DELETE triggers that might access to subject
+ table and therefore might need delete to be done immediately.
+ So we turn-off the batching.
+ */
+ (void) tbl->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+ }
tbl->prepare_for_position();
tbl->mark_columns_needed_for_delete();
}
@@ -822,7 +856,7 @@ bool multi_delete::send_eof()
}
}
if (!transactional_tables)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
/* Commit or rollback the current SQL statement */
if (transactional_tables)
@@ -869,7 +903,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
/* If it is a temporary table, close and regenerate it */
if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
{
- handlerton *table_type= table->s->db_type;
+ handlerton *table_type= table->s->db_type();
TABLE_SHARE *share= table->s;
if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
goto trunc_by_del;
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 5a9871c07c5..ea7545fe5cb 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -110,8 +109,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
SELECT_LEX *first_select= unit->first_select();
TABLE *table= 0;
select_union *derived_result;
- bool is_union= first_select->next_select() &&
- first_select->next_select()->linkage == UNION_TYPE;
/* prevent name resolving out of derived table */
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
@@ -182,7 +179,7 @@ exit:
orig_table_list->table_name= table->s->table_name.str;
orig_table_list->table_name_length= table->s->table_name.length;
table->derived_select_number= first_select->select_number;
- table->s->tmp_table= TMP_TABLE;
+ table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (orig_table_list->referencing_view)
table->grant= orig_table_list->grant;
@@ -239,9 +236,7 @@ bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
SELECT_LEX *first_select= unit->first_select();
select_union *derived_result= orig_table_list->derived_result;
SELECT_LEX *save_current_select= lex->current_select;
- bool is_union= first_select->next_select() &&
- first_select->next_select()->linkage == UNION_TYPE;
- if (is_union)
+ if (unit->is_union())
{
// execute union without clean up
res= unit->exec();
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 98483ce2de6..a3eb93f87da 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index dc7a437d7d1..61442c52de7 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -148,15 +147,9 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
if (thd->warn_list.elements < thd->variables.max_error_count)
{
- /*
- The following code is here to change the allocation to not
- use the thd->mem_root, which is freed after each query
- */
- MEM_ROOT *old_root= thd->mem_root;
- thd->mem_root= &thd->warn_root;
- if ((err= new MYSQL_ERROR(thd, code, level, msg)))
- thd->warn_list.push_back(err);
- thd->mem_root= old_root;
+ /* We have to use warn_root, as mem_root is freed after each query */
+ if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
+ thd->warn_list.push_back(err, &thd->warn_root);
}
thd->warn_count[(uint) level]++;
thd->total_warn_count++;
diff --git a/sql/sql_error.h b/sql/sql_error.h
index f4a7b14ba1a..f98264dce50 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 5951acdcc40..300ec7f3c62 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,8 +1,7 @@
/* Copyright (C) 2000-2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -93,7 +92,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags);
Pointer to the TABLE_LIST struct.
*/
-static char *mysql_ha_hash_get_key(TABLE_LIST *tables, uint *key_len_p,
+static char *mysql_ha_hash_get_key(TABLE_LIST *tables, size_t *key_len_p,
my_bool first __attribute__((unused)))
{
*key_len_p= strlen(tables->alias) + 1 ; /* include '\0' in comparisons */
@@ -168,7 +167,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
}
else if (! reopen) /* Otherwise we have 'tables' already. */
{
- if (hash_search(&thd->handler_tables_hash, (byte*) tables->alias,
+ if (hash_search(&thd->handler_tables_hash, (uchar*) tables->alias,
strlen(tables->alias) + 1))
{
DBUG_PRINT("info",("duplicate '%s'", tables->alias));
@@ -209,10 +208,10 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
namelen= strlen(tables->table_name) + 1;
aliaslen= strlen(tables->alias) + 1;
if (!(my_multi_malloc(MYF(MY_WME),
- &hash_tables, sizeof(*hash_tables),
- &db, dblen,
- &name, namelen,
- &alias, aliaslen,
+ &hash_tables, (uint) sizeof(*hash_tables),
+ &db, (uint) dblen,
+ &name, (uint) namelen,
+ &alias, (uint) aliaslen,
NullS)))
goto err;
/* structure copy */
@@ -225,7 +224,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
memcpy(hash_tables->alias, tables->alias, aliaslen);
/* add to hash */
- if (my_hash_insert(&thd->handler_tables_hash, (byte*) hash_tables))
+ if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
{
my_free((char*) hash_tables, MYF(0));
mysql_ha_close(thd, tables);
@@ -271,7 +270,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
tables->db, tables->table_name, tables->alias));
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (byte*) tables->alias,
+ (uchar*) tables->alias,
strlen(tables->alias) + 1)))
{
/*
@@ -296,7 +295,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
}
VOID(pthread_mutex_unlock(&LOCK_open));
}
- hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
+ hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
}
else
{
@@ -346,7 +345,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
String buffer(buff, sizeof(buff), system_charset_info);
int error, keyno= -1;
uint num_rows;
- byte *key;
+ uchar *key;
uint key_len;
bool not_used;
DBUG_ENTER("mysql_ha_read");
@@ -363,7 +362,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
it++;
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (byte*) tables->alias,
+ (uchar*) tables->alias,
strlen(tables->alias) + 1)))
{
table= hash_tables->table;
@@ -516,7 +515,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
List_iterator<Item> it_ke(*key_expr);
Item *item;
- for (key_len=0 ; (item=it_ke++) ; key_part++)
+ key_part_map keypart_map;
+ for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
{
my_bitmap_map *old_map;
// 'item' can be changed by fix_fields() call
@@ -533,15 +533,16 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
(void) item->save_in_field(key_part->field, 1);
dbug_tmp_restore_column_map(table->write_set, old_map);
key_len+=key_part->store_length;
+ keypart_map= (keypart_map << 1) | 1;
}
- if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
+ if (!(key= (uchar*) thd->calloc(ALIGN_SIZE(key_len))))
goto err;
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno, 1);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->index_read(table->record[0],
- key,key_len,ha_rkey_mode);
+ key, keypart_map, ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode];
break;
}
@@ -681,7 +682,7 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags,
while (*table_ptr)
{
if ((mode_flags & MYSQL_HA_FLUSH_ALL) ||
- ((*table_ptr)->s->version != refresh_version))
+ (*table_ptr)->needs_reopen_or_name_lock())
{
/* The first time it is required, lock for close_thread_table(). */
if (! did_lock && ! is_locked)
@@ -731,13 +732,13 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags)
table->alias, mode_flags));
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (byte*) table->alias,
+ (uchar*) table->alias,
strlen(table->alias) + 1)))
{
if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE))
{
/* This is a final close. Remove from hash. */
- hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
+ hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
}
else
{
@@ -782,15 +783,22 @@ void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table)
safe_mutex_assert_owner(&LOCK_open);
for (; table; table= table->next)
{
- TABLE_LIST *hash_tables;
- if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
- (byte*) table->alias,
- strlen(table->alias) + 1)))
+ /*
+ Some elements in open table list, for example placeholders used for
+ name-locking, can have alias set to 0.
+ */
+ if (table->alias)
{
- /* Mark table as ready for reopen. */
- hash_tables->table= NULL;
- /* End open index/table scans. */
- table->file->ha_index_or_rnd_end();
+ TABLE_LIST *hash_tables;
+ if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
+ (uchar*) table->alias,
+ strlen(table->alias) + 1)))
+ {
+ /* Mark table as ready for reopen. */
+ hash_tables->table= NULL;
+ /* End open index/table scans. */
+ table->file->ha_index_or_rnd_end();
+ }
}
}
DBUG_VOID_RETURN;
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 69d21f8b7bb..023bd1fec94 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -273,7 +272,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
List<String> *names,
String *name, String *description, String *example)
{
- char buff[8]; // Max int length
+ uchar buff[8]; // Max int length
int count= 0;
int iindex_topic, iindex_relations;
Field *rtopic_id, *rkey_id;
@@ -296,22 +295,21 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
rkey_id->store((longlong) key_id, TRUE);
rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
- (byte *) buff,
- rkey_id->pack_length(),
+ buff, (key_part_map) 1,
HA_READ_KEY_EXACT);
for ( ;
!key_res && key_id == (int16) rkey_id->val_int() ;
key_res= relations->file->index_next(relations->record[0]))
{
- char topic_id_buff[8];
+ uchar 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, TRUE);
field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW);
- if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
- field->pack_length(), HA_READ_KEY_EXACT))
+ if (!topics->file->index_read(topics->record[0], topic_id_buff,
+ (key_part_map)1, HA_READ_KEY_EXACT))
{
memorize_variant_topic(thd,topics,count,find_fields,
names,name,description,example);
@@ -568,7 +566,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond,
cond->fix_fields(thd, &cond); // can never fail
/* Assume that no indexes cover all required fields */
- table->used_keys.clear_all();
+ table->covering_keys.clear_all();
SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||
@@ -639,7 +637,7 @@ bool mysqld_help(THD *thd, const char *mask)
MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("mysqld_help");
- bzero((gptr)tables,sizeof(tables));
+ bzero((uchar*)tables,sizeof(tables));
tables[0].alias= tables[0].table_name= (char*) "help_topic";
tables[0].lock_type= TL_READ;
tables[0].next_global= tables[0].next_local=
@@ -656,13 +654,16 @@ bool mysqld_help(THD *thd, const char *mask)
tables[3].lock_type= TL_READ;
tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
- if (open_and_lock_tables(thd, tables))
- goto error;
+ Open_tables_state open_tables_state_backup;
+ if (open_system_tables_for_read(thd, tables, &open_tables_state_backup))
+ goto error2;
/*
Init tables and fields to be usable from items
tables do not contain VIEWs => we can pass 0 as conds
*/
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
if (setup_tables(thd, &thd->lex->select_lex.context,
&thd->lex->select_lex.top_join_list,
tables, &leaves, FALSE))
@@ -780,8 +781,13 @@ bool mysqld_help(THD *thd, const char *mask)
}
send_eof(thd);
+ close_system_tables(thd, &open_tables_state_backup);
DBUG_RETURN(FALSE);
+
error:
+ close_system_tables(thd, &open_tables_state_backup);
+
+error2:
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index eca301aa1c6..b0c96530548 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -30,7 +29,7 @@
waited for to open and lock the table.
If accessing the thread succeeded, in
- delayed_insert::get_local_table() the table of the thread is copied
+ Delayed_insert::get_local_table() the table of the thread is copied
for local use. A copy is required because the normal insert logic
works on a target table, but the other threads table object must not
be used. The insert logic uses the record buffer to create a record.
@@ -60,11 +59,12 @@
#include "sql_trigger.h"
#include "sql_select.h"
#include "sql_show.h"
+#include "slave.h"
+#include "rpl_mi.h"
-static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
-static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
-static int write_delayed(THD *thd, TABLE *table, enum_duplicates dup,
+static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
+static int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
LEX_STRING query, bool ignore, bool log_on);
static void end_delayed_insert(THD *thd);
pthread_handler_t handle_delayed_insert(void *arg);
@@ -82,6 +82,65 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
#endif
+/*
+ Check that insert/update fields are from the same single table of a view.
+
+ SYNOPSIS
+ check_view_single_update()
+ fields The insert/update fields to be checked.
+ view The view for insert.
+ map [in/out] The insert table map.
+
+ DESCRIPTION
+ This function is called in 2 cases:
+ 1. to check insert fields. In this case *map will be set to 0.
+ Insert fields are checked to be all from the same single underlying
+ table of the given view. Otherwise the error is thrown. Found table
+ map is returned in the map parameter.
+ 2. to check update fields of the ON DUPLICATE KEY UPDATE clause.
+ In this case *map contains table_map found on the previous call of
+ the function to check insert fields. Update fields are checked to be
+ from the same table as the insert fields.
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
+ table_map *map)
+{
+ /* it is join view => we need to find the table for update */
+ List_iterator_fast<Item> it(fields);
+ Item *item;
+ TABLE_LIST *tbl= 0; // reset for call to check_single_table()
+ table_map tables= 0;
+
+ while ((item= it++))
+ tables|= item->used_tables();
+
+ /* Check found map against provided map */
+ if (*map)
+ {
+ if (tables != *map)
+ goto error;
+ return FALSE;
+ }
+
+ if (view->check_single_table(&tbl, tables, view) || tbl == 0)
+ goto error;
+
+ view->table= tbl->table;
+ *map= tables;
+
+ return FALSE;
+
+error:
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0),
+ view->view_db.str, view->view_name.str);
+ return TRUE;
+}
+
/*
Check if insert fields are correct.
@@ -106,7 +165,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- bool check_unique)
+ bool check_unique, table_map *map)
{
TABLE *table= table_list->table;
@@ -130,15 +189,12 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
return -1;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (grant_option)
- {
- Field_iterator_table fields;
- fields.set_table(table);
- if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
- table->s->db.str, table->s->table_name.str,
- &fields))
- return -1;
- }
+ Field_iterator_table field_it;
+ field_it.set_table(table);
+ if (check_grant_all_columns(thd, INSERT_ACL, &table->grant,
+ table->s->db.str, table->s->table_name.str,
+ &field_it))
+ return -1;
#endif
clear_timestamp_auto_bits(table->timestamp_field_type,
TIMESTAMP_AUTO_SET_ON_INSERT);
@@ -184,21 +240,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
- /* it is join view => we need to find table for update */
- List_iterator_fast<Item> it(fields);
- Item *item;
- TABLE_LIST *tbl= 0; // reset for call to check_single_table()
- table_map map= 0;
-
- while ((item= it++))
- map|= item->used_tables();
- if (table_list->check_single_table(&tbl, map, table_list) || tbl == 0)
- {
- my_error(ER_VIEW_MULTIUPDATE, MYF(0),
- table_list->view_db.str, table_list->view_name.str);
+ if (check_view_single_update(fields, table_list, map))
return -1;
- }
- table_list->table= table= tbl->table;
+ table= table_list->table;
}
if (check_unique && thd->dup_field)
@@ -256,7 +300,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
- List<Item> &update_fields)
+ List<Item> &update_fields, table_map *map)
{
TABLE *table= insert_table_list->table;
my_bool timestamp_mark;
@@ -277,6 +321,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
return -1;
+ if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
+ check_view_single_update(update_fields, insert_table_list, map))
+ return -1;
+
if (table->timestamp_field)
{
/* Don't set timestamp column if this is modified. */
@@ -291,6 +339,204 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
return 0;
}
+/*
+ Prepare triggers for INSERT-like statement.
+
+ SYNOPSIS
+ prepare_triggers_for_insert_stmt()
+ table Table to which insert will happen
+
+ NOTE
+ Prepare triggers for INSERT-like statement by marking fields
+ used by triggers and inform handlers that batching of UPDATE/DELETE
+ cannot be done if there are BEFORE UPDATE/DELETE triggers.
+*/
+
+void prepare_triggers_for_insert_stmt(TABLE *table)
+{
+ if (table->triggers)
+ {
+ if (table->triggers->has_triggers(TRG_EVENT_DELETE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER DELETE triggers that might access to
+ subject table and therefore might need delete to be done
+ immediately. So we turn-off the batching.
+ */
+ (void) table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
+ }
+ if (table->triggers->has_triggers(TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER UPDATE triggers that might access to subject
+ table and therefore might need update to be done immediately.
+ So we turn-off the batching.
+ */
+ (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+ }
+ }
+ table->mark_columns_needed_for_insert();
+}
+
+
+/**
+ Upgrade table-level lock of INSERT statement to TL_WRITE if
+ a more concurrent lock is infeasible for some reason. This is
+ necessary for engines without internal locking support (MyISAM).
+ An engine with internal locking implementation might later
+ downgrade the lock in handler::store_lock() method.
+*/
+
+static
+void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
+ enum_duplicates duplic,
+ bool is_multi_insert)
+{
+ if (duplic == DUP_UPDATE ||
+ duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT)
+ {
+ *lock_type= TL_WRITE;
+ return;
+ }
+
+ if (*lock_type == TL_WRITE_DELAYED)
+ {
+ /*
+ We do not use delayed threads if:
+ - we're running in the safe mode or skip-new mode -- the
+ feature is disabled in these modes
+ - we're executing this statement on a replication slave --
+ we need to ensure serial execution of queries on the
+ slave
+ - it is INSERT .. ON DUPLICATE KEY UPDATE - in this case the
+ insert cannot be concurrent
+ - this statement is directly or indirectly invoked from
+ a stored function or trigger (under pre-locking) - to
+ avoid deadlocks, since INSERT DELAYED involves a lock
+ upgrade (TL_WRITE_DELAYED -> TL_WRITE) which we should not
+ attempt while keeping other table level locks.
+ - this statement itself may require pre-locking.
+ We should upgrade the lock even though in most cases
+ delayed functionality may work. Unfortunately, we can't
+ easily identify whether the subject table is not used in
+ the statement indirectly via a stored function or trigger:
+ if it is used, that will lead to a deadlock between the
+ client connection and the delayed thread.
+ */
+ if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
+ thd->slave_thread ||
+ thd->variables.max_insert_delayed_threads == 0 ||
+ thd->prelocked_mode ||
+ thd->lex->uses_stored_routines())
+ {
+ *lock_type= TL_WRITE;
+ return;
+ }
+ bool log_on= (thd->options & OPTION_BIN_LOG ||
+ ! (thd->security_ctx->master_access & SUPER_ACL));
+ if (global_system_variables.binlog_format == BINLOG_FORMAT_STMT &&
+ log_on && mysql_bin_log.is_open() && is_multi_insert)
+ {
+ /*
+ Statement-based binary logging does not work in this case, because:
+ a) two concurrent statements may have their rows intermixed in the
+ queue, leading to autoincrement replication problems on slave (because
+ the values generated used for one statement don't depend only on the
+ value generated for the first row of this statement, so are not
+ replicable)
+ b) if first row of the statement has an error the full statement is
+ not binlogged, while next rows of the statement may be inserted.
+ c) if first row succeeds, statement is binlogged immediately with a
+ zero error code (i.e. "no error"), if then second row fails, query
+ will fail on slave too and slave will stop (wrongly believing that the
+ master got no error).
+ So we fallback to non-delayed INSERT.
+ Note that to be fully correct, we should test the "binlog format which
+ the delayed thread is going to use for this row". But in the common case
+ where the global binlog format is not changed and the session binlog
+ format may be changed, that is equal to the global binlog format.
+ We test it without mutex for speed reasons (condition rarely true), and
+ in the common case (global not changed) it is as good as without mutex;
+ if global value is changed, anyway there is uncertainty as the delayed
+ thread may be old and use the before-the-change value.
+ */
+ *lock_type= TL_WRITE;
+ }
+ }
+}
+
+
+/**
+ Find or create a delayed insert thread for the first table in
+ the table list, then open and lock the remaining tables.
+ If a table can not be used with insert delayed, upgrade the lock
+ and open and lock all tables using the standard mechanism.
+
+ @param thd thread context
+ @param table_list list of "descriptors" for tables referenced
+ directly in statement SQL text.
+ The first element in the list corresponds to
+ the destination table for inserts, remaining
+ tables, if any, are usually tables referenced
+ by sub-queries in the right part of the
+ INSERT.
+
+ @return Status of the operation. In case of success 'table'
+ member of every table_list element points to an instance of
+ class TABLE.
+
+ @sa open_and_lock_tables for more information about MySQL table
+ level locking
+*/
+
+static
+bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
+{
+ DBUG_ENTER("open_and_lock_for_insert_delayed");
+
+#ifndef EMBEDDED_LIBRARY
+ if (delayed_get_table(thd, table_list))
+ DBUG_RETURN(TRUE);
+
+ if (table_list->table)
+ {
+ /*
+ Open tables used for sub-selects or in stored functions, will also
+ cache these functions.
+ */
+ if (open_and_lock_tables(thd, table_list->next_global))
+ {
+ end_delayed_insert(thd);
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ First table was not processed by open_and_lock_tables(),
+ we need to set updatability flag "by hand".
+ */
+ if (!table_list->derived && !table_list->view)
+ table_list->updatable= 1; // usual table
+ DBUG_RETURN(FALSE);
+ }
+#endif
+ /*
+ * This is embedded library and we don't have auxiliary
+ threads OR
+ * a lock upgrade was requested inside delayed_get_table
+ because
+ - there are too many delayed insert threads OR
+ - the table has triggers.
+ Use a normal insert.
+ */
+ table_list->lock_type= TL_WRITE;
+ DBUG_RETURN(open_and_lock_tables(thd, table_list));
+}
+
+
+/**
+ INSERT statement implementation
+*/
bool mysql_insert(THD *thd,TABLE_LIST *table_list,
List<Item> &fields,
@@ -301,13 +547,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
bool ignore)
{
int error, res;
- /*
- log_on is about delayed inserts only.
- By default, both logs are enabled (this won't cause problems if the server
- runs without --log-update or --log-bin).
- */
- bool log_on= ((thd->options & OPTION_BIN_LOG) ||
- (!(thd->security_ctx->master_access & SUPER_ACL)));
bool transactional_table, joins_freed= FALSE;
bool changed;
uint value_count;
@@ -321,80 +560,67 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
Name_resolution_context_state ctx_state;
#ifndef EMBEDDED_LIBRARY
char *query= thd->query;
+ /*
+ log_on is about delayed inserts only.
+ By default, both logs are enabled (this won't cause problems if the server
+ runs without --log-update or --log-bin).
+ */
+ bool log_on= ((thd->options & OPTION_BIN_LOG) ||
+ (!(thd->security_ctx->master_access & SUPER_ACL)));
#endif
thr_lock_type lock_type = table_list->lock_type;
Item *unused_conds= 0;
DBUG_ENTER("mysql_insert");
/*
- in safe mode or with skip-new change delayed insert to be regular
- if we are told to replace duplicates, the insert cannot be concurrent
- delayed insert changed to regular in slave thread
- */
-#ifdef EMBEDDED_LIBRARY
- if (lock_type == TL_WRITE_DELAYED)
- lock_type=TL_WRITE;
-#else
- if ((lock_type == TL_WRITE_DELAYED &&
- ((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
- thd->slave_thread || !thd->variables.max_insert_delayed_threads)) ||
- (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
- (duplic == DUP_UPDATE))
- lock_type=TL_WRITE;
-#endif
- table_list->lock_type= lock_type;
+ Upgrade lock type if the requested lock is incompatible with
+ the current connection mode or table operation.
+ */
+ upgrade_lock_type(thd, &table_list->lock_type, duplic,
+ values_list.elements > 1);
-#ifndef EMBEDDED_LIBRARY
- if (lock_type == TL_WRITE_DELAYED)
+ /*
+ We can't write-delayed into a table locked with LOCK TABLES:
+ this will lead to a deadlock, since the delayed thread will
+ never be able to get a lock on the table. QQQ: why not
+ upgrade the lock here instead?
+ */
+ if (table_list->lock_type == TL_WRITE_DELAYED && thd->locked_tables &&
+ find_locked_table(thd, table_list->db, table_list->table_name))
{
- if (thd->locked_tables)
- {
- DBUG_ASSERT(table_list->db); /* Must be set in the parser */
- if (find_locked_table(thd, table_list->db, table_list->table_name))
- {
- my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
- table_list->table_name);
- DBUG_RETURN(TRUE);
- }
- }
- if ((table= delayed_get_table(thd,table_list)) && !thd->is_fatal_error)
- {
- /*
- Open tables used for sub-selects or in stored functions, will also
- cache these functions.
- */
- res= open_and_lock_tables(thd, table_list->next_global);
- /*
- First is not processed by open_and_lock_tables() => we need set
- updateability flags "by hands".
- */
- if (!table_list->derived && !table_list->view)
- table_list->updatable= 1; // usual table
- }
- else
- {
- /* Too many delayed insert threads; Use a normal insert */
- table_list->lock_type= lock_type= TL_WRITE;
- res= open_and_lock_tables(thd, table_list);
- }
+ my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
+ table_list->table_name);
+ DBUG_RETURN(TRUE);
+ }
+
+ if (table_list->lock_type == TL_WRITE_DELAYED)
+ {
+ if (open_and_lock_for_insert_delayed(thd, table_list))
+ DBUG_RETURN(TRUE);
}
else
-#endif /* EMBEDDED_LIBRARY */
- res= open_and_lock_tables(thd, table_list);
- if (res || thd->is_fatal_error)
- DBUG_RETURN(TRUE);
+ {
+ if (open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(TRUE);
+ }
thd->proc_info="init";
thd->used_tables=0;
values= its++;
+ value_count= values->elements;
if (mysql_prepare_insert(thd, table_list, table, fields, values,
update_fields, update_values, duplic, &unused_conds,
- FALSE))
+ FALSE,
+ (fields.elements || !value_count),
+ !ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES))))
goto abort;
/* mysql_prepare_insert set table_list->table if it was not set */
table= table_list->table;
+ lock_type= table_list->lock_type;
context= &thd->lex->select_lex.context;
/*
@@ -416,7 +642,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- value_count= values->elements;
while ((values= its++))
{
counter++;
@@ -455,6 +680,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->cuted_fields = 0L;
table->next_number_field=table->found_next_number_field;
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ goto abort;
+#endif
+
error=0;
thd->proc_info="update";
if (duplic != DUP_ERROR || ignore)
@@ -477,20 +710,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
table->file->ha_start_bulk_insert(values_list.elements);
- thd->no_trans_update= 0;
- thd->abort_on_warning= (!ignore &&
- (thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES |
- MODE_STRICT_ALL_TABLES)));
+ thd->no_trans_update.stmt= FALSE;
+ thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
- if ((fields.elements || !value_count) &&
- check_that_all_fields_are_given_values(thd, table, table_list))
- {
- /* thd->net.report_error is now set, which will abort the next loop */
- error= 1;
- }
+ prepare_triggers_for_insert_stmt(table);
- table->mark_columns_needed_for_insert();
if (table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd))
@@ -617,22 +843,48 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (mysql_bin_log.is_open())
{
if (error <= 0)
+ {
+ /*
+ [Guilhem wrote] Temporary errors may have filled
+ thd->net.last_error/errno. For example if there has
+ been a disk full error when writing the row, and it was
+ MyISAM, then thd->net.last_error/errno will be set to
+ "disk full"... and the my_pwrite() will wait until free
+ space appears, and so when it finishes then the
+ write_row() was entirely successful
+ */
+ /* todo: consider removing */
thd->clear_error();
+ }
+ /* bug#22725:
+
+ A query which per-row-loop can not be interrupted with
+ KILLED, like INSERT, and that does not invoke stored
+ routines can be binlogged with neglecting the KILLED error.
+
+ If there was no error (error == zero) until after the end of
+ inserting loop the KILLED flag that appeared later can be
+ disregarded since previously possible invocation of stored
+ routines did not result in any error due to the KILLED. In
+ such case the flag is ignored for constructing binlog event.
+ */
+ DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_table, FALSE) &&
+ transactional_table, FALSE,
+ (error>0) ? thd->killed : THD::NOT_KILLED) &&
transactional_table)
{
error=1;
}
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
}
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
-
+
if (thd->lock)
{
mysql_unlock_tables(thd, thd->lock);
@@ -668,6 +920,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table->next_number_field->val_int() : 0));
table->next_number_field=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+ table->auto_increment_field_not_null= FALSE;
if (duplic != DUP_ERROR || ignore)
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (duplic == DUP_REPLACE &&
@@ -741,7 +994,6 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
Field_translator *trans_start= view->field_translation,
*trans_end= trans_start + num;
Field_translator *trans;
- Field **field_ptr= table->field;
uint used_fields_buff_size= bitmap_buffer_size(table->s->fields);
uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size);
MY_BITMAP used_fields;
@@ -866,6 +1118,10 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
+ check_fields TRUE if need to check that all INSERT fields are
+ given values.
+ abort_on_warning whether to report if some INSERT field is not
+ assigned as an error (TRUE) or as a warning (FALSE).
TODO (in far future)
In cases of:
@@ -886,17 +1142,21 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
TABLE *table, List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic,
- COND **where, bool select_insert)
+ COND **where, bool select_insert,
+ bool check_fields, bool abort_on_warning)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
Name_resolution_context *context= &select_lex->context;
Name_resolution_context_state ctx_state;
bool insert_into_view= (table_list->view != 0);
bool res= 0;
+ table_map map= 0;
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
+ /* INSERT should have a SELECT or VALUES clause */
+ DBUG_ASSERT (!select_insert || !values);
/*
For subqueries in VALUES() we should not see the table in which we are
@@ -928,44 +1188,52 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert))
DBUG_RETURN(TRUE);
- /* Save the state of the current name resolution context. */
- ctx_state.save_state(context, table_list);
-
- /*
- Perform name resolution only in the first table - 'table_list',
- which is the table that is inserted into.
- */
- table_list->next_local= 0;
- context->resolve_in_table_list_only(table_list);
/* Prepare the fields in the statement. */
- if (values &&
- !(res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view) ||
- setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) &&
- duplic == DUP_UPDATE)
+ if (values)
{
- select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields);
- select_lex->no_wrap_view_item= FALSE;
+ /* if we have INSERT ... VALUES () we cannot have a GROUP BY clause */
+ DBUG_ASSERT (!select_lex->group_list.elements);
+
+ /* Save the state of the current name resolution context. */
+ ctx_state.save_state(context, table_list);
+
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part.
- */
- if (select_lex->group_list.elements == 0)
+ Perform name resolution only in the first table - 'table_list',
+ which is the table that is inserted into.
+ */
+ table_list->next_local= 0;
+ context->resolve_in_table_list_only(table_list);
+
+ res= check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view, &map) ||
+ setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+
+ if (!res && check_fields)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ bool saved_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= abort_on_warning;
+ res= check_that_all_fields_are_given_values(thd,
+ table ? table :
+ context->table_list->table,
+ context->table_list);
+ thd->abort_on_warning= saved_abort_on_warning;
}
+
+ if (!res && duplic == DUP_UPDATE)
+ {
+ select_lex->no_wrap_view_item= TRUE;
+ res= check_update_fields(thd, context->table_list, update_fields, &map);
+ select_lex->no_wrap_view_item= FALSE;
+ }
+
+ /* Restore the current context. */
+ ctx_state.restore_state(context, table_list);
+
if (!res)
res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
- /* Restore the current context. */
- ctx_state.restore_state(context, table_list);
-
if (res)
DBUG_RETURN(res);
@@ -976,7 +1244,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
Item *fake_conds= 0;
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 1)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE);
@@ -1019,7 +1287,7 @@ static int last_uniq_key(TABLE *table,uint keynr)
then both on update triggers will work instead. Similarly both on
delete triggers will be invoked if we will delete conflicting records.
- Sets thd->no_trans_update if table which is updated didn't have
+ Sets thd->no_trans_update.stmt to TRUE if table which is updated didn't have
transactions.
RETURN VALUE
@@ -1112,11 +1380,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err;
}
}
- key_copy((byte*) key,table->record[0],table->key_info+key_nr,0);
+ key_copy((uchar*) key,table->record[0],table->key_info+key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr,
- (byte*) key,
- table->key_info[key_nr].
- key_length,
+ (uchar*) key, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))))
goto err;
}
@@ -1134,7 +1400,8 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
DBUG_ASSERT(info->update_fields->elements ==
info->update_values->elements);
if (fill_record_n_invoke_before_triggers(thd, *info->update_fields,
- *info->update_values, 0,
+ *info->update_values,
+ info->ignore,
table->triggers,
TRG_EVENT_UPDATE))
goto before_trg_err;
@@ -1147,32 +1414,38 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
+ table->file->restore_auto_increment(prev_insert_id);
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
{
- table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
goto err;
- }
- info->updated++;
- /*
- If ON DUP KEY UPDATE updates a row instead of inserting one, it's
- like a regular UPDATE statement: it should not affect the value of a
- next SELECT LAST_INSERT_ID() or mysql_insert_id().
- Except if LAST_INSERT_ID(#) was in the INSERT query, which is
- handled separately by THD::arg_of_last_insert_id_function.
- */
- insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
- if (table->next_number_field)
- table->file->adjust_next_insert_id_after_explicit_value(table->next_number_field->val_int());
- trg_error= (table->triggers &&
- table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
- TRG_ACTION_AFTER, TRUE));
- info->copied++;
+ }
+ if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) ||
+ compare_record(table))
+ {
+ info->updated++;
+ /*
+ If ON DUP KEY UPDATE updates a row instead of inserting one, it's
+ like a regular UPDATE statement: it should not affect the value of a
+ next SELECT LAST_INSERT_ID() or mysql_insert_id().
+ Except if LAST_INSERT_ID(#) was in the INSERT query, which is
+ handled separately by THD::arg_of_last_insert_id_function.
+ */
+ insert_id_for_cur_row= table->file->insert_id_for_cur_row= 0;
+ if (table->next_number_field)
+ table->file->adjust_next_insert_id_after_explicit_value(
+ table->next_number_field->val_int());
+ trg_error= (table->triggers &&
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER, TRUE));
+ info->copied++;
+ }
+
goto ok_or_after_trg_err;
}
else /* DUP_REPLACE */
@@ -1218,7 +1491,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err;
info->deleted++;
if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ thd->no_trans_update.stmt= TRUE;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, TRUE))
@@ -1259,7 +1532,7 @@ ok_or_after_trg_err:
if (key)
my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ thd->no_trans_update.stmt= TRUE;
DBUG_RETURN(trg_error);
err:
@@ -1292,7 +1565,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
{
if (!bitmap_is_set(write_set, (*field)->field_index) &&
((*field)->flags & NO_DEFAULT_VALUE_FLAG) &&
- ((*field)->real_type() != FIELD_TYPE_ENUM))
+ ((*field)->real_type() != MYSQL_TYPE_ENUM))
{
bool view= FALSE;
if (table_list)
@@ -1354,8 +1627,14 @@ public:
}
};
+/**
+ Delayed_insert - context of a thread responsible for delayed insert
+ into one table. When processing delayed inserts, we create an own
+ thread for every distinct table. Later on all delayed inserts directed
+ into that table are handled by a dedicated thread.
+*/
-class delayed_insert :public ilink {
+class Delayed_insert :public ilink {
uint locks_in_memory;
public:
THD thd;
@@ -1369,7 +1648,7 @@ public:
ulong group_count;
TABLE_LIST table_list; // Argument
- delayed_insert()
+ Delayed_insert()
:locks_in_memory(0),
table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
group_count(0)
@@ -1385,6 +1664,7 @@ public:
Statement-based replication of INSERT DELAYED has problems with RAND()
and user vars, so in mixed mode we go to row-based.
*/
+ thd.lex->set_stmt_unsafe();
thd.set_current_stmt_binlog_row_based_if_mixed();
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
@@ -1399,7 +1679,7 @@ public:
delayed_insert_threads++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
}
- ~delayed_insert()
+ ~Delayed_insert()
{
/* The following is not really needed, but just for safety */
delayed_row *row;
@@ -1447,15 +1727,21 @@ public:
};
-I_List<delayed_insert> delayed_threads;
+I_List<Delayed_insert> delayed_threads;
-delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
+/**
+ Return an instance of delayed insert thread that can handle
+ inserts into a given table, if it exists. Otherwise return NULL.
+*/
+
+static
+Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
{
thd->proc_info="waiting for delay_list";
pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list
- I_List_iterator<delayed_insert> it(delayed_threads);
- delayed_insert *tmp;
+ I_List_iterator<Delayed_insert> it(delayed_threads);
+ Delayed_insert *tmp;
while ((tmp=it++))
{
if (!strcmp(tmp->thd.db, table_list->db) &&
@@ -1470,11 +1756,36 @@ delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
}
-static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
+/**
+ Attempt to find or create a delayed insert thread to handle inserts
+ into this table.
+
+ @return In case of success, table_list->table points to a local copy
+ of the delayed table or is set to NULL, which indicates a
+ request for lock upgrade. In case of failure, value of
+ table_list->table is undefined.
+ @retval TRUE - this thread ran out of resources OR
+ - a newly created delayed insert thread ran out of
+ resources OR
+ - the created thread failed to open and lock the table
+ (e.g. because it does not exist) OR
+ - the table opened in the created thread turned out to
+ be a view
+ @retval FALSE - table successfully opened OR
+ - too many delayed insert threads OR
+ - the table has triggers and we have to fall back to
+ a normal INSERT
+ Two latter cases indicate a request for lock upgrade.
+
+ XXX: why do we regard INSERT DELAYED into a view as an error and
+ do not simply a lock upgrade?
+*/
+
+static
+bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
{
int error;
- delayed_insert *tmp;
- TABLE *table;
+ Delayed_insert *tmp;
DBUG_ENTER("delayed_get_table");
/* Must be set in the parser */
@@ -1497,10 +1808,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
*/
if (! (tmp= find_handler(thd, table_list)))
{
- if (!(tmp=new delayed_insert()))
+ if (!(tmp=new Delayed_insert()))
{
- my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert));
- goto err1;
+ my_error(ER_OUTOFMEMORY,MYF(0),sizeof(Delayed_insert));
+ thd->fatal_error();
+ goto end_create;
}
pthread_mutex_lock(&LOCK_thread_count);
thread_count++;
@@ -1509,9 +1821,10 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
tmp->thd.query= my_strdup(table_list->table_name,MYF(MY_WME));
if (tmp->thd.db == NULL || tmp->thd.query == NULL)
{
+ /* The error is reported */
delete tmp;
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- goto err1;
+ thd->fatal_error();
+ goto end_create;
}
tmp->table_list= *table_list; // Needed to open table
tmp->table_list.alias= tmp->table_list.table_name= tmp->thd.query;
@@ -1527,7 +1840,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
tmp->unlock();
delete tmp;
my_error(ER_CANT_CREATE_THREAD, MYF(0), error);
- goto err1;
+ thd->fatal_error();
+ goto end_create;
}
/* Wait until table is open */
@@ -1540,59 +1854,71 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
thd->proc_info="got old table";
if (tmp->thd.killed)
{
- if (tmp->thd.is_fatal_error)
- {
- /* Copy error message and abort */
- thd->fatal_error();
- strmov(thd->net.last_error,tmp->thd.net.last_error);
- thd->net.last_errno=tmp->thd.net.last_errno;
+ if (tmp->thd.net.report_error)
+ {
+ /*
+ Copy the error message. Note that we don't treat fatal
+ errors in the delayed thread as fatal errors in the
+ main thread. Use of my_message will enable stored
+ procedures continue handlers.
+ */
+ my_message(tmp->thd.net.last_errno, tmp->thd.net.last_error,
+ MYF(0));
}
tmp->unlock();
- goto err;
+ goto end_create;
}
if (thd->killed)
{
tmp->unlock();
- goto err;
+ goto end_create;
}
}
pthread_mutex_unlock(&LOCK_delayed_create);
}
pthread_mutex_lock(&tmp->mutex);
- table= tmp->get_local_table(thd);
+ table_list->table= tmp->get_local_table(thd);
pthread_mutex_unlock(&tmp->mutex);
- if (table)
+ if (table_list->table)
+ {
+ DBUG_ASSERT(thd->net.report_error == 0);
thd->di=tmp;
- else if (tmp->thd.is_fatal_error)
- thd->fatal_error();
+ }
/* Unlock the delayed insert object after its last access. */
tmp->unlock();
- DBUG_RETURN((table_list->table=table));
+ DBUG_RETURN((table_list->table == NULL));
- err1:
- thd->fatal_error();
- err:
+end_create:
pthread_mutex_unlock(&LOCK_delayed_create);
- DBUG_RETURN(0); // Continue with normal insert
+ DBUG_RETURN(thd->net.report_error);
}
-/*
- As we can't let many threads modify the same TABLE structure, we create
- an own structure for each tread. This includes a row buffer to save the
- column values and new fields that points to the new row buffer.
- The memory is allocated in the client thread and is freed automaticly.
+/**
+ As we can't let many client threads modify the same TABLE
+ structure of the dedicated delayed insert thread, we create an
+ own structure for each client thread. This includes a row
+ buffer to save the column values and new fields that point to
+ the new row buffer. The memory is allocated in the client
+ thread and is freed automatically.
+
+ @pre This function is called from the client thread. Delayed
+ insert thread mutex must be acquired before invoking this
+ function.
+
+ @return Not-NULL table object on success. NULL in case of an error,
+ which is set in client_thd.
*/
-TABLE *delayed_insert::get_local_table(THD* client_thd)
+TABLE *Delayed_insert::get_local_table(THD* client_thd)
{
my_ptrdiff_t adjust_ptrs;
Field **field,**org_field, *found_next_number_field;
TABLE *copy;
TABLE_SHARE *share= table->s;
- byte *bitmap;
- DBUG_ENTER("delayed_insert::get_local_table");
+ uchar *bitmap;
+ DBUG_ENTER("Delayed_insert::get_local_table");
/* First request insert thread to get a lock */
status=1;
@@ -1610,8 +1936,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
goto error;
if (dead)
{
- strmov(client_thd->net.last_error,thd.net.last_error);
- client_thd->net.last_errno=thd.net.last_errno;
+ my_message(thd.net.last_errno, thd.net.last_error, MYF(0));
goto error;
}
}
@@ -1636,7 +1961,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
/* We don't need to change the file handler here */
/* Assign the pointers for the field pointers array and the record. */
field= copy->field= (Field**) (copy + 1);
- bitmap= (byte*) (field + share->fields + 1);
+ bitmap= (uchar*) (field + share->fields + 1);
copy->record[0]= (bitmap + share->column_bitmap_size * 2);
memcpy((char*) copy->record[0], (char*) table->record[0], share->reclength);
/*
@@ -1651,7 +1976,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
for (org_field= table->field; *org_field; org_field++, field++)
{
if (!(*field= (*org_field)->new_field(client_thd->mem_root, copy, 1)))
- DBUG_RETURN(0);
+ goto error;
(*field)->orig_table= copy; // Remove connection
(*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0]
if (*org_field == found_next_number_field)
@@ -1697,15 +2022,16 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
/* Put a question in queue */
-static int
-write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
- LEX_STRING query, bool ignore, bool log_on)
+static
+int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
+ LEX_STRING query, bool ignore, bool log_on)
{
delayed_row *row= 0;
- delayed_insert *di=thd->di;
+ Delayed_insert *di=thd->di;
const Discrete_interval *forced_auto_inc;
DBUG_ENTER("write_delayed");
- DBUG_PRINT("enter", ("query = '%s' length %u", query.str, query.length));
+ DBUG_PRINT("enter", ("query = '%s' length %lu", query.str,
+ (ulong) query.length));
thd->proc_info="waiting for handler insert";
pthread_mutex_lock(&di->mutex);
@@ -1781,11 +2107,15 @@ write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
DBUG_RETURN(1);
}
+/**
+ Signal the delayed insert thread that this user connection
+ is finished using it for this statement.
+*/
static void end_delayed_insert(THD *thd)
{
DBUG_ENTER("end_delayed_insert");
- delayed_insert *di=thd->di;
+ Delayed_insert *di=thd->di;
pthread_mutex_lock(&di->mutex);
DBUG_PRINT("info",("tables in use: %d",di->tables_in_use));
if (!--di->tables_in_use || di->thd.killed)
@@ -1804,12 +2134,10 @@ void kill_delayed_threads(void)
{
VOID(pthread_mutex_lock(&LOCK_delayed_insert)); // For unlink from list
- I_List_iterator<delayed_insert> it(delayed_threads);
- delayed_insert *tmp;
+ I_List_iterator<Delayed_insert> it(delayed_threads);
+ Delayed_insert *tmp;
while ((tmp=it++))
{
- /* Ensure that the thread doesn't kill itself while we are looking at it */
- pthread_mutex_lock(&tmp->mutex);
tmp->thd.killed= THD::KILL_CONNECTION;
if (tmp->thd.mysys_var)
{
@@ -1828,7 +2156,6 @@ void kill_delayed_threads(void)
}
pthread_mutex_unlock(&tmp->thd.mysys_var->mutex);
}
- pthread_mutex_unlock(&tmp->mutex);
}
VOID(pthread_mutex_unlock(&LOCK_delayed_insert)); // For unlink from list
}
@@ -1840,13 +2167,13 @@ void kill_delayed_threads(void)
pthread_handler_t handle_delayed_insert(void *arg)
{
- delayed_insert *di=(delayed_insert*) arg;
+ Delayed_insert *di=(Delayed_insert*) arg;
THD *thd= &di->thd;
pthread_detach_this_thread();
/* Add thread to THD list so that's it's visible in 'show processlist' */
pthread_mutex_lock(&LOCK_thread_count);
- thd->thread_id=thread_id++;
+ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thd->end_time();
threads.append(thd);
thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
@@ -1877,14 +2204,8 @@ pthread_handler_t handle_delayed_insert(void *arg)
strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
goto err;
}
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
/* open table */
-
if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED)))
{
thd->fatal_error(); // Abort waiting inserts
@@ -1896,6 +2217,15 @@ pthread_handler_t handle_delayed_insert(void *arg)
my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.table_name);
goto err;
}
+ if (di->table->triggers)
+ {
+ /*
+ Table has triggers. This is not an error, but we do
+ not support triggers with delayed insert. Terminate the delayed
+ thread without an error and thus request lock upgrade.
+ */
+ goto err;
+ }
di->table->copy_blobs=1;
/* One can now use this */
@@ -2088,7 +2418,7 @@ static void free_delayed_insert_blobs(register TABLE *table)
{
if ((*ptr)->flags & BLOB_FLAG)
{
- char *str;
+ uchar *str;
((Field_blob *) (*ptr))->get_ptr(&str);
my_free(str,MYF(MY_ALLOW_ZERO_PTR));
((Field_blob *) (*ptr))->reset();
@@ -2097,7 +2427,7 @@ static void free_delayed_insert_blobs(register TABLE *table)
}
-bool delayed_insert::handle_inserts(void)
+bool Delayed_insert::handle_inserts(void)
{
int error;
ulong max_rows;
@@ -2122,7 +2452,7 @@ bool delayed_insert::handle_inserts(void)
thd.proc_info="insert";
max_rows= delayed_insert_limit;
- if (thd.killed || table->s->version != refresh_version)
+ if (thd.killed || table->needs_reopen_or_name_lock())
{
thd.killed= THD::KILL_CONNECTION;
max_rows= ULONG_MAX; // Do as much as possible
@@ -2150,8 +2480,9 @@ bool delayed_insert::handle_inserts(void)
use values from the previous interval (of the previous rows).
*/
bool log_query= (row->log_query && row->query.str != NULL);
- DBUG_PRINT("delayed", ("query: '%s' length: %u", row->query.str ?
- row->query.str : "[NULL]", row->query.length));
+ DBUG_PRINT("delayed", ("query: '%s' length: %lu", row->query.str ?
+ row->query.str : "[NULL]",
+ (ulong) row->query.length));
if (log_query)
{
/*
@@ -2233,7 +2564,7 @@ bool delayed_insert::handle_inserts(void)
if (table->s->blob_fields)
free_delayed_insert_blobs(table);
- thread_safe_sub(delayed_rows_in_use,1,&LOCK_delayed_status);
+ thread_safe_decrement(delayed_rows_in_use,&LOCK_delayed_status);
thread_safe_increment(delayed_insert_writes,&LOCK_delayed_status);
pthread_mutex_lock(&mutex);
@@ -2361,7 +2692,7 @@ bool mysql_insert_select_prepare(THD *thd)
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates,
- &select_lex->where, TRUE))
+ &select_lex->where, TRUE, FALSE, FALSE))
DBUG_RETURN(TRUE);
/*
@@ -2408,6 +2739,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
LEX *lex= thd->lex;
int res;
+ table_map map= 0;
SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
@@ -2420,12 +2752,22 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
res= check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view) ||
+ !insert_into_view, &map) ||
setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
- if (info.handle_duplicates == DUP_UPDATE)
+ if (!res && fields->elements)
+ {
+ bool saved_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= !info.ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES));
+ res= check_that_all_fields_are_given_values(thd, table_list->table,
+ table_list);
+ thd->abort_on_warning= saved_abort_on_warning;
+ }
+
+ if (info.handle_duplicates == DUP_UPDATE && !res)
{
- /* Save the state of the current name resolution context. */
Name_resolution_context *context= &lex->select_lex.context;
Name_resolution_context_state ctx_state;
@@ -2438,21 +2780,43 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->select_lex.no_wrap_view_item= TRUE;
res= res || check_update_fields(thd, context->table_list,
- *info.update_fields);
+ *info.update_fields, &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
- When we are not using GROUP BY we can refer to other tables in the
- ON DUPLICATE KEY part
- */
- if (lex->select_lex.group_list.elements == 0)
+ When we are not using GROUP BY and there are no ungrouped aggregate functions
+ we can refer to other tables in the ON DUPLICATE KEY part.
+ We use next_name_resolution_table descructively, so check it first (views?)
+ */
+ DBUG_ASSERT (!table_list->next_name_resolution_table);
+ if (lex->select_lex.group_list.elements == 0 &&
+ !lex->select_lex.with_sum_func)
+ /*
+ We must make a single context out of the two separate name resolution contexts :
+ the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
+ To do that we must concatenate the two lists
+ */
+ table_list->next_name_resolution_table=
+ ctx_state.get_first_name_resolution_table();
+
+ res= res || setup_fields(thd, 0, *info.update_values,
+ MARK_COLUMNS_READ, 0, 0);
+ if (!res)
{
- context->table_list->next_local= ctx_state.save_next_local;
- /* first_name_resolution_table was set by resolve_in_table_list_only() */
- context->first_name_resolution_table->
- next_name_resolution_table= ctx_state.save_next_local;
+ /*
+ Traverse the update values list and substitute fields from the
+ select for references (Item_ref objects) to them. This is done in
+ order to get correct values from those fields when the select
+ employs a temporary table.
+ */
+ List_iterator<Item> li(*info.update_values);
+ Item *item;
+
+ while ((item= li++))
+ {
+ item->transform(&Item::update_value_transformer,
+ (uchar*)lex->current_select);
+ }
}
- res= res || setup_fields(thd, 0, *info.update_values, MARK_COLUMNS_READ,
- 0, 0);
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -2472,7 +2836,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
query
*/
if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
- unique_table(thd, table_list, table_list->next_global))
+ unique_table(thd, table_list, table_list->next_global, 0))
{
/* Using same table for INSERT and SELECT */
lex->current_select->options|= OPTION_BUFFER_RESULT;
@@ -2493,24 +2857,31 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
+
+#ifdef HAVE_REPLICATION
+ if (thd->slave_thread &&
+ (info.handle_duplicates == DUP_UPDATE) &&
+ (table->next_number_field != NULL) &&
+ rpl_master_has_bug(&active_mi->rli, 24432))
+ DBUG_RETURN(1);
+#endif
+
thd->cuted_fields=0;
if (info.ignore || info.handle_duplicates != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (info.handle_duplicates == DUP_REPLACE &&
(!table->triggers || !table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- res= ((fields->elements &&
- check_that_all_fields_are_given_values(thd, table, table_list)) ||
- table_list->prepare_where(thd, 0, TRUE) ||
+ res= (table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd));
if (!res)
- table->mark_columns_needed_for_insert();
+ prepare_triggers_for_insert_stmt(table);
DBUG_RETURN(res);
}
@@ -2554,6 +2925,7 @@ select_insert::~select_insert()
if (table)
{
table->next_number_field=0;
+ table->auto_increment_field_not_null= FALSE;
table->file->ha_reset();
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -2646,8 +3018,7 @@ void select_insert::send_error(uint errcode,const char *err)
If the creation of the table failed (due to a syntax error, for
example), no table will have been opened and therefore 'table'
will be NULL. In that case, we still need to execute the rollback
- and the end of the function to truncate the binary log, but we can
- skip all the intermediate steps.
+ and the end of the function.
*/
if (table)
{
@@ -2678,13 +3049,11 @@ void select_insert::send_error(uint errcode,const char *err)
if (!table->file->has_transactions())
{
if (mysql_bin_log.is_open())
- {
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
table->file->has_transactions(), FALSE);
- }
if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
!can_rollback_data())
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
query_cache_invalidate3(thd, table, 1);
}
}
@@ -2725,7 +3094,7 @@ bool select_insert::send_eof()
*/
if (!trans_table &&
(!table->s->tmp_table || !thd->current_stmt_binlog_row_based))
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
/*
@@ -2785,8 +3154,8 @@ bool select_insert::send_eof()
***************************************************************************/
/*
- Create table from lists of fields and items (or open existing table
- with same name).
+ Create table from lists of fields and items (or just return TABLE
+ object for pre-opened existing table).
SYNOPSIS
create_table_from_items()
@@ -2795,25 +3164,31 @@ bool select_insert::send_eof()
temporary table flag)
create_table in Pointer to TABLE_LIST object providing database
and name for table to be created or to be open
- extra_fields in/out Initial list of fields for table to be created
- keys in List of keys for table to be created
+ alter_info in/out Initial list of columns and indexes for the table
+ to be created
items in List of items which should be used to produce rest
of fields for the table (corresponding fields will
- be added to the end of 'extra_fields' list)
+ be added to the end of alter_info->create_list)
lock out Pointer to the MYSQL_LOCK object for table created
- (open) will be returned in this parameter. Since
- this table is not included in THD::lock caller is
- responsible for explicitly unlocking this table.
+ (or open temporary table) will be returned in this
+ parameter. Since this table is not included in
+ THD::lock caller is responsible for explicitly
+ unlocking this table.
hooks
NOTES
- If 'create_info->options' bitmask has HA_LEX_CREATE_IF_NOT_EXISTS
- flag and table with name provided already exists then this function will
- simply open existing table.
- Also note that create, open and lock sequence in this function is not
- atomic and thus contains gap for deadlock and can cause other troubles.
- Since this function contains some logic specific to CREATE TABLE ... SELECT
- it should be changed before it can be used in other contexts.
+ This function behaves differently for base and temporary tables:
+ - For base table we assume that either table exists and was pre-opened
+ and locked at open_and_lock_tables() stage (and in this case we just
+ emit error or warning and return pre-opened TABLE object) or special
+ placeholder was put in table cache that guarantees that this table
+ won't be created or opened until the placeholder will be removed
+ (so there is an exclusive lock on this table).
+ - We don't pre-open existing temporary table, instead we either open
+ or create and then open table in this function.
+
+ Since this function contains some logic specific to CREATE TABLE ...
+ SELECT it should be changed before it can be used in other contexts.
RETURN VALUES
non-zero Pointer to TABLE object for table created or opened
@@ -2822,8 +3197,7 @@ bool select_insert::send_eof()
static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE_LIST *create_table,
- List<create_field> *extra_fields,
- List<Key> *keys,
+ Alter_info *alter_info,
List<Item> *items,
MYSQL_LOCK **lock,
TABLEOP_HOOKS *hooks)
@@ -2839,6 +3213,25 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
bool not_used;
DBUG_ENTER("create_table_from_items");
+ DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
+
+ if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
+ create_table->table->db_stat)
+ {
+ /* Table already exists and was open at open_and_lock_tables() stage. */
+ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ {
+ create_info->table_existed= 1; // Mark that table existed
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
+ create_table->table_name);
+ DBUG_RETURN(create_table->table);
+ }
+
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
+ DBUG_RETURN(0);
+ }
+
tmp_table.alias= 0;
tmp_table.timestamp_field= 0;
tmp_table.s= &share;
@@ -2868,10 +3261,17 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(0);
if (item->maybe_null)
cr_field->flags &= ~NOT_NULL_FLAG;
- extra_fields->push_back(cr_field);
+ alter_info->create_list.push_back(cr_field);
}
+
+ DBUG_EXECUTE_IF("sleep_create_select_before_create", my_sleep(6000000););
+
/*
- create and lock table
+ Create and lock table.
+
+ Note that we either creating (or opening existing) temporary table or
+ creating base table on which name we have exclusive lock. So code below
+ should not cause deadlocks or races.
We don't log the statement, it will be logged later.
@@ -2881,63 +3281,72 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
don't want to delete from it) 2) it would be written before the CREATE
TABLE, which is a wrong order. So we keep binary logging disabled when we
open_table().
- NOTE: By locking table which we just have created (or for which we just
- have have found that it already exists) separately from other tables used
- by the statement we create potential window for deadlock.
- TODO: create and open should be done atomic !
*/
{
tmp_disable_binlog(thd);
- if (!mysql_create_table(thd, create_table->db, create_table->table_name,
- create_info, *extra_fields, *keys, 0,
- select_field_count, 0))
+ if (!mysql_create_table_no_lock(thd, create_table->db,
+ create_table->table_name,
+ create_info, alter_info, 0,
+ select_field_count))
{
- /*
- If we are here in prelocked mode we either create temporary table
- or prelocked mode is caused by the SELECT part of this statement.
- */
- DBUG_ASSERT(!thd->prelocked_mode ||
- create_info->options & HA_LEX_CREATE_TMP_TABLE ||
- thd->lex->requires_prelocking());
+ if (create_info->table_existed &&
+ !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ /*
+ This means that someone created table underneath server
+ or it was created via different mysqld front-end to the
+ cluster. We don't have much options but throw an error.
+ */
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
+ DBUG_RETURN(0);
+ }
- /*
- NOTE: We don't want to ignore set of locked tables here if we are
- under explicit LOCK TABLES since it will open gap for deadlock
- too wide (and also is not backward compatible).
- */
+ DBUG_EXECUTE_IF("sleep_create_select_before_open", my_sleep(6000000););
- if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
- (MYSQL_LOCK_IGNORE_FLUSH |
- ((thd->prelocked_mode == PRELOCKED) ?
- MYSQL_OPEN_IGNORE_LOCKED_TABLES:0)))))
- quick_rm_table(create_info->db_type, create_table->db,
- table_case_name(create_info, create_table->table_name),
- 0);
+ if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (reopen_name_locked_table(thd, create_table, FALSE))
+ {
+ quick_rm_table(create_info->db_type, create_table->db,
+ table_case_name(create_info, create_table->table_name),
+ 0);
+ }
+ else
+ table= create_table->table;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ else
+ {
+ if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
+ MYSQL_OPEN_TEMPORARY_ONLY)) &&
+ !create_info->table_existed)
+ {
+ /*
+ This shouldn't happen as creation of temporary table should make
+ it preparable for open. But let us do close_temporary_table() here
+ just in case.
+ */
+ close_temporary_table(thd, create_table);
+ }
+ }
}
reenable_binlog(thd);
if (!table) // open failed
DBUG_RETURN(0);
}
- /*
- FIXME: What happens if trigger manages to be created while we are
- obtaining this lock ? May be it is sensible just to disable
- trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH
- save us from that ?
- */
+ DBUG_EXECUTE_IF("sleep_create_select_before_lock", my_sleep(6000000););
+
table->reginfo.lock_type=TL_WRITE;
hooks->prelock(&table, 1); // Call prelock hooks
if (! ((*lock)= mysql_lock_tables(thd, &table, 1,
MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
{
- VOID(pthread_mutex_lock(&LOCK_open));
- hash_delete(&open_cache,(byte*) table);
- VOID(pthread_mutex_unlock(&LOCK_open));
- quick_rm_table(create_info->db_type, create_table->db,
- table_case_name(create_info, create_table->table_name), 0);
+ if (!create_info->table_existed)
+ drop_open_table(thd, table, create_table->db, create_table->table_name);
DBUG_RETURN(0);
}
- table->file->extra(HA_EXTRA_WRITE_CACHE);
DBUG_RETURN(table);
}
@@ -2948,6 +3357,24 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_ENTER("select_create::prepare");
TABLEOP_HOOKS *hook_ptr= NULL;
+ /*
+ For row-based replication, the CREATE-SELECT statement is written
+ in two pieces: the first one contain the CREATE TABLE statement
+ necessary to create the table and the second part contain the rows
+ that should go into the table.
+
+ For non-temporary tables, the start of the CREATE-SELECT
+ implicitly commits the previous transaction, and all events
+ forming the statement will be stored the transaction cache. At end
+ of the statement, the entire statement is committed as a
+ transaction, and all events are written to the binary log.
+
+ On the master, the table is locked for the duration of the
+ statement, but since the CREATE part is replicated as a simple
+ statement, there is no way to lock the table for accesses on the
+ slave. Hence, we have to hold on to the CREATE part of the
+ statement until the statement has finished.
+ */
class MY_HOOKS : public TABLEOP_HOOKS {
public:
MY_HOOKS(select_create *x) : ptr(x) { }
@@ -2957,7 +3384,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
TABLE const *const table = *tables;
if (ptr->get_thd()->current_stmt_binlog_row_based &&
- table->s->tmp_table == NO_TMP_TABLE &&
+ !table->s->tmp_table &&
!ptr->get_create_info()->table_existed)
{
ptr->binlog_show_create_table(tables, count);
@@ -2973,9 +3400,9 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unit= u;
/*
- Start a statement transaction before the create if we are creating
- a non-temporary table and are using row-based replication for the
- statement.
+ Start a statement transaction before the create if we are using
+ row-based replication for the statement. If we are creating a
+ temporary table, we need to start a statement transaction.
*/
if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 &&
thd->current_stmt_binlog_row_based)
@@ -2984,7 +3411,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
if (!(table= create_table_from_items(thd, create_info, create_table,
- extra_fields, keys, &values,
+ alter_info, &values,
&thd->extra_lock, hook_ptr)))
DBUG_RETURN(-1); // abort() deletes table
@@ -3014,7 +3441,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
if (!thd->prelocked_mode)
table->file->ha_start_bulk_insert((ha_rows) 0);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -3022,6 +3449,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(1);
table->mark_columns_needed_for_insert();
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
DBUG_RETURN(0);
}
@@ -3075,13 +3503,35 @@ void select_create::store_values(List<Item> &values)
void select_create::send_error(uint errcode,const char *err)
{
+ DBUG_ENTER("select_create::send_error");
+
+ DBUG_PRINT("info",
+ ("Current statement %s row-based",
+ thd->current_stmt_binlog_row_based ? "is" : "is NOT"));
+ DBUG_PRINT("info",
+ ("Current table (at 0x%lu) %s a temporary (or non-existant) table",
+ (ulong) table,
+ table && !table->s->tmp_table ? "is NOT" : "is"));
+ DBUG_PRINT("info",
+ ("Table %s prior to executing this statement",
+ get_create_info()->table_existed ? "existed" : "did not exist"));
+
/*
- Disable binlog, because we "roll back" partial inserts in ::abort
- by removing the table, even for non-transactional tables.
+ This will execute any rollbacks that are necessary before writing
+ the transcation cache.
+
+ We disable the binary log since nothing should be written to the
+ binary log. This disabling is important, since we potentially do
+ a "roll back" of non-transactional tables by removing the table,
+ and the actual rollback might generate events that should not be
+ written to the binary log.
+
*/
tmp_disable_binlog(thd);
select_insert::send_error(errcode, err);
reenable_binlog(thd);
+
+ DBUG_VOID_RETURN;
}
@@ -3092,61 +3542,61 @@ bool select_create::send_eof()
abort();
else
{
+ /*
+ Do an implicit commit at end of statement for non-temporary
+ tables. This can fail, but we should unlock the table
+ nevertheless.
+ */
+ if (!table->s->tmp_table)
+ ha_commit(thd); // Can fail, but we proceed anyway
+
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- VOID(pthread_mutex_lock(&LOCK_open));
- mysql_unlock_tables(thd, thd->extra_lock);
- if (!table->s->tmp_table)
+ if (thd->extra_lock)
{
- if (close_thread_table(thd, &table))
- broadcast_refresh();
+ mysql_unlock_tables(thd, thd->extra_lock);
+ thd->extra_lock=0;
}
- thd->extra_lock=0;
- table=0;
- VOID(pthread_mutex_unlock(&LOCK_open));
}
return tmp;
}
+
void select_create::abort()
{
- VOID(pthread_mutex_lock(&LOCK_open));
+ DBUG_ENTER("select_create::abort");
+
+ /*
+ We roll back the statement, including truncating the transaction
+ cache of the binary log, if the statement failed.
+
+ We roll back the statement prior to deleting the table and prior
+ to releasing the lock on the table, since there might be potential
+ for failure if the rollback is executed after the drop or after
+ unlocking the table.
+
+ We also roll back the statement regardless of whether the creation
+ of the table succeeded or not, since we need to reset the binary
+ log state.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ ha_rollback_stmt(thd);
+
if (thd->extra_lock)
{
mysql_unlock_tables(thd, thd->extra_lock);
thd->extra_lock=0;
}
+
if (table)
{
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- handlerton *table_type=table->s->db_type;
- if (!table->s->tmp_table)
- {
- ulong version= table->s->version;
- table->s->version= 0;
- hash_delete(&open_cache,(byte*) table);
- if (!create_info->table_existed)
- {
- quick_rm_table(table_type, create_table->db,
- create_table->table_name, 0);
- /*
- We roll back the statement, including truncating the
- transaction cache of the binary log, if the statement
- failed.
- */
- if (thd->current_stmt_binlog_row_based)
- ha_rollback_stmt(thd);
- }
- /* Tell threads waiting for refresh that something has happened */
- if (version != refresh_version)
- broadcast_refresh();
- }
- else if (!create_info->table_existed)
- close_temporary_table(thd, table, 1, 1);
+ if (!create_info->table_existed)
+ drop_open_table(thd, table, create_table->db, create_table->table_name);
table=0; // Safety
}
- VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_VOID_RETURN;
}
@@ -3157,8 +3607,8 @@ void select_create::abort()
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
template class List_iterator_fast<List_item>;
#ifndef EMBEDDED_LIBRARY
-template class I_List<delayed_insert>;
-template class I_List_iterator<delayed_insert>;
+template class I_List<Delayed_insert>;
+template class I_List_iterator<Delayed_insert>;
template class I_List<delayed_row>;
#endif /* EMBEDDED_LIBRARY */
#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 33b32ad76b9..e9a6d8b4d3b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -34,13 +33,13 @@ sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
/* Macros to look like lex */
-#define yyGet() *(lex->ptr++)
-#define yyGetLast() lex->ptr[-1]
-#define yyPeek() lex->ptr[0]
-#define yyPeek2() lex->ptr[1]
-#define yyUnget() lex->ptr--
-#define yySkip() lex->ptr++
-#define yyLength() ((uint) (lex->ptr - lex->tok_start)-1)
+#define yyGet() ((uchar) *(lip->ptr++))
+#define yyGetLast() ((uchar) lip->ptr[-1])
+#define yyPeek() ((uchar) lip->ptr[0])
+#define yyPeek2() ((uchar) lip->ptr[1])
+#define yyUnget() lip->ptr--
+#define yySkip() lip->ptr++
+#define yyLength() ((uint) (lip->ptr - lip->tok_start)-1)
/* Longest standard keyword name */
#define TOCK_NAME_LENGTH 24
@@ -70,6 +69,17 @@ static uchar to_upper_lex[]=
208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
};
+/*
+ Names of the index hints (for error messages). Keep in sync with
+ index_hint_type
+*/
+
+const char * index_hint_type_name[] =
+{
+ "IGNORE INDEX",
+ "USE INDEX",
+ "FORCE INDEX"
+};
inline int lex_casecmp(const char *s, const char *t, uint len)
{
@@ -101,20 +111,51 @@ void lex_free(void)
}
+void
+st_parsing_options::reset()
+{
+ allows_variable= TRUE;
+ allows_select_into= TRUE;
+ allows_select_procedure= TRUE;
+ allows_derived= TRUE;
+}
+
+Lex_input_stream::Lex_input_stream(THD *thd,
+ const char* buffer,
+ unsigned int length)
+: m_thd(thd),
+ yylineno(1),
+ yytoklen(0),
+ yylval(NULL),
+ ptr(buffer),
+ tok_start(NULL),
+ tok_end(NULL),
+ end_of_query(buffer + length),
+ tok_start_prev(NULL),
+ buf(buffer),
+ next_state(MY_LEX_START),
+ found_semicolon(NULL),
+ ignore_space(test(thd->variables.sql_mode & MODE_IGNORE_SPACE)),
+ stmt_prepare_mode(FALSE)
+{
+}
+
+Lex_input_stream::~Lex_input_stream()
+{}
+
+
/*
This is called before every query that is to be parsed.
Because of this, it's critical to not do too much things here.
(We already do too much here)
*/
-void lex_start(THD *thd, const uchar *buf, uint length)
+void lex_start(THD *thd)
{
LEX *lex= thd->lex;
DBUG_ENTER("lex_start");
lex->thd= lex->unit.thd= thd;
- lex->buf= lex->ptr= buf;
- lex->end_of_query= buf+length;
lex->context_stack.empty();
lex->unit.init_query();
@@ -144,17 +185,13 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->describe= 0;
lex->subqueries= FALSE;
lex->view_prepare_mode= FALSE;
- lex->stmt_prepare_mode= FALSE;
lex->derived_tables= 0;
lex->lock_option= TL_READ;
- lex->found_semicolon= 0;
lex->safe_to_cache_query= 1;
- lex->time_zone_tables_used= 0;
lex->leaf_tables_insert= 0;
+ lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
- lex->next_state=MY_LEX_START;
- lex->yylineno = 1;
lex->in_comment=0;
lex->length=0;
lex->part_info= 0;
@@ -164,7 +201,6 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
lex->select_lex.group_list.empty();
lex->select_lex.order_list.empty();
- lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
@@ -173,6 +209,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->spcont= NULL;
lex->proc_list.first= 0;
lex->escape_used= FALSE;
+ lex->query_tables= 0;
lex->reset_query_tables_list(FALSE);
lex->expr_allows_subselect= TRUE;
@@ -183,6 +220,21 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
+ /*
+ ok, there must be a better solution for this, long-term
+ I tried "bzero" in the sql_yacc.yy code, but that for
+ some reason made the values zero, even if they were set
+ */
+ lex->server_options.server_name= 0;
+ lex->server_options.server_name_length= 0;
+ lex->server_options.host= 0;
+ lex->server_options.db= 0;
+ lex->server_options.username= 0;
+ lex->server_options.password= 0;
+ lex->server_options.scheme= 0;
+ lex->server_options.socket= 0;
+ lex->server_options.owner= 0;
+ lex->server_options.port= -1;
DBUG_VOID_RETURN;
}
@@ -197,28 +249,34 @@ void lex_end(LEX *lex)
lex->yacc_yyss= 0;
lex->yacc_yyvs= 0;
}
+
+ /* release used plugins */
+ plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
+ lex->plugins.elements);
+ reset_dynamic(&lex->plugins);
+
DBUG_VOID_RETURN;
}
-static int find_keyword(LEX *lex, uint len, bool function)
+static int find_keyword(Lex_input_stream *lip, uint len, bool function)
{
- const uchar *tok=lex->tok_start;
+ const char *tok= lip->tok_start;
- SYMBOL *symbol= get_hash_symbol((const char *)tok,len,function);
+ SYMBOL *symbol= get_hash_symbol(tok, len, function);
if (symbol)
{
- lex->yylval->symbol.symbol=symbol;
- lex->yylval->symbol.str= (char*) tok;
- lex->yylval->symbol.length=len;
-
+ lip->yylval->symbol.symbol=symbol;
+ lip->yylval->symbol.str= (char*) tok;
+ lip->yylval->symbol.length=len;
+
if ((symbol->tok == NOT_SYM) &&
- (lex->thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE))
+ (lip->m_thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE))
return NOT2_SYM;
if ((symbol->tok == OR_OR_SYM) &&
- !(lex->thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
+ !(lip->m_thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
return OR2_SYM;
-
+
return symbol->tok;
}
return 0;
@@ -251,12 +309,12 @@ bool is_lex_native_function(const LEX_STRING *name)
/* make a copy of token before ptr and set yytoklen */
-static LEX_STRING get_token(LEX *lex,uint length)
+static LEX_STRING get_token(Lex_input_stream *lip, uint skip, uint length)
{
LEX_STRING tmp;
yyUnget(); // ptr points now after last token char
- tmp.length=lex->yytoklen=length;
- tmp.str=(char*) lex->thd->strmake((char*) lex->tok_start,tmp.length);
+ tmp.length=lip->yytoklen=length;
+ tmp.str= lip->m_thd->strmake(lip->tok_start + skip, tmp.length);
return tmp;
}
@@ -267,19 +325,22 @@ static LEX_STRING get_token(LEX *lex,uint length)
future to operate multichar strings (like ucs2)
*/
-static LEX_STRING get_quoted_token(LEX *lex,uint length, char quote)
+static LEX_STRING get_quoted_token(Lex_input_stream *lip,
+ uint skip,
+ uint length, char quote)
{
LEX_STRING tmp;
- const uchar *from, *end;
- uchar *to;
+ const char *from, *end;
+ char *to;
yyUnget(); // ptr points now after last token char
- tmp.length=lex->yytoklen=length;
- tmp.str=(char*) lex->thd->alloc(tmp.length+1);
- for (from= lex->tok_start, to= (uchar*) tmp.str, end= to+length ;
- to != end ;
- )
+ tmp.length= lip->yytoklen=length;
+ tmp.str=(char*) lip->m_thd->alloc(tmp.length+1);
+ from= lip->tok_start + skip;
+ to= tmp.str;
+ end= to+length;
+ for ( ; to != end; )
{
- if ((*to++= *from++) == (uchar) quote)
+ if ((*to++= *from++) == quote)
from++; // Skip double quotes
}
*to= 0; // End null for safety
@@ -292,31 +353,31 @@ static LEX_STRING get_quoted_token(LEX *lex,uint length, char quote)
Fix sometimes to do only one scan of the string
*/
-static char *get_text(LEX *lex)
+static char *get_text(Lex_input_stream *lip)
{
reg1 uchar c,sep;
uint found_escape=0;
- CHARSET_INFO *cs= lex->thd->charset();
+ CHARSET_INFO *cs= lip->m_thd->charset();
sep= yyGetLast(); // String should end with this
- while (lex->ptr != lex->end_of_query)
+ while (lip->ptr != lip->end_of_query)
{
c = yyGet();
#ifdef USE_MB
- int l;
- if (use_mb(cs) &&
- (l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query))) {
- lex->ptr += l-1;
+ {
+ int l;
+ if (use_mb(cs) &&
+ (l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query))) {
+ lip->ptr += l-1;
continue;
+ }
}
#endif
if (c == '\\' &&
- !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
+ !(lip->m_thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
{ // Escaped character
found_escape=1;
- if (lex->ptr == lex->end_of_query)
+ if (lip->ptr == lip->end_of_query)
return 0;
yySkip();
}
@@ -331,37 +392,36 @@ static char *get_text(LEX *lex)
yyUnget();
/* Found end. Unescape and return string */
- const uchar *str, *end;
- uchar *start;
+ const char *str, *end;
+ char *start;
- str=lex->tok_start+1;
- end=lex->ptr-1;
- if (!(start=(uchar*) lex->thd->alloc((uint) (end-str)+1)))
+ str=lip->tok_start+1;
+ end=lip->ptr-1;
+ if (!(start= (char*) lip->m_thd->alloc((uint) (end-str)+1)))
return (char*) ""; // Sql_alloc has set error flag
if (!found_escape)
{
- lex->yytoklen=(uint) (end-str);
- memcpy(start,str,lex->yytoklen);
- start[lex->yytoklen]=0;
+ lip->yytoklen=(uint) (end-str);
+ memcpy(start,str,lip->yytoklen);
+ start[lip->yytoklen]=0;
}
else
{
- uchar *to;
+ char *to;
for (to=start ; str != end ; str++)
{
#ifdef USE_MB
int l;
if (use_mb(cs) &&
- (l = my_ismbchar(cs,
- (const char *)str, (const char *)end))) {
+ (l = my_ismbchar(cs, str, end))) {
while (l--)
*to++ = *str++;
str--;
continue;
}
#endif
- if (!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
+ if (!(lip->m_thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
*str == '\\' && str+1 != end)
{
switch(*++str) {
@@ -398,9 +458,9 @@ static char *get_text(LEX *lex)
*to++ = *str;
}
*to=0;
- lex->yytoklen=(uint) (to-start);
+ lip->yytoklen=(uint) (to-start);
}
- return (char*) start;
+ return start;
}
}
return 0; // unexpected end of query
@@ -511,20 +571,21 @@ int MYSQLlex(void *arg, void *yythd)
int tokval, result_state;
uint length;
enum my_lex_states state;
- LEX *lex= ((THD *)yythd)->lex;
+ THD *thd= (THD *)yythd;
+ Lex_input_stream *lip= thd->m_lip;
+ LEX *lex= thd->lex;
YYSTYPE *yylval=(YYSTYPE*) arg;
- CHARSET_INFO *cs= ((THD *) yythd)->charset();
+ CHARSET_INFO *cs= thd->charset();
uchar *state_map= cs->state_map;
uchar *ident_map= cs->ident_map;
- lex->yylval=yylval; // The global state
+ lip->yylval=yylval; // The global state
- lex->tok_end_prev= lex->tok_end;
- lex->tok_start_prev= lex->tok_start;
+ lip->tok_start_prev= lip->tok_start;
- lex->tok_start=lex->tok_end=lex->ptr;
- state=lex->next_state;
- lex->next_state=MY_LEX_OPERATOR_OR_IDENT;
+ lip->tok_start=lip->tok_end=lip->ptr;
+ state=lip->next_state;
+ lip->next_state=MY_LEX_OPERATOR_OR_IDENT;
LINT_INIT(c);
for (;;)
{
@@ -535,9 +596,9 @@ int MYSQLlex(void *arg, void *yythd)
for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet())
{
if (c == '\n')
- lex->yylineno++;
+ lip->yylineno++;
}
- lex->tok_start=lex->ptr-1; // Start of real token
+ lip->tok_start=lip->ptr-1; // Start of real token
state= (enum my_lex_states) state_map[c];
break;
case MY_LEX_ESCAPE:
@@ -556,20 +617,20 @@ int MYSQLlex(void *arg, void *yythd)
state=MY_LEX_COMMENT;
break;
}
- yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first chr
+ yylval->lex_str.str=(char*) (lip->ptr=lip->tok_start);// Set to first chr
yylval->lex_str.length=1;
c=yyGet();
if (c != ')')
- lex->next_state= MY_LEX_START; // Allow signed numbers
+ lip->next_state= MY_LEX_START; // Allow signed numbers
if (c == ',')
- lex->tok_start=lex->ptr; // Let tok_start point at next item
+ lip->tok_start=lip->ptr; // Let tok_start point at next item
/*
Check for a placeholder: it should not precede a possible identifier
because of binlogging: when a placeholder is replaced with
its value in a query for the binlog, the query must stay
grammatically correct.
*/
- else if (c == '?' && lex->stmt_prepare_mode && !ident_map[yyPeek()])
+ else if (c == '?' && lip->stmt_prepare_mode && !ident_map[yyPeek()])
return(PARAM_MARKER);
return((int) c);
@@ -580,14 +641,14 @@ int MYSQLlex(void *arg, void *yythd)
break;
}
/* Found N'string' */
- lex->tok_start++; // Skip N
+ lip->tok_start++; // Skip N
yySkip(); // Skip '
- if (!(yylval->lex_str.str = get_text(lex)))
+ if (!(yylval->lex_str.str = get_text(lip)))
{
state= MY_LEX_CHAR; // Read char by char
break;
}
- yylval->lex_str.length= lex->yytoklen;
+ yylval->lex_str.length= lip->yytoklen;
return(NCHAR_STRING);
case MY_LEX_IDENT_OR_HEX:
@@ -603,32 +664,28 @@ int MYSQLlex(void *arg, void *yythd)
break;
}
case MY_LEX_IDENT:
- const uchar *start;
+ const char *start;
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(cs))
{
result_state= IDENT_QUOTED;
if (my_mbcharlen(cs, yyGetLast()) > 1)
{
- int l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query);
+ int l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query);
if (l == 0) {
state = MY_LEX_CHAR;
continue;
}
- lex->ptr += l - 1;
+ lip->ptr += l - 1;
}
while (ident_map[c=yyGet()])
{
if (my_mbcharlen(cs, c) > 1)
{
int l;
- if ((l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query)) == 0)
+ if ((l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query)) == 0)
break;
- lex->ptr += l-1;
+ lip->ptr += l-1;
}
}
}
@@ -639,9 +696,9 @@ int MYSQLlex(void *arg, void *yythd)
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
- length= (uint) (lex->ptr - lex->tok_start)-1;
- start= lex->ptr;
- if (lex->ignore_space)
+ length= (uint) (lip->ptr - lip->tok_start)-1;
+ start= lip->ptr;
+ if (lip->ignore_space)
{
/*
If we find a space then this can't be an identifier. We notice this
@@ -649,19 +706,19 @@ int MYSQLlex(void *arg, void *yythd)
*/
for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
}
- if (start == lex->ptr && c == '.' && ident_map[yyPeek()])
- lex->next_state=MY_LEX_IDENT_SEP;
+ if (start == lip->ptr && c == '.' && ident_map[yyPeek()])
+ lip->next_state=MY_LEX_IDENT_SEP;
else
{ // '(' must follow directly if function
yyUnget();
- if ((tokval = find_keyword(lex,length,c == '(')))
+ if ((tokval = find_keyword(lip, length,c == '(')))
{
- lex->next_state= MY_LEX_START; // Allow signed numbers
+ lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval); // Was keyword
}
yySkip(); // next state does a unget
}
- yylval->lex_str=get_token(lex,length);
+ yylval->lex_str=get_token(lip, 0, length);
/*
Note: "SELECT _bla AS 'alias'"
@@ -678,12 +735,12 @@ int MYSQLlex(void *arg, void *yythd)
return(result_state); // IDENT or IDENT_QUOTED
case MY_LEX_IDENT_SEP: // Found ident and now '.'
- yylval->lex_str.str=(char*) lex->ptr;
+ yylval->lex_str.str=(char*) lip->ptr;
yylval->lex_str.length=1;
c=yyGet(); // should be '.'
- lex->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword)
+ lip->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword)
if (!ident_map[yyPeek()]) // Probably ` or "
- lex->next_state= MY_LEX_START;
+ lip->next_state= MY_LEX_START;
return((int) c);
case MY_LEX_NUMBER_IDENT: // number or ident which num-start
@@ -703,36 +760,32 @@ int MYSQLlex(void *arg, void *yythd)
{
yySkip();
while (my_isdigit(cs,yyGet())) ;
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 0, yyLength());
return(FLOAT_NUM);
}
}
yyUnget(); /* purecov: inspected */
}
- else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
- lex->tok_start[0] == '0' )
+ else if (c == 'x' && (lip->ptr - lip->tok_start) == 2 &&
+ lip->tok_start[0] == '0' )
{ // Varbinary
while (my_isxdigit(cs,(c = yyGet()))) ;
- if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
+ if ((lip->ptr - lip->tok_start) >= 4 && !ident_map[c])
{
- yylval->lex_str=get_token(lex,yyLength());
- yylval->lex_str.str+=2; // Skip 0x
- yylval->lex_str.length-=2;
- lex->yytoklen-=2;
+ /* skip '0x' */
+ yylval->lex_str=get_token(lip, 2, yyLength()-2);
return (HEX_NUM);
}
yyUnget();
}
- else if (c == 'b' && (lex->ptr - lex->tok_start) == 2 &&
- lex->tok_start[0] == '0' )
+ else if (c == 'b' && (lip->ptr - lip->tok_start) == 2 &&
+ lip->tok_start[0] == '0' )
{ // b'bin-number'
while (my_isxdigit(cs,(c = yyGet()))) ;
- if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
+ if ((lip->ptr - lip->tok_start) >= 4 && !ident_map[c])
{
- yylval->lex_str= get_token(lex, yyLength());
- yylval->lex_str.str+= 2; // Skip 0x
- yylval->lex_str.length-= 2;
- lex->yytoklen-= 2;
+ /* Skip '0b' */
+ yylval->lex_str= get_token(lip, 2, yyLength()-2);
return (BIN_NUM);
}
yyUnget();
@@ -749,11 +802,9 @@ int MYSQLlex(void *arg, void *yythd)
if (my_mbcharlen(cs, c) > 1)
{
int l;
- if ((l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query)) == 0)
+ if ((l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query)) == 0)
break;
- lex->ptr += l-1;
+ lip->ptr += l-1;
}
}
}
@@ -765,20 +816,19 @@ int MYSQLlex(void *arg, void *yythd)
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
if (c == '.' && ident_map[yyPeek()])
- lex->next_state=MY_LEX_IDENT_SEP;// Next is '.'
+ lip->next_state=MY_LEX_IDENT_SEP;// Next is '.'
- yylval->lex_str= get_token(lex,yyLength());
+ yylval->lex_str= get_token(lip, 0, yyLength());
return(result_state);
case MY_LEX_USER_VARIABLE_DELIMITER: // Found quote char
{
uint double_quotes= 0;
char quote_char= c; // Used char
- lex->tok_start=lex->ptr; // Skip first `
while ((c=yyGet()))
{
- int length;
- if ((length= my_mbcharlen(cs, c)) == 1)
+ int var_length;
+ if ((var_length= my_mbcharlen(cs, c)) == 1)
{
if (c == quote_char)
{
@@ -790,25 +840,26 @@ int MYSQLlex(void *arg, void *yythd)
}
}
#ifdef USE_MB
- else if (length < 1)
+ else if (var_length < 1)
break; // Error
- lex->ptr+= length-1;
+ lip->ptr+= var_length-1;
#endif
}
if (double_quotes)
- yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes,
+ yylval->lex_str=get_quoted_token(lip, 1,
+ yyLength() - double_quotes -1,
quote_char);
else
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 1, yyLength() -1);
if (c == quote_char)
yySkip(); // Skip end `
- lex->next_state= MY_LEX_START;
+ lip->next_state= MY_LEX_START;
return(IDENT_QUOTED);
}
- case MY_LEX_INT_OR_REAL: // Compleat int or incompleat real
+ case MY_LEX_INT_OR_REAL: // Complete int or incomplete real
if (c != '.')
{ // Found complete integer number.
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 0, yyLength());
return int_token(yylval->lex_str.str,yylval->lex_str.length);
}
// fall through
@@ -826,47 +877,45 @@ int MYSQLlex(void *arg, void *yythd)
break;
}
while (my_isdigit(cs,yyGet())) ;
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 0, yyLength());
return(FLOAT_NUM);
}
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 0, yyLength());
return(DECIMAL_NUM);
case MY_LEX_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
while (my_isxdigit(cs,(c = yyGet()))) ;
- length=(lex->ptr - lex->tok_start); // Length of hexnum+3
+ length=(lip->ptr - lip->tok_start); // Length of hexnum+3
if (!(length & 1) || c != '\'')
{
return(ABORT_SYM); // Illegal hex constant
}
yyGet(); // get_token makes an unget
- yylval->lex_str=get_token(lex,length);
- yylval->lex_str.str+=2; // Skip x'
- yylval->lex_str.length-=3; // Don't count x' and last '
- lex->yytoklen-=3;
+ yylval->lex_str=get_token(lip,
+ 2, // skip x'
+ length-3); // don't count x' and last '
return (HEX_NUM);
case MY_LEX_BIN_NUMBER: // Found b'bin-string'
yyGet(); // Skip '
while ((c= yyGet()) == '0' || c == '1');
- length= (lex->ptr - lex->tok_start); // Length of bin-num + 3
+ length= (lip->ptr - lip->tok_start); // Length of bin-num + 3
if (c != '\'')
return(ABORT_SYM); // Illegal hex constant
yyGet(); // get_token makes an unget
- yylval->lex_str= get_token(lex, length);
- yylval->lex_str.str+= 2; // Skip b'
- yylval->lex_str.length-= 3; // Don't count b' and last '
- lex->yytoklen-= 3;
- return (BIN_NUM);
+ yylval->lex_str= get_token(lip,
+ 2, // skip b'
+ length-3); // don't count b' and last '
+ return (BIN_NUM);
case MY_LEX_CMP_OP: // Incomplete comparison operator
if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
yySkip();
- if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
+ if ((tokval = find_keyword(lip, (uint) (lip->ptr - lip->tok_start),0)))
{
- lex->next_state= MY_LEX_START; // Allow signed numbers
+ lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
}
state = MY_LEX_CHAR; // Something fishy found
@@ -880,9 +929,9 @@ int MYSQLlex(void *arg, void *yythd)
if (state_map[yyPeek()] == MY_LEX_CMP_OP)
yySkip();
}
- if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
+ if ((tokval = find_keyword(lip, (uint) (lip->ptr - lip->tok_start),0)))
{
- lex->next_state= MY_LEX_START; // Found long op
+ lip->next_state= MY_LEX_START; // Found long op
return(tokval);
}
state = MY_LEX_CHAR; // Something fishy found
@@ -895,24 +944,24 @@ int MYSQLlex(void *arg, void *yythd)
break;
}
yySkip();
- tokval = find_keyword(lex,2,0); // Is a bool operator
- lex->next_state= MY_LEX_START; // Allow signed numbers
+ tokval = find_keyword(lip,2,0); // Is a bool operator
+ lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
case MY_LEX_STRING_OR_DELIMITER:
- if (((THD *) yythd)->variables.sql_mode & MODE_ANSI_QUOTES)
+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
{
state= MY_LEX_USER_VARIABLE_DELIMITER;
break;
}
/* " used for strings */
case MY_LEX_STRING: // Incomplete text string
- if (!(yylval->lex_str.str = get_text(lex)))
+ if (!(yylval->lex_str.str = get_text(lip)))
{
state= MY_LEX_CHAR; // Read char by char
break;
}
- yylval->lex_str.length=lex->yytoklen;
+ yylval->lex_str.length=lip->yytoklen;
return(TEXT_STRING);
case MY_LEX_COMMENT: // Comment
@@ -936,7 +985,7 @@ int MYSQLlex(void *arg, void *yythd)
state=MY_LEX_START;
if (my_isdigit(cs,yyPeek()))
{ // Version number
- version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
+ version=strtol((char*) lip->ptr,(char**) &lip->ptr,10);
}
if (version <= MYSQL_VERSION_ID)
{
@@ -944,13 +993,13 @@ int MYSQLlex(void *arg, void *yythd)
break;
}
}
- while (lex->ptr != lex->end_of_query &&
+ while (lip->ptr != lip->end_of_query &&
((c=yyGet()) != '*' || yyPeek() != '/'))
{
if (c == '\n')
- lex->yylineno++;
+ lip->yylineno++;
}
- if (lex->ptr != lex->end_of_query)
+ if (lip->ptr != lip->end_of_query)
yySkip(); // remove last '/'
state = MY_LEX_START; // Try again
break;
@@ -975,14 +1024,13 @@ int MYSQLlex(void *arg, void *yythd)
case MY_LEX_SEMICOLON: // optional line terminator
if (yyPeek())
{
- THD* thd= (THD*)yythd;
if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
- !lex->stmt_prepare_mode)
+ !lip->stmt_prepare_mode)
{
lex->safe_to_cache_query= 0;
- lex->found_semicolon=(char*) lex->ptr;
+ lip->found_semicolon= lip->ptr;
thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
- lex->next_state= MY_LEX_END;
+ lip->next_state= MY_LEX_END;
return (END_OF_INPUT);
}
state= MY_LEX_CHAR; // Return ';'
@@ -990,15 +1038,15 @@ int MYSQLlex(void *arg, void *yythd)
}
/* fall true */
case MY_LEX_EOL:
- if (lex->ptr >= lex->end_of_query)
+ if (lip->ptr >= lip->end_of_query)
{
- lex->next_state=MY_LEX_END; // Mark for next loop
+ lip->next_state=MY_LEX_END; // Mark for next loop
return(END_OF_INPUT);
}
state=MY_LEX_CHAR;
break;
case MY_LEX_END:
- lex->next_state=MY_LEX_END;
+ lip->next_state=MY_LEX_END;
return(0); // We found end of input last time
/* Actually real shouldn't start with . but allow them anyhow */
@@ -1018,26 +1066,26 @@ int MYSQLlex(void *arg, void *yythd)
case MY_LEX_STRING_OR_DELIMITER:
break;
case MY_LEX_USER_END:
- lex->next_state=MY_LEX_SYSTEM_VAR;
+ lip->next_state=MY_LEX_SYSTEM_VAR;
break;
default:
- lex->next_state=MY_LEX_HOSTNAME;
+ lip->next_state=MY_LEX_HOSTNAME;
break;
}
- yylval->lex_str.str=(char*) lex->ptr;
+ yylval->lex_str.str=(char*) lip->ptr;
yylval->lex_str.length=1;
return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname
for (c=yyGet() ;
my_isalnum(cs,c) || c == '.' || c == '_' || c == '$';
c= yyGet()) ;
- yylval->lex_str=get_token(lex,yyLength());
+ yylval->lex_str=get_token(lip, 0, yyLength());
return(LEX_HOSTNAME);
case MY_LEX_SYSTEM_VAR:
- yylval->lex_str.str=(char*) lex->ptr;
+ yylval->lex_str.str=(char*) lip->ptr;
yylval->lex_str.length=1;
yySkip(); // Skip '@'
- lex->next_state= (state_map[yyPeek()] ==
+ lip->next_state= (state_map[yyPeek()] ==
MY_LEX_USER_VARIABLE_DELIMITER ?
MY_LEX_OPERATOR_OR_IDENT :
MY_LEX_IDENT_OR_KEYWORD);
@@ -1054,27 +1102,59 @@ int MYSQLlex(void *arg, void *yythd)
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
if (c == '.')
- lex->next_state=MY_LEX_IDENT_SEP;
- length= (uint) (lex->ptr - lex->tok_start)-1;
+ lip->next_state=MY_LEX_IDENT_SEP;
+ length= (uint) (lip->ptr - lip->tok_start)-1;
if (length == 0)
return(ABORT_SYM); // Names must be nonempty.
- if ((tokval= find_keyword(lex,length,0)))
+ if ((tokval= find_keyword(lip, length,0)))
{
yyUnget(); // Put back 'c'
return(tokval); // Was keyword
}
- yylval->lex_str=get_token(lex,length);
+ yylval->lex_str=get_token(lip, 0, length);
return(result_state);
}
}
}
+Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
+ :drop_list(rhs.drop_list, mem_root),
+ alter_list(rhs.alter_list, mem_root),
+ key_list(rhs.key_list, mem_root),
+ create_list(rhs.create_list, mem_root),
+ flags(rhs.flags),
+ keys_onoff(rhs.keys_onoff),
+ tablespace_op(rhs.tablespace_op),
+ partition_names(rhs.partition_names, mem_root),
+ no_parts(rhs.no_parts),
+ change_level(rhs.change_level),
+ datetime_field(rhs.datetime_field),
+ error_if_not_empty(rhs.error_if_not_empty)
+{
+ /*
+ Make deep copies of used objects.
+ This is not a fully deep copy - clone() implementations
+ of Alter_drop, Alter_column, Key, foreign_key, key_part_spec
+ do not copy string constants. At the same length the only
+ reason we make a copy currently is that ALTER/CREATE TABLE
+ code changes input Alter_info definitions, but string
+ constants never change.
+ */
+ list_copy_and_replace_each_value(drop_list, mem_root);
+ list_copy_and_replace_each_value(alter_list, mem_root);
+ list_copy_and_replace_each_value(key_list, mem_root);
+ list_copy_and_replace_each_value(create_list, mem_root);
+ /* partition_names are not deeply copied currently */
+}
+
+
/*
Skip comment in the end of statement.
SYNOPSIS
skip_rear_comments()
+ cs character set
begin pointer to the beginning of statement
end pointer to the end of statement
@@ -1085,10 +1165,12 @@ int MYSQLlex(void *arg, void *yythd)
Pointer to the last non-comment symbol of the statement.
*/
-const uchar *skip_rear_comments(const uchar *begin, const uchar *end)
+const char *skip_rear_comments(CHARSET_INFO *cs, const char *begin,
+ const char *end)
{
- while (begin < end && (end[-1] <= ' ' || end[-1] == '*' ||
- end[-1] == '/' || end[-1] == ';'))
+ while (begin < end && (end[-1] == '*' ||
+ end[-1] == '/' || end[-1] == ';' ||
+ my_isspace(cs, end[-1])))
end-= 1;
return end;
}
@@ -1156,6 +1238,7 @@ void st_select_lex::init_query()
cond_count= between_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
+ select_n_where_fields= 0;
select_n_having_items= 0;
subquery_in_having= explicit_limit= 0;
is_item_list_lookup= 0;
@@ -1173,28 +1256,29 @@ void st_select_lex::init_select()
group_list.empty();
type= db= 0;
having= 0;
- use_index_ptr= ignore_index_ptr= 0;
table_join_options= 0;
in_sum_expr= with_wild= 0;
options= 0;
sql_cache= SQL_CACHE_UNSPECIFIED;
braces= 0;
- when_list.empty();
expr_list.empty();
interval_list.empty();
- use_index.empty();
ftfunc_list_alloc.empty();
inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;
linkage= UNSPECIFIED_TYPE;
order_list.elements= 0;
order_list.first= 0;
- order_list.next= (byte**) &order_list.first;
+ order_list.next= (uchar**) &order_list.first;
/* Set limit and offset to default values */
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
is_correlated= 0;
+ cur_pos_in_select_list= UNDEF_POS;
+ non_agg_fields.empty();
+ cond_value= having_value= Item::COND_UNDEF;
+ inner_refs_list.empty();
}
/*
@@ -1384,9 +1468,17 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last)
if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
{
// Select is dependent of outer select
- s->uncacheable|= UNCACHEABLE_DEPENDENT;
+ s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
SELECT_LEX_UNIT *munit= s->master_unit();
- munit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
+ for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select())
+ {
+ if (sl != s &&
+ !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED)))
+ sl->uncacheable|= UNCACHEABLE_UNITED;
+ }
}
is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE;
@@ -1397,14 +1489,11 @@ bool st_select_lex_node::inc_in_sum_expr() { return 1; }
uint st_select_lex_node::get_in_sum_expr() { return 0; }
TABLE_LIST* st_select_lex_node::get_table_list() { return 0; }
List<Item>* st_select_lex_node::get_item_list() { return 0; }
-List<String>* st_select_lex_node::get_use_index() { return 0; }
-List<String>* st_select_lex_node::get_ignore_index() { return 0; }
-TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
+TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
- List<String> *use_index,
- List<String> *ignore_index,
+ List<index_hint> *hints,
LEX_STRING *option)
{
return 0;
@@ -1511,19 +1600,6 @@ List<Item>* st_select_lex::get_item_list()
return &item_list;
}
-
-List<String>* st_select_lex::get_use_index()
-{
- return use_index_ptr;
-}
-
-
-List<String>* st_select_lex::get_ignore_index()
-{
- return ignore_index_ptr;
-}
-
-
ulong st_select_lex::get_table_join_options()
{
return table_join_options;
@@ -1544,6 +1620,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
(Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items +
item_list.elements +
select_n_having_items +
+ select_n_where_fields +
order_group_num)*5)) == 0;
}
@@ -1627,6 +1704,36 @@ void st_select_lex::print_limit(THD *thd, String *str)
}
}
+/**
+ @brief Restore the LEX and THD in case of a parse error.
+
+ This is a clean up call that is invoked by the Bison generated
+ parser before returning an error from MYSQLparse. If your
+ semantic actions manipulate with the global thread state (which
+ is a very bad practice and should not normally be employed) and
+ need a clean-up in case of error, and you can not use %destructor
+ rule in the grammar file itself, this function should be used
+ to implement the clean up.
+*/
+
+void st_lex::cleanup_lex_after_parse_error(THD *thd)
+{
+ /*
+ Delete sphead for the side effect of restoring of the original
+ LEX state, thd->lex, thd->mem_root and thd->free_list if they
+ were replaced when parsing stored procedure statements. We
+ will never use sphead object after a parse error, so it's okay
+ to delete it only for the sake of the side effect.
+ TODO: make this functionality explicit in sp_head class.
+ Sic: we must nullify the member of the main lex, not the
+ current one that will be thrown away
+ */
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+}
/*
Initialize (or reset) Query_tables_list object.
@@ -1648,6 +1755,17 @@ void st_select_lex::print_limit(THD *thd, String *str)
void Query_tables_list::reset_query_tables_list(bool init)
{
+ if (!init && query_tables)
+ {
+ TABLE_LIST *table= query_tables;
+ for (;;)
+ {
+ delete table->view;
+ if (query_tables_last == &table->next_global ||
+ !(table= table->next_global))
+ break;
+ }
+ }
query_tables= 0;
query_tables_last= &query_tables;
query_tables_own_last= 0;
@@ -1667,7 +1785,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
- binlog_row_based_if_mixed= FALSE;
+ binlog_stmt_flags= 0;
}
@@ -1700,8 +1818,13 @@ void Query_tables_list::destroy_query_tables_list()
st_lex::st_lex()
:result(0), yacc_yyss(0), yacc_yyvs(0),
- sql_command(SQLCOM_END)
+ sql_command(SQLCOM_END), option_type(OPT_DEFAULT)
{
+
+ my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
+ plugins_static_buffer,
+ INITIAL_LEX_PLUGIN_LIST_SIZE,
+ INITIAL_LEX_PLUGIN_LIST_SIZE);
reset_query_tables_list(TRUE);
}
@@ -1732,13 +1855,14 @@ bool st_lex::can_be_merged()
bool selects_allow_merge= select_lex.next_select() == 0;
if (selects_allow_merge)
{
- for (SELECT_LEX_UNIT *unit= select_lex.first_inner_unit();
- unit;
- unit= unit->next_unit())
+ for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
+ tmp_unit;
+ tmp_unit= tmp_unit->next_unit())
{
- if (unit->first_select()->parent_lex == this &&
- (unit->item == 0 ||
- (unit->item->place() != IN_WHERE && unit->item->place() != IN_ON)))
+ if (tmp_unit->first_select()->parent_lex == this &&
+ (tmp_unit->item == 0 ||
+ (tmp_unit->item->place() != IN_WHERE &&
+ tmp_unit->item->place() != IN_ON)))
{
selects_allow_merge= 0;
break;
@@ -1747,7 +1871,6 @@ bool st_lex::can_be_merged()
}
return (selects_allow_merge &&
- select_lex.order_list.elements == 0 &&
select_lex.group_list.elements == 0 &&
select_lex.having == 0 &&
select_lex.with_sum_func == 0 &&
@@ -1968,7 +2091,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
{
select_lex.context.table_list=
select_lex.context.first_name_resolution_table= first->next_local;
- select_lex.table_list.first= (byte*) (first->next_local);
+ select_lex.table_list.first= (uchar*) (first->next_local);
select_lex.table_list.elements--; //safety
first->next_local= 0;
/*
@@ -2024,31 +2147,6 @@ void st_lex::first_lists_tables_same()
/*
- Add implicitly used time zone description tables to global table list
- (if needed).
-
- SYNOPSYS
- st_lex::add_time_zone_tables_to_query_tables()
- thd - pointer to current thread context
-
- RETURN VALUE
- TRUE - error
- FALSE - success
-*/
-
-bool st_lex::add_time_zone_tables_to_query_tables(THD *thd)
-{
- /* We should not add these tables twice */
- if (!time_zone_tables_used)
- {
- time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last);
- if (time_zone_tables_used == &fake_time_zone_tables_list)
- return TRUE;
- }
- return FALSE;
-}
-
-/*
Link table back that was unlinked with unlink_first_table()
SYNOPSIS
@@ -2074,7 +2172,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
{
first->next_local= (TABLE_LIST*) select_lex.table_list.first;
select_lex.context.table_list= first;
- select_lex.table_list.first= (byte*) first;
+ select_lex.table_list.first= (uchar*) first;
select_lex.table_list.elements++; //safety
}
}
@@ -2117,7 +2215,6 @@ void st_lex::cleanup_after_one_table_open()
/* remove underlying units (units of VIEW) subtree */
select_lex.cut_subtree();
}
- time_zone_tables_used= 0;
}
@@ -2258,3 +2355,80 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
are in sql_union.cc
*/
+/*
+ Sets the kind of hints to be added by the calls to add_index_hint().
+
+ SYNOPSIS
+ set_index_hint_type()
+ type the kind of hints to be added from now on.
+ clause the clause to use for hints to be added from now on.
+
+ DESCRIPTION
+ Used in filling up the tagged hints list.
+ This list is filled by first setting the kind of the hint as a
+ context variable and then adding hints of the current kind.
+ Then the context variable index_hint_type can be reset to the
+ next hint type.
+*/
+void st_select_lex::set_index_hint_type(enum index_hint_type type,
+ index_clause_map clause)
+{
+ current_index_hint_type= type;
+ current_index_hint_clause= clause;
+}
+
+
+/*
+ Makes an array to store index usage hints (ADD/FORCE/IGNORE INDEX).
+
+ SYNOPSIS
+ alloc_index_hints()
+ thd current thread.
+*/
+
+void st_select_lex::alloc_index_hints (THD *thd)
+{
+ index_hints= new (thd->mem_root) List<index_hint>();
+}
+
+
+
+/*
+ adds an element to the array storing index usage hints
+ (ADD/FORCE/IGNORE INDEX).
+
+ SYNOPSIS
+ add_index_hint()
+ thd current thread.
+ str name of the index.
+ length number of characters in str.
+
+ RETURN VALUE
+ 0 on success, non-zero otherwise
+*/
+bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
+{
+ return index_hints->push_front (new (thd->mem_root)
+ index_hint(current_index_hint_type,
+ current_index_hint_clause,
+ str, length));
+}
+
+/**
+ A routine used by the parser to decide whether we are specifying a full
+ partitioning or if only partitions to add or to split.
+
+ @note This needs to be outside of WITH_PARTITION_STORAGE_ENGINE since it
+ is used from the sql parser that doesn't have any #ifdef's
+
+ @retval TRUE Yes, it is part of a management partition command
+ @retval FALSE No, not a management partition command
+*/
+
+bool st_lex::is_partition_management() const
+{
+ return (sql_command == SQLCOM_ALTER_TABLE &&
+ (alter_info.flags == ALTER_ADD_PARTITION ||
+ alter_info.flags == ALTER_REORGANIZE_PARTITION));
+}
+
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index c572bddefbf..1136925e049 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -111,6 +110,7 @@ enum enum_sql_command {
SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
SQLCOM_SHOW_PLUGINS,
SQLCOM_SHOW_CONTRIBUTORS,
+ SQLCOM_CREATE_SERVER, SQLCOM_DROP_SERVER, SQLCOM_ALTER_SERVER,
SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
@@ -174,18 +174,26 @@ enum enum_drop_mode
typedef List<Item> List_item;
+/* SERVERS CACHE CHANGES */
+typedef struct st_lex_server_options
+{
+ long port;
+ uint server_name_length;
+ char *server_name, *host, *db, *username, *password, *scheme, *socket, *owner;
+} LEX_SERVER_OPTIONS;
+
typedef struct st_lex_master_info
{
char *host, *user, *password, *log_file_name;
uint port, connect_retry;
ulonglong pos;
ulong server_id;
- /*
- Variable for MASTER_SSL option.
- MASTER_SSL=0 in CHANGE MASTER TO corresponds to SSL_DISABLE
- MASTER_SSL=1 corresponds to SSL_ENABLE
- */
- enum {SSL_UNCHANGED=0, SSL_DISABLE, SSL_ENABLE} ssl;
+ /*
+ Enum is used for making it possible to detect if the user
+ changed variable or if it should be left at old value
+ */
+ enum {SSL_UNCHANGED, SSL_DISABLE, SSL_ENABLE}
+ ssl, ssl_verify_server_cert;
char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher;
char *relay_log_name;
ulong relay_log_pos;
@@ -209,6 +217,47 @@ enum tablespace_op_type
};
/*
+ String names used to print a statement with index hints.
+ Keep in sync with index_hint_type.
+*/
+extern const char * index_hint_type_name[];
+typedef uchar index_clause_map;
+
+/*
+ Bits in index_clause_map : one for each possible FOR clause in
+ USE/FORCE/IGNORE INDEX index hint specification
+*/
+#define INDEX_HINT_MASK_JOIN (1)
+#define INDEX_HINT_MASK_GROUP (1 << 1)
+#define INDEX_HINT_MASK_ORDER (1 << 2)
+
+#define INDEX_HINT_MASK_ALL (INDEX_HINT_MASK_JOIN | INDEX_HINT_MASK_GROUP | \
+ INDEX_HINT_MASK_ORDER)
+
+/* Single element of an USE/FORCE/IGNORE INDEX list specified as a SQL hint */
+class index_hint : public Sql_alloc
+{
+public:
+ /* The type of the hint : USE/FORCE/IGNORE */
+ enum index_hint_type type;
+ /* Where the hit applies to. A bitmask of INDEX_HINT_MASK_<place> values */
+ index_clause_map clause;
+ /*
+ The index name. Empty (str=NULL) name represents an empty list
+ USE INDEX () clause
+ */
+ LEX_STRING key_name;
+
+ index_hint (enum index_hint_type type_arg, index_clause_map clause_arg,
+ char *str, uint length) :
+ type(type_arg), clause(clause_arg)
+ {
+ key_name.str= str;
+ key_name.length= length;
+ }
+};
+
+/*
The state of the lex parsing for selects
master and slaves are pointers to select_lex.
@@ -360,7 +409,7 @@ public:
static void *operator new(size_t size)
{
- return (void*) sql_alloc((uint) size);
+ return sql_alloc(size);
}
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
@@ -386,15 +435,12 @@ public:
virtual uint get_in_sum_expr();
virtual TABLE_LIST* get_table_list();
virtual List<Item>* get_item_list();
- virtual List<String>* get_use_index();
- virtual List<String>* get_ignore_index();
virtual ulong get_table_join_options();
virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
- List<String> *use_index= 0,
- List<String> *ignore_index= 0,
+ List<index_hint> *hints= 0,
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
@@ -424,7 +470,8 @@ protected:
select_result *result;
ulonglong found_rows_for_union;
- bool res;
+ bool saved_error;
+
public:
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
@@ -494,9 +541,10 @@ public:
bool change_result(select_subselect *result, select_subselect *old_result);
void set_limit(st_select_lex *values);
void set_thd(THD *thd_arg) { thd= thd_arg; }
+ inline bool is_union ();
- friend void lex_start(THD *thd, const uchar *buf, uint length);
- friend int subselect_union_engine::exec(bool);
+ friend void lex_start(THD *thd);
+ friend int subselect_union_engine::exec();
List<Item> *get_unit_column_types();
};
@@ -514,6 +562,8 @@ public:
Item *where, *having; /* WHERE & HAVING clauses */
Item *prep_where; /* saved WHERE clause for prepared statement processing */
Item *prep_having;/* saved HAVING clause for prepared statement processing */
+ /* Saved values of the WHERE and HAVING clauses*/
+ Item::cond_result cond_value, having_value;
/* point on lex in which it was created, used in view subquery detection */
st_lex *parent_lex;
enum olap_type olap;
@@ -521,8 +571,7 @@ public:
SQL_LIST table_list;
SQL_LIST group_list; /* GROUP BY clause. */
List<Item> item_list; /* list of fields & expressions */
- List<String> interval_list, use_index, *use_index_ptr,
- ignore_index, *ignore_index_ptr;
+ List<String> interval_list;
bool is_item_list_lookup;
/*
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
@@ -544,7 +593,6 @@ public:
SQL_LIST order_list; /* ORDER clause */
List<List_item> expr_list;
- List<List_item> when_list; /* WHEN clause (expression) */
SQL_LIST *gorder_list;
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
// Arrays of pointers to top elements of all_fields list
@@ -558,6 +606,11 @@ public:
uint select_n_having_items;
uint cond_count; /* number of arguments of and/or/xor in where/having/on */
uint between_count; /* number of between predicates in where/having/on */
+ /*
+ Number of fields used in select list or where clause of current select
+ and all inner subselects.
+ */
+ uint select_n_where_fields;
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
/*
@@ -575,7 +628,8 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
-
+ /* List of references to fields referenced from inner selects */
+ List<Item_outer_ref> inner_refs_list;
/* Number of Item_sum-derived objects in this SELECT */
uint n_sum_items;
/* Number of Item_sum-derived objects in children and descendant SELECTs */
@@ -608,7 +662,26 @@ public:
bool no_wrap_view_item;
/* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test;
+ /* List of fields that aren't under an aggregate function */
+ List<Item_field> non_agg_fields;
+ /* index in the select list of the expression currently being fixed */
+ int cur_pos_in_select_list;
+ List<udf_func> udf_list; /* udf function calls stack */
+ /*
+ This is a copy of the original JOIN USING list that comes from
+ the parser. The parser :
+ 1. Sets the natural_join of the second TABLE_LIST in the join
+ and the st_select_lex::prev_join_using.
+ 2. Makes a parent TABLE_LIST and sets its is_natural_join/
+ join_using_fields members.
+ 3. Uses the wrapper TABLE_LIST as a table in the upper level.
+ We cannot assign directly to join_using_fields in the parser because
+ at stage (1.) the parent TABLE_LIST is not constructed yet and
+ the assignment will override the JOIN USING fields of the lower level
+ joins on the right.
+ */
+ List<String> *prev_join_using;
void init_query();
void init_select();
st_select_lex_unit* master_unit();
@@ -645,8 +718,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
- List<String> *use_index= 0,
- List<String> *ignore_index= 0,
+ List<index_hint> *hints= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
bool init_nested_join(THD *thd);
@@ -655,15 +727,13 @@ public:
void add_joined_table(TABLE_LIST *table);
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
- List<String>* get_use_index();
- List<String>* get_ignore_index();
ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type);
inline void init_order()
{
order_list.elements= 0;
order_list.first= 0;
- order_list.next= (byte**) &order_list.first;
+ order_list.next= (uchar**) &order_list.first;
}
/*
This method created for reiniting LEX in mysql_admin_table() and can be
@@ -674,7 +744,7 @@ public:
void cut_subtree() { slave= 0; }
bool test_limit();
- friend void lex_start(THD *thd, const uchar *buf, uint length);
+ friend void lex_start(THD *thd);
st_select_lex() : n_sum_items(0), n_child_sum_items(0) {}
void make_empty_select()
{
@@ -696,9 +766,42 @@ public:
select lexes.
*/
void cleanup_all_joins(bool full);
+
+ void set_index_hint_type(enum index_hint_type type, index_clause_map clause);
+
+ /*
+ Add a index hint to the tagged list of hints. The type and clause of the
+ hint will be the current ones (set by set_index_hint())
+ */
+ bool add_index_hint (THD *thd, char *str, uint length);
+
+ /* make a list to hold index hints */
+ void alloc_index_hints (THD *thd);
+ /* read and clear the index hints */
+ List<index_hint>* pop_index_hints(void)
+ {
+ List<index_hint> *hints= index_hints;
+ index_hints= NULL;
+ return hints;
+ }
+
+ void clear_index_hints(void) { index_hints= NULL; }
+
+private:
+ /* current index hint kind. used in filling up index_hints */
+ enum index_hint_type current_index_hint_type;
+ index_clause_map current_index_hint_clause;
+ /* a list of USE/FORCE/IGNORE INDEX */
+ List<index_hint> *index_hints;
};
typedef class st_select_lex SELECT_LEX;
+inline bool st_select_lex_unit::is_union ()
+{
+ return first_select()->next_select() &&
+ first_select()->next_select()->linkage == UNION_TYPE;
+}
+
#define ALTER_ADD_COLUMN (1L << 0)
#define ALTER_DROP_COLUMN (1L << 1)
#define ALTER_CHANGE_COLUMN (1L << 2)
@@ -727,26 +830,77 @@ typedef class st_select_lex SELECT_LEX;
#define ALTER_REMOVE_PARTITIONING (1L << 25)
#define ALTER_FOREIGN_KEY (1L << 26)
-typedef struct st_alter_info
+enum enum_alter_table_change_level
+{
+ ALTER_TABLE_METADATA_ONLY= 0,
+ ALTER_TABLE_DATA_CHANGED= 1,
+ ALTER_TABLE_INDEX_CHANGED= 2
+};
+
+/**
+ @brief Parsing data for CREATE or ALTER TABLE.
+
+ This structure contains a list of columns or indexes to be created,
+ altered or dropped.
+*/
+
+class Alter_info
{
- List<Alter_drop> drop_list;
- List<Alter_column> alter_list;
- uint flags;
- enum enum_enable_or_disable keys_onoff;
- enum tablespace_op_type tablespace_op;
- List<char> partition_names;
- uint no_parts;
-
- st_alter_info(){clear();}
- void clear()
+public:
+ List<Alter_drop> drop_list;
+ List<Alter_column> alter_list;
+ List<Key> key_list;
+ List<create_field> create_list;
+ uint flags;
+ enum enum_enable_or_disable keys_onoff;
+ enum tablespace_op_type tablespace_op;
+ List<char> partition_names;
+ uint no_parts;
+ enum_alter_table_change_level change_level;
+ create_field *datetime_field;
+ bool error_if_not_empty;
+
+
+ Alter_info() :
+ flags(0),
+ keys_onoff(LEAVE_AS_IS),
+ tablespace_op(NO_TABLESPACE_OP),
+ no_parts(0),
+ change_level(ALTER_TABLE_METADATA_ONLY),
+ datetime_field(NULL),
+ error_if_not_empty(FALSE)
+ {}
+
+ void reset()
{
+ drop_list.empty();
+ alter_list.empty();
+ key_list.empty();
+ create_list.empty();
+ flags= 0;
keys_onoff= LEAVE_AS_IS;
tablespace_op= NO_TABLESPACE_OP;
no_parts= 0;
partition_names.empty();
+ change_level= ALTER_TABLE_METADATA_ONLY;
+ datetime_field= 0;
+ error_if_not_empty= FALSE;
}
- void reset(){drop_list.empty();alter_list.empty();clear();}
-} ALTER_INFO;
+ /**
+ Construct a copy of this object to be used for mysql_alter_table
+ and mysql_create_table. Historically, these two functions modify
+ their Alter_info arguments. This behaviour breaks re-execution of
+ prepared statements and stored procedures and is compensated by
+ always supplying a copy of Alter_info to these functions.
+
+ @return You need to use check the error in THD for out
+ of memory condition after calling this function.
+ */
+ Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root);
+private:
+ Alter_info &operator=(const Alter_info &rhs); // not implemented
+ Alter_info(const Alter_info &rhs); // not implemented
+};
struct st_sp_chistics
{
@@ -810,18 +964,10 @@ public:
in which it was right after query parsing.
*/
SQL_LIST sroutines_list;
- byte **sroutines_list_own_last;
+ uchar **sroutines_list_own_last;
uint sroutines_list_own_elements;
/*
- Tells if the parsing stage detected that some items require row-based
- binlogging to give a reliable binlog/replication, or if we will use
- stored functions or triggers which themselves need require row-based
- binlogging.
- */
- bool binlog_row_based_if_mixed;
-
- /*
These constructor and destructor serve for creation/destruction
of Query_tables_list instances which are used as backup storage.
*/
@@ -868,6 +1014,48 @@ public:
query_tables_own_last= 0;
}
}
+
+ /**
+ Has the parser/scanner detected that this statement is unsafe?
+ */
+ inline bool is_stmt_unsafe() const {
+ return binlog_stmt_flags & (1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
+ /**
+ Flag the current (top-level) statement as unsafe.
+
+ The flag will be reset after the statement has finished.
+
+ */
+ inline void set_stmt_unsafe() {
+ binlog_stmt_flags|= (1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
+ inline void clear_stmt_unsafe() {
+ binlog_stmt_flags&= ~(1U << BINLOG_STMT_FLAG_UNSAFE);
+ }
+
+ /**
+ true if the parsed tree contains references to stored procedures
+ or functions, false otherwise
+ */
+ bool uses_stored_routines() const
+ { return sroutines_list.elements != 0; }
+
+private:
+ enum enum_binlog_stmt_flag {
+ BINLOG_STMT_FLAG_UNSAFE,
+ BINLOG_STMT_FLAG_COUNT
+ };
+
+ /*
+ Tells if the parsing stage detected properties of the statement,
+ for example: that some items require row-based binlogging to give
+ a reliable binlog/replication, or if we will use stored functions
+ or triggers which themselves need require row-based binlogging.
+ */
+ uint32 binlog_stmt_flags;
};
@@ -883,10 +1071,64 @@ struct st_parsing_options
bool allows_select_procedure;
bool allows_derived;
- st_parsing_options()
- : allows_variable(TRUE), allows_select_into(TRUE),
- allows_select_procedure(TRUE), allows_derived(TRUE)
- {}
+ st_parsing_options() { reset(); }
+ void reset();
+};
+
+
+/**
+ This class represents the character input stream consumed during
+ lexical analysis.
+*/
+class Lex_input_stream
+{
+public:
+ Lex_input_stream(THD *thd, const char* buff, unsigned int length);
+ ~Lex_input_stream();
+
+ /** Current thread. */
+ THD *m_thd;
+
+ /** Current line number. */
+ uint yylineno;
+
+ /** Length of the last token parsed. */
+ uint yytoklen;
+
+ /** Interface with bison, value of the last token parsed. */
+ LEX_YYSTYPE yylval;
+
+ /** Pointer to the current position in the input stream. */
+ const char* ptr;
+
+ /** Starting position of the last token parsed. */
+ const char* tok_start;
+
+ /** Ending position of the last token parsed. */
+ const char* tok_end;
+
+ /** End of the query text in the input stream. */
+ const char* end_of_query;
+
+ /** Starting position of the previous token parsed. */
+ const char* tok_start_prev;
+
+ /** Begining of the query text in the input stream. */
+ const char* buf;
+
+ /** Current state of the lexical analyser. */
+ enum my_lex_states next_state;
+
+ /** Position of ';' in the stream, to delimit multiple queries. */
+ const char* found_semicolon;
+
+ /** SQL_MODE = IGNORE_SPACE. */
+ bool ignore_space;
+ /*
+ TRUE if we're parsing a prepared statement: in this mode
+ we should allow placeholders and disallow multi-statements.
+ */
+ bool stmt_prepare_mode;
};
@@ -894,28 +1136,19 @@ struct st_parsing_options
typedef struct st_lex : public Query_tables_list
{
- uint yylineno,yytoklen; /* Simulate lex */
- LEX_YYSTYPE yylval;
SELECT_LEX_UNIT unit; /* most upper unit */
SELECT_LEX select_lex; /* first SELECT_LEX */
/* current SELECT_LEX in parsing */
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
- const uchar *buf; /* The beginning of string, used by SPs */
- const uchar *ptr,*tok_start,*tok_end,*end_of_query;
-
- /* The values of tok_start/tok_end as they were one call of MYSQLlex before */
- const uchar *tok_start_prev, *tok_end_prev;
char *length,*dec,*change;
LEX_STRING name;
- Table_ident *like_name;
char *help_arg;
char *backup_dir; /* For RESTORE/BACKUP */
char* to_log; /* For PURGE MASTER LOGS TO */
char* x509_subject,*x509_issuer,*ssl_cipher;
- char* found_semicolon; /* For multi queries - next query */
String *wild;
sql_exchange *exchange;
select_result *result;
@@ -923,8 +1156,13 @@ typedef struct st_lex : public Query_tables_list
LEX_STRING comment, ident;
LEX_USER *grant_user;
XID *xid;
- gptr yacc_yyss,yacc_yyvs;
+ uchar* yacc_yyss, *yacc_yyvs;
THD *thd;
+
+ /* maintain a list of used plugins for this LEX */
+ DYNAMIC_ARRAY plugins;
+ plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE];
+
CHARSET_INFO *charset, *underscore_charset;
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
@@ -944,8 +1182,6 @@ typedef struct st_lex : public Query_tables_list
List<String> interval_list;
List<LEX_USER> users_list;
List<LEX_COLUMN> columns;
- List<Key> key_list;
- List<create_field> create_list;
List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values;
List<set_var_base> var_list;
@@ -975,6 +1211,7 @@ typedef struct st_lex : public Query_tables_list
HA_CREATE_INFO create_info;
KEY_CREATE_INFO key_create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
+ LEX_SERVER_OPTIONS server_options;
USER_RESOURCES mqh;
ulong type;
/*
@@ -998,7 +1235,6 @@ typedef struct st_lex : public Query_tables_list
thr_lock_type lock_option;
enum SSL_type ssl_type; /* defined in violite.h */
- enum my_lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
enum enum_ha_read_modes ha_read_mode;
@@ -1030,7 +1266,7 @@ typedef struct st_lex : public Query_tables_list
uint8 create_view_algorithm;
uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
- bool in_comment, ignore_space, verbose, no_write_to_binlog;
+ bool in_comment, verbose, no_write_to_binlog;
bool tx_chain, tx_release;
/*
Special JOIN::prepare mode: changing of query is prohibited.
@@ -1040,15 +1276,10 @@ typedef struct st_lex : public Query_tables_list
to an .frm file. We need this definition to stay untouched.
*/
bool view_prepare_mode;
- /*
- TRUE if we're parsing a prepared statement: in this mode
- we should allow placeholders and disallow multistatements.
- */
- bool stmt_prepare_mode;
bool safe_to_cache_query;
bool subqueries, ignore;
st_parsing_options parsing_options;
- ALTER_INFO alter_info;
+ Alter_info alter_info;
/* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
/*
@@ -1060,11 +1291,6 @@ typedef struct st_lex : public Query_tables_list
bool prepared_stmt_code_is_varref;
/* Names of user variables holding parameters (in EXECUTE) */
List<LEX_STRING> prepared_stmt_params;
- /*
- Points to part of global table list which contains time zone tables
- implicitly used by the statement.
- */
- TABLE_LIST *time_zone_tables_used;
sp_head *sphead;
sp_name *spname;
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
@@ -1112,7 +1338,8 @@ typedef struct st_lex : public Query_tables_list
Pointers to part of LOAD DATA statement that should be rewritten
during replication ("LOCAL 'filename' REPLACE INTO" part).
*/
- const uchar *fname_start, *fname_end;
+ const char *fname_start;
+ const char *fname_end;
/*
Reference to a struct that contains information in various commands
@@ -1127,6 +1354,8 @@ typedef struct st_lex : public Query_tables_list
virtual ~st_lex()
{
destroy_query_tables_list();
+ plugin_unlock_list(NULL, (plugin_ref *)plugins.buffer, plugins.elements);
+ delete_dynamic(&plugins);
}
inline void uncacheable(uint8 cause)
@@ -1151,7 +1380,6 @@ typedef struct st_lex : public Query_tables_list
TABLE_LIST *unlink_first_table(bool *link_to_local);
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
void first_lists_tables_same();
- bool add_time_zone_tables_to_query_tables(THD *thd);
bool can_be_merged();
bool can_use_merged();
@@ -1201,18 +1429,23 @@ typedef struct st_lex : public Query_tables_list
{
return context_stack.head();
}
+ /*
+ Restore the LEX and THD in case of a parse error.
+ */
+ static void cleanup_lex_after_parse_error(THD *thd);
void reset_n_backup_query_tables_list(Query_tables_list *backup);
void restore_backup_query_tables_list(Query_tables_list *backup);
bool table_or_sp_used();
+ bool is_partition_management() const;
} LEX;
struct st_lex_local: public st_lex
{
static void *operator new(size_t size)
{
- return (void*) sql_alloc((uint) size);
+ return sql_alloc(size);
}
static void *operator new(size_t size, MEM_ROOT *mem_root)
{
@@ -1226,10 +1459,11 @@ struct st_lex_local: public st_lex
extern void lex_init(void);
extern void lex_free(void);
-extern void lex_start(THD *thd, const uchar *buf, uint length);
+extern void lex_start(THD *thd);
extern void lex_end(LEX *lex);
extern int MYSQLlex(void *arg, void *yythd);
-extern const uchar *skip_rear_comments(const uchar *ubegin, const uchar *uend);
+extern const char *skip_rear_comments(CHARSET_INFO *cs, const char *ubegin,
+ const char *uend);
extern bool is_lex_native_function(const LEX_STRING *name);
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index d57a7dfe4e3..49b649133d0 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2003, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,3 +36,37 @@ void free_list(I_List <i_string> *list)
while ((tmp= list->get()))
delete tmp;
}
+
+
+base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root)
+{
+ if (rhs.elements)
+ {
+ /*
+ It's okay to allocate an array of nodes at once: we never
+ call a destructor for list_node objects anyway.
+ */
+ first= (list_node*) alloc_root(mem_root,
+ sizeof(list_node) * rhs.elements);
+ if (first)
+ {
+ elements= rhs.elements;
+ list_node *dst= first;
+ list_node *src= rhs.first;
+ for (; dst < first + elements - 1; dst++, src= src->next)
+ {
+ dst->info= src->info;
+ dst->next= dst + 1;
+ }
+ /* Copy the last node */
+ dst->info= src->info;
+ dst->next= &end_of_list;
+ /* Setup 'last' member */
+ last= &dst->next;
+ return;
+ }
+ }
+ elements= 0;
+ first= &end_of_list;
+ last= &first;
+}
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 070fd1e3d9a..2e068f7f961 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -1,9 +1,10 @@
+#ifndef INCLUDES_MYSQL_SQL_LIST_H
+#define INCLUDES_MYSQL_SQL_LIST_H
/* 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,21 +25,23 @@
class Sql_alloc
{
public:
- static void *operator new(size_t size)
+ static void *operator new(size_t size) throw ()
{
- return (void*) sql_alloc((uint) size);
+ return sql_alloc(size);
}
static void *operator new[](size_t size)
{
- return (void*) sql_alloc((uint) size);
+ return sql_alloc(size);
}
- static void *operator new[](size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, (uint) size); }
- static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, (uint) size); }
+ static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{ /* never called */ }
+ static void operator delete[](void *ptr, MEM_ROOT *mem_root)
+ { /* never called */ }
static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); }
#ifdef HAVE_purify
bool dummy;
@@ -62,21 +65,24 @@ public:
pointer.
*/
-class list_node :public Sql_alloc
+
+/**
+ list_node - a node of a single-linked list.
+ @note We never call a destructor for instances of this class.
+*/
+
+struct list_node :public Sql_alloc
{
-public:
list_node *next;
void *info;
list_node(void *info_par,list_node *next_par)
:next(next_par),info(info_par)
- {}
+ {}
list_node() /* For end_of_list */
- {
- info=0;
- next= this;
- }
- friend class base_list;
- friend class base_list_iterator;
+ {
+ info= 0;
+ next= this;
+ }
};
@@ -92,12 +98,28 @@ public:
inline void empty() { elements=0; first= &end_of_list; last=&first;}
inline base_list() { empty(); }
+ /**
+ This is a shallow copy constructor that implicitly passes the ownership
+ from the source list to the new instance. The old instance is not
+ updated, so both objects end up sharing the same nodes. If one of
+ the instances then adds or removes a node, the other becomes out of
+ sync ('last' pointer), while still operational. Some old code uses and
+ relies on this behaviour. This logic is quite tricky: please do not use
+ it in any new code.
+ */
inline base_list(const base_list &tmp) :Sql_alloc()
{
elements= tmp.elements;
first= tmp.first;
last= elements ? tmp.last : &first;
}
+ /**
+ Construct a deep copy of the argument in memory root mem_root.
+ The elements themselves are copied by pointer. If you also
+ need to copy elements by value, you should employ
+ list_copy_and_replace_each_value after creating a copy.
+ */
+ base_list(const base_list &rhs, MEM_ROOT *mem_root);
inline base_list(bool error) { }
inline bool push_back(void *info)
{
@@ -184,6 +206,15 @@ public:
elements+= list->elements;
}
}
+ /**
+ Swap two lists.
+ */
+ inline void swap(base_list &rhs)
+ {
+ swap_variables(list_node *, first, rhs.first);
+ swap_variables(list_node **, last, rhs.last);
+ swap_variables(uint, elements, rhs.elements);
+ }
inline list_node* last_node() { return *last; }
inline list_node* first_node() { return first;}
inline void *head() { return first->info; }
@@ -348,6 +379,8 @@ template <class T> class List :public base_list
public:
inline List() :base_list() {}
inline List(const List<T> &tmp) :base_list(tmp) {}
+ inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
+ base_list(tmp, mem_root) {}
inline bool push_back(T *a) { return base_list::push_back(a); }
inline bool push_back(T *a, MEM_ROOT *mem_root)
{ return base_list::push_back(a, mem_root); }
@@ -423,7 +456,7 @@ struct ilink
}
static void operator delete(void* ptr_arg, size_t size)
{
- my_free((gptr)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
+ my_free((uchar*)ptr_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
}
inline ilink()
@@ -546,3 +579,32 @@ public:
I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
};
+
+/**
+ Make a deep copy of each list element.
+
+ @note A template function and not a template method of class List
+ is employed because of explicit template instantiation:
+ in server code there are explicit instantiations of List<T> and
+ an explicit instantiation of a template requires that any method
+ of the instantiated class used in the template can be resolved.
+ Evidently not all template arguments have clone() method with
+ the right signature.
+
+ @return You must query the error state in THD for out-of-memory
+ situation after calling this function.
+*/
+
+template <typename T>
+inline
+void
+list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
+{
+ /* Make a deep copy of each element */
+ List_iterator<T> it(list);
+ T *el;
+ while ((el= it++))
+ it.replace(el->clone(mem_root));
+}
+
+#endif // INCLUDES_MYSQL_SQL_LIST_H
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 9f75b52daef..0138030487b 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,7 +25,7 @@
class READ_INFO {
File file;
- byte *buffer, /* Buffer for read text */
+ uchar *buffer, /* Buffer for read text */
*end_of_buff; /* Data in bufferts ends here */
uint buff_length, /* Length of buffert */
max_length; /* Max length of row */
@@ -41,7 +40,7 @@ class READ_INFO {
public:
bool error,line_cuted,found_null,enclosed;
- byte *row_start, /* Found row starts here */
+ uchar *row_start, /* Found row starts here */
*row_end; /* Found row ends here */
CHARSET_INFO *read_charset;
@@ -83,10 +82,11 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
List<Item> &set_values, READ_INFO &read_info,
String &enclosed, ulong skip_lines,
bool ignore_check_option_errors);
+#ifndef EMBEDDED_LIBRARY
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
bool transactional_table);
-
+#endif /* EMBEDDED_LIBRARY */
/*
Execute LOAD DATA query
@@ -175,7 +175,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table is marked to be 'used for insert' in which case we should never
mark this table as 'const table' (ie, one that has only one row).
*/
- if (unique_table(thd, table_list, table_list->next_global))
+ if (unique_table(thd, table_list, table_list->next_global, 0))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
@@ -226,7 +226,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
}
- table->mark_columns_needed_for_insert();
+ prepare_triggers_for_insert_stmt(table);
uint tot_length=0;
bool use_blobs= 0, use_vars= 0;
@@ -305,6 +305,15 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if ((stat_info.st_mode & S_IFIFO) == S_IFIFO)
is_fifo = 1;
#endif
+
+ if (opt_secure_file_priv &&
+ strncmp(opt_secure_file_priv, name, strlen(opt_secure_file_priv)))
+ {
+ /* Read only allowed from within dir specified by secure_file_priv */
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
+ DBUG_RETURN(TRUE);
+ }
+
}
if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0)
DBUG_RETURN(TRUE);
@@ -316,7 +325,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
info.handle_duplicates=handle_duplicates;
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
- READ_INFO read_info(file,tot_length,thd->variables.collation_database,
+ READ_INFO read_info(file,tot_length,
+ ex->cs ? ex->cs : thd->variables.collation_database,
*field_term,*ex->line_start, *ex->line_term, *enclosed,
info.escape_char, read_file_from_client, is_fifo);
if (read_info.error)
@@ -366,7 +376,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->file->ha_start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -403,9 +413,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (error)
{
- if (transactional_table)
- ha_autocommit_or_rollback(thd,error);
-
if (read_file_from_client)
while (!read_info.next_line())
;
@@ -453,15 +460,17 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
}
#endif /*!EMBEDDED_LIBRARY*/
+ if (transactional_table)
+ ha_autocommit_or_rollback(thd,error);
+
error= -1; // Error on read
goto err;
}
sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
- send_ok(thd,info.copied+info.deleted,0L,name);
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
{
@@ -494,6 +503,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
+ /* ok to client sent only after binlog write and engine commit */
+ send_ok(thd, info.copied + info.deleted, 0L, name);
err:
table->file->ha_release_auto_increment();
if (thd->lock)
@@ -501,11 +512,14 @@ err:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ table->auto_increment_field_not_null= FALSE;
thd->abort_on_warning= 0;
DBUG_RETURN(error);
}
+#ifndef EMBEDDED_LIBRARY
+
/* Not a very useful function; just to avoid duplication of code */
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
@@ -522,6 +536,7 @@ static bool write_execute_load_query_log_event(THD *thd,
return mysql_bin_log.write(&e);
}
+#endif
/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
@@ -537,7 +552,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
Item_field *sql_field;
TABLE *table= table_list->table;
ulonglong id;
- bool no_trans_update;
+ bool no_trans_update_stmt, err;
DBUG_ENTER("read_fixed_length");
id= 0;
@@ -561,11 +576,11 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
continue;
}
it.rewind();
- byte *pos=read_info.row_start;
+ uchar *pos=read_info.row_start;
#ifdef HAVE_purify
read_info.row_end[0]=0;
#endif
- no_trans_update= !table->file->has_transactions();
+ no_trans_update_stmt= !table->file->has_transactions();
restore_record(table, s->default_values);
/*
@@ -590,13 +605,13 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_TOO_FEW_RECORDS,
ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+ if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
+ ((Field_timestamp*) field)->set_time();
}
else
{
uint length;
- byte save_chr;
- if (field == table->next_number_field)
- table->auto_increment_field_not_null= TRUE;
+ uchar save_chr;
if ((length=(uint) (read_info.row_end-pos)) >
field->field_length)
length=field->field_length;
@@ -631,9 +646,11 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(-1);
}
- if (write_record(thd, table, &info))
+ err= write_record(thd, table, &info);
+ table->auto_increment_field_not_null= FALSE;
+ if (err)
DBUG_RETURN(1);
- thd->no_trans_update= no_trans_update;
+ thd->no_trans_update.stmt= no_trans_update_stmt;
/*
We don't need to reset auto-increment field since we are restoring
@@ -668,12 +685,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
TABLE *table= table_list->table;
uint enclosed_length;
ulonglong id;
- bool no_trans_update;
+ bool no_trans_update_stmt, err;
DBUG_ENTER("read_sep_field");
enclosed_length=enclosed.length();
id= 0;
- no_trans_update= !table->file->has_transactions();
+ no_trans_update_stmt= !table->file->has_transactions();
for (;;it.rewind())
{
@@ -688,7 +705,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
while ((item= it++))
{
uint length;
- byte *pos;
+ uchar *pos;
if (read_info.read_field())
break;
@@ -708,13 +725,16 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (item->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field *)item)->field;
- field->reset();
+ if (field->reset())
+ {
+ my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
+ thd->row_count);
+ DBUG_RETURN(1);
+ }
field->set_null();
- if (field == table->next_number_field)
- table->auto_increment_field_not_null= TRUE;
if (!field->maybe_null())
{
- if (field->type() == FIELD_TYPE_TIMESTAMP)
+ if (field->type() == MYSQL_TYPE_TIMESTAMP)
((Field_timestamp*) field)->set_time();
else if (field != table->next_number_field)
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -757,6 +777,15 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
{
if (item->type() == Item::FIELD_ITEM)
{
+ Field *field= ((Item_field *)item)->field;
+ if (field->reset())
+ {
+ my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
+ thd->row_count);
+ DBUG_RETURN(1);
+ }
+ if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
+ ((Field_timestamp*) field)->set_time();
/*
QQ: We probably should not throw warning for each field.
But how about intention to always have the same number
@@ -790,14 +819,15 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(-1);
}
-
- if (write_record(thd, table, &info))
+ err= write_record(thd, table, &info);
+ table->auto_increment_field_not_null= FALSE;
+ if (err)
DBUG_RETURN(1);
/*
We don't need to reset auto-increment field since we are restoring
its default value at the beginning of each loop iteration.
*/
- thd->no_trans_update= no_trans_update;
+ thd->no_trans_update.stmt= no_trans_update_stmt;
if (read_info.next_line()) // Skip to next line
break;
if (read_info.line_cuted)
@@ -884,7 +914,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
set_if_bigger(length,line_start.length());
stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
- if (!(buffer=(byte*) my_malloc(buff_length+1,MYF(0))))
+ if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
error=1; /* purecov: inspected */
else
{
@@ -894,7 +924,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
(is_fifo ? READ_FIFO : READ_CACHE),0L,1,
MYF(MY_WME)))
{
- my_free((gptr) buffer,MYF(0)); /* purecov: inspected */
+ my_free((uchar*) buffer,MYF(0)); /* purecov: inspected */
error=1;
}
else
@@ -925,7 +955,7 @@ READ_INFO::~READ_INFO()
{
if (need_end_io_cache)
::end_io_cache(&cache);
- my_free((gptr) buffer,MYF(0));
+ my_free((uchar*) buffer,MYF(0));
error=1;
}
}
@@ -958,7 +988,7 @@ inline int READ_INFO::terminator(char *ptr,uint length)
int READ_INFO::read_field()
{
int chr,found_enclosed_char;
- byte *to,*new_buffer;
+ uchar *to,*new_buffer;
found_null=0;
if (found_end_of_line)
@@ -981,7 +1011,7 @@ int READ_INFO::read_field()
if (chr == enclosed_char)
{
found_enclosed_char=enclosed_char;
- *to++=(byte) chr; // If error
+ *to++=(uchar) chr; // If error
}
else
{
@@ -1023,7 +1053,7 @@ int READ_INFO::read_field()
{
if ((chr=GET) == my_b_EOF)
{
- *to++= (byte) escape_char;
+ *to++= (uchar) escape_char;
goto found_eof;
}
/*
@@ -1035,7 +1065,7 @@ int READ_INFO::read_field()
*/
if (escape_char != enclosed_char || chr == escape_char)
{
- *to++ = (byte) unescape((char) chr);
+ *to++ = (uchar) unescape((char) chr);
continue;
}
PUSH(chr);
@@ -1060,7 +1090,7 @@ int READ_INFO::read_field()
{
if ((chr=GET) == found_enclosed_char)
{ // Remove dupplicated
- *to++ = (byte) chr;
+ *to++ = (uchar) chr;
continue;
}
// End of enclosed field if followed by field_term or line_term
@@ -1100,12 +1130,12 @@ int READ_INFO::read_field()
return 0;
}
}
- *to++ = (byte) chr;
+ *to++ = (uchar) chr;
}
/*
** We come here if buffer is too small. Enlarge it and continue
*/
- if (!(new_buffer=(byte*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
+ if (!(new_buffer=(uchar*) my_realloc((char*) buffer,buff_length+1+IO_SIZE,
MYF(MY_WME))))
return (error=1);
to=new_buffer + (to-buffer);
@@ -1140,7 +1170,7 @@ found_eof:
int READ_INFO::read_fixed_length()
{
int chr;
- byte *to;
+ uchar *to;
if (found_end_of_line)
return 1; // One have to call next_line
@@ -1160,10 +1190,10 @@ int READ_INFO::read_fixed_length()
{
if ((chr=GET) == my_b_EOF)
{
- *to++= (byte) escape_char;
+ *to++= (uchar) escape_char;
goto found_eof;
}
- *to++ =(byte) unescape((char) chr);
+ *to++ =(uchar) unescape((char) chr);
continue;
}
if (chr == line_term_char)
@@ -1175,7 +1205,7 @@ int READ_INFO::read_fixed_length()
return 0;
}
}
- *to++ = (byte) chr;
+ *to++ = (uchar) chr;
}
row_end=to; // Found full line
return 0;
@@ -1206,7 +1236,7 @@ int READ_INFO::next_line()
#ifdef USE_MB
if (my_mbcharlen(read_charset, chr) > 1)
{
- for (int i=1;
+ for (uint i=1;
chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
i++)
chr = GET;
diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc
index 3645ddb82cb..4e61c664106 100644
--- a/sql/sql_locale.cc
+++ b/sql/sql_locale.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index b3c67ab5db7..171ab55145a 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000, 2002, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -119,7 +118,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
{
struct handler_cb *next= cb->next;
cb->action();
- my_free((gptr)cb, MYF(0));
+ my_free((uchar*)cb, MYF(0));
cb= next;
}
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 8376b3bbfcc..7b707f813fc 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2004-2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,7 +24,7 @@
#include <sys/mman.h>
#endif
-mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_length)
+mapped_files::mapped_files(const char * filename,uchar *magic,uint magic_length)
{
#ifdef HAVE_MMAP
name=my_strdup(filename,MYF(0));
@@ -38,18 +37,18 @@ mapped_files::mapped_files(const my_string filename,byte *magic,uint magic_lengt
struct stat stat_buf;
if (!fstat(file,&stat_buf))
{
- if (!(map=(byte*) my_mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
+ if (!(map=(uchar*) my_mmap(0,(size=(ulong) stat_buf.st_size),PROT_READ,
MAP_SHARED | MAP_NORESERVE,file,
0L)))
{
error=errno;
- my_error(ER_NO_FILE_MAPPING, MYF(0), (my_string) name, error);
+ my_error(ER_NO_FILE_MAPPING, MYF(0), (char *) name, error);
}
}
if (map && memcmp(map,magic,magic_length))
{
my_error(ER_WRONG_MAGIC, MYF(0), name);
- VOID(my_munmap(map,size));
+ VOID(my_munmap((char*) map,size));
map=0;
}
if (!map)
@@ -67,7 +66,7 @@ mapped_files::~mapped_files()
#ifdef HAVE_MMAP
if (file >= 0)
{
- VOID(my_munmap(map,size));
+ VOID(my_munmap((char*) map,size));
VOID(my_close(file,MYF(0)));
file= -1; map=0;
}
@@ -83,7 +82,7 @@ static I_List<mapped_files> maps_in_use;
** else alloc new object
*/
-mapped_files *map_file(const my_string name,byte *magic,uint magic_length)
+mapped_files *map_file(const char * name,uchar *magic,uint magic_length)
{
#ifdef HAVE_MMAP
VOID(pthread_mutex_lock(&LOCK_mapped_file));
diff --git a/sql/sql_map.h b/sql/sql_map.h
index bfa6011ac54..a1efba0da6f 100644
--- a/sql/sql_map.h
+++ b/sql/sql_map.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2005 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,11 +21,11 @@
#endif
class mapped_files;
-mapped_files *map_file(const my_string name,byte *magic,uint magic_length);
+mapped_files *map_file(const char * name,uchar *magic,uint magic_length);
void unmap_file(mapped_files *map);
class mapped_files :public ilink {
- byte *map;
+ uchar *map;
ha_rows size;
char *name; // name of mapped file
File file; // >= 0 if open
@@ -34,11 +33,11 @@ class mapped_files :public ilink {
uint use_count;
public:
- mapped_files(const my_string name,byte *magic,uint magic_length);
+ mapped_files(const char * name,uchar *magic,uint magic_length);
~mapped_files();
friend class mapped_file;
- friend mapped_files *map_file(const my_string name,byte *magic,
+ friend mapped_files *map_file(const char * name,uchar *magic,
uint magic_length);
friend void unmap_file(mapped_files *map);
};
@@ -48,7 +47,7 @@ class mapped_file
{
mapped_files *file;
public:
- mapped_file(const my_string name,byte *magic,uint magic_length)
+ mapped_file(const char * name,uchar *magic,uint magic_length)
{
file=map_file(name,magic,magic_length); /* old or new map */
}
@@ -56,7 +55,7 @@ public:
{
unmap_file(file); /* free map */
}
- byte *map()
+ uchar *map()
{
return file->map;
}
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 3d06030536f..dccfcbaf8ac 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -55,8 +54,8 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new
new_select->linkage=OLAP_TYPE;
new_select->olap=NON_EXISTING_ONE;
new_select->group_list.elements=0;
- new_select->group_list.first=(byte *)0;
- new_select->group_list.next=(byte **)&new_select->group_list.first;
+ new_select->group_list.first=(uchar *)0;
+ new_select->group_list.next=(uchar **)&new_select->group_list.first;
List<Item> privlist;
List_iterator<Item> list_it(select_lex->item_list);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f57ae1caf94..8e55610df36 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,25 +26,7 @@
#include "sp.h"
#include "sp_cache.h"
#include "events.h"
-#include "event_data_objects.h"
-
-#ifdef HAVE_OPENSSL
-/*
- Without SSL the handshake consists of one packet. This packet
- has both client capabilites and scrambled password.
- With SSL the handshake might consist of two packets. If the first
- packet (client capabilities) has CLIENT_SSL flag set, we have to
- switch to SSL and read the second packet. The scrambled password
- is in the second packet and client_capabilites field will be ignored.
- Maybe it is better to accept flags other than CLIENT_SSL from the
- second packet?
-*/
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
+#include "sql_trigger.h"
/* Used in error handling only */
#define SP_TYPE_STRING(LP) \
@@ -57,68 +38,49 @@
(LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
"FUNCTION" : "PROCEDURE")
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
-static void decrease_user_connections(USER_CONN *uc);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-static bool check_multi_update_lock(THD *thd);
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
+static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
const char *any_db="*any*"; // Special symbol for check_access
const LEX_STRING command_name[]={
- C_STRING_WITH_LEN("Sleep"),
- C_STRING_WITH_LEN("Quit"),
- C_STRING_WITH_LEN("Init DB"),
- C_STRING_WITH_LEN("Query"),
- C_STRING_WITH_LEN("Field List"),
- C_STRING_WITH_LEN("Create DB"),
- C_STRING_WITH_LEN("Drop DB"),
- C_STRING_WITH_LEN("Refresh"),
- C_STRING_WITH_LEN("Shutdown"),
- C_STRING_WITH_LEN("Statistics"),
- C_STRING_WITH_LEN("Processlist"),
- C_STRING_WITH_LEN("Connect"),
- C_STRING_WITH_LEN("Kill"),
- C_STRING_WITH_LEN("Debug"),
- C_STRING_WITH_LEN("Ping"),
- C_STRING_WITH_LEN("Time"),
- C_STRING_WITH_LEN("Delayed insert"),
- C_STRING_WITH_LEN("Change user"),
- C_STRING_WITH_LEN("Binlog Dump"),
- C_STRING_WITH_LEN("Table Dump"),
- C_STRING_WITH_LEN("Connect Out"),
- C_STRING_WITH_LEN("Register Slave"),
- C_STRING_WITH_LEN("Prepare"),
- C_STRING_WITH_LEN("Execute"),
- C_STRING_WITH_LEN("Long Data"),
- C_STRING_WITH_LEN("Close stmt"),
- C_STRING_WITH_LEN("Reset stmt"),
- C_STRING_WITH_LEN("Set option"),
- C_STRING_WITH_LEN("Fetch"),
- C_STRING_WITH_LEN("Daemon"),
- C_STRING_WITH_LEN("Error") // Last command number
+ { C_STRING_WITH_LEN("Sleep") },
+ { C_STRING_WITH_LEN("Quit") },
+ { C_STRING_WITH_LEN("Init DB") },
+ { C_STRING_WITH_LEN("Query") },
+ { C_STRING_WITH_LEN("Field List") },
+ { C_STRING_WITH_LEN("Create DB") },
+ { C_STRING_WITH_LEN("Drop DB") },
+ { C_STRING_WITH_LEN("Refresh") },
+ { C_STRING_WITH_LEN("Shutdown") },
+ { C_STRING_WITH_LEN("Statistics") },
+ { C_STRING_WITH_LEN("Processlist") },
+ { C_STRING_WITH_LEN("Connect") },
+ { C_STRING_WITH_LEN("Kill") },
+ { C_STRING_WITH_LEN("Debug") },
+ { C_STRING_WITH_LEN("Ping") },
+ { C_STRING_WITH_LEN("Time") },
+ { C_STRING_WITH_LEN("Delayed insert") },
+ { C_STRING_WITH_LEN("Change user") },
+ { C_STRING_WITH_LEN("Binlog Dump") },
+ { C_STRING_WITH_LEN("Table Dump") },
+ { C_STRING_WITH_LEN("Connect Out") },
+ { C_STRING_WITH_LEN("Register Slave") },
+ { C_STRING_WITH_LEN("Prepare") },
+ { C_STRING_WITH_LEN("Execute") },
+ { C_STRING_WITH_LEN("Long Data") },
+ { C_STRING_WITH_LEN("Close stmt") },
+ { C_STRING_WITH_LEN("Reset stmt") },
+ { C_STRING_WITH_LEN("Set option") },
+ { C_STRING_WITH_LEN("Fetch") },
+ { C_STRING_WITH_LEN("Daemon") },
+ { C_STRING_WITH_LEN("Error") } // Last command number
};
const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
-#ifdef __WIN__
-static void test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
- MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-}
-static void init_signals(void)
-{
- int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
- for (int i=0 ; i < 7 ; i++)
- signal( signals[i], test_signal) ;
-}
-#endif
static void unlock_locked_tables(THD *thd)
{
@@ -157,11 +119,12 @@ bool end_active_trans(THD *thd)
if (ha_commit(thd))
error=1;
}
- thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
DBUG_RETURN(error);
}
+
bool begin_trans(THD *thd)
{
int error=0;
@@ -213,409 +176,6 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables)
return 0;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static HASH hash_user_connections;
-
-static int get_or_create_user_conn(THD *thd, const char *user,
- const char *host,
- USER_RESOURCES *mqh)
-{
- int return_val= 0;
- uint temp_len, user_len;
- char temp_user[USER_HOST_BUFF_SIZE];
- struct user_conn *uc;
-
- DBUG_ASSERT(user != 0);
- DBUG_ASSERT(host != 0);
-
- user_len= strlen(user);
- temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- /* First connection for user; Create a user connection object */
- if (!(uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)))))
- {
- net_send_error(thd, 0, NullS); // Out of memory
- return_val= 1;
- goto end;
- }
- uc->user=(char*) (uc+1);
- memcpy(uc->user,temp_user,temp_len+1);
- uc->host= uc->user + user_len + 1;
- uc->len= temp_len;
- uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
- uc->user_resources= *mqh;
- uc->intime= thd->thr_create_time;
- if (my_hash_insert(&hash_user_connections, (byte*) uc))
- {
- my_free((char*) uc,0);
- net_send_error(thd, 0, NullS); // Out of memory
- return_val= 1;
- goto end;
- }
- }
- thd->user_connect=uc;
- uc->connections++;
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- return return_val;
-
-}
-#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
-
-
-/*
- Check if user exist and password supplied is correct.
-
- SYNOPSIS
- check_user()
- thd thread handle, thd->security_ctx->{host,user,ip} are used
- command originator of the check: now check_user is called
- during connect and change user procedures; used for
- logging.
- passwd scrambled password received from client
- passwd_len length of scrambled password
- db database name to connect to, may be NULL
- check_count dont know exactly
-
- Note, that host, user and passwd may point to communication buffer.
- Current implementation does not depend on that, but future changes
- should be done with this in mind; 'thd' is INOUT, all other params
- are 'IN'.
-
- RETURN VALUE
- 0 OK; thd->security_ctx->user/master_access/priv_user/db_access and
- thd->db are updated; OK is sent to client;
- -1 access denied or handshake error; error is sent to client;
- >0 error, not sent to client
-*/
-
-int check_user(THD *thd, enum enum_server_command command,
- const char *passwd, uint passwd_len, const char *db,
- bool check_count)
-{
- DBUG_ENTER("check_user");
-
-#ifdef NO_EMBEDDED_ACCESS_CHECKS
- thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
- /* Change database if necessary */
- if (db && db[0])
- {
- /*
- thd->db is saved in caller and needs to be freed by caller if this
- function returns 0
- */
- thd->reset_db(NULL, 0);
- if (mysql_change_db(thd, db, FALSE))
- {
- /* Send the error to the client */
- net_send_error(thd);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- DBUG_RETURN(0);
-#else
-
- my_bool opt_secure_auth_local;
- pthread_mutex_lock(&LOCK_global_system_variables);
- opt_secure_auth_local= opt_secure_auth;
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- /*
- If the server is running in secure auth mode, short scrambles are
- forbidden.
- */
- if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
- {
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
- }
- if (passwd_len != 0 &&
- passwd_len != SCRAMBLE_LENGTH &&
- passwd_len != SCRAMBLE_LENGTH_323)
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
-
- /*
- Clear thd->db as it points to something, that will be freed when
- connection is closed. We don't want to accidentally free a wrong pointer
- if connect failed. Also in case of 'CHANGE USER' failure, current
- database will be switched to 'no database selected'.
- */
- thd->reset_db(NULL, 0);
-
- USER_RESOURCES ur;
- int res= acl_getroot(thd, &ur, passwd, passwd_len);
-#ifndef EMBEDDED_LIBRARY
- if (res == -1)
- {
- /*
- This happens when client (new) sends password scrambled with
- scramble(), but database holds old value (scrambled with
- scramble_323()). Here we please client to send scrambled_password
- in old format.
- */
- NET *net= &thd->net;
- if (opt_secure_auth_local)
- {
- net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip);
- DBUG_RETURN(-1);
- }
- /* We have to read very specific packet size */
- if (send_old_password_request(thd) ||
- my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
- {
- inc_host_errors(&thd->remote.sin_addr);
- DBUG_RETURN(ER_HANDSHAKE_ERROR);
- }
- /* Final attempt to check the user based on reply */
- /* So as passwd is short, errcode is always >= 0 */
- res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
- }
-#endif /*EMBEDDED_LIBRARY*/
- /* here res is always >= 0 */
- if (res == 0)
- {
- if (!(thd->main_security_ctx.master_access &
- NO_ACCESS)) // authentication is OK
- {
- DBUG_PRINT("info",
- ("Capabilities: %lu packet_length: %ld Host: '%s' "
- "Login user: '%s' Priv_user: '%s' Using password: %s "
- "Access: %lu db: '%s'",
- thd->client_capabilities,
- thd->max_client_packet_length,
- thd->main_security_ctx.host_or_ip,
- thd->main_security_ctx.user,
- thd->main_security_ctx.priv_user,
- passwd_len ? "yes": "no",
- thd->main_security_ctx.master_access,
- (thd->db ? thd->db : "*none*")));
-
- if (check_count)
- {
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool count_ok= thread_count <= max_connections + delayed_insert_threads
- || (thd->main_security_ctx.master_access & SUPER_ACL);
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- if (!count_ok)
- { // too many connections
- net_send_error(thd, ER_CON_COUNT_ERROR);
- DBUG_RETURN(-1);
- }
- }
-
- /* Why logging is performed before all checks've passed? */
- general_log_print(thd, command,
- (thd->main_security_ctx.priv_user ==
- thd->main_security_ctx.user ?
- (char*) "%s@%s on %s" :
- (char*) "%s@%s as anonymous on %s"),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- db ? db : (char*) "");
-
- /*
- This is the default access rights for the current database. It's
- set to 0 here because we don't have an active database yet (and we
- may not have an active database to set.
- */
- thd->main_security_ctx.db_access=0;
-
- /* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
- max_user_connections) &&
- get_or_create_user_conn(thd,
- (opt_old_style_user_limits ? thd->main_security_ctx.user :
- thd->main_security_ctx.priv_user),
- (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
- thd->main_security_ctx.priv_host),
- &ur))
- DBUG_RETURN(-1);
- if (thd->user_connect &&
- (thd->user_connect->user_resources.conn_per_hour ||
- thd->user_connect->user_resources.user_conn ||
- max_user_connections) &&
- check_for_max_user_connections(thd, thd->user_connect))
- DBUG_RETURN(-1);
-
- /* Change database if necessary */
- if (db && db[0])
- {
- if (mysql_change_db(thd, db, FALSE))
- {
- /* Send error to the client */
- net_send_error(thd);
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- DBUG_RETURN(-1);
- }
- }
- send_ok(thd);
- thd->password= test(passwd_len); // remember for error messages
- /* Ready to handle queries */
- DBUG_RETURN(0);
- }
- }
- else if (res == 2) // client gave short hash, server has long hash
- {
- net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- DBUG_RETURN(-1);
- }
- net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
- thd->main_security_ctx.user,
- thd->main_security_ctx.host_or_ip,
- passwd_len ? ER(ER_YES) : ER(ER_NO));
- DBUG_RETURN(-1);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-/*
- Check for maximum allowable user connections, if the mysqld server is
- started with corresponding variable that is greater then 0.
-*/
-
-extern "C" byte *get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=buff->len;
- return (byte*) buff->user;
-}
-
-extern "C" void free_user(struct user_conn *uc)
-{
- my_free((char*) uc,MYF(0));
-}
-
-void init_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
- 0,0,
- (hash_get_key) get_key_conn, (hash_free_key) free_user,
- 0);
-#endif
-}
-
-
-/*
- check if user has already too many connections
-
- SYNOPSIS
- check_for_max_user_connections()
- thd Thread handle
- uc User connect object
-
- NOTES
- If check fails, we decrease user connection count, which means one
- shouldn't call decrease_user_connections() after this function.
-
- RETURN
- 0 ok
- 1 error
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
-{
- int error=0;
- DBUG_ENTER("check_for_max_user_connections");
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (max_user_connections && !uc->user_resources.user_conn &&
- max_user_connections < (uint) uc->connections)
- {
- net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
- error=1;
- goto end;
- }
- time_out_user_resource_limits(thd, uc);
- if (uc->user_resources.user_conn &&
- uc->user_resources.user_conn < uc->connections)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_user_connections",
- (long) uc->user_resources.user_conn);
- error= 1;
- goto end;
- }
- if (uc->user_resources.conn_per_hour &&
- uc->user_resources.conn_per_hour <= uc->conn_per_hour)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
- "max_connections_per_hour",
- (long) uc->user_resources.conn_per_hour);
- error=1;
- goto end;
- }
- uc->conn_per_hour++;
-
- end:
- if (error)
- uc->connections--; // no need for decrease_user_connections() here
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-}
-
-/*
- Decrease user connection count
-
- SYNOPSIS
- decrease_user_connections()
- uc User connection object
-
- NOTES
- If there is a n user connection object for a connection
- (which only happens if 'max_user_connections' is defined or
- if someone has created a resource grant for a user), then
- the connection count is always incremented on connect.
-
- The user connect object is not freed if some users has
- 'max connections per hour' defined as we need to be able to hold
- count over the lifetime of the connection.
-*/
-
-static void decrease_user_connections(USER_CONN *uc)
-{
- DBUG_ENTER("decrease_user_connections");
- (void) pthread_mutex_lock(&LOCK_user_conn);
- DBUG_ASSERT(uc->connections);
- if (!--uc->connections && !mqh_used)
- {
- /* Last connection for user; Delete it */
- (void) hash_delete(&hash_user_connections,(byte*) uc);
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_VOID_RETURN;
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-void free_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- hash_free(&hash_user_connections);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
/*
Mark all commands that somehow changes a table
@@ -633,7 +193,7 @@ uint sql_command_flags[SQLCOM_END+1];
void init_update_queries(void)
{
- bzero((gptr) &sql_command_flags, sizeof(sql_command_flags));
+ bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA;
@@ -699,404 +259,6 @@ bool is_update_query(enum enum_sql_command command)
return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
}
-/*
- Reset per-hour user resource limits when it has been more than
- an hour since they were last checked
-
- SYNOPSIS:
- time_out_user_resource_limits()
- thd Thread handler
- uc User connection details
-
- NOTE:
- This assumes that the LOCK_user_conn mutex has been acquired, so it is
- safe to test and modify members of the USER_CONN structure.
-*/
-
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
-{
- time_t check_time = thd->start_time ? thd->start_time : time(NULL);
- DBUG_ENTER("time_out_user_resource_limits");
-
- /* If more than a hour since last check, reset resource checking */
- if (check_time - uc->intime >= 3600)
- {
- uc->questions=1;
- uc->updates=0;
- uc->conn_per_hour=0;
- uc->intime=check_time;
- }
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Check if maximum queries per hour limit has been reached
- returns 0 if OK.
-*/
-
-static bool check_mqh(THD *thd, uint check_command)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- bool error= 0;
- USER_CONN *uc=thd->user_connect;
- DBUG_ENTER("check_mqh");
- DBUG_ASSERT(uc != 0);
-
- (void) pthread_mutex_lock(&LOCK_user_conn);
-
- time_out_user_resource_limits(thd, uc);
-
- /* Check that we have not done too many questions / hour */
- if (uc->user_resources.questions &&
- uc->questions++ >= uc->user_resources.questions)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
- (long) uc->user_resources.questions);
- error=1;
- goto end;
- }
- if (check_command < (uint) SQLCOM_END)
- {
- /* Check that we have not done too many updates / hour */
- if (uc->user_resources.updates &&
- (sql_command_flags[check_command] & CF_CHANGES_DATA) &&
- uc->updates++ >= uc->user_resources.updates)
- {
- net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
- (long) uc->user_resources.updates);
- error=1;
- goto end;
- }
- }
-end:
- (void) pthread_mutex_unlock(&LOCK_user_conn);
- DBUG_RETURN(error);
-#else
- return (0);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
-static void reset_mqh(LEX_USER *lu, bool get_them= 0)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- (void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
- {
- USER_CONN *uc;
- uint temp_len=lu->user.length+lu->host.length+2;
- char temp_user[USER_HOST_BUFF_SIZE];
-
- memcpy(temp_user,lu->user.str,lu->user.length);
- memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
- temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
- if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len)))
- {
- uc->questions=0;
- get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- else
- {
- /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
- for (uint idx=0;idx < hash_user_connections.records; idx++)
- {
- USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
- idx);
- if (get_them)
- get_mqh(uc->user,uc->host,uc);
- uc->questions=0;
- uc->updates=0;
- uc->conn_per_hour=0;
- }
- }
- (void) pthread_mutex_unlock(&LOCK_user_conn);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-void thd_init_client_charset(THD *thd, uint cs_number)
-{
- /*
- Use server character set and collation if
- - opt_character_set_client_handshake is not set
- - client has not specified a character set
- - client character set is the same as the servers
- - client character set doesn't exists in server
- */
- if (!opt_character_set_client_handshake ||
- !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
- !my_strcasecmp(&my_charset_latin1,
- global_system_variables.character_set_client->name,
- thd->variables.character_set_client->name))
- {
- 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;
- }
-}
-
-
-/*
- Perform handshake, authorize client and update thd ACL variables.
- SYNOPSIS
- check_connection()
- thd thread handle
-
- RETURN
- 0 success, OK is sent to user, thd is updated.
- -1 error, which is sent to user
- > 0 error code (not sent to user)
-*/
-
-#ifndef EMBEDDED_LIBRARY
-static int check_connection(THD *thd)
-{
- uint connect_errors= 0;
- NET *net= &thd->net;
- ulong pkt_len= 0;
- char *end;
-
- DBUG_PRINT("info",
- ("New connection received on %s", vio_description(net->vio)));
-#ifdef SIGNAL_WITH_VIO_CLOSE
- thd->set_active_vio(net->vio);
-#endif
-
- if (!thd->main_security_ctx.host) // If TCP/IP connection
- {
- char ip[30];
-
- if (vio_peer_addr(net->vio, ip, &thd->peer_port))
- return (ER_BAD_HOST_ERROR);
- if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- if (!(specialflag & SPECIAL_NO_RESOLVE))
- {
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->main_security_ctx.host=
- ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->main_security_ctx.host)
- {
- if (thd->main_security_ctx.host != my_localhost)
- thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
- HOSTNAME_LENGTH)]= 0;
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- }
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
- }
- DBUG_PRINT("info",("Host: %s ip: %s",
- (thd->main_security_ctx.host ?
- thd->main_security_ctx.host : "unknown host"),
- (thd->main_security_ctx.ip ?
- thd->main_security_ctx.ip : "unknown ip")));
- if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
- return(ER_HOST_NOT_PRIVILEGED);
- }
- else /* Hostname given means that the connection was on a socket */
- {
- DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
- thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
- thd->main_security_ctx.ip= 0;
- /* Reset sin_addr */
- bzero((char*) &thd->remote, sizeof(thd->remote));
- }
- vio_keepalive(net->vio, TRUE);
- {
- /* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
- ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
- CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
-
- if (opt_using_transactions)
- client_flags|=CLIENT_TRANSACTIONS;
-#ifdef HAVE_COMPRESS
- client_flags |= CLIENT_COMPRESS;
-#endif /* HAVE_COMPRESS */
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is available! */
-#endif /* HAVE_OPENSSL */
-
- end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
- int4store((uchar*) end, thd->thread_id);
- end+= 4;
- /*
- So as check_connection is the only entry point to authorization
- procedure, scramble is set here. This gives us new scramble for
- each handshake.
- */
- create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
- /*
- Old clients does not understand long scrambles, but can ignore packet
- tail: that's why first part of the scramble is placed here, and second
- part at the end of packet.
- */
- end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-
- int2store(end, client_flags);
- /* write server characteristics: up to 16 bytes allowed */
- end[2]=(char) default_charset_info->number;
- int2store(end+3, thd->server_status);
- bzero(end+5, 13);
- end+= 18;
- /* write scramble tail */
- end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
- SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-
- /* At this point we write connection message and read reply */
- if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
- (uint) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < MIN_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#ifdef _CUSTOMCONFIG_
-#include "_cust_sql_parse.h"
-#endif
- if (connect_errors)
- reset_host_errors(&thd->remote.sin_addr);
- if (thd->packet.alloc(thd->variables.net_buffer_length))
- return(ER_OUT_OF_RESOURCES);
-
- thd->client_capabilities=uint2korr(net->read_pos);
- if (thd->client_capabilities & CLIENT_PROTOCOL_41)
- {
- thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
- DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- thd_init_client_charset(thd, (uint) net->read_pos[8]);
- thd->update_charset();
- end= (char*) net->read_pos+32;
- }
- else
- {
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
- }
-
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-#ifdef HAVE_OPENSSL
- DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
- if (thd->client_capabilities & CLIENT_SSL)
- {
- /* Do the SSL layering. */
- if (!ssl_acceptor_fd)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("IO layer change in progress..."));
- if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
- {
- DBUG_PRINT("error", ("Failed to accept new SSL connection"));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len= my_net_read(net)) == packet_error ||
- pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
- pkt_len));
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
- }
-#endif
-
- if (end >= (char*) net->read_pos+ pkt_len +2)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
- }
-
- if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
- if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
- opt_using_transactions)
- net->return_status= &thd->server_status;
- net->read_timeout=(uint) thd->variables.net_read_timeout;
-
- char *user= end;
- char *passwd= strend(user)+1;
- uint user_len= passwd - user - 1;
- char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
-
- /*
- Old clients send null-terminated string as password; new clients send
- the size (1 byte) + string (not null-terminated). Hence in case of empty
- password both send '\0'.
-
- This strlen() can't be easily deleted without changing protocol.
- */
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
- db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
- db + passwd_len + 1 : 0;
- /* strlen() can't be easily deleted without changing protocol */
- uint db_len= db ? strlen(db) : 0;
-
- if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
-
- /* Since 4.1 all database names are stored in utf8 */
- if (db)
- {
- db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info,
- db, db_len,
- thd->charset(), &dummy_errors)]= 0;
- db= db_buff;
- }
-
- user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
- system_charset_info, user, user_len,
- thd->charset(), &dummy_errors)]= '\0';
- user= user_buff;
-
- /* If username starts and ends in "'", chop them off */
- if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
- {
- user[user_len-1]= 0;
- user++;
- user_len-= 2;
- }
-
- if (thd->main_security_ctx.user)
- x_free(thd->main_security_ctx.user);
- if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
- return (ER_OUT_OF_RESOURCES);
- return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
-}
-
void execute_init_command(THD *thd, sys_var_str *init_command_var,
rw_lock_t *var_mutex)
@@ -1129,145 +291,6 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
}
-pthread_handler_t handle_one_connection(void *arg)
-{
- THD *thd=(THD*) arg;
- uint launch_time =
- (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
- if (launch_time >= slow_launch_time)
- statistic_increment(slow_launch_threads,&LOCK_status );
-
- pthread_detach_this_thread();
-
-#if !defined( __WIN__) // Win32 calls this in pthread_create
- /* The following calls needs to be done before we call DBUG_ macros */
- if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-#endif
-
- /*
- handle_one_connection() is the only way a thread would start
- and would always be on top of the stack, therefore, the thread
- stack always starts at the address of the first local variable
- of handle_one_connection, which is thd. We need to know the
- start of the stack so that we could check for stack overruns.
- */
- DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
- thd->thread_id));
- /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-
-#if defined(__WIN__)
- init_signals();
-#elif !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
- thd->thread_stack= (char*) &thd;
- if (thd->store_globals())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES, 1);
- statistic_increment(aborted_connects,&LOCK_status);
- end_thread(thd,0);
- return 0;
- }
-
- do
- {
- int error;
- NET *net= &thd->net;
- Security_context *sctx= thd->security_ctx;
- net->no_send_error= 0;
-
- if ((error=check_connection(thd)))
- { // Wrong permissions
- if (error > 0)
- net_printf_error(thd, error, sctx->host_or_ip);
-#ifdef __NT__
- if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
- my_sleep(1000); /* must wait after eof() */
-#endif
- statistic_increment(aborted_connects,&LOCK_status);
- goto end_thread;
- }
-#ifdef __NETWARE__
- netware_reg_user(sctx->ip, sctx->user, "MySQL");
-#endif
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
- if (thd->client_capabilities & CLIENT_COMPRESS)
- net->compress=1; // Use compression
-
- thd->version= refresh_version;
- thd->proc_info= 0;
- thd->command= COM_SLEEP;
- thd->set_time();
- thd->init_for_queries();
-
- if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
- {
- execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
- if (thd->query_error)
- {
- thd->killed= THD::KILL_CONNECTION;
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip, "init_connect command failed");
- sql_print_warning("%s", net->last_error);
- }
- thd->proc_info=0;
- thd->set_time();
- thd->init_for_queries();
- }
-
- while (!net->error && net->vio != 0 &&
- !(thd->killed == THD::KILL_CONNECTION))
- {
- net->no_send_error= 0;
- if (do_command(thd))
- break;
- }
- if (thd->user_connect)
- decrease_user_connections(thd->user_connect);
- if (net->error && net->vio != 0 && net->report_error)
- {
- if (!thd->killed && thd->variables.log_warnings > 1)
- sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- sctx->user ? sctx->user : "unauthenticated",
- sctx->host_or_ip,
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
- net_send_error(thd, net->last_errno, NullS);
- statistic_increment(aborted_threads,&LOCK_status);
- }
- else if (thd->killed)
- {
- statistic_increment(aborted_threads,&LOCK_status);
- }
-
-end_thread:
- close_connection(thd, 0, 1);
- end_thread(thd,1);
- /*
- If end_thread returns, we are either running with --one-thread
- or this thread has been schedule to handle the next query
- */
- thd= current_thd;
- thd->thread_stack= (char*) &thd;
- } while (!(test_flags & TEST_NO_THREADS));
- /* The following is only executed if we are not using --one-thread */
- return(0); /* purecov: deadcode */
-}
-
-#endif /* EMBEDDED_LIBRARY */
-
/*
Execute commands from bootstrap_file.
Used when creating the initial grant tables
@@ -1278,6 +301,7 @@ pthread_handler_t handle_bootstrap(void *arg)
THD *thd=(THD*) arg;
FILE *file=bootstrap_file;
char *buff;
+ const char* found_semicolon= NULL;
/* The following must be called before DBUG_ENTER */
thd->thread_stack= (char*) &thd;
@@ -1294,11 +318,6 @@ pthread_handler_t handle_bootstrap(void *arg)
#ifndef EMBEDDED_LIBRARY
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd;
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
#endif /* EMBEDDED_LIBRARY */
if (thd->variables.max_join_size == HA_POS_ERROR)
@@ -1347,27 +366,45 @@ pthread_handler_t handle_bootstrap(void *arg)
buff[length-1] == ';'))
length--;
buff[length]=0;
+
+ /* Skip lines starting with delimiter */
+ if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0)
+ continue;
+
thd->query_length=length;
- thd->query= thd->memdup_w_gap(buff, length+1,
- thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
+ thd->query= (char*) thd->memdup_w_gap(buff, length+1,
+ thd->db_length+1+
+ QUERY_CACHE_FLAGS_SIZE);
thd->query[length] = '\0';
+ DBUG_PRINT("query",("%-.4096s",thd->query));
/*
We don't need to obtain LOCK_thread_count here because in bootstrap
mode we have only one thread.
*/
thd->query_id=next_query_id();
- mysql_parse(thd,thd->query,length);
+ thd->set_time();
+ mysql_parse(thd, thd->query, length, & found_semicolon);
close_thread_tables(thd); // Free tables
+
if (thd->is_fatal_error)
break;
+
+ if (thd->net.report_error)
+ {
+ /* The query failed, send error to log and abort bootstrap */
+ net_send_error(thd);
+ thd->fatal_error();
+ break;
+ }
+
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
#ifdef USING_TRANSACTIONS
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
#endif
}
- /* thd->fatal_error should be set in case something went wrong */
end:
+ /* Remember the exit code of bootstrap */
bootstrap_error= thd->is_fatal_error;
net_end(&thd->net);
@@ -1516,8 +553,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
*/
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
res= ha_commit(thd);
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
break;
case COMMIT_RELEASE:
do_release= 1; /* fall through */
@@ -1534,8 +571,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_rollback(thd))
res= -1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
if (!res && (completion == ROLLBACK_AND_CHAIN))
res= begin_trans(thd);
break;
@@ -1557,7 +594,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
#ifndef EMBEDDED_LIBRARY
/*
- Read one command from socket and execute it (query or simple command).
+ Read one command from connection and execute it (query or simple command).
This function is called in loop from thread function.
SYNOPSIS
do_command()
@@ -1568,24 +605,26 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
bool do_command(THD *thd)
{
- char *packet;
- uint old_timeout;
+ char *packet= 0;
ulong packet_length;
- NET *net;
+ NET *net= &thd->net;
enum enum_server_command command;
DBUG_ENTER("do_command");
- net= &thd->net;
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
*/
thd->lex->current_select= 0;
- packet=0;
- old_timeout=net->read_timeout;
- /* Wait max for 8 hours */
- net->read_timeout=(uint) thd->variables.net_wait_timeout;
+ /*
+ This thread will do a blocking read from the client which
+ will be interrupted when the next command is received from
+ the client, the connection is closed or "net_wait_timeout"
+ number of seconds has passed
+ */
+ net_set_read_timeout(net, thd->variables.net_wait_timeout);
+
thd->clear_error(); // Clear error message
net_new_transaction(net);
@@ -1614,7 +653,10 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command].str));
}
- net->read_timeout=old_timeout; // restore it
+
+ /* Restore read timeout value */
+ net_set_read_timeout(net, thd->variables.net_read_timeout);
+
/*
packet_length contains length of data, as it was stored in packet
header. In case of malformed header, packet_length can be zero.
@@ -1654,7 +696,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_ENTER("dispatch_command");
if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ {
thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
+ }
thd->command=command;
/*
@@ -1665,7 +710,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id=query_id;
+ thd->query_id= global_query_id;
if (command != COM_STATISTICS && command != COM_PING)
next_query_id();
thread_running++;
@@ -1678,11 +723,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_INIT_DB:
{
LEX_STRING tmp;
- statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]);
thd->convert_string(&tmp, system_charset_info,
packet, packet_length-1, thd->charset());
- if (!mysql_change_db(thd, tmp.str, FALSE))
+ if (!mysql_change_db(thd, &tmp, FALSE))
{
general_log_print(thd, command, "%s",thd->db);
send_ok(thd);
@@ -1714,15 +758,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
thd->enable_slow_log= opt_log_slow_admin_statements;
- db.str= thd->alloc(db_len + tbl_len + 2);
- db.length= db_len;
+ db.str= (char*) thd->alloc(db_len + tbl_len + 2);
if (!db.str)
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break;
}
+ db.length= db_len;
tbl_name= strmake(db.str, packet + 1, db_len)+1;
strmake(tbl_name, packet + db_len + 2, tbl_len);
mysql_table_dump(thd, &db, tbl_name);
@@ -1730,7 +774,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_CHANGE_USER:
{
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
char *user= (char*) packet, *packet_end= packet+ packet_length;
char *passwd= strend(user)+1;
@@ -1747,7 +791,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *save_db;
uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
*passwd++ : strlen(passwd));
- uint dummy_errors, save_db_length, db_length, res;
+ uint dummy_errors, save_db_length, db_length;
+ int res;
Security_context save_security_ctx= *thd->security_ctx;
USER_CONN *save_user_connect;
@@ -1794,6 +839,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* authentication failure, we shall restore old user */
if (res > 0)
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ else
+ thd->clear_error(); // Error already sent to client
x_free(thd->security_ctx->user);
*thd->security_ctx= save_security_ctx;
thd->user_connect= save_user_connect;
@@ -1807,8 +854,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect)
decrease_user_connections(save_user_connect);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
- x_free((gptr) save_db);
- x_free((gptr) save_security_ctx.user);
+ x_free((uchar*) save_db);
+ x_free((uchar*) save_security_ctx.user);
}
break;
}
@@ -1849,17 +896,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *packet_end= thd->query + thd->query_length;
/* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */
const char *format= "%.*b";
+ const char* found_semicolon= NULL;
+
general_log_print(thd, command, format, thd->query_length, thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
- mysql_parse(thd,thd->query, thd->query_length);
+ mysql_parse(thd, thd->query, thd->query_length, & found_semicolon);
- while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
+ while (!thd->killed && found_semicolon && !thd->net.report_error)
{
- char *packet= thd->lex->found_semicolon;
+ char *next_packet= (char*) found_semicolon;
net->no_send_error= 0;
/*
Multiple queries exits, execute them individually
@@ -1867,24 +916,24 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->lock || thd->open_tables || thd->derived_tables ||
thd->prelocked_mode)
close_thread_tables(thd);
- ulong length= (ulong)(packet_end-packet);
+ ulong length= (ulong)(packet_end - next_packet);
log_slow_statement(thd);
/* Remove garbage at start of query */
- while (my_isspace(thd->charset(), *packet) && length > 0)
+ while (my_isspace(thd->charset(), *next_packet) && length > 0)
{
- packet++;
+ next_packet++;
length--;
}
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
- thd->query= packet;
+ thd->query= next_packet;
thd->query_id= next_query_id();
thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- mysql_parse(thd, packet, length);
+ mysql_parse(thd, next_packet, length, & found_semicolon);
}
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1901,18 +950,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *fields, *packet_end= packet + packet_length - 1, *arg_end;
/* Locked closure of all tables */
- TABLE_LIST *locked_tables= NULL;
TABLE_LIST table_list;
LEX_STRING conv_name;
- /* Saved variable value */
- my_bool old_innodb_table_locks= thd->variables.innodb_table_locks;
- uint dummy;
+ size_t dummy;
/* used as fields initializator */
- lex_start(thd, 0, 0);
+ lex_start(thd);
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
bzero((char*) &table_list,sizeof(table_list));
if (thd->copy_db_to(&table_list.db, &dummy))
break;
@@ -1926,7 +971,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
packet= arg_end + 1;
if (!my_strcasecmp(system_charset_info, table_list.db,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
if (schema_table)
@@ -1934,7 +979,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
thd->query_length= (uint) (packet_end - packet); // Don't count end \0
- if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
+ if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
break;
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (lower_case_table_names)
@@ -1943,15 +988,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (check_access(thd,SELECT_ACL,table_list.db,&table_list.grant.privilege,
0, 0, test(table_list.schema_table)))
break;
- if (grant_option &&
- check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
+ if (check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
break;
/* init structures for VIEW processing */
table_list.select_lex= &(thd->lex->select_lex);
- mysql_init_query(thd, (uchar*)"", 0);
+
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
+
thd->lex->
- select_lex.table_list.link_in_list((byte*) &table_list,
- (byte**) &table_list.next_local);
+ select_lex.table_list.link_in_list((uchar*) &table_list,
+ (uchar**) &table_list.next_local);
thd->lex->add_to_query_tables(&table_list);
/* switch on VIEW optimisation: do not fill temporary tables */
@@ -1975,8 +1022,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
LEX_STRING db, alias;
HA_CREATE_INFO create_info;
- statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB]);
if (thd->LEX_STRING_make(&db, packet, packet_length -1) ||
thd->LEX_STRING_make(&alias, db.str, db.length) ||
check_db_name(&db))
@@ -1995,8 +1041,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DROP_DB: // QQ: To be removed
{
- statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_DROP_DB]);
LEX_STRING db;
if (thd->LEX_STRING_make(&db, packet, packet_length - 1) ||
@@ -2025,7 +1070,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ushort flags;
uint32 slave_server_id;
- statistic_increment(thd->status_var.com_other,&LOCK_status);
+ status_var_increment(thd->status_var.com_other);
thd->enable_slow_log= opt_log_slow_admin_statements;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -2051,8 +1096,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_REFRESH:
{
bool not_used;
- statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
@@ -2064,7 +1108,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
/*
@@ -2075,7 +1119,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
enum mysql_enum_shutdown_level level=
(enum mysql_enum_shutdown_level) (uchar) packet[0];
- DBUG_PRINT("quit",("Got shutdown command for level %u", level));
if (level == SHUTDOWN_DEFAULT)
level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable
else if (level != SHUTDOWN_WAIT_ALL_BUFFERS)
@@ -2107,6 +1150,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
STATUS_VAR current_global_status_var;
ulong uptime;
uint length;
+ ulonglong queries_per_second1000;
#ifndef EMBEDDED_LIBRARY
char buff[250];
uint buff_len= sizeof(buff);
@@ -2116,22 +1160,25 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
general_log_print(thd, command, NullS);
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
calc_sum_of_all_status(&current_global_status_var);
- uptime= (ulong) (thd->start_time - start_time);
+ if (!(uptime= (ulong) (thd->start_time - server_start_time)))
+ queries_per_second1000= 0;
+ else
+ queries_per_second1000= thd->query_id * LL(1000) / uptime;
+
length= my_snprintf((char*) buff, buff_len - 1,
"Uptime: %lu Threads: %d Questions: %lu "
"Slow queries: %lu Opens: %lu Flush tables: %lu "
- "Open tables: %u Queries per second avg: %.3f",
+ "Open tables: %u Queries per second avg: %u.%u",
uptime,
(int) thread_count, (ulong) thd->query_id,
current_global_status_var.long_query_count,
current_global_status_var.opened_tables,
refresh_version,
cached_open_tables(),
- (uptime ? (ulonglong2double(thd->query_id) /
- (double) uptime) : (double) 0));
+ (uint) (queries_per_second1000 / 1000),
+ (uint) (queries_per_second1000 % 1000));
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
{
@@ -2143,18 +1190,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
#ifndef EMBEDDED_LIBRARY
- VOID(my_net_write(net, buff, length));
+ VOID(my_net_write(net, (uchar*) buff, length));
VOID(net_flush(net));
#endif
break;
}
case COM_PING:
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd, PROCESS_ACL))
break;
@@ -2165,22 +1211,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
ulong id=(ulong) uint4korr(packet);
sql_kill(thd,id,false);
break;
}
case COM_SET_OPTION:
{
- statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
- &LOCK_status);
- enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
- switch (command) {
- case MYSQL_OPTION_MULTI_STATEMENTS_ON:
+ status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
+ uint opt_command= uint2korr(packet);
+
+ switch (opt_command) {
+ case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
send_eof(thd);
break;
- case MYSQL_OPTION_MULTI_STATEMENTS_OFF:
+ case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
send_eof(thd);
break;
@@ -2191,7 +1237,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_DEBUG:
- statistic_increment(thd->status_var.com_other, &LOCK_status);
+ status_var_increment(thd->status_var.com_other);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status();
@@ -2316,8 +1362,9 @@ void log_slow_statement(THD *thd)
int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
enum enum_schema_tables schema_table_idx)
{
+ SELECT_LEX *schema_select_lex= NULL;
DBUG_ENTER("prepare_schema_table");
- SELECT_LEX *sel= 0;
+
switch (schema_table_idx) {
case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
@@ -2325,11 +1372,9 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
- check_global_access(thd, SHOW_DB_ACL))
- DBUG_RETURN(1);
break;
#endif
+
case SCH_TABLE_NAMES:
case SCH_TABLES:
case SCH_VIEWS:
@@ -2342,61 +1387,44 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
#else
{
LEX_STRING db;
- uint dummy;
+ size_t dummy;
if (lex->select_lex.db == NULL &&
thd->copy_db_to(&lex->select_lex.db, &dummy))
{
DBUG_RETURN(1);
}
- db.str= lex->select_lex.db;
+ schema_select_lex= new SELECT_LEX();
+ db.str= schema_select_lex->db= lex->select_lex.db;
+ schema_select_lex->table_list.first= NULL;
db.length= strlen(db.str);
+
if (check_db_name(&db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
DBUG_RETURN(1);
}
- if (check_access(thd, SELECT_ACL, db.str, &thd->col_access, 0, 0,
- is_schema_db(db.str)))
- DBUG_RETURN(1); /* purecov: inspected */
- if (!thd->col_access && check_grant_db(thd, db.str))
- {
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->security_ctx->priv_user, thd->security_ctx->priv_host,
- db.str);
- DBUG_RETURN(1);
- }
break;
}
#endif
case SCH_COLUMNS:
case SCH_STATISTICS:
+ {
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
- if (table_ident)
- {
- TABLE_LIST **query_tables_last= lex->query_tables_last;
- sel= new SELECT_LEX();
- /* 'parent_lex' is used in init_query() so it must be before it. */
- sel->parent_lex= lex;
- sel->init_query();
- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
- (List<String> *) 0, (List<String> *) 0))
- DBUG_RETURN(1);
- lex->query_tables_last= query_tables_last;
- TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
- char *db= table_list->db;
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &table_list->grant.privilege, 0, 0,
- test(table_list->schema_table)))
- DBUG_RETURN(1); /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
- UINT_MAX, 0))
- DBUG_RETURN(1);
- break;
- }
+ DBUG_ASSERT(table_ident);
+ TABLE_LIST **query_tables_last= lex->query_tables_last;
+ schema_select_lex= new SELECT_LEX();
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+ schema_select_lex->parent_lex= lex;
+ schema_select_lex->init_query();
+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ DBUG_RETURN(1);
+ lex->query_tables_last= query_tables_last;
+ break;
+ }
#endif
case SCH_OPEN_TABLES:
case SCH_VARIABLES:
@@ -2422,7 +1450,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
DBUG_RETURN(1);
}
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
- table_list->schema_select_lex= sel;
+ table_list->schema_select_lex= schema_select_lex;
table_list->schema_table_reformed= 1;
DBUG_RETURN(0);
}
@@ -2460,7 +1488,7 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length)
}
/* We must allocate some extra memory for query cache */
thd->query_length= 0; // Extra safety: Avoid races
- if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ if (!(thd->query= (char*) thd->memdup_w_gap((uchar*) (packet),
packet_length,
thd->db_length+ 1 +
QUERY_CACHE_FLAGS_SIZE)))
@@ -2493,6 +1521,91 @@ static void reset_one_shot_variables(THD *thd)
}
+static
+bool sp_process_definer(THD *thd)
+{
+ DBUG_ENTER("sp_process_definer");
+
+ LEX *lex= thd->lex;
+
+ /*
+ If the definer is not specified, this means that CREATE-statement missed
+ DEFINER-clause. DEFINER-clause can be missed in two cases:
+
+ - The user submitted a statement w/o the clause. This is a normal
+ case, we should assign CURRENT_USER as definer.
+
+ - Our slave received an updated from the master, that does not
+ replicate definer for stored rountines. We should also assign
+ CURRENT_USER as definer here, but also we should mark this routine
+ as NON-SUID. This is essential for the sake of backward
+ compatibility.
+
+ The problem is the slave thread is running under "special" user (@),
+ that actually does not exist. In the older versions we do not fail
+ execution of a stored routine if its definer does not exist and
+ continue the execution under the authorization of the invoker
+ (BUG#13198). And now if we try to switch to slave-current-user (@),
+ we will fail.
+
+ Actually, this leads to the inconsistent state of master and
+ slave (different definers, different SUID behaviour), but it seems,
+ this is the best we can do.
+ */
+
+ if (!lex->definer)
+ {
+ Query_arena original_arena;
+ Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena);
+
+ lex->definer= create_default_definer(thd);
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ /* Error has been already reported. */
+ if (lex->definer == NULL)
+ DBUG_RETURN(TRUE);
+
+ if (thd->slave_thread)
+ lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
+ }
+ else
+ {
+ /*
+ If the specified definer differs from the current user, we
+ should check that the current user has SUPER privilege (in order
+ to create a stored routine under another user one must have
+ SUPER privilege).
+ */
+ if ((strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, lex->definer->host.str,
+ thd->security_ctx->priv_host)) &&
+ check_global_access(thd, SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ /* Check that the specified definer exists. Emit a warning if not. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!is_acl_user(lex->definer->host.str, lex->definer->user.str))
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+ DBUG_RETURN(FALSE);
+}
+
+
/*
Execute command saved in thd and lex->sql_command
@@ -2522,7 +1635,7 @@ mysql_execute_command(THD *thd)
{
bool res= FALSE;
bool need_start_waiting= FALSE; // have protection against global read lock
- int result= 0;
+ int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
SELECT_LEX *select_lex= &lex->select_lex;
@@ -2570,13 +1683,36 @@ mysql_execute_command(THD *thd)
Don't reset warnings when executing a stored routine.
*/
if ((all_tables || &lex->select_lex != lex->all_selects_list ||
- lex->sroutines.records) && !thd->spcont ||
- lex->time_zone_tables_used)
+ lex->sroutines.records) && !thd->spcont)
mysql_reset_errors(thd, 0);
#ifdef HAVE_REPLICATION
if (unlikely(thd->slave_thread))
{
+ if (lex->sql_command == SQLCOM_DROP_TRIGGER)
+ {
+ /*
+ When dropping a trigger, we need to load its table name
+ before checking slave filter rules.
+ */
+ add_table_for_trigger(thd, thd->lex->spname, 1, &all_tables);
+
+ if (!all_tables)
+ {
+ /*
+ If table name cannot be loaded,
+ it means the trigger does not exists possibly because
+ CREATE TRIGGER was previously skipped for this trigger
+ according to slave filtering rules.
+ Returning success without producing any errors in this case.
+ */
+ DBUG_RETURN(0);
+ }
+
+ // force searching in slave.cc:tables_ok()
+ all_tables->updating= 1;
+ }
+
/*
Check if statment should be skipped because of slave filtering
rules
@@ -2640,8 +1776,7 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
- statistic_increment(thd->status_var.com_stat[lex->sql_command],
- &LOCK_status);
+ status_var_increment(thd->status_var.com_stat[lex->sql_command]);
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -2817,7 +1952,7 @@ mysql_execute_command(THD *thd)
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_backup_table(thd, first_table);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -2829,7 +1964,7 @@ mysql_execute_command(THD *thd)
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_restore_table(thd, first_table);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -2914,12 +2049,10 @@ mysql_execute_command(THD *thd)
&first_table->grant.privilege, 0, 0,
test(first_table->schema_table)))
goto error; /* purecov: inspected */
- if (grant_option)
- {
- /* Check that the first table has CREATE privilege */
- if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
- goto error;
- }
+ /* Check that the first table has CREATE privilege */
+ if (check_grant(thd, CREATE_ACL, all_tables, 0, 1, 0))
+ goto error;
+
pthread_mutex_lock(&LOCK_active_mi);
/*
fetch_master_table will send the error to the client on failure.
@@ -2951,17 +2084,47 @@ mysql_execute_command(THD *thd)
// Skip first table, which is the table we are creating
TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
TABLE_LIST *select_tables= lex->query_tables;
+ /*
+ Code below (especially in mysql_create_table() and select_create
+ methods) may modify HA_CREATE_INFO structure in LEX, so we have to
+ use a copy of this structure to make execution prepared statement-
+ safe. A shallow copy is enough as this code won't modify any memory
+ referenced from this structure.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
+ /*
+ We need to copy alter_info for the same reasons of re-execution
+ safety, only in case of Alter_info we have to do (almost) a deep
+ copy.
+ */
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (thd->is_fatal_error)
+ {
+ /* If out of memory when creating a copy of alter_info. */
+ res= 1;
+ goto end_with_restore_list;
+ }
if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list;
+ /* Might have been updated in create_table_precheck */
+ create_info.alias= create_table->alias;
+
#ifndef HAVE_READLINK
- lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+ if (create_info.data_file_name)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
+ "DATA DIRECTORY option ignored");
+ if (create_info.index_file_name)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
+ "INDEX DIRECTORY option ignored");
+ create_info.data_file_name= create_info.index_file_name= NULL;
#else
/* Fix names if symlinked tables */
- if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+ if (append_file_to_dir(thd, &create_info.data_file_name,
create_table->table_name) ||
- append_file_to_dir(thd, &lex->create_info.index_file_name,
+ append_file_to_dir(thd, &create_info.index_file_name,
create_table->table_name))
goto end_with_restore_list;
#endif
@@ -2969,14 +2132,14 @@ mysql_execute_command(THD *thd)
If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
*/
- if ((lex->create_info.used_fields &
+ if ((create_info.used_fields &
(HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
HA_CREATE_USED_CHARSET)
{
- lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
- lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- lex->create_info.default_table_charset= lex->create_info.table_charset;
- lex->create_info.table_charset= 0;
+ create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
+ create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ create_info.default_table_charset= create_info.table_charset;
+ create_info.table_charset= 0;
}
/*
The create-select command will open and read-lock the select table
@@ -3015,16 +2178,23 @@ mysql_execute_command(THD *thd)
select_lex->options|= SELECT_NO_UNLOCK;
unit->set_limit(select_lex);
- if (!(res= open_and_lock_tables(thd, select_tables)))
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ lex->link_first_table_back(create_table, link_to_local);
+ create_table->create= TRUE;
+ }
+
+ if (!(res= open_and_lock_tables(thd, lex->query_tables)))
{
/*
Is table which we are changing used somewhere in other parts
of query
*/
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, create_table, select_tables)))
+ create_table= lex->unlink_first_table(&link_to_local);
+ if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
{
update_non_unique_table_error(create_table, "CREATE", duplicate);
res= 1;
@@ -3032,15 +2202,15 @@ mysql_execute_command(THD *thd)
}
}
/* If we create merge table, we have to test tables in merge, too */
- if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ if (create_info.used_fields & HA_CREATE_USED_UNION)
{
TABLE_LIST *tab;
- for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+ for (tab= (TABLE_LIST*) create_info.merge_list.first;
tab;
tab= tab->next_local)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, tab, select_tables)))
+ if ((duplicate= unique_table(thd, tab, select_tables, 0)))
{
update_non_unique_table_error(tab, "CREATE", duplicate);
res= 1;
@@ -3049,13 +2219,16 @@ mysql_execute_command(THD *thd)
}
}
+ /*
+ select_create is currently not re-execution friendly and
+ needs to be created for every execution of a PS/SP.
+ */
if ((result= new select_create(create_table,
- &lex->create_info,
- lex->create_list,
- lex->key_list,
- select_lex->item_list,
- lex->duplicates,
- lex->ignore)))
+ &create_info,
+ &alter_info,
+ select_lex->item_list,
+ lex->duplicates,
+ lex->ignore)))
{
/*
CREATE from SELECT give its SELECT_LEX for SELECT,
@@ -3064,26 +2237,25 @@ mysql_execute_command(THD *thd)
res= handle_select(thd, lex, result, 0);
delete result;
}
- /* reset for PS */
- lex->create_list.empty();
- lex->key_list.empty();
}
+ else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ create_table= lex->unlink_first_table(&link_to_local);
+
}
else
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
thd->options|= OPTION_KEEP_LOG;
/* regular create */
- if (lex->like_name)
- res= mysql_create_like_table(thd, create_table, &lex->create_info,
- lex->like_name);
+ if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ res= mysql_create_like_table(thd, create_table, select_tables,
+ &create_info);
else
{
res= mysql_create_table(thd, create_table->db,
- create_table->table_name, &lex->create_info,
- lex->create_list,
- lex->key_list, 0, 0, 1);
+ create_table->table_name, &create_info,
+ &alter_info, 0, 0);
}
if (!res)
send_ok(thd);
@@ -3095,15 +2267,46 @@ end_with_restore_list:
break;
}
case SQLCOM_CREATE_INDEX:
+ /* Fall through */
+ case SQLCOM_DROP_INDEX:
+ /*
+ CREATE INDEX and DROP INDEX are implemented by calling ALTER
+ TABLE with proper arguments.
+
+ In the future ALTER TABLE will notice that the request is to
+ only add indexes and create these one by one for the existing
+ table without having to do a full rebuild.
+ */
+ {
+ /* Prepare stack copies to be re-execution safe */
+ HA_CREATE_INFO create_info;
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ goto error;
+
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
- thd->enable_slow_log= opt_log_slow_admin_statements;
if (end_active_trans(thd))
goto error;
- res= mysql_create_index(thd, first_table, lex->key_list);
- break;
+ /*
+ Currently CREATE INDEX or DROP INDEX cause a full table rebuild
+ and thus classify as slow administrative statements just like
+ ALTER TABLE.
+ */
+ thd->enable_slow_log= opt_log_slow_admin_statements;
+
+ bzero((char*) &create_info, sizeof(create_info));
+ create_info.db_type= 0;
+ create_info.row_type= ROW_TYPE_NOT_USED;
+ create_info.default_table_charset= thd->variables.collation_database;
+ res= mysql_alter_table(thd, first_table->db, first_table->table_name,
+ &create_info, first_table, &alter_info,
+ 0, (ORDER*) 0, 0);
+ break;
+ }
#ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START:
{
@@ -3146,10 +2349,21 @@ end_with_restore_list:
ulong priv=0;
ulong priv_needed= ALTER_ACL;
/*
+ Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
+ so we have to use a copy of this structure to make execution
+ prepared statement- safe. A shallow copy is enough as no memory
+ referenced from this structure will be modified.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
+ Alter_info alter_info(lex->alter_info, thd->mem_root);
+
+ if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ goto error;
+ /*
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
*/
- if (lex->alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
+ if (alter_info.flags & (ALTER_DROP_PARTITION | ALTER_RENAME))
priv_needed|= DROP_ACL;
/* Must be set in the parser */
@@ -3161,32 +2375,30 @@ end_with_restore_list:
is_schema_db(select_lex->db))||
check_merge_table_access(thd, first_table->db,
(TABLE_LIST *)
- lex->create_info.merge_list.first))
+ create_info.merge_list.first))
goto error; /* purecov: inspected */
- if (grant_option)
- {
- if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
- goto error;
- if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
- { // Rename of table
- TABLE_LIST tmp_table;
- bzero((char*) &tmp_table,sizeof(tmp_table));
- tmp_table.table_name= lex->name.str;
- tmp_table.db=select_lex->db;
- tmp_table.grant.privilege=priv;
- if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
- UINT_MAX, 0))
- goto error;
- }
+ if (check_grant(thd, priv_needed, all_tables, 0, UINT_MAX, 0))
+ goto error;
+ if (lex->name.str && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
+ { // Rename of table
+ TABLE_LIST tmp_table;
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.table_name= lex->name.str;
+ tmp_table.db=select_lex->db;
+ tmp_table.grant.privilege=priv;
+ if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, 0,
+ UINT_MAX, 0))
+ goto error;
}
+
/* Don't yet allow changing of symlinks with ALTER TABLE */
- if (lex->create_info.data_file_name)
+ if (create_info.data_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"DATA DIRECTORY option ignored");
- if (lex->create_info.index_file_name)
+ if (create_info.index_file_name)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"INDEX DIRECTORY option ignored");
- lex->create_info.data_file_name=lex->create_info.index_file_name=0;
+ create_info.data_file_name= create_info.index_file_name= NULL;
/* ALTER TABLE ends previous transaction */
if (end_active_trans(thd))
goto error;
@@ -3200,12 +2412,12 @@ end_with_restore_list:
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_alter_table(thd, select_lex->db, lex->name.str,
- &lex->create_info,
- first_table, lex->create_list,
- lex->key_list,
+ &create_info,
+ first_table,
+ &alter_info,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
- lex->ignore, &lex->alter_info, 1);
+ lex->ignore);
break;
}
case SQLCOM_RENAME_TABLE:
@@ -3220,21 +2432,18 @@ end_with_restore_list:
&table->next_local->grant.privilege, 0, 0,
test(table->next_local->schema_table)))
goto error;
- if (grant_option)
- {
- TABLE_LIST old_list, new_list;
- /*
- we do not need initialize old_list and new_list because we will
- come table[0] and table->next[0] there
- */
- old_list= table[0];
- new_list= table->next_local[0];
- if (check_grant(thd, ALTER_ACL, &old_list, 0, 1, 0) ||
- (!test_all_bits(table->next_local->grant.privilege,
- INSERT_ACL | CREATE_ACL) &&
- check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
- goto error;
- }
+ TABLE_LIST old_list, new_list;
+ /*
+ we do not need initialize old_list and new_list because we will
+ come table[0] and table->next[0] there
+ */
+ old_list= table[0];
+ new_list= table->next_local[0];
+ if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, 0, 1, 0) ||
+ (!test_all_bits(table->next_local->grant.privilege,
+ INSERT_ACL | CREATE_ACL) &&
+ check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, 0, 1, 0)))
+ goto error;
}
query_cache_invalidate3(thd, first_table, 0);
if (end_active_trans(thd) || mysql_rename_tables(thd, first_table, 0))
@@ -3267,12 +2476,7 @@ end_with_restore_list:
/* Ignore temporary tables if this is "SHOW CREATE VIEW" */
if (lex->only_view)
first_table->skip_temporary= 1;
-
- if (check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
- &first_table->grant.privilege, 0, 0,
- test(first_table->schema_table)))
- goto error;
- if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
+ if (check_show_create_table_access(thd, first_table))
goto error;
res= mysqld_show_create(thd, first_table);
break;
@@ -3296,7 +2500,9 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, REPAIR and binlog writing doesn't require synchronization */
+ /*
+ Presumably, REPAIR and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3304,7 +2510,7 @@ end_with_restore_list:
thd->query, thd->query_length, 0, FALSE);
}
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3315,7 +2521,7 @@ end_with_restore_list:
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res = mysql_check_table(thd, first_table, &lex->check_opt);
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3329,7 +2535,9 @@ end_with_restore_list:
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, ANALYZE and binlog writing doesn't require synchronization */
+ /*
+ Presumably, ANALYZE and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3337,7 +2545,7 @@ end_with_restore_list:
thd->query, thd->query_length, 0, FALSE);
}
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3349,12 +2557,14 @@ end_with_restore_list:
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
- mysql_recreate_table(thd, first_table, 1) :
+ mysql_recreate_table(thd, first_table) :
mysql_optimize_table(thd, first_table, &lex->check_opt);
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
+ /*
+ Presumably, OPTIMIZE and binlog writing doesn't require synchronization
+ */
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
@@ -3362,7 +2572,7 @@ end_with_restore_list:
thd->query, thd->query_length, 0, FALSE);
}
}
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
break;
}
@@ -3372,22 +2582,23 @@ end_with_restore_list:
break;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
- res= (result= mysql_update(thd, all_tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- select_lex->order_list.elements,
- (ORDER *) select_lex->order_list.first,
- unit->select_limit_cnt,
- lex->duplicates, lex->ignore));
+ res= (up_result= mysql_update(thd, all_tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ unit->select_limit_cnt,
+ lex->duplicates, lex->ignore));
/* mysql_update return 2 if we need to switch to multi-update */
- if (result != 2)
+ if (up_result != 2)
break;
+ /* Fall through */
case SQLCOM_UPDATE_MULTI:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* if we switched from normal update, rights are checked */
- if (result != 2)
+ if (up_result != 2)
{
if ((res= multi_update_precheck(thd, all_tables)))
break;
@@ -3440,6 +2651,36 @@ end_with_restore_list:
break;
}
case SQLCOM_REPLACE:
+#ifndef DBUG_OFF
+ if (mysql_bin_log.is_open())
+ {
+ /*
+ Generate an incident log event before writing the real event
+ to the binary log. We put this event is before the statement
+ since that makes it simpler to check that the statement was
+ not executed on the slave (since incidents usually stop the
+ slave).
+
+ Observe that any row events that are generated will be
+ generated before.
+
+ This is only for testing purposes and will not be present in a
+ release build.
+ */
+
+ Incident incident= INCIDENT_NONE;
+ DBUG_PRINT("debug", ("Just before generate_incident()"));
+ DBUG_EXECUTE_IF("incident_database_resync_on_replace",
+ incident= INCIDENT_LOST_EVENTS;);
+ if (incident)
+ {
+ Incident_log_event ev(thd, incident);
+ mysql_bin_log.write(&ev);
+ mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
+ }
+ DBUG_PRINT("debug", ("Just after generate_incident()"));
+ }
+#endif
case SQLCOM_INSERT:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3472,7 +2713,7 @@ end_with_restore_list:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- select_result *result;
+ select_result *sel_result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
@@ -3497,17 +2738,19 @@ end_with_restore_list:
{
/* Skip first table, which is the table we are inserting in */
TABLE_LIST *second_table= first_table->next_local;
- select_lex->table_list.first= (byte*) second_table;
+ select_lex->table_list.first= (uchar*) second_table;
select_lex->context.table_list=
select_lex->context.first_name_resolution_table= second_table;
res= mysql_insert_select_prepare(thd);
- if (!res && (result= new select_insert(first_table, first_table->table,
- &lex->field_list,
- &lex->update_list,
- &lex->value_list,
- lex->duplicates, lex->ignore)))
+ if (!res && (sel_result= new select_insert(first_table,
+ first_table->table,
+ &lex->field_list,
+ &lex->update_list,
+ &lex->value_list,
+ lex->duplicates,
+ lex->ignore)))
{
- res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
+ res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
/*
Invalidate the table in the query cache if something changed
after unlocking when changes become visible.
@@ -3525,10 +2768,10 @@ end_with_restore_list:
first_table->next_local= save_table;
thd->lock=0;
}
- delete result;
+ delete sel_result;
}
/* revert changes for SP */
- select_lex->table_list.first= (byte*) first_table;
+ select_lex->table_list.first= (uchar*) first_table;
}
/*
@@ -3550,7 +2793,7 @@ end_with_restore_list:
break;
}
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, DELETE_ACL, all_tables))
+ if (check_one_table_access(thd, DROP_ACL, all_tables))
goto error;
/*
Don't allow this within a transaction because we want to use
@@ -3591,7 +2834,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables=
(TABLE_LIST *)thd->lex->auxiliary_table_list.first;
- multi_delete *result;
+ multi_delete *del_result;
if (!thd->locked_tables &&
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
@@ -3616,8 +2859,8 @@ end_with_restore_list:
if ((res= mysql_multi_delete_prepare(thd)))
goto error;
- if (!thd->is_fatal_error && (result= new multi_delete(aux_tables,
- lex->table_count)))
+ if (!thd->is_fatal_error &&
+ (del_result= new multi_delete(aux_tables, lex->table_count)))
{
res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(),
@@ -3629,8 +2872,8 @@ end_with_restore_list:
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
- result, unit, select_lex);
- delete result;
+ del_result, unit, select_lex);
+ delete del_result;
}
else
res= TRUE; // Error
@@ -3657,7 +2900,7 @@ end_with_restore_list:
we silently add IF EXISTS if TEMPORARY was used.
*/
if (thd->slave_thread)
- lex->drop_if_exists= 1;
+ lex->drop_if_exists= 1;
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->options|= OPTION_KEEP_LOG;
@@ -3667,14 +2910,6 @@ end_with_restore_list:
lex->drop_temporary);
}
break;
- case SQLCOM_DROP_INDEX:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (check_one_table_access(thd, INDEX_ACL, all_tables))
- goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- goto error;
- res= mysql_drop_index(thd, first_table, &lex->alter_info);
- break;
case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd,PROCESS_ACL))
@@ -3707,16 +2942,21 @@ end_with_restore_list:
goto error;
#else
{
- if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0,0))
+ if (check_access(thd, FILE_ACL, any_db,0,0,0,0))
goto error;
res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS);
break;
}
#endif
case SQLCOM_CHANGE_DB:
- if (!mysql_change_db(thd,select_lex->db,FALSE))
+ {
+ LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };
+
+ if (!mysql_change_db(thd, &db_str, FALSE))
send_ok(thd);
+
break;
+ }
case SQLCOM_LOAD:
{
@@ -3809,6 +3049,12 @@ end_with_restore_list:
break;
case SQLCOM_CREATE_DB:
{
+ /*
+ As mysql_create_db() may modify HA_CREATE_INFO structure passed to
+ it, we need to use a copy of LEX::create_info to make execution
+ prepared statement- safe.
+ */
+ HA_CREATE_INFO create_info(lex->create_info);
if (end_active_trans(thd))
{
res= -1;
@@ -3841,7 +3087,7 @@ end_with_restore_list:
is_schema_db(lex->name.str)))
break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
- lex->name.str), &lex->create_info, 0);
+ lex->name.str), &create_info, 0);
break;
}
case SQLCOM_DROP_DB:
@@ -3934,6 +3180,7 @@ end_with_restore_list:
case SQLCOM_ALTER_DB:
{
LEX_STRING *db= &lex->name;
+ HA_CREATE_INFO create_info(lex->create_info);
if (check_db_name(db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
@@ -3963,7 +3210,7 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
- res= mysql_alter_db(thd, db->str, &lex->create_info);
+ res= mysql_alter_db(thd, db->str, &create_info);
break;
}
case SQLCOM_SHOW_CREATE_DB:
@@ -3987,15 +3234,23 @@ end_with_restore_list:
"function calls as part of this statement");
break;
}
+
+ res= sp_process_definer(thd);
+ if (res)
+ break;
+
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
- res= Events::get_instance()->
- create_event(thd, lex->event_parse_data,
- lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS);
+ {
+ bool if_not_exists= (lex->create_info.options &
+ HA_LEX_CREATE_IF_NOT_EXISTS);
+ res= Events::create_event(thd, lex->event_parse_data, if_not_exists);
break;
+ }
case SQLCOM_ALTER_EVENT:
- res= Events::get_instance()->update_event(thd, lex->event_parse_data,
- lex->spname);
+ res= Events::update_event(thd, lex->event_parse_data,
+ lex->spname ? &lex->spname->m_db : NULL,
+ lex->spname ? &lex->spname->m_name : NULL);
break;
default:
DBUG_ASSERT(0);
@@ -4013,41 +3268,16 @@ end_with_restore_list:
}
/* lex->unit.cleanup() is called outside, no need to call it here */
break;
- case SQLCOM_DROP_EVENT:
case SQLCOM_SHOW_CREATE_EVENT:
- {
- DBUG_ASSERT(lex->spname);
- if (! lex->spname->m_db.str)
- {
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- goto error;
- }
- if (check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
- is_schema_db(lex->spname->m_db.str)))
- break;
-
- if (lex->spname->m_name.length > NAME_LEN)
- {
- my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
- /* this jumps to the end of the function and skips own messaging */
- goto error;
- }
-
- if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
- res= Events::get_instance()->show_create_event(thd, lex->spname->m_db,
- lex->spname->m_name);
- else
- {
- uint affected= 1;
- if (!(res= Events::get_instance()->drop_event(thd,
- lex->spname->m_db,
- lex->spname->m_name,
- lex->drop_if_exists,
- FALSE)))
- send_ok(thd);
- }
+ res= Events::show_create_event(thd, lex->spname->m_db,
+ lex->spname->m_name);
+ break;
+ case SQLCOM_DROP_EVENT:
+ if (!(res= Events::drop_event(thd,
+ lex->spname->m_db, lex->spname->m_name,
+ lex->drop_if_exists)))
+ send_ok(thd);
break;
- }
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
@@ -4166,8 +3396,7 @@ end_with_restore_list:
uint grants= lex->all_privileges
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
: lex->grant;
- if (grant_option &&
- check_grant_routine(thd, grants | GRANT_ACL, all_tables,
+ if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error;
/* Conditionally writes to binlog */
@@ -4178,10 +3407,8 @@ end_with_restore_list:
}
else
{
- if (grant_option && check_grant(thd,
- (lex->grant | lex->grant_tot_col |
- GRANT_ACL),
- all_tables, 0, UINT_MAX, 0))
+ if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL),
+ all_tables, 0, UINT_MAX, 0))
goto error;
/* Conditionally writes to binlog */
res= mysql_table_grant(thd, all_tables, lex->users_list,
@@ -4211,7 +3438,7 @@ end_with_restore_list:
{
if (!(user= get_current_user(thd, tmp_user)))
goto error;
- reset_mqh(user);
+ reset_mqh(user, 0);
}
}
}
@@ -4241,7 +3468,9 @@ end_with_restore_list:
We WANT to write and we CAN write.
! we write after unlocking the table.
*/
- /* Presumably, RESET and binlog writing doesn't require synchronization */
+ /*
+ Presumably, RESET and binlog writing doesn't require synchronization
+ */
if (!lex->no_write_to_binlog && write_to_binlog)
{
if (mysql_bin_log.is_open())
@@ -4374,8 +3603,7 @@ end_with_restore_list:
res= TRUE; // cannot happen
else
{
- if ((thd->options &
- (OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG)) &&
+ if (((thd->options & OPTION_KEEP_LOG) || thd->no_trans_update.all) &&
!thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
@@ -4437,7 +3665,7 @@ end_with_restore_list:
{
uint namelen;
char *name;
- int result= SP_INTERNAL_ERROR;
+ int sp_result= SP_INTERNAL_ERROR;
DBUG_ASSERT(lex->sphead != 0);
DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
@@ -4483,86 +3711,11 @@ end_with_restore_list:
}
#endif
- /*
- If the definer is not specified, this means that CREATE-statement missed
- DEFINER-clause. DEFINER-clause can be missed in two cases:
-
- - The user submitted a statement w/o the clause. This is a normal
- case, we should assign CURRENT_USER as definer.
-
- - Our slave received an updated from the master, that does not
- replicate definer for stored rountines. We should also assign
- CURRENT_USER as definer here, but also we should mark this routine
- as NON-SUID. This is essential for the sake of backward
- compatibility.
-
- The problem is the slave thread is running under "special" user (@),
- that actually does not exist. In the older versions we do not fail
- execution of a stored routine if its definer does not exist and
- continue the execution under the authorization of the invoker
- (BUG#13198). And now if we try to switch to slave-current-user (@),
- we will fail.
-
- Actually, this leads to the inconsistent state of master and
- slave (different definers, different SUID behaviour), but it seems,
- this is the best we can do.
- */
-
- if (!lex->definer)
- {
- bool res= FALSE;
- Query_arena original_arena;
- Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-
- if (!(lex->definer= create_default_definer(thd)))
- res= TRUE;
-
- if (ps_arena)
- thd->restore_active_arena(ps_arena, &original_arena);
-
- /* Error has been already reported. */
- if (res)
- goto create_sp_error;
-
- if (thd->slave_thread)
- lex->sphead->m_chistics->suid= SP_IS_NOT_SUID;
- }
-
- /*
- If the specified definer differs from the current user, we should check
- that the current user has SUPER privilege (in order to create a stored
- routine under another user one must have SUPER privilege).
- */
-
- else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host))
- {
- if (check_global_access(thd, SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- goto create_sp_error;
- }
- }
-
- /* Check that the specified definer exists. Emit a warning if not. */
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
- {
- push_warning_printf(thd,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_NO_SUCH_USER,
- ER(ER_NO_SUCH_USER),
- lex->definer->user.str,
- lex->definer->host.str);
- }
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+ if (sp_process_definer(thd))
+ goto create_sp_error;
- res= (result= lex->sphead->create(thd));
- switch (result) {
+ res= (sp_result= lex->sphead->create(thd));
+ switch (sp_result) {
case SP_OK:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */
@@ -4599,10 +3752,7 @@ end_with_restore_list:
clean up the environment.
*/
create_sp_error:
- lex->unit.cleanup();
- delete lex->sphead;
- lex->sphead= 0;
- if (result != SP_OK )
+ if (sp_result != SP_OK )
goto error;
send_ok(thd);
break; /* break super switch */
@@ -4648,7 +3798,7 @@ create_sp_error:
goto error;
}
- my_bool nsok= thd->net.no_send_ok;
+ my_bool save_no_send_ok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE;
if (sp->m_flags & sp_head::MULTI_RESULTS)
{
@@ -4659,7 +3809,7 @@ create_sp_error:
back
*/
my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
goto error;
}
/*
@@ -4675,7 +3825,7 @@ create_sp_error:
if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, FALSE))
{
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
goto error;
}
#endif
@@ -4700,7 +3850,7 @@ create_sp_error:
thd->variables.select_limit= select_limit;
- thd->net.no_send_ok= nsok;
+ thd->net.no_send_ok= save_no_send_ok;
thd->server_status&= ~bits_to_be_cleared;
if (!res)
@@ -4717,7 +3867,7 @@ create_sp_error:
case SQLCOM_ALTER_PROCEDURE:
case SQLCOM_ALTER_FUNCTION:
{
- int result;
+ int sp_result;
sp_head *sp;
st_sp_chistics chistics;
@@ -4732,7 +3882,7 @@ create_sp_error:
if (! sp)
{
if (lex->spname->m_db.str)
- result= SP_KEY_NOT_FOUND;
+ sp_result= SP_KEY_NOT_FOUND;
else
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
@@ -4757,7 +3907,7 @@ create_sp_error:
{
my_message(ER_BINLOG_UNSAFE_ROUTINE,
ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
- result= SP_INTERNAL_ERROR;
+ sp_result= SP_INTERNAL_ERROR;
}
else
{
@@ -4767,15 +3917,19 @@ create_sp_error:
follow the restrictions that log-bin-trust-function-creators=0
already puts on CREATE FUNCTION.
*/
- if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
- /* Conditionally writes to binlog */
- result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
- else
- /* Conditionally writes to binlog */
- result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
+ /* Conditionally writes to binlog */
+
+ int type= lex->sql_command == SQLCOM_ALTER_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE :
+ TYPE_ENUM_FUNCTION;
+
+ sp_result= sp_update_routine(thd,
+ type,
+ lex->spname,
+ &lex->sp_chistics);
}
}
- switch (result)
+ switch (sp_result)
{
case SP_OK:
send_ok(thd);
@@ -4794,13 +3948,13 @@ create_sp_error:
case SQLCOM_DROP_PROCEDURE:
case SQLCOM_DROP_FUNCTION:
{
- int result;
+ int sp_result;
int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
- result= sp_routine_exists_in_table(thd, type, lex->spname);
+ sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
mysql_reset_errors(thd, 0);
- if (result == SP_OK)
+ if (sp_result == SP_OK)
{
char *db= lex->spname->m_db.str;
char *name= lex->spname->m_name.str;
@@ -4821,12 +3975,13 @@ create_sp_error:
ER(ER_PROC_AUTO_REVOKE_FAIL));
}
#endif
- if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
- /* Conditionally writes to binlog */
- result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
- else
- /* Conditionally writes to binlog */
- result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
+ /* Conditionally writes to binlog */
+
+ int type= lex->sql_command == SQLCOM_DROP_PROCEDURE ?
+ TYPE_ENUM_PROCEDURE :
+ TYPE_ENUM_FUNCTION;
+
+ sp_result= sp_drop_routine(thd, type, lex->spname);
}
else
{
@@ -4840,7 +3995,6 @@ create_sp_error:
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
goto error;
- /* Does NOT write to binlog */
if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
{
send_ok(thd);
@@ -4850,16 +4004,15 @@ create_sp_error:
}
#endif
if (lex->spname->m_db.str)
- result= SP_KEY_NOT_FOUND;
+ sp_result= SP_KEY_NOT_FOUND;
else
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
goto error;
}
}
- res= result;
- switch (result)
- {
+ res= sp_result;
+ switch (sp_result) {
case SP_OK:
send_ok(thd);
break;
@@ -4885,13 +4038,8 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_PROC:
{
- if (lex->spname->m_name.length > NAME_LEN)
+ if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
- goto error;
- }
- if (sp_show_create_procedure(thd, lex->spname) != SP_OK)
- { /* We don't distinguish between errors for now */
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
SP_COM_STRING(lex), lex->spname->m_name.str);
goto error;
@@ -4900,13 +4048,8 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_FUNC:
{
- if (lex->spname->m_name.length > NAME_LEN)
+ if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
- goto error;
- }
- if (sp_show_create_function(thd, lex->spname) != SP_OK)
- { /* We don't distinguish between errors for now */
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
SP_COM_STRING(lex), lex->spname->m_name.str);
goto error;
@@ -4916,14 +4059,14 @@ create_sp_error:
#ifdef NOT_USED
case SQLCOM_SHOW_STATUS_PROC:
{
- res= sp_show_status_procedure(thd, (lex->wild ?
- lex->wild->ptr() : NullS));
+ res= sp_show_status_routine(thd, TYPE_ENUM_PROCEDURE,
+ (lex->wild ? lex->wild->ptr() : NullS));
break;
}
case SQLCOM_SHOW_STATUS_FUNC:
{
- res= sp_show_status_function(thd, (lex->wild ?
- lex->wild->ptr() : NullS));
+ res= sp_show_status_routine(thd, TYPE_ENUM_FUNCTION,
+ (lex->wild ? lex->wild->ptr() : NullS));
break;
}
#endif
@@ -4933,11 +4076,6 @@ create_sp_error:
{
sp_head *sp;
- if (lex->spname->m_name.length > NAME_LEN)
- {
- my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
- goto error;
- }
if (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname,
&thd->sp_proc_cache, FALSE);
@@ -4979,9 +4117,6 @@ create_sp_error:
/* Conditionally writes to binlog. */
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
- /* We don't care about trigger body after this point */
- delete lex->sphead;
- lex->sphead= 0;
break;
}
case SQLCOM_DROP_TRIGGER:
@@ -5031,9 +4166,8 @@ create_sp_error:
thd->transaction.xid_state.xa_state=XA_ACTIVE;
thd->transaction.xid_state.xid.set(thd->lex->xid);
xid_cache_insert(&thd->transaction.xid_state);
- thd->options= ((thd->options & ~(OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG)) |
- OPTION_BEGIN);
+ thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
+ thd->no_trans_update.all= FALSE;
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
break;
@@ -5126,8 +4260,8 @@ create_sp_error:
xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5157,8 +4291,8 @@ create_sp_error:
my_error(ER_XAER_RMERR, MYF(0));
else
send_ok(thd);
- thd->options&= ~(OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE |
- OPTION_KEEP_LOG);
+ thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5190,6 +4324,70 @@ create_sp_error:
#endif /* EMBEDDED_LIBRARY */
break;
}
+ case SQLCOM_CREATE_SERVER:
+ {
+ int error;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((error= create_server(thd, &lex->server_options)))
+ {
+ DBUG_PRINT("info", ("problem creating server <%s>",
+ lex->server_options.server_name));
+ my_error(error, MYF(0), lex->server_options.server_name);
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
+ case SQLCOM_ALTER_SERVER:
+ {
+ int error;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((error= alter_server(thd, &lex->server_options)))
+ {
+ DBUG_PRINT("info", ("problem altering server <%s>",
+ lex->server_options.server_name));
+ my_error(error, MYF(0), lex->server_options.server_name);
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
+ case SQLCOM_DROP_SERVER:
+ {
+ int err_code;
+ LEX *lex= thd->lex;
+ DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
+
+ if (check_global_access(thd, SUPER_ACL))
+ break;
+
+ if ((err_code= drop_server(thd, &lex->server_options)))
+ {
+ if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
+ {
+ DBUG_PRINT("info", ("problem dropping server %s",
+ lex->server_options.server_name));
+ my_error(err_code, MYF(0), lex->server_options.server_name);
+ }
+ else
+ {
+ send_ok(thd, 0);
+ }
+ break;
+ }
+ send_ok(thd, 1);
+ break;
+ }
default:
#ifndef EMBEDDED_LIBRARY
DBUG_ASSERT(0); /* Impossible */
@@ -5301,6 +4499,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
thd Thread handler
privilege requested privilege
all_tables global table list of query
+ no_errors FALSE/TRUE - report/don't report error to
+ the client (using my_error() call).
RETURN
0 - OK
@@ -5308,7 +4508,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
*/
bool check_single_table_access(THD *thd, ulong privilege,
- TABLE_LIST *all_tables)
+ TABLE_LIST *all_tables, bool no_errors)
{
Security_context * backup_ctx= thd->security_ctx;
@@ -5324,12 +4524,14 @@ bool check_single_table_access(THD *thd, ulong privilege,
db_name= all_tables->db;
if (check_access(thd, privilege, db_name,
- &all_tables->grant.privilege, 0, 0,
+ &all_tables->grant.privilege, 0, no_errors,
test(all_tables->schema_table)))
goto deny;
/* Show only 1 table for check_grant */
- if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
+ if (!(all_tables->belong_to_view &&
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
+ check_grant(thd, privilege, all_tables, 0, 1, no_errors))
goto deny;
thd->security_ctx= backup_ctx;
@@ -5357,7 +4559,7 @@ deny:
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
{
- if (check_single_table_access (thd,privilege,all_tables))
+ if (check_single_table_access (thd,privilege,all_tables, FALSE))
return 1;
/* Check rights on tables of subselects and implictly opened tables */
@@ -5370,7 +4572,7 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables)
*/
if (view && subselects_tables->belong_to_view == view)
{
- if (check_single_table_access (thd, privilege, subselects_tables))
+ if (check_single_table_access (thd, privilege, subselects_tables, FALSE))
return 1;
subselects_tables= subselects_tables->next_global;
}
@@ -5430,7 +4632,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (schema_db)
{
- if (want_access & ~(SELECT_ACL | EXTRA_ACL))
+ if (!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL) ||
+ (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
{
if (!no_errors)
{
@@ -5494,9 +4697,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
db_access, want_access));
db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
- /* grant_option is set if there exists a single table or column grant */
if (db_access == want_access ||
- (grant_option && !dont_check_global_grants &&
+ (!dont_check_global_grants &&
!(want_access & ~(db_access | TABLE_ACLS | PROC_ACLS))))
DBUG_RETURN(FALSE); /* Ok */
@@ -5546,6 +4748,65 @@ bool check_global_access(THD *thd, ulong want_access)
}
+static bool check_show_access(THD *thd, TABLE_LIST *table)
+{
+ switch (get_schema_table_idx(table->schema_table)) {
+ case SCH_SCHEMATA:
+ return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
+ check_global_access(thd, SHOW_DB_ACL);
+
+ case SCH_TABLE_NAMES:
+ case SCH_TABLES:
+ case SCH_VIEWS:
+ case SCH_TRIGGERS:
+ case SCH_EVENTS:
+ {
+ const char *dst_db_name= table->schema_select_lex->db;
+
+ DBUG_ASSERT(dst_db_name);
+
+ if (check_access(thd, SELECT_ACL, dst_db_name,
+ &thd->col_access, FALSE, FALSE,
+ is_schema_db(dst_db_name)))
+ return TRUE;
+
+ if (!thd->col_access && check_grant_db(thd, dst_db_name))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host,
+ dst_db_name);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ case SCH_COLUMNS:
+ case SCH_STATISTICS:
+ {
+ TABLE_LIST *dst_table;
+ dst_table= (TABLE_LIST *) table->schema_select_lex->table_list.first;
+
+ DBUG_ASSERT(dst_table);
+
+ if (check_access(thd, SELECT_ACL | EXTRA_ACL,
+ dst_table->db,
+ &dst_table->grant.privilege,
+ FALSE, FALSE,
+ test(dst_table->schema_table)))
+ return FALSE;
+
+ return (check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE));
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
/*
Check the privilege for all used tables.
@@ -5573,9 +4834,9 @@ bool
check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
bool no_errors)
{
- uint found=0;
- ulong found_access=0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
TABLE_LIST *org_tables= tables;
+#endif
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx;
/*
@@ -5596,7 +4857,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
- information_schema_name.str);
+ INFORMATION_SCHEMA_NAME.str);
return TRUE;
}
/*
@@ -5604,10 +4865,17 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
Remove SHOW_VIEW_ACL, because it will be checked during making view
*/
tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
- if (tables->derived || tables->schema_table ||
- (tables->table && (int)tables->table->s->tmp_table) ||
- my_tz_check_n_skip_implicit_tables(&tables,
- thd->lex->time_zone_tables_used))
+
+ if (tables->schema_table_reformed)
+ {
+ if (check_show_access(thd, tables))
+ goto deny;
+
+ continue;
+ }
+
+ if (tables->derived ||
+ (tables->table && (int)tables->table->s->tmp_table))
continue;
thd->security_ctx= sctx;
if ((sctx->master_access & want_access) ==
@@ -5616,26 +4884,17 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
tables->grant.privilege= want_access;
else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
{
- if (found && !grant_option) // db already checked
- tables->grant.privilege=found_access;
- else
- {
- if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
- goto deny; // Access denied
- found_access=tables->grant.privilege;
- found=1;
- }
+ goto deny; // Access denied
}
else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table)))
goto deny;
}
thd->security_ctx= backup_ctx;
- if (grant_option)
- return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
+ return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
test(want_access & EXTRA_ACL), UINT_MAX, no_errors);
- return FALSE;
deny:
thd->security_ctx= backup_ctx;
return TRUE;
@@ -5665,11 +4924,10 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
return TRUE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (grant_option)
return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
-#endif
-
+#else
return FALSE;
+#endif
}
@@ -5731,7 +4989,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) &&
- !grant_option || !check_grant(thd, access, table, 0, 1, 1))
+ !check_grant(thd, access, table, 0, 1, 1))
DBUG_RETURN(0);
}
}
@@ -5782,7 +5040,7 @@ long max_stack_used;
- Passing to check_stack_overrun() prevents the compiler from removing it.
*/
bool check_stack_overrun(THD *thd, long margin,
- char *buf __attribute__((unused)))
+ uchar *buf __attribute__((unused)))
{
long stack_used;
DBUG_ASSERT(thd == current_thd);
@@ -5814,19 +5072,19 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
if (!lex->yacc_yyvs)
old_info= *yystacksize;
*yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
- if (!(lex->yacc_yyvs= (char*)
- my_realloc((gptr) lex->yacc_yyvs,
+ if (!(lex->yacc_yyvs= (uchar*)
+ my_realloc(lex->yacc_yyvs,
*yystacksize*sizeof(**yyvs),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
- !(lex->yacc_yyss= (char*)
- my_realloc((gptr) lex->yacc_yyss,
+ !(lex->yacc_yyss= (uchar*)
+ my_realloc(lex->yacc_yyss,
*yystacksize*sizeof(**yyss),
MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
return 1;
if (old_info)
{ // Copy old info from stack
- memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss));
- memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs));
+ memcpy(lex->yacc_yyss, (uchar*) *yyss, old_info*sizeof(**yyss));
+ memcpy(lex->yacc_yyvs, (uchar*) *yyvs, old_info*sizeof(**yyvs));
}
*yyss=(short*) lex->yacc_yyss;
*yyvs=(YYSTYPE*) lex->yacc_yyvs;
@@ -5834,20 +5092,6 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
}
-/****************************************************************************
- Initialize global thd variables needed for query
-****************************************************************************/
-
-void
-mysql_init_query(THD *thd, uchar *buf, uint length)
-{
- DBUG_ENTER("mysql_init_query");
- lex_start(thd, buf, length);
- mysql_reset_thd_for_next_command(thd);
- DBUG_VOID_RETURN;
-}
-
-
/*
Reset THD part responsible for command processing state.
@@ -5886,8 +5130,10 @@ void mysql_reset_thd_for_next_command(THD *thd)
in ha_rollback_trans() about some tables couldn't be rolled back.
*/
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
- thd->options&= ~(OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG);
-
+ {
+ thd->options&= ~OPTION_KEEP_LOG;
+ thd->no_trans_update.all= FALSE;
+ }
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->tmp_table_used= 0;
if (!thd->in_sub_stmt)
@@ -6051,26 +5297,61 @@ void mysql_init_multi_delete(LEX *lex)
lex->query_tables_last= &lex->query_tables;
}
+
/*
When you modify mysql_parse(), you may need to mofify
mysql_test_parse_for_slave() in this same file.
*/
-void mysql_parse(THD *thd, char *inBuf, uint length)
+/**
+ Parse a query.
+ @param thd Current thread
+ @param inBuf Begining of the query text
+ @param length Length of the query text
+ @param [out] semicolon For multi queries, position of the character of
+ the next query in the query text.
+*/
+
+void mysql_parse(THD *thd, const char *inBuf, uint length,
+ const char ** found_semicolon)
{
DBUG_ENTER("mysql_parse");
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
- mysql_init_query(thd, (uchar*) inBuf, length);
- if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
+ /*
+ Warning.
+ The purpose of query_cache_send_result_to_client() is to lookup the
+ query in the query cache first, to avoid parsing and executing it.
+ So, the natural implementation would be to:
+ - first, call query_cache_send_result_to_client,
+ - second, if caching failed, initialise the lexical and syntactic parser.
+ The problem is that the query cache depends on a clean initialization
+ of (among others) lex->safe_to_cache_query and thd->server_status,
+ which are reset respectively in
+ - lex_start()
+ - mysql_reset_thd_for_next_command()
+ So, initializing the lexical analyser *before* using the query cache
+ is required for the cache to work properly.
+ FIXME: cleanup the dependencies in the code to simplify this.
+ */
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
+
+ if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0)
{
LEX *lex= thd->lex;
-
+
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
-
- if (!MYSQLparse((void *)thd) && ! thd->is_fatal_error)
+
+ Lex_input_stream lip(thd, inBuf, length);
+ thd->m_lip= &lip;
+
+ int err= MYSQLparse(thd);
+ *found_semicolon= lip.found_semicolon;
+
+ if (!err && ! thd->is_fatal_error)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect &&
@@ -6081,12 +5362,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
else
#endif
{
- if (thd->net.report_error)
- {
- delete lex->sphead;
- lex->sphead= NULL;
- }
- else
+ if (! thd->net.report_error)
{
/*
Binlog logs a string starting from thd->query and having length
@@ -6098,15 +5374,14 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (lex->found_semicolon &&
- (thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
+ if (lip.found_semicolon &&
+ (thd->query_length= (ulong)(lip.found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
mysql_execute_command(thd);
query_cache_end_of_result(thd);
}
}
- lex->unit.cleanup();
}
else
{
@@ -6114,24 +5389,25 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
- /*
- The first thing we do after parse error is freeing sp_head to
- ensure that we have restored original memroot.
- */
- if (lex->sphead)
- {
- /* Clean up after failed stored procedure/function */
- delete lex->sphead;
- lex->sphead= NULL;
- }
query_cache_abort(&thd->net);
- lex->unit.cleanup();
}
+ if (thd->lex->sphead)
+ {
+ delete thd->lex->sphead;
+ thd->lex->sphead= 0;
+ }
+ lex->unit.cleanup();
thd->proc_info="freeing items";
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
}
+ else
+ {
+ /* There are no multi queries in the cache. */
+ *found_semicolon= NULL;
+ }
+
DBUG_VOID_RETURN;
}
@@ -6152,8 +5428,13 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
bool error= 0;
DBUG_ENTER("mysql_test_parse_for_slave");
- mysql_init_query(thd, (uchar*) inBuf, length);
- if (!MYSQLparse((void*) thd) && ! thd->is_fatal_error &&
+ Lex_input_stream lip(thd, inBuf, length);
+ thd->m_lip= &lip;
+ lex_start(thd);
+ mysql_reset_thd_for_next_command(thd);
+ int err= MYSQLparse((void*) thd);
+
+ if (!err && ! thd->is_fatal_error &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
@@ -6169,7 +5450,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
** Return 0 if ok
******************************************************************************/
-bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
+bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
@@ -6182,25 +5463,30 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
LEX *lex= thd->lex;
DBUG_ENTER("add_field_to_list");
- if (strlen(field_name) > NAME_LEN)
+ if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), field_name); /* purecov: inspected */
+ my_error(ER_TOO_LONG_IDENT, MYF(0), field_name->str); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
{
- lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::PRIMARY, NullS,
- &default_key_create_info,
- 0, lex->col_list));
+ Key *key;
+ lex->col_list.push_back(new key_part_spec(field_name->str, 0));
+ key= new Key(Key::PRIMARY, NullS,
+ &default_key_create_info,
+ 0, lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
- lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::UNIQUE, NullS,
- &default_key_create_info, 0,
- lex->col_list));
+ Key *key;
+ lex->col_list.push_back(new key_part_spec(field_name->str, 0));
+ key= new Key(Key::UNIQUE, NullS,
+ &default_key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
@@ -6215,9 +5501,9 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
*/
if (default_value->type() == Item::FUNC_ITEM &&
!(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
- type == FIELD_TYPE_TIMESTAMP))
+ type == MYSQL_TYPE_TIMESTAMP))
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
else if (default_value->type() == Item::NULL_ITEM)
@@ -6226,24 +5512,24 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
else if (type_modifier & AUTO_INCREMENT_FLAG)
{
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
+ my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
}
}
- if (on_update_value && type != FIELD_TYPE_TIMESTAMP)
+ if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
{
- my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
+ my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
DBUG_RETURN(1);
}
- if (type == FIELD_TYPE_TIMESTAMP && length)
+ if (type == MYSQL_TYPE_TIMESTAMP && length)
{
/* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1.
In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4),
@@ -6255,12 +5541,12 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
}
if (!(new_field= new create_field()) ||
- new_field->init(thd, field_name, type, length, decimals, type_modifier,
+ new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
interval_list, cs, uint_geom_type))
DBUG_RETURN(1);
- lex->create_list.push_back(new_field);
+ lex->alter_info.create_list.push_back(new_field);
lex->last_field=new_field;
DBUG_RETURN(0);
}
@@ -6285,7 +5571,7 @@ add_proc_to_list(THD* thd, Item *item)
*item_ptr= item;
order->item=item_ptr;
order->free_me=0;
- thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
+ thd->lex->proc_list.link_in_list((uchar*) order,(uchar**) &order->next);
return 0;
}
@@ -6307,7 +5593,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
order->free_me=0;
order->used=0;
order->counter_used= 0;
- list.link_in_list((byte*) order,(byte**) &order->next);
+ list.link_in_list((uchar*) order,(uchar**) &order->next);
DBUG_RETURN(0);
}
@@ -6337,8 +5623,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
- List<String> *use_index_arg,
- List<String> *ignore_index_arg,
+ List<index_hint> *index_hints_arg,
LEX_STRING *option)
{
register TABLE_LIST *ptr;
@@ -6373,7 +5658,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
DBUG_RETURN(0);
}
- if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
+ if (!(alias_str= (char*) thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
}
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
@@ -6397,7 +5682,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
@@ -6405,7 +5690,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0))
{
my_error(ER_UNKNOWN_TABLE, MYF(0),
- ptr->table_name, information_schema_name.str);
+ ptr->table_name, INFORMATION_SCHEMA_NAME.str);
DBUG_RETURN(0);
}
ptr->schema_table_name= ptr->table_name;
@@ -6413,12 +5698,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
ptr->select_lex= lex->current_select;
ptr->cacheable_table= 1;
- if (use_index_arg)
- ptr->use_index=(List<String> *) thd->memdup((gptr) use_index_arg,
- sizeof(*use_index_arg));
- if (ignore_index_arg)
- ptr->ignore_index=(List<String> *) thd->memdup((gptr) ignore_index_arg,
- sizeof(*ignore_index_arg));
+ ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
if (lock_type != TL_IGNORE)
@@ -6465,7 +5745,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
previous table reference to 'ptr'. Here we also add one element to the
list 'table_list'.
*/
- table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
+ table_list.link_in_list((uchar*) ptr, (uchar**) &ptr->next_local);
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
@@ -6504,11 +5784,12 @@ bool st_select_lex::init_nested_join(THD *thd)
sizeof(NESTED_JOIN))))
DBUG_RETURN(1);
nested_join= ptr->nested_join=
- ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+ ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
join_list->push_front(ptr);
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nested_join)";
embedding= ptr;
join_list= &nested_join->join_list;
join_list->empty();
@@ -6589,10 +5870,11 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
sizeof(NESTED_JOIN))))
DBUG_RETURN(0);
nested_join= ptr->nested_join=
- ((NESTED_JOIN*) ((byte*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
+ ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
ptr->embedding= embedding;
ptr->join_list= join_list;
+ ptr->alias= (char*) "(nest_last_join)";
embedded_list= &nested_join->join_list;
embedded_list->empty();
@@ -6609,11 +5891,8 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
If this is a JOIN ... USING, move the list of joined fields to the
table reference that describes the join.
*/
- if (table->join_using_fields)
- {
- ptr->join_using_fields= table->join_using_fields;
- table->join_using_fields= NULL;
- }
+ if (prev_join_using)
+ ptr->join_using_fields= prev_join_using;
}
}
join_list->push_front(ptr);
@@ -6749,18 +6028,18 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
0 on success
*/
-bool st_select_lex_unit::add_fake_select_lex(THD *thd)
+bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
{
SELECT_LEX *first_sl= first_select();
DBUG_ENTER("add_fake_select_lex");
DBUG_ASSERT(!fake_select_lex);
- if (!(fake_select_lex= new (thd->mem_root) SELECT_LEX()))
+ if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
fake_select_lex->include_standalone(this,
(SELECT_LEX_NODE**)&fake_select_lex);
fake_select_lex->select_number= INT_MAX;
- fake_select_lex->parent_lex= thd->lex; /* Used in init_query. */
+ fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
fake_select_lex->make_empty_select();
fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
fake_select_lex->select_limit= 0;
@@ -6770,7 +6049,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd)
fake_select_lex->context.resolve_in_select_list= TRUE;
fake_select_lex->context.select_lex= fake_select_lex;
- if (!first_sl->next_select())
+ if (!is_union())
{
/*
This works only for
@@ -6780,9 +6059,9 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd)
*/
global_parameters= fake_select_lex;
fake_select_lex->no_table_names_allowed= 1;
- thd->lex->current_select= fake_select_lex;
+ thd_arg->lex->current_select= fake_select_lex;
}
- thd->lex->pop_context();
+ thd_arg->lex->pop_context();
DBUG_RETURN(0);
}
@@ -6869,6 +6148,7 @@ void add_join_on(TABLE_LIST *b, Item *expr)
a Left join argument
b Right join argument
using_fields Field names from USING clause
+ lex The current st_select_lex
IMPLEMENTATION
This function marks that table b should be joined with a either via
@@ -6897,10 +6177,11 @@ void add_join_on(TABLE_LIST *b, Item *expr)
None
*/
-void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields)
+void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
+ SELECT_LEX *lex)
{
b->natural_join= a;
- b->join_using_fields= using_fields;
+ lex->prev_join_using= using_fields;
}
@@ -7088,7 +6369,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
#endif
if (options & REFRESH_USER_RESOURCES)
- reset_mqh((LEX_USER *) NULL);
+ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
return result;
}
@@ -7182,7 +6463,7 @@ bool append_file_to_dir(THD *thd, const char **filename_ptr,
/* Fix is using unix filename format on dos */
strmov(buff,*filename_ptr);
end=convert_dirname(buff, *filename_ptr, NullS);
- if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
+ if (!(ptr= (char*) thd->alloc((size_t) (end-buff) + strlen(table_name)+1)))
return 1; // End of memory
*filename_ptr=ptr;
strxmov(ptr,buff,table_name,NullS);
@@ -7208,8 +6489,9 @@ bool check_simple_select()
if (lex->current_select != &lex->select_lex)
{
char command[80];
- strmake(command, lex->yylval->symbol.str,
- min(lex->yylval->symbol.length, sizeof(command)-1));
+ Lex_input_stream *lip= thd->m_lip;
+ strmake(command, lip->yylval->symbol.str,
+ min(lip->yylval->symbol.length, sizeof(command)-1));
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
return 1;
}
@@ -7287,53 +6569,6 @@ Item * all_any_subquery_creator(Item *left_expr,
/*
- CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
- the proper arguments. This isn't very fast but it should work for most
- cases.
-
- In the future ALTER TABLE will notice that only added indexes
- and create these one by one for the existing table without having to do
- a full rebuild.
-
- One should normally create all indexes with CREATE TABLE or ALTER TABLE.
-*/
-
-bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
-{
- List<create_field> fields;
- ALTER_INFO alter_info;
- alter_info.flags= ALTER_ADD_INDEX;
- HA_CREATE_INFO create_info;
- DBUG_ENTER("mysql_create_index");
- bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= 0;
- create_info.default_table_charset= thd->variables.collation_database;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
- &create_info, table_list,
- fields, keys, 0, (ORDER*)0,
- 0, &alter_info, 1));
-}
-
-
-bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
-{
- List<create_field> fields;
- List<Key> keys;
- HA_CREATE_INFO create_info;
- DBUG_ENTER("mysql_drop_index");
- bzero((char*) &create_info,sizeof(create_info));
- create_info.db_type= 0;
- create_info.default_table_charset= thd->variables.collation_database;
- alter_info->clear();
- alter_info->flags= ALTER_DROP_INDEX;
- DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->table_name,
- &create_info, table_list,
- fields, keys, 0, (ORDER*)0,
- 0, alter_info, 1));
-}
-
-
-/*
Multi update query pre-check
SYNOPSIS
@@ -7370,12 +6605,11 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
else if ((check_access(thd, UPDATE_ACL, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) ||
- grant_option &&
check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) &&
(check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
+ check_grant(thd, SELECT_ACL, table, 0, 1, 0)))
DBUG_RETURN(TRUE);
table->table_in_first_from_clause= 1;
@@ -7383,19 +6617,17 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
/*
Is there tables of subqueries?
*/
- if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
+ if (&lex->select_lex != lex->all_selects_list)
{
DBUG_PRINT("info",("Checking sub query list"));
for (table= tables; table; table= table->next_global)
{
- if (!my_tz_check_n_skip_implicit_tables(&table,
- lex->time_zone_tables_used) &&
- !table->table_in_first_from_clause)
+ if (!table->table_in_first_from_clause)
{
if (check_access(thd, SELECT_ACL, table->db,
&table->grant.privilege, 0, 0,
test(table->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))
+ check_grant(thd, SELECT_ACL, table, 0, 1, 0))
DBUG_RETURN(TRUE);
}
}
@@ -7602,6 +6834,25 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
}
+/**
+ @brief Check privileges for SHOW CREATE TABLE statement.
+
+ @param thd Thread context
+ @param table Target table
+
+ @retval TRUE Failure
+ @retval FALSE Success
+*/
+
+static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
+{
+ return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
+ &table->grant.privilege, 0, 0,
+ test(table->schema_table)) ||
+ check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
+}
+
+
/*
CREATE TABLE query pre-check
@@ -7627,7 +6878,6 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL);
- lex->create_info.alias= create_table->alias;
if (check_access(thd, want_priv, create_table->db,
&create_table->grant.privilege, 0, 0,
test(create_table->schema_table)) ||
@@ -7635,7 +6885,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto err;
- if (grant_option && want_priv != CREATE_TMP_ACL &&
+ if (want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table, 0, 1, 0))
goto err;
@@ -7667,6 +6917,11 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
goto err;
}
+ else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+ {
+ if (check_show_create_table_access(thd, tables))
+ goto err;
+ }
error= FALSE;
err:
@@ -7812,26 +7067,62 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user)
/*
- Check that length of a string does not exceed some limit.
+ Check that byte length of a string does not exceed some limit.
SYNOPSIS
- check_string_length()
- str string to be checked
- err_msg error message to be displayed if the string is too long
- max_length max length
+ check_string_byte_length()
+ str string to be checked
+ err_msg error message to be displayed if the string is too long
+ max_byte_length max length in bytes
RETURN
FALSE the passed string is not longer than max_length
TRUE the passed string is longer than max_length
+
+ NOTE
+ The function is not used in existing code but can be useful later?
*/
-bool check_string_length(LEX_STRING *str, const char *err_msg,
- uint max_length)
+bool check_string_byte_length(LEX_STRING *str, const char *err_msg,
+ uint max_byte_length)
{
- if (str->length <= max_length)
+ if (str->length <= max_byte_length)
return FALSE;
- my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_byte_length);
+
+ return TRUE;
+}
+
+
+/*
+ Check that char length of a string does not exceed some limit.
+
+ SYNOPSIS
+ check_string_char_length()
+ str string to be checked
+ err_msg error message to be displayed if the string is too long
+ max_char_length max length in symbols
+ cs string charset
+
+ RETURN
+ FALSE the passed string is not longer than max_char_length
+ TRUE the passed string is longer than max_char_length
+*/
+
+
+bool check_string_char_length(LEX_STRING *str, const char *err_msg,
+ uint max_char_length, CHARSET_INFO *cs,
+ bool no_error)
+{
+ int well_formed_error;
+ uint res= cs->cset->well_formed_len(cs, str->str, str->str + str->length,
+ max_char_length, &well_formed_error);
+
+ if (!well_formed_error && str->length == res)
+ return FALSE;
+ if (!no_error)
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
return TRUE;
}
diff --git a/sql/sql_parse.cc.rej b/sql/sql_parse.cc.rej
deleted file mode 100644
index 6e2bd03867d..00000000000
--- a/sql/sql_parse.cc.rej
+++ /dev/null
@@ -1,166 +0,0 @@
-***************
-*** 67,109 ****
- static void decrease_user_connections(USER_CONN *uc);
- #endif /* NO_EMBEDDED_ACCESS_CHECKS */
- static bool check_multi_update_lock(THD *thd);
-- static void remove_escape(char *name);
- static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
-
- const char *any_db="*any*"; // Special symbol for check_access
-
-! LEX_STRING command_name[]={
-! (char *)STRING_WITH_LEN("Sleep"),
-! (char *)STRING_WITH_LEN("Quit"),
-! (char *)STRING_WITH_LEN("Init DB"),
-! (char *)STRING_WITH_LEN("Query"),
-! (char *)STRING_WITH_LEN("Field List"),
-! (char *)STRING_WITH_LEN("Create DB"),
-! (char *)STRING_WITH_LEN("Drop DB"),
-! (char *)STRING_WITH_LEN("Refresh"),
-! (char *)STRING_WITH_LEN("Shutdown"),
-! (char *)STRING_WITH_LEN("Statistics"),
-! (char *)STRING_WITH_LEN("Processlist"),
-! (char *)STRING_WITH_LEN("Connect"),
-! (char *)STRING_WITH_LEN("Kill"),
-! (char *)STRING_WITH_LEN("Debug"),
-! (char *)STRING_WITH_LEN("Ping"),
-! (char *)STRING_WITH_LEN("Time"),
-! (char *)STRING_WITH_LEN("Delayed insert"),
-! (char *)STRING_WITH_LEN("Change user"),
-! (char *)STRING_WITH_LEN("Binlog Dump"),
-! (char *)STRING_WITH_LEN("Table Dump"),
-! (char *)STRING_WITH_LEN("Connect Out"),
-! (char *)STRING_WITH_LEN("Register Slave"),
-! (char *)STRING_WITH_LEN("Prepare"),
-! (char *)STRING_WITH_LEN("Execute"),
-! (char *)STRING_WITH_LEN("Long Data"),
-! (char *)STRING_WITH_LEN("Close stmt"),
-! (char *)STRING_WITH_LEN("Reset stmt"),
-! (char *)STRING_WITH_LEN("Set option"),
-! (char *)STRING_WITH_LEN("Fetch"),
-! (char *)STRING_WITH_LEN("Daemon"),
-! (char *)STRING_WITH_LEN("Error") // Last command number
- };
-
- const char *xa_state_names[]={
---- 67,108 ----
- static void decrease_user_connections(USER_CONN *uc);
- #endif /* NO_EMBEDDED_ACCESS_CHECKS */
- static bool check_multi_update_lock(THD *thd);
- static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
-
- const char *any_db="*any*"; // Special symbol for check_access
-
-! const LEX_STRING command_name[]={
-! C_STRING_WITH_LEN("Sleep"),
-! C_STRING_WITH_LEN("Quit"),
-! C_STRING_WITH_LEN("Init DB"),
-! C_STRING_WITH_LEN("Query"),
-! C_STRING_WITH_LEN("Field List"),
-! C_STRING_WITH_LEN("Create DB"),
-! C_STRING_WITH_LEN("Drop DB"),
-! C_STRING_WITH_LEN("Refresh"),
-! C_STRING_WITH_LEN("Shutdown"),
-! C_STRING_WITH_LEN("Statistics"),
-! C_STRING_WITH_LEN("Processlist"),
-! C_STRING_WITH_LEN("Connect"),
-! C_STRING_WITH_LEN("Kill"),
-! C_STRING_WITH_LEN("Debug"),
-! C_STRING_WITH_LEN("Ping"),
-! C_STRING_WITH_LEN("Time"),
-! C_STRING_WITH_LEN("Delayed insert"),
-! C_STRING_WITH_LEN("Change user"),
-! C_STRING_WITH_LEN("Binlog Dump"),
-! C_STRING_WITH_LEN("Table Dump"),
-! C_STRING_WITH_LEN("Connect Out"),
-! C_STRING_WITH_LEN("Register Slave"),
-! C_STRING_WITH_LEN("Prepare"),
-! C_STRING_WITH_LEN("Execute"),
-! C_STRING_WITH_LEN("Long Data"),
-! C_STRING_WITH_LEN("Close stmt"),
-! C_STRING_WITH_LEN("Reset stmt"),
-! C_STRING_WITH_LEN("Set option"),
-! C_STRING_WITH_LEN("Fetch"),
-! C_STRING_WITH_LEN("Daemon"),
-! C_STRING_WITH_LEN("Error") // Last command number
- };
-
- const char *xa_state_names[]={
-***************
-*** 1738,1744 ****
- password. New clients send the size (1 byte) + string (not null
- terminated, so also '\0' for empty string).
- */
-! char db_buff[NAME_LEN+1]; // buffer to store db in utf8
- char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
---- 1736,1742 ----
- password. New clients send the size (1 byte) + string (not null
- terminated, so also '\0' for empty string).
- */
-! char db_buff[NAME_LEN+1]; // buffer to store db in utf8
- char *db= passwd;
- uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- *passwd++ : strlen(passwd);
-***************
-*** 2315,2321 ****
- DBUG_RETURN(1);
- }
- db= lex->select_lex.db;
-- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db);
---- 2312,2317 ----
- DBUG_RETURN(1);
- }
- db= lex->select_lex.db;
- if (check_db_name(db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db);
-***************
-*** 6310,6345 ****
- }
-
-
-- /* Fix escaping of _, % and \ in database and table names (for ODBC) */
--
-- static void remove_escape(char *name)
-- {
-- if (!*name) // For empty DB names
-- return;
-- char *to;
-- #ifdef USE_MB
-- char *strend=name+(uint) strlen(name);
-- #endif
-- for (to=name; *name ; name++)
-- {
-- #ifdef USE_MB
-- int l;
-- if (use_mb(system_charset_info) &&
-- (l = my_ismbchar(system_charset_info, name, strend)))
-- {
-- while (l--)
-- *to++ = *name++;
-- name--;
-- continue;
-- }
-- #endif
-- if (*name == '\\' && name[1])
-- name++; // Skip '\\'
-- *to++= *name;
-- }
-- *to=0;
-- }
--
- /****************************************************************************
- ** save order by and tables in own lists
- ****************************************************************************/
---- 6296,6301 ----
- }
-
-
- /****************************************************************************
- ** save order by and tables in own lists
- ****************************************************************************/
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index dcc35293b84..d47aacee924 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -124,47 +123,23 @@ uint32 get_partition_id_hash_sub(partition_info *part_info);
uint32 get_partition_id_key_sub(partition_info *part_info);
uint32 get_partition_id_linear_hash_sub(partition_info *part_info);
uint32 get_partition_id_linear_key_sub(partition_info *part_info);
-#endif
-
static uint32 get_next_partition_via_walking(PARTITION_ITERATOR*);
+static void set_up_range_analysis_info(partition_info *part_info);
static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR*);
+#endif
+
uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter);
uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter);
int get_part_iter_for_interval_via_mapping(partition_info *part_info,
bool is_subpart,
- char *min_value, char *max_value,
+ uchar *min_value, uchar *max_value,
uint flags,
PARTITION_ITERATOR *part_iter);
int get_part_iter_for_interval_via_walking(partition_info *part_info,
bool is_subpart,
- char *min_value, char *max_value,
+ uchar *min_value, uchar *max_value,
uint flags,
PARTITION_ITERATOR *part_iter);
-static void set_up_range_analysis_info(partition_info *part_info);
-
-/*
- A routine used by the parser to decide whether we are specifying a full
- partitioning or if only partitions to add or to split.
-
- SYNOPSIS
- is_partition_management()
- lex Reference to the lex object
-
- RETURN VALUE
- TRUE Yes, it is part of a management partition command
- FALSE No, not a management partition command
-
- DESCRIPTION
- This needs to be outside of WITH_PARTITION_STORAGE_ENGINE since it is
- used from the sql parser that doesn't have any #ifdef's
-*/
-
-my_bool is_partition_management(LEX *lex)
-{
- return (lex->sql_command == SQLCOM_ALTER_TABLE &&
- (lex->alter_info.flags == ALTER_ADD_PARTITION ||
- lex->alter_info.flags == ALTER_REORGANIZE_PARTITION));
-}
#ifdef WITH_PARTITION_STORAGE_ENGINE
/*
@@ -319,8 +294,8 @@ bool check_reorganise_list(partition_info *new_part_info,
> 0 Error code
*/
-int get_parts_for_update(const byte *old_data, byte *new_data,
- const byte *rec0, partition_info *part_info,
+int get_parts_for_update(const uchar *old_data, uchar *new_data,
+ const uchar *rec0, partition_info *part_info,
uint32 *old_part_id, uint32 *new_part_id,
longlong *new_func_value)
{
@@ -393,7 +368,7 @@ int get_parts_for_update(const byte *old_data, byte *new_data,
calculate the partition id.
*/
-int get_part_for_delete(const byte *buf, const byte *rec0,
+int get_part_for_delete(const uchar *buf, const uchar *rec0,
partition_info *part_info, uint32 *part_id)
{
int error;
@@ -785,9 +760,9 @@ static bool handle_list_of_fields(List_iterator<char> it,
}
else
{
- if (table->s->db_type->partition_flags &&
- (table->s->db_type->partition_flags() & HA_USE_AUTO_PARTITION) &&
- (table->s->db_type->partition_flags() & HA_CAN_PARTITION))
+ if (table->s->db_type()->partition_flags &&
+ (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
+ (table->s->db_type()->partition_flags() & HA_CAN_PARTITION))
{
/*
This engine can handle automatic partitioning and there is no
@@ -932,7 +907,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
context->table_list= &tables;
context->first_name_resolution_table= &tables;
context->last_name_resolution_table= NULL;
- func_expr->walk(&Item::change_context_processor, 0, (byte*) context);
+ func_expr->walk(&Item::change_context_processor, 0, (uchar*) context);
save_where= thd->where;
thd->where= "partition function";
/*
@@ -1665,8 +1640,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
goto end;
if (unlikely(check_primary_key(table)))
goto end;
- if (unlikely((!(table->s->db_type->partition_flags &&
- (table->s->db_type->partition_flags() & HA_CAN_PARTITION_UNIQUE))) &&
+ if (unlikely((!(table->s->db_type()->partition_flags &&
+ (table->s->db_type()->partition_flags() & HA_CAN_PARTITION_UNIQUE))) &&
check_unique_keys(table)))
goto end;
if (unlikely(set_up_partition_bitmap(thd, part_info)))
@@ -1698,7 +1673,7 @@ end:
static int add_write(File fptr, const char *buf, uint len)
{
- uint len_written= my_write(fptr, (const byte*)buf, len, MYF(0));
+ uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0));
if (likely(len == len_written))
return 0;
@@ -1873,7 +1848,7 @@ static int add_keyword_int(File fptr, const char *keyword, longlong num)
static int add_engine(File fptr, handlerton *engine_type)
{
- const char *engine_str= hton2plugin[engine_type->slot]->name.str;
+ const char *engine_str= ha_resolve_storage_engine_name(engine_type);
DBUG_PRINT("info", ("ENGINE: %s", engine_str));
int err= add_string(fptr, "ENGINE = ");
return err + add_string(fptr, engine_str);
@@ -1893,12 +1868,15 @@ static int add_partition_options(File fptr, partition_element *p_elem)
err+= add_keyword_int(fptr,"MAX_ROWS",(longlong)p_elem->part_max_rows);
if (p_elem->part_min_rows)
err+= add_keyword_int(fptr,"MIN_ROWS",(longlong)p_elem->part_min_rows);
- if (p_elem->data_file_name)
- err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE,
- p_elem->data_file_name);
- if (p_elem->index_file_name)
- err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE,
- p_elem->index_file_name);
+ if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
+ {
+ if (p_elem->data_file_name)
+ err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE,
+ p_elem->data_file_name);
+ if (p_elem->index_file_name)
+ err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE,
+ p_elem->index_file_name);
+ }
if (p_elem->part_comment)
err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment);
return err + add_engine(fptr,p_elem->engine_type);
@@ -2003,7 +1981,6 @@ char *generate_partition_syntax(partition_info *part_info,
{
uint i,j, tot_no_parts, no_subparts;
partition_element *part_elem;
- partition_element *save_part_elem= NULL;
ulonglong buffer_length;
char path[FN_REFLEN];
int err= 0;
@@ -2143,13 +2120,13 @@ char *generate_partition_syntax(partition_info *part_info,
goto close_file;
*buf_length= (uint)buffer_length;
if (use_sql_alloc)
- buf= sql_alloc(*buf_length+1);
+ buf= (char*) sql_alloc(*buf_length+1);
else
- buf= my_malloc(*buf_length+1, MYF(MY_WME));
+ buf= (char*) my_malloc(*buf_length+1, MYF(MY_WME));
if (!buf)
goto close_file;
- if (unlikely(my_read(fptr, (byte*)buf, *buf_length, MYF(MY_FNABP))))
+ if (unlikely(my_read(fptr, (uchar*)buf, *buf_length, MYF(MY_FNABP))))
{
if (!use_sql_alloc)
my_free(buf, MYF(0));
@@ -2187,8 +2164,8 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields)
if (!part_info)
DBUG_RETURN(FALSE);
- if (table->s->db_type->partition_flags &&
- (table->s->db_type->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
+ if (table->s->db_type()->partition_flags &&
+ (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
DBUG_RETURN(FALSE);
for (fld= part_info->full_part_field_array; *fld; fld++)
if (bitmap_is_set(fields, (*fld)->field_index))
@@ -2412,8 +2389,8 @@ static uint32 get_part_id_linear_key(partition_info *part_info,
*/
static void copy_to_part_field_buffers(Field **ptr,
- char **field_bufs,
- char **restore_ptr)
+ uchar **field_bufs,
+ uchar **restore_ptr)
{
Field *field;
while ((field= *(ptr++)))
@@ -2424,7 +2401,7 @@ static void copy_to_part_field_buffers(Field **ptr,
{
CHARSET_INFO *cs= ((Field_str*)field)->charset();
uint len= field->pack_length();
- char *field_buf= *field_bufs;
+ uchar *field_buf= *field_bufs;
/*
We only use the field buffer for VARCHAR and CHAR strings
which isn't of a binary collation. We also only use the
@@ -2435,17 +2412,17 @@ static void copy_to_part_field_buffers(Field **ptr,
if (field->type() == MYSQL_TYPE_VARCHAR)
{
uint len_bytes= ((Field_varstring*)field)->length_bytes;
- my_strnxfrm(cs, (uchar*)(field_buf + len_bytes), (len - len_bytes),
- (uchar*)(field->ptr + len_bytes), field->field_length);
+ my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes),
+ field->ptr + len_bytes, field->field_length);
if (len_bytes == 1)
- *field_buf= (uchar)field->field_length;
+ *field_buf= (uchar) field->field_length;
else
int2store(field_buf, field->field_length);
}
else
{
- my_strnxfrm(cs, (uchar*)field_buf, len,
- (uchar*)field->ptr, field->field_length);
+ my_strnxfrm(cs, field_buf, len,
+ field->ptr, field->field_length);
}
field->ptr= field_buf;
}
@@ -2464,7 +2441,7 @@ static void copy_to_part_field_buffers(Field **ptr,
RETURN VALUES
*/
-static void restore_part_field_pointers(Field **ptr, char **restore_ptr)
+static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
{
Field *field;
while ((field= *(ptr++)))
@@ -3306,16 +3283,16 @@ static bool check_part_func_bound(Field **ptr)
get the partition identity and restore field pointers afterwards.
*/
-static uint32 get_sub_part_id_from_key(const TABLE *table,byte *buf,
+static uint32 get_sub_part_id_from_key(const TABLE *table,uchar *buf,
KEY *key_info,
const key_range *key_spec)
{
- byte *rec0= table->record[0];
+ uchar *rec0= table->record[0];
partition_info *part_info= table->part_info;
uint32 part_id;
DBUG_ENTER("get_sub_part_id_from_key");
- key_restore(buf, (byte*)key_spec->key, key_info, key_spec->length);
+ key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
part_id= part_info->get_subpartition_id(part_info);
else
@@ -3349,16 +3326,16 @@ static uint32 get_sub_part_id_from_key(const TABLE *table,byte *buf,
get the partition identity and restore field pointers afterwards.
*/
-bool get_part_id_from_key(const TABLE *table, byte *buf, KEY *key_info,
+bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
const key_range *key_spec, uint32 *part_id)
{
bool result;
- byte *rec0= table->record[0];
+ uchar *rec0= table->record[0];
partition_info *part_info= table->part_info;
longlong func_value;
DBUG_ENTER("get_part_id_from_key");
- key_restore(buf, (byte*)key_spec->key, key_info, key_spec->length);
+ key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
result= part_info->get_part_partition_id(part_info, part_id,
&func_value);
@@ -3394,18 +3371,18 @@ bool get_part_id_from_key(const TABLE *table, byte *buf, KEY *key_info,
get the partition identity and restore field pointers afterwards.
*/
-void get_full_part_id_from_key(const TABLE *table, byte *buf,
+void get_full_part_id_from_key(const TABLE *table, uchar *buf,
KEY *key_info,
const key_range *key_spec,
part_id_range *part_spec)
{
bool result;
partition_info *part_info= table->part_info;
- byte *rec0= table->record[0];
+ uchar *rec0= table->record[0];
longlong func_value;
DBUG_ENTER("get_full_part_id_from_key");
- key_restore(buf, (byte*)key_spec->key, key_info, key_spec->length);
+ key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
if (likely(rec0 == buf))
result= part_info->get_partition_id(part_info, &part_spec->start_part,
&func_value);
@@ -3493,7 +3470,7 @@ void prune_partition_set(const TABLE *table, part_id_range *part_spec)
RETURN VALUE
part_spec
*/
-void get_partition_set(const TABLE *table, byte *buf, const uint index,
+void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec, part_id_range *part_spec)
{
partition_info *part_info= table->part_info;
@@ -3702,9 +3679,9 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
possible to retrace this given an item tree.
*/
-bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
- uint part_info_len,
- uchar *part_state, uint part_state_len,
+bool mysql_unpack_partition(THD *thd,
+ const char *part_buf, uint part_info_len,
+ const char *part_state, uint part_state_len,
TABLE* table, bool is_create_table_ind,
handlerton *default_db_type)
{
@@ -3717,7 +3694,11 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
thd->lex= &lex;
thd->variables.character_set_client= system_charset_info;
- lex_start(thd, part_buf, part_info_len);
+
+ Lex_input_stream lip(thd, part_buf, part_info_len);
+ thd->m_lip= &lip;
+
+ lex_start(thd);
/*
We need to use the current SELECT_LEX since I need to keep the
Name_resolution_context object which is referenced from the
@@ -3771,20 +3752,15 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
ha_legacy_type(default_db_type)));
if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
{
- if (old_lex->like_name)
+ if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
{
/*
- This code is executed when we do a CREATE TABLE t1 LIKE t2
- old_lex->like_name contains the t2 and the table we are opening has
- name t1.
+ This code is executed when we create table in CREATE TABLE t1 LIKE t2.
+ old_lex->query_tables contains table list element for t2 and the table
+ we are opening has name t1.
*/
- Table_ident *table_ident= old_lex->like_name;
- char *src_db= table_ident->db.str ? table_ident->db.str : thd->db;
- char *src_table= table_ident->table.str;
- char buf[FN_REFLEN];
- build_table_filename(buf, sizeof(buf), src_db, src_table, "", 0);
- if (partition_default_handling(table, part_info,
- FALSE, buf))
+ if (partition_default_handling(table, part_info, FALSE,
+ old_lex->query_tables->table->s->path.str))
{
result= TRUE;
goto end;
@@ -3830,9 +3806,9 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
char *part_func_string= NULL;
char *subpart_func_string= NULL;
if ((part_func_len &&
- !((part_func_string= thd->alloc(part_func_len)))) ||
+ !((part_func_string= (char*) thd->alloc(part_func_len)))) ||
(subpart_func_len &&
- !((subpart_func_string= thd->alloc(subpart_func_len)))))
+ !((subpart_func_string= (char*) thd->alloc(subpart_func_len)))))
{
mem_alloc_error(part_func_len);
thd->free_items();
@@ -4125,7 +4101,7 @@ error:
change patterns.
*/
-uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
+uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
HA_CREATE_INFO *create_info,
handlerton *old_db_type,
bool *partition_changed,
@@ -4203,8 +4179,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
alter_info->no_parts= curr_part_no - new_part_no;
}
}
- if (table->s->db_type->alter_table_flags &&
- (!(flags= table->s->db_type->alter_table_flags(alter_info->flags))))
+ if (table->s->db_type()->alter_table_flags &&
+ (!(flags= table->s->db_type()->alter_table_flags(alter_info->flags))))
{
my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
DBUG_RETURN(1);
@@ -4739,6 +4715,7 @@ state of p1.
}
alt_part_info->part_type= tab_part_info->part_type;
alt_part_info->subpart_type= tab_part_info->subpart_type;
+ alt_part_info->no_subparts= tab_part_info->no_subparts;
DBUG_ASSERT(!alt_part_info->use_default_partitions);
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
ULL(0),
@@ -4949,7 +4926,7 @@ the generated partition syntax in a correct manner.
create_info->db_type= table->part_info->default_engine_type;
}
DBUG_PRINT("info", ("New engine type: %s",
- hton2plugin[create_info->db_type->slot]->name.str));
+ ha_resolve_storage_engine_name(create_info->db_type)));
thd->work_part_info= NULL;
*partition_changed= TRUE;
}
@@ -5369,7 +5346,6 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
List_iterator<partition_element> temp_it(part_info->temp_partitions);
uint no_temp_partitions= part_info->temp_partitions.elements;
uint no_elements= part_info->partitions.elements;
- uint i= 0;
DBUG_ENTER("write_log_dropped_partitions");
ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
@@ -5742,7 +5718,6 @@ static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
bool dont_crash)
{
partition_info *part_info= lpt->part_info;
- uint count_loop= 0;
DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry;
DBUG_ENTER("write_log_completed");
@@ -5992,8 +5967,6 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
alter_info ALTER TABLE info
create_info Create info for CREATE TABLE
table_list List of the table involved
- create_list The fields in the resulting table
- key_list The keys in the resulting table
db Database name of new table
table_name Table name of new table
@@ -6007,17 +5980,14 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
*/
uint fast_alter_partition_table(THD *thd, TABLE *table,
- ALTER_INFO *alter_info,
+ Alter_info *alter_info,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
- List<create_field> *create_list,
- List<Key> *key_list, char *db,
+ char *db,
const char *table_name,
uint fast_alter_partition)
{
/* Set-up struct used to write frm files */
- ulonglong copied= 0;
- ulonglong deleted= 0;
partition_info *part_info= table->part_info;
ALTER_PARTITION_PARAM_TYPE lpt_obj;
ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
@@ -6030,8 +6000,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->part_info= part_info;
lpt->alter_info= alter_info;
lpt->create_info= create_info;
- lpt->create_list= create_list;
- lpt->key_list= key_list;
lpt->db_options= create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
lpt->db_options|= HA_OPTION_PACK_RECORD;
@@ -6109,7 +6077,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
The first approach here was to downgrade locks. Now a different approach
is decided upon. The idea is that the handler will have access to the
- ALTER_INFO when store_lock arrives with TL_WRITE_ALLOW_READ. So if the
+ Alter_info when store_lock arrives with TL_WRITE_ALLOW_READ. So if the
handler knows that this functionality can be handled with a lower lock
level it will set the lock level to TL_WRITE_ALLOW_WRITE immediately.
Thus the need to downgrade the lock disappears.
@@ -6382,7 +6350,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
user
*/
DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted,
- table, table_list, FALSE, lpt,
+ table, table_list, FALSE, NULL,
written_bin_log));
}
#endif
@@ -6406,8 +6374,8 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
also for other programs.
*/
-void set_field_ptr(Field **ptr, const byte *new_buf,
- const byte *old_buf)
+void set_field_ptr(Field **ptr, const uchar *new_buf,
+ const uchar *old_buf)
{
my_ptrdiff_t diff= (new_buf - old_buf);
DBUG_ENTER("set_field_ptr");
@@ -6440,8 +6408,8 @@ void set_field_ptr(Field **ptr, const byte *new_buf,
also for other programs.
*/
-void set_key_field_ptr(KEY *key_info, const byte *new_buf,
- const byte *old_buf)
+void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
+ const uchar *old_buf)
{
KEY_PART_INFO *key_part= key_info->key_part;
uint key_parts= key_info->key_parts;
@@ -6692,7 +6660,7 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
int get_part_iter_for_interval_via_mapping(partition_info *part_info,
bool is_subpart,
- char *min_value, char *max_value,
+ uchar *min_value, uchar *max_value,
uint flags,
PARTITION_ITERATOR *part_iter)
{
@@ -6736,7 +6704,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
}
}
else
- DBUG_ASSERT(0);
+ assert(0);
/*
Find minimum: Do special handling if the interval has left bound in form
@@ -6848,7 +6816,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info,
int get_part_iter_for_interval_via_walking(partition_info *part_info,
bool is_subpart,
- char *min_value, char *max_value,
+ uchar *min_value, uchar *max_value,
uint flags,
PARTITION_ITERATOR *part_iter)
{
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 4372c26a851..d0c66083768 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -57,11 +56,11 @@ bool check_reorganise_list(partition_info *new_part_info,
partition_info *old_part_info,
List<char> list_part_names);
handler *get_ha_partition(partition_info *part_info);
-int get_parts_for_update(const byte *old_data, byte *new_data,
- const byte *rec0, partition_info *part_info,
+int get_parts_for_update(const uchar *old_data, uchar *new_data,
+ const uchar *rec0, partition_info *part_info,
uint32 *old_part_id, uint32 *new_part_id,
longlong *func_value);
-int get_part_for_delete(const byte *buf, const byte *rec0,
+int get_part_for_delete(const uchar *buf, const uchar *rec0,
partition_info *part_info, uint32 *part_id);
void prune_partition_set(const TABLE *table, part_id_range *part_spec);
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
@@ -71,16 +70,16 @@ char *generate_partition_syntax(partition_info *part_info,
uint *buf_length, bool use_sql_alloc,
bool show_partition_options);
bool partition_key_modified(TABLE *table, const MY_BITMAP *fields);
-void get_partition_set(const TABLE *table, byte *buf, const uint index,
+void get_partition_set(const TABLE *table, uchar *buf, const uint index,
const key_range *key_spec,
part_id_range *part_spec);
-void get_full_part_id_from_key(const TABLE *table, byte *buf,
+void get_full_part_id_from_key(const TABLE *table, uchar *buf,
KEY *key_info,
const key_range *key_spec,
part_id_range *part_spec);
-bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
+bool mysql_unpack_partition(THD *thd, const char *part_buf,
uint part_info_len,
- uchar *part_state, uint part_state_len,
+ const char *part_state, uint part_state_len,
TABLE *table, bool is_create_table_ind,
handlerton *default_db_type);
void make_used_partitions_str(partition_info *part_info, String *parts_str);
@@ -202,7 +201,7 @@ typedef struct st_partition_iter
typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
bool is_subpart,
- char *min_val, char *max_val,
+ uchar *min_val, uchar *max_val,
uint flags,
PARTITION_ITERATOR *part_iter);
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 8cd4c661fb8..37301751d03 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,15 +15,25 @@
#include "mysql_priv.h"
#include <my_pthread.h>
+#include <my_getopt.h>
#define REPORT_TO_LOG 1
#define REPORT_TO_USER 2
+#ifdef DBUG_OFF
+#define plugin_ref_to_int(A) A
+#define plugin_int_to_ref(A) A
+#else
+#define plugin_ref_to_int(A) (A ? A[0] : NULL)
+#define plugin_int_to_ref(A) &(A)
+#endif
+
extern struct st_mysql_plugin *mysqld_builtins[];
+char *opt_plugin_load= NULL;
char *opt_plugin_dir_ptr;
char opt_plugin_dir[FN_REFLEN];
/*
- When you ad a new plugin type, add both a string and make sure that the
+ When you ad a new plugin type, add both a string and make sure that the
init and deinit array are correctly updated.
*/
const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
@@ -32,25 +41,37 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ C_STRING_WITH_LEN("UDF") },
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
{ C_STRING_WITH_LEN("FTPARSER") },
- { C_STRING_WITH_LEN("DAEMON") }
+ { C_STRING_WITH_LEN("DAEMON") },
+ { C_STRING_WITH_LEN("INFORMATION SCHEMA") }
};
+extern int initialize_schema_table(st_plugin_int *plugin);
+extern int finalize_schema_table(st_plugin_int *plugin);
+
+/*
+ The number of elements in both plugin_type_initialize and
+ plugin_type_deinitialize should equal to the number of plugins
+ defined.
+*/
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_initialize_handlerton,0,0
+ 0,ha_initialize_handlerton,0,0,initialize_schema_table
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
- 0,ha_finalize_handlerton,0,0
+ 0,ha_finalize_handlerton,0,0,finalize_schema_table
};
+#ifdef HAVE_DLOPEN
static const char *plugin_interface_version_sym=
"_mysql_plugin_interface_version_";
static const char *sizeof_st_plugin_sym=
"_mysql_sizeof_struct_st_plugin_";
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
static int min_plugin_interface_version= MYSQL_PLUGIN_INTERFACE_VERSION & ~0xFF;
+#endif
+
/* Note that 'int version' must be the first field of every plugin
sub-structure (plugin->info).
*/
@@ -59,36 +80,205 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
0x0000,
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
- MYSQL_DAEMON_INTERFACE_VERSION
+ MYSQL_DAEMON_INTERFACE_VERSION,
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0x0000, /* UDF: not implemented */
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
- MYSQL_DAEMON_INTERFACE_VERSION
+ MYSQL_DAEMON_INTERFACE_VERSION,
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
+static bool initialized= 0;
+
+/*
+ A mutex LOCK_plugin must be acquired before accessing the
+ following variables/structures.
+ We are always manipulating ref count, so a rwlock here is unneccessary.
+*/
+pthread_mutex_t LOCK_plugin;
static DYNAMIC_ARRAY plugin_dl_array;
static DYNAMIC_ARRAY plugin_array;
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
-static rw_lock_t THR_LOCK_plugin;
-static bool initialized= 0;
-
+static bool reap_needed= false;
static int plugin_array_version=0;
+/*
+ write-lock on LOCK_system_variables_hash is required before modifying
+ the following variables/structures
+*/
+static MEM_ROOT plugin_mem_root;
+static uint global_variables_dynamic_size= 0;
+static HASH bookmark_hash;
+
+
+/*
+ hidden part of opaque value passed to variable check functions.
+ Used to provide a object-like structure to non C++ consumers.
+*/
+struct st_item_value_holder : public st_mysql_value
+{
+ Item *item;
+};
+
+
+/*
+ stored in bookmark_hash, this structure is never removed from the
+ hash and is used to mark a single offset for a thd local variable
+ even if plugins have been uninstalled and reinstalled, repeatedly.
+ This structure is allocated from plugin_mem_root.
+
+ The key format is as follows:
+ 1 byte - variable type code
+ name_len bytes - variable name
+ '\0' - end of key
+*/
+struct st_bookmark
+{
+ uint name_len;
+ int offset;
+ uint version;
+ char key[1];
+};
+
+
+/*
+ skeleton of a plugin variable - portion of structure common to all.
+*/
+struct st_mysql_sys_var
+{
+ MYSQL_PLUGIN_VAR_HEADER;
+};
+
+
+/*
+ sys_var class for access to all plugin variables visible to the user
+*/
+class sys_var_pluginvar: public sys_var
+{
+public:
+ struct st_plugin_int *plugin;
+ struct st_mysql_sys_var *plugin_var;
+
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
+ static void operator delete(void *ptr_arg,size_t size)
+ { TRASH(ptr_arg, size); }
+
+ sys_var_pluginvar(const char *name_arg,
+ struct st_mysql_sys_var *plugin_var_arg)
+ :sys_var(name_arg), plugin_var(plugin_var_arg) {}
+ sys_var_pluginvar *cast_pluginvar() { return this; }
+ bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
+ bool check_type(enum_var_type type)
+ { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
+ bool check_update_type(Item_result type);
+ SHOW_TYPE show_type();
+ uchar* real_value_ptr(THD *thd, enum_var_type type);
+ TYPELIB* plugin_var_typelib(void);
+ uchar* value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+ bool check(THD *thd, set_var *var);
+ void set_default(THD *thd, enum_var_type type);
+ bool update(THD *thd, set_var *var);
+};
+
+
/* prototypes */
-my_bool plugin_register_builtin(struct st_mysql_plugin *plugin);
-void plugin_load(void);
+static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv);
+static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
+ const char *list);
+static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
+ int *, char **, my_bool);
+static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
+ struct st_plugin_int **);
+static void unlock_variables(THD *thd, struct system_variables *vars);
+static void cleanup_variables(THD *thd, struct system_variables *vars);
+static void plugin_vars_free_values(sys_var *vars);
+static void plugin_opt_set_limits(struct my_option *options,
+ const struct st_mysql_sys_var *opt);
+#define my_intern_plugin_lock(A,B) intern_plugin_lock(A,B CALLER_INFO)
+#define my_intern_plugin_lock_ci(A,B) intern_plugin_lock(A,B ORIG_CALLER_INFO)
+static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref plugin
+ CALLER_INFO_PROTO);
+static void intern_plugin_unlock(LEX *lex, plugin_ref plugin);
+static void reap_plugins(void);
+
+
+/* declared in set_var.cc */
+extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
+
+
+/****************************************************************************
+ Value type thunks, allows the C world to play in the C++ world
+****************************************************************************/
+
+static int item_value_type(struct st_mysql_value *value)
+{
+ switch (((st_item_value_holder*)value)->item->result_type()) {
+ case INT_RESULT:
+ return MYSQL_VALUE_TYPE_INT;
+ case REAL_RESULT:
+ return MYSQL_VALUE_TYPE_REAL;
+ default:
+ return MYSQL_VALUE_TYPE_STRING;
+ }
+}
+
+static const char *item_val_str(struct st_mysql_value *value,
+ char *buffer, int *length)
+{
+ String str(buffer, *length, system_charset_info), *res;
+ if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
+ return NULL;
+ *length= res->length();
+ if (res->c_ptr_quick() == buffer)
+ return buffer;
+
+ /*
+ Lets be nice and create a temporary string since the
+ buffer was too small
+ */
+ return current_thd->strmake(res->c_ptr_quick(), res->length());
+}
+
+
+static int item_val_int(struct st_mysql_value *value, long long *buf)
+{
+ Item *item= ((st_item_value_holder*)value)->item;
+ *buf= item->val_int();
+ if (item->is_null())
+ return 1;
+ return 0;
+}
+
+
+static int item_val_real(struct st_mysql_value *value, double *buf)
+{
+ Item *item= ((st_item_value_holder*)value)->item;
+ *buf= item->val_real();
+ if (item->is_null())
+ return 1;
+ return 0;
+}
+
+
+/****************************************************************************
+ Plugin support code
+****************************************************************************/
+
+#ifdef HAVE_DLOPEN
static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
{
uint i;
+ struct st_plugin_dl *tmp;
DBUG_ENTER("plugin_dl_find");
for (i= 0; i < plugin_dl_array.elements; i++)
{
- struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
- struct st_plugin_dl *);
+ tmp= dynamic_element(&plugin_dl_array, i, struct st_plugin_dl *);
if (tmp->ref_count &&
! my_strnncoll(files_charset_info,
(const uchar *)dl->str, dl->length,
@@ -102,22 +292,24 @@ static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
{
uint i;
+ struct st_plugin_dl *tmp;
DBUG_ENTER("plugin_dl_insert_or_reuse");
for (i= 0; i < plugin_dl_array.elements; i++)
{
- struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
- struct st_plugin_dl *);
+ tmp= dynamic_element(&plugin_dl_array, i, struct st_plugin_dl *);
if (! tmp->ref_count)
{
memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
DBUG_RETURN(tmp);
}
}
- if (insert_dynamic(&plugin_dl_array, (gptr)plugin_dl))
+ if (insert_dynamic(&plugin_dl_array, (uchar*)plugin_dl))
DBUG_RETURN(0);
DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
struct st_plugin_dl *));
}
+#endif /* HAVE_DLOPEN */
+
static inline void free_plugin_mem(struct st_plugin_dl *p)
{
@@ -127,9 +319,10 @@ static inline void free_plugin_mem(struct st_plugin_dl *p)
#endif
my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR));
if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION)
- my_free((gptr)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
}
+
static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
{
#ifdef HAVE_DLOPEN
@@ -145,7 +338,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
plugin directory are used (to make this even remotely secure).
*/
if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
- dl->length > NAME_LEN ||
+ check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
+ system_charset_info, 1) ||
plugin_dir_len + dl->length + 1 >= FN_REFLEN)
{
if (report & REPORT_TO_USER)
@@ -277,7 +471,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
/* Duplicate and convert dll name */
plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
- if (! (plugin_dl.dl.str= my_malloc(plugin_dl.dl.length, MYF(0))))
+ if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
{
free_plugin_mem(&plugin_dl);
if (report & REPORT_TO_USER)
@@ -317,6 +511,9 @@ static void plugin_dl_del(const LEX_STRING *dl)
#ifdef HAVE_DLOPEN
uint i;
DBUG_ENTER("plugin_dl_del");
+
+ safe_mutex_assert_owner(&LOCK_plugin);
+
for (i= 0; i < plugin_dl_array.elements; i++)
{
struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
@@ -346,50 +543,121 @@ static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int ty
DBUG_ENTER("plugin_find_internal");
if (! initialized)
DBUG_RETURN(0);
+
+ safe_mutex_assert_owner(&LOCK_plugin);
+
if (type == MYSQL_ANY_PLUGIN)
{
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
{
struct st_plugin_int *plugin= (st_plugin_int *)
- hash_search(&plugin_hash[i], (const byte *)name->str, name->length);
+ hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
if (plugin)
DBUG_RETURN(plugin);
}
}
else
DBUG_RETURN((st_plugin_int *)
- hash_search(&plugin_hash[type], (const byte *)name->str, name->length));
+ hash_search(&plugin_hash[type], (const uchar *)name->str, name->length));
DBUG_RETURN(0);
}
-my_bool plugin_is_ready(const LEX_STRING *name, int type)
+static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
{
- my_bool rc= FALSE;
+ SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
struct st_plugin_int *plugin;
DBUG_ENTER("plugin_is_ready");
- rw_rdlock(&THR_LOCK_plugin);
- if ((plugin= plugin_find_internal(name, type)) &&
- plugin->state == PLUGIN_IS_READY)
- rc= TRUE;
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_lock(&LOCK_plugin);
+ if ((plugin= plugin_find_internal(name, type)))
+ {
+ rc= SHOW_OPTION_DISABLED;
+ if (plugin->state == PLUGIN_IS_READY)
+ rc= SHOW_OPTION_YES;
+ }
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(rc);
}
-struct st_plugin_int *plugin_lock(const LEX_STRING *name, int type)
+bool plugin_is_ready(const LEX_STRING *name, int type)
{
- struct st_plugin_int *rc;
- DBUG_ENTER("plugin_lock");
- rw_wrlock(&THR_LOCK_plugin);
- if ((rc= plugin_find_internal(name, type)))
+ bool rc= FALSE;
+ if (plugin_status(name, type) == SHOW_OPTION_YES)
+ rc= TRUE;
+ return rc;
+}
+
+
+SHOW_COMP_OPTION sys_var_have_plugin::get_option()
+{
+ LEX_STRING plugin_name= { (char *) plugin_name_str, plugin_name_len };
+ return plugin_status(&plugin_name, plugin_type);
+}
+
+
+static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
+{
+ st_plugin_int *pi= plugin_ref_to_int(rc);
+ DBUG_ENTER("intern_plugin_lock");
+
+ safe_mutex_assert_owner(&LOCK_plugin);
+
+ if (pi->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
{
- if (rc->state & (PLUGIN_IS_READY | PLUGIN_IS_UNINITIALIZED))
- rc->ref_count++;
- else
- rc= 0;
+ plugin_ref plugin;
+#ifdef DBUG_OFF
+ /* built-in plugins don't need ref counting */
+ if (!pi->plugin_dl)
+ DBUG_RETURN(pi);
+
+ plugin= pi;
+#else
+ /*
+ For debugging, we do an additional malloc which allows the
+ memory manager and/or valgrind to track locked references and
+ double unlocks to aid resolving reference counting.problems.
+ */
+ if (!(plugin= (plugin_ref) my_malloc_ci(sizeof(pi), MYF(MY_WME))))
+ DBUG_RETURN(NULL);
+
+ *plugin= pi;
+#endif
+ pi->ref_count++;
+ DBUG_PRINT("info",("thd: 0x%lx, plugin: \"%s\", ref_count: %d",
+ (long) current_thd, pi->name.str, pi->ref_count));
+
+ if (lex)
+ insert_dynamic(&lex->plugins, (uchar*)&plugin);
+ DBUG_RETURN(plugin);
}
- rw_unlock(&THR_LOCK_plugin);
+ DBUG_RETURN(NULL);
+}
+
+
+plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO)
+{
+ LEX *lex= thd ? thd->lex : 0;
+ plugin_ref rc;
+ DBUG_ENTER("plugin_lock");
+ pthread_mutex_lock(&LOCK_plugin);
+ rc= my_intern_plugin_lock_ci(lex, *ptr);
+ pthread_mutex_unlock(&LOCK_plugin);
+ DBUG_RETURN(rc);
+}
+
+
+plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type
+ CALLER_INFO_PROTO)
+{
+ LEX *lex= thd ? thd->lex : 0;
+ plugin_ref rc= NULL;
+ st_plugin_int *plugin;
+ DBUG_ENTER("plugin_lock_by_name");
+ pthread_mutex_lock(&LOCK_plugin);
+ if ((plugin= plugin_find_internal(name, type)))
+ rc= my_intern_plugin_lock_ci(lex, plugin_int_to_ref(plugin));
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(rc);
}
@@ -408,13 +676,20 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
DBUG_RETURN(tmp);
}
}
- if (insert_dynamic(&plugin_array, (gptr)plugin))
+ if (insert_dynamic(&plugin_array, (uchar*)plugin))
DBUG_RETURN(0);
DBUG_RETURN(dynamic_element(&plugin_array, plugin_array.elements - 1,
struct st_plugin_int *));
}
-static my_bool plugin_add(const LEX_STRING *name, const LEX_STRING *dl, int report)
+
+/*
+ NOTE
+ Requires that a write-lock is held on LOCK_system_variables_hash
+*/
+static bool plugin_add(MEM_ROOT *tmp_root,
+ const LEX_STRING *name, const LEX_STRING *dl,
+ int *argc, char **argv, int report)
{
struct st_plugin_int tmp;
struct st_mysql_plugin *plugin;
@@ -427,6 +702,8 @@ static my_bool plugin_add(const LEX_STRING *name, const LEX_STRING *dl, int repo
sql_print_error(ER(ER_UDF_EXISTS), name->str);
DBUG_RETURN(TRUE);
}
+ /* Clear the whole struct to catch future extensions. */
+ bzero((char*) &tmp, sizeof(tmp));
if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
DBUG_RETURN(TRUE);
/* Find plugin by name */
@@ -460,14 +737,23 @@ static my_bool plugin_add(const LEX_STRING *name, const LEX_STRING *dl, int repo
tmp.name.length= name_len;
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
- if (! (tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
- goto err;
- plugin_array_version++;
- if (my_hash_insert(&plugin_hash[plugin->type], (byte*)tmp_plugin_ptr))
+ if (!test_plugin_options(tmp_root, &tmp, argc, argv, true))
{
- tmp_plugin_ptr->state= PLUGIN_IS_FREED;
+ if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
+ {
+ plugin_array_version++;
+ if (!my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
+ {
+ init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096);
+ DBUG_RETURN(FALSE);
+ }
+ tmp_plugin_ptr->state= PLUGIN_IS_FREED;
+ }
+ mysql_del_sys_var_chain(tmp.system_vars);
goto err;
}
+ /* plugin was disabled */
+ plugin_dl_del(dl);
DBUG_RETURN(FALSE);
}
}
@@ -481,8 +767,14 @@ err:
}
-void plugin_deinitialize(struct st_plugin_int *plugin)
+static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
{
+ /*
+ we don't want to hold the LOCK_plugin mutex as it may cause
+ deinitialization to deadlock if plugins have worker threads
+ with plugin locks
+ */
+ safe_mutex_assert_not_owner(&LOCK_plugin);
if (plugin->plugin->status_vars)
{
@@ -510,7 +802,7 @@ void plugin_deinitialize(struct st_plugin_int *plugin)
{
sql_print_error("Plugin '%s' of type %s failed deinitialization",
plugin->name.str, plugin_type_names[plugin->plugin->type].str);
- }
+ }
}
else if (plugin->plugin->deinit)
{
@@ -522,19 +814,37 @@ void plugin_deinitialize(struct st_plugin_int *plugin)
}
}
plugin->state= PLUGIN_IS_UNINITIALIZED;
+
+ /*
+ We do the check here because NDB has a worker THD which doesn't
+ exit until NDB is shut down.
+ */
+ if (ref_check && plugin->ref_count)
+ sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
+ plugin->name.str, plugin->ref_count);
}
static void plugin_del(struct st_plugin_int *plugin)
{
DBUG_ENTER("plugin_del(plugin)");
- hash_delete(&plugin_hash[plugin->plugin->type], (byte*)plugin);
- plugin_dl_del(&plugin->plugin_dl->dl);
+ safe_mutex_assert_owner(&LOCK_plugin);
+ /* Free allocated strings before deleting the plugin. */
+ plugin_vars_free_values(plugin->system_vars);
+ hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
+ if (plugin->plugin_dl)
+ plugin_dl_del(&plugin->plugin_dl->dl);
plugin->state= PLUGIN_IS_FREED;
plugin_array_version++;
+ rw_wrlock(&LOCK_system_variables_hash);
+ mysql_del_sys_var_chain(plugin->system_vars);
+ rw_unlock(&LOCK_system_variables_hash);
+ free_root(&plugin->mem_root, MYF(0));
DBUG_VOID_RETURN;
}
+#ifdef NOT_USED
+
static void plugin_del(const LEX_STRING *name)
{
struct st_plugin_int *plugin;
@@ -544,18 +854,125 @@ static void plugin_del(const LEX_STRING *name)
DBUG_VOID_RETURN;
}
-void plugin_unlock(struct st_plugin_int *plugin)
+#endif
+
+static void reap_plugins(void)
{
- DBUG_ENTER("plugin_unlock");
- rw_wrlock(&THR_LOCK_plugin);
- DBUG_ASSERT(plugin && plugin->ref_count);
- plugin->ref_count--;
- if (plugin->state == PLUGIN_IS_DELETED && ! plugin->ref_count)
+ uint count, idx;
+ struct st_plugin_int *plugin, **reap, **list;
+
+ safe_mutex_assert_owner(&LOCK_plugin);
+
+ if (!reap_needed)
+ return;
+
+ reap_needed= false;
+ count= plugin_array.elements;
+ reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
+ *(reap++)= NULL;
+
+ for (idx= 0; idx < count; idx++)
{
- plugin_deinitialize(plugin);
+ plugin= dynamic_element(&plugin_array, idx, struct st_plugin_int *);
+ if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
+ {
+ /* change the status flag to prevent reaping by another thread */
+ plugin->state= PLUGIN_IS_DYING;
+ *(reap++)= plugin;
+ }
+ }
+
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ list= reap;
+ while ((plugin= *(--list)))
+ plugin_deinitialize(plugin, true);
+
+ pthread_mutex_lock(&LOCK_plugin);
+
+ while ((plugin= *(--reap)))
plugin_del(plugin);
+
+ my_afree(reap);
+}
+
+static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
+{
+ int i;
+ st_plugin_int *pi;
+ DBUG_ENTER("intern_plugin_unlock");
+
+ safe_mutex_assert_owner(&LOCK_plugin);
+
+ if (!plugin)
+ DBUG_VOID_RETURN;
+
+ pi= plugin_ref_to_int(plugin);
+
+#ifdef DBUG_OFF
+ if (!pi->plugin_dl)
+ DBUG_VOID_RETURN;
+#else
+ my_free((uchar*) plugin, MYF(MY_WME));
+#endif
+
+ DBUG_PRINT("info",("unlocking plugin, name= %s, ref_count= %d",
+ pi->name.str, pi->ref_count));
+ if (lex)
+ {
+ /*
+ Remove one instance of this plugin from the use list.
+ We are searching backwards so that plugins locked last
+ could be unlocked faster - optimizing for LIFO semantics.
+ */
+ for (i= lex->plugins.elements - 1; i >= 0; i--)
+ if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
+ {
+ delete_dynamic_element(&lex->plugins, i);
+ break;
+ }
+ DBUG_ASSERT(i >= 0);
}
- rw_unlock(&THR_LOCK_plugin);
+
+ DBUG_ASSERT(pi->ref_count);
+ pi->ref_count--;
+
+ if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
+ reap_needed= true;
+
+ DBUG_VOID_RETURN;
+}
+
+
+void plugin_unlock(THD *thd, plugin_ref plugin)
+{
+ LEX *lex= thd ? thd->lex : 0;
+ DBUG_ENTER("plugin_unlock");
+ if (!plugin)
+ DBUG_VOID_RETURN;
+#ifdef DBUG_OFF
+ /* built-in plugins don't need ref counting */
+ if (!plugin_dlib(plugin))
+ DBUG_VOID_RETURN;
+#endif
+ pthread_mutex_lock(&LOCK_plugin);
+ intern_plugin_unlock(lex, plugin);
+ reap_plugins();
+ pthread_mutex_unlock(&LOCK_plugin);
+ DBUG_VOID_RETURN;
+}
+
+
+void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
+{
+ LEX *lex= thd ? thd->lex : 0;
+ DBUG_ENTER("plugin_unlock_list");
+ DBUG_ASSERT(list);
+ pthread_mutex_lock(&LOCK_plugin);
+ while (count--)
+ intern_plugin_unlock(lex, *list++);
+ reap_plugins();
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_VOID_RETURN;
}
@@ -564,6 +981,8 @@ static int plugin_initialize(struct st_plugin_int *plugin)
{
DBUG_ENTER("plugin_initialize");
+ safe_mutex_assert_owner(&LOCK_plugin);
+
if (plugin_type_initialize[plugin->plugin->type])
{
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
@@ -606,17 +1025,43 @@ static int plugin_initialize(struct st_plugin_int *plugin)
#endif /* FIX_LATER */
}
+ /*
+ set the plugin attribute of plugin's sys vars so they are pointing
+ to the active plugin
+ */
+ if (plugin->system_vars)
+ {
+ sys_var_pluginvar *var= plugin->system_vars->cast_pluginvar();
+ for (;;)
+ {
+ var->plugin= plugin;
+ if (!var->next)
+ break;
+ var= var->next->cast_pluginvar();
+ }
+ }
+
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
}
-static byte *get_hash_key(const byte *buff, uint *length,
+
+static uchar *get_hash_key(const uchar *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
struct st_plugin_int *plugin= (st_plugin_int *)buff;
*length= (uint)plugin->name.length;
- return((byte *)plugin->name.str);
+ return((uchar *)plugin->name.str);
+}
+
+
+static uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ struct st_bookmark *var= (st_bookmark *)buff;
+ *length= var->name_len + 1;
+ return (uchar*) var->key;
}
@@ -625,19 +1070,30 @@ static byte *get_hash_key(const byte *buff, uint *length,
From there we load up the dynamic types (assuming we have not been told to
skip this part).
- Finally we inializie everything, aka the dynamic that have yet to initialize.
+ Finally we initialize everything, aka the dynamic that have yet to initialize.
*/
-int plugin_init(int skip_dynamic_loading)
+int plugin_init(int *argc, char **argv, int flags)
{
uint i;
+ bool def_enabled, is_myisam;
struct st_mysql_plugin **builtins;
struct st_mysql_plugin *plugin;
+ struct st_plugin_int tmp, *plugin_ptr, **reap;
+ MEM_ROOT tmp_root;
DBUG_ENTER("plugin_init");
if (initialized)
DBUG_RETURN(0);
- my_rwlock_init(&THR_LOCK_plugin, NULL);
+ init_alloc_root(&plugin_mem_root, 4096, 4096);
+ init_alloc_root(&tmp_root, 4096, 4096);
+
+ if (hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
+ get_bookmark_hash_key, NULL, HASH_UNIQUE))
+ goto err;
+
+
+ pthread_mutex_init(&LOCK_plugin, MY_MUTEX_INIT_FAST);
if (my_init_dynamic_array(&plugin_dl_array,
sizeof(struct st_plugin_dl),16,16) ||
@@ -648,10 +1104,14 @@ int plugin_init(int skip_dynamic_loading)
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
{
if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
- get_hash_key, NULL, 0))
+ get_hash_key, NULL, HASH_UNIQUE))
goto err;
}
+ pthread_mutex_lock(&LOCK_plugin);
+
+ initialized= 1;
+
/*
First we register builtin plugins
*/
@@ -659,83 +1119,185 @@ int plugin_init(int skip_dynamic_loading)
{
for (plugin= *builtins; plugin->info; plugin++)
{
-// if (!(strcmp(plugin->name, "MyISAM")))
+ /* by default, only ndbcluster is disabled */
+ def_enabled=
+ my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0;
+ bzero(&tmp, sizeof(tmp));
+ tmp.plugin= plugin;
+ tmp.name.str= (char *)plugin->name;
+ tmp.name.length= strlen(plugin->name);
+
+ free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
+ if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled))
+ continue;
+
+ if (register_builtin(plugin, &tmp, &plugin_ptr))
+ goto err_unlock;
+
+ /* only initialize MyISAM and CSV at this stage */
+ if (!(is_myisam=
+ !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM")) &&
+ my_strcasecmp(&my_charset_latin1, plugin->name, "CSV"))
+ continue;
+
+ if (plugin_initialize(plugin_ptr))
+ goto err_unlock;
+
+ /*
+ initialize the global default storage engine so that it may
+ not be null in any child thread.
+ */
+ if (is_myisam)
{
- if (plugin_register_builtin(plugin))
- goto err;
- struct st_plugin_int *tmp= dynamic_element(&plugin_array,
- plugin_array.elements-1,
- struct st_plugin_int *);
- if (plugin_initialize(tmp))
- goto err;
+ DBUG_ASSERT(!global_system_variables.table_plugin);
+ global_system_variables.table_plugin=
+ my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
+ DBUG_ASSERT(plugin_ptr->ref_count == 1);
}
}
}
+ /* should now be set to MyISAM storage engine */
+ DBUG_ASSERT(global_system_variables.table_plugin);
+
+ pthread_mutex_unlock(&LOCK_plugin);
+
/* Register all dynamic plugins */
- if (!skip_dynamic_loading)
- plugin_load();
+ if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
+ {
+ if (opt_plugin_load &&
+ plugin_load_list(&tmp_root, argc, argv, opt_plugin_load))
+ goto err;
+ if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
+ plugin_load(&tmp_root, argc, argv);
+ }
- initialized= 1;
+ if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
+ goto end;
/*
Now we initialize all remaining plugins
*/
+
+ pthread_mutex_lock(&LOCK_plugin);
+ reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
+ *(reap++)= NULL;
+
for (i= 0; i < plugin_array.elements; i++)
{
- struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
- struct st_plugin_int *);
- if (tmp->state == PLUGIN_IS_UNINITIALIZED)
+ plugin_ptr= dynamic_element(&plugin_array, i, struct st_plugin_int *);
+ if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
{
- if (plugin_initialize(tmp))
+ if (plugin_initialize(plugin_ptr))
{
- plugin_deinitialize(tmp);
- plugin_del(tmp);
+ plugin_ptr->state= PLUGIN_IS_DYING;
+ *(reap++)= plugin_ptr;
}
}
}
+ /*
+ Check if any plugins have to be reaped
+ */
+ while ((plugin_ptr= *(--reap)))
+ {
+ pthread_mutex_unlock(&LOCK_plugin);
+ plugin_deinitialize(plugin_ptr, true);
+ pthread_mutex_lock(&LOCK_plugin);
+ plugin_del(plugin_ptr);
+ }
+
+ pthread_mutex_unlock(&LOCK_plugin);
+ my_afree(reap);
+
+end:
+ free_root(&tmp_root, MYF(0));
+
DBUG_RETURN(0);
+err_unlock:
+ pthread_mutex_unlock(&LOCK_plugin);
err:
+ free_root(&tmp_root, MYF(0));
DBUG_RETURN(1);
}
-my_bool plugin_register_builtin(struct st_mysql_plugin *plugin)
+static bool register_builtin(struct st_mysql_plugin *plugin,
+ struct st_plugin_int *tmp,
+ struct st_plugin_int **ptr)
{
- struct st_plugin_int tmp;
+ DBUG_ENTER("register_builtin");
+
+ tmp->state= PLUGIN_IS_UNINITIALIZED;
+ tmp->ref_count= 0;
+ tmp->plugin_dl= 0;
+
+ if (insert_dynamic(&plugin_array, (uchar*)tmp))
+ DBUG_RETURN(1);
+
+ *ptr= dynamic_element(&plugin_array, plugin_array.elements - 1,
+ struct st_plugin_int *);
+
+ if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+
+#ifdef NOT_USED_YET
+/*
+ Register a plugin at run time. (note, this doesn't initialize a plugin)
+ Will be useful for embedded applications.
+
+ SYNOPSIS
+ plugin_register_builtin()
+ thd current thread (used to store scratch data in mem_root)
+ plugin static plugin to install
+
+ RETURN
+ false - plugin registered successfully
+*/
+bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
+{
+ struct st_plugin_int tmp, *ptr;
+ bool result= true;
+ int dummy_argc= 0;
DBUG_ENTER("plugin_register_builtin");
+ bzero(&tmp, sizeof(tmp));
tmp.plugin= plugin;
tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name);
- tmp.state= PLUGIN_IS_UNINITIALIZED;
- /* Cannot be unloaded */
- tmp.ref_count= 1;
- tmp.plugin_dl= 0;
+ pthread_mutex_lock(&LOCK_plugin);
+ rw_wrlock(&LOCK_system_variables_hash);
- if (insert_dynamic(&plugin_array, (gptr)&tmp))
- DBUG_RETURN(1);
+ if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true))
+ goto end;
- if (my_hash_insert(&plugin_hash[plugin->type],
- (byte*)dynamic_element(&plugin_array,
- plugin_array.elements - 1,
- struct st_plugin_int *)))
- DBUG_RETURN(1);
+ if ((result= register_builtin(plugin, &tmp, &ptr)))
+ mysql_del_sys_var_chain(tmp.system_vars);
- DBUG_RETURN(0);
+end:
+ rw_unlock(&LOCK_system_variables_hash);
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ DBUG_RETURN(result);;
}
+#endif /* NOT_USED_YET */
-void plugin_load(void)
+/*
+ called only by plugin_init()
+*/
+static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
{
TABLE_LIST tables;
TABLE *table;
READ_RECORD read_record_info;
int error;
- MEM_ROOT mem;
THD *new_thd;
DBUG_ENTER("plugin_load");
@@ -745,44 +1307,52 @@ void plugin_load(void)
delete new_thd;
DBUG_VOID_RETURN;
}
- init_sql_alloc(&mem, 1024, 0);
new_thd->thread_stack= (char*) &tables;
new_thd->store_globals();
new_thd->db= my_strdup("mysql", MYF(0));
new_thd->db_length= 5;
- bzero((gptr)&tables, sizeof(tables));
+ bzero((uchar*)&tables, sizeof(tables));
tables.alias= tables.table_name= (char*)"plugin";
tables.lock_type= TL_READ;
tables.db= new_thd->db;
if (simple_open_n_lock_tables(new_thd, &tables))
{
DBUG_PRINT("error",("Can't open plugin table"));
- sql_print_error("Can't open the mysql.plugin table. Please run the mysql_upgrade script to create it.");
+ sql_print_error("Can't open the mysql.plugin table. Please "
+ "run mysql_upgrade to create it.");
goto end;
}
table= tables.table;
init_read_record(&read_record_info, new_thd, table, NULL, 1, 0);
table->use_all_columns();
+ /*
+ there're no other threads running yet, so we don't need a mutex.
+ but plugin_add() before is designed to work in multi-threaded
+ environment, and it uses safe_mutex_assert_owner(), so we lock
+ the mutex here to satisfy the assert
+ */
+ pthread_mutex_lock(&LOCK_plugin);
while (!(error= read_record_info.read_record(&read_record_info)))
{
DBUG_PRINT("info", ("init plugin record"));
String str_name, str_dl;
- get_field(&mem, table->field[0], &str_name);
- get_field(&mem, table->field[1], &str_dl);
-
+ get_field(tmp_root, table->field[0], &str_name);
+ get_field(tmp_root, table->field[1], &str_dl);
+
LEX_STRING name= {(char *)str_name.ptr(), str_name.length()};
LEX_STRING dl= {(char *)str_dl.ptr(), str_dl.length()};
- if (plugin_add(&name, &dl, REPORT_TO_LOG))
+ if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.",
str_name.c_ptr(), str_dl.c_ptr());
+ free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
}
+ pthread_mutex_unlock(&LOCK_plugin);
if (error > 0)
sql_print_error(ER(ER_GET_ERRNO), my_errno);
end_read_record(&read_record_info);
new_thd->version--; // Force close to free memory
end:
- free_root(&mem, MYF(0));
close_thread_tables(new_thd);
delete new_thd;
/* Remember that we don't have a THD */
@@ -791,46 +1361,222 @@ end:
}
+/*
+ called only by plugin_init()
+*/
+static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
+ const char *list)
+{
+ char buffer[FN_REFLEN];
+ LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
+ struct st_plugin_dl *plugin_dl;
+ struct st_mysql_plugin *plugin;
+ char *p= buffer;
+ DBUG_ENTER("plugin_load_list");
+ while (list)
+ {
+ if (p == buffer + sizeof(buffer) - 1)
+ break;
+ switch ((*(p++)= *(list++))) {
+ case '\0':
+ list= NULL; /* terminate the loop */
+ /* fall through */
+#ifndef __WIN__
+ case ':': /* can't use this as delimiter as it may be drive letter */
+#endif
+ case ';':
+ name.str[name.length]= '\0';
+ if (str != &dl) // load all plugins in named module
+ {
+ dl= name;
+ if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG)))
+ {
+ for (plugin= plugin_dl->plugins; plugin->info; plugin++)
+ {
+ name.str= (char *) plugin->name;
+ name.length= strlen(name.str);
+
+ free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
+ if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+ goto error;
+ }
+ plugin_dl_del(&dl); // reduce ref count
+ }
+ }
+ else
+ {
+ free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
+ if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+ goto error;
+ }
+ name.length= dl.length= 0;
+ dl.str= NULL; name.str= p= buffer;
+ str= &name;
+ continue;
+ case '=':
+ case '#':
+ if (str == &name)
+ {
+ str= &dl;
+ str->str= p;
+ continue;
+ }
+ default:
+ str->length++;
+ continue;
+ }
+ }
+ DBUG_RETURN(FALSE);
+error:
+ sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
+ name.str, dl.str);
+ DBUG_RETURN(TRUE);
+}
+
+
void plugin_shutdown(void)
{
- uint i;
+ uint i, count= plugin_array.elements, free_slots= 0;
+ struct st_plugin_int **plugins, *plugin;
+ struct st_plugin_dl **dl;
DBUG_ENTER("plugin_shutdown");
- /*
- We loop through all plugins and call deinit() if they have one.
- */
- for (i= 0; i < plugin_array.elements; i++)
+ if (initialized)
{
- struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
- struct st_plugin_int *);
- plugin_deinitialize(tmp);
+ pthread_mutex_lock(&LOCK_plugin);
+
+ reap_needed= true;
+
+ /*
+ We want to shut down plugins in a reasonable order, this will
+ become important when we have plugins which depend upon each other.
+ Circular references cannot be reaped so they are forced afterwards.
+ TODO: Have an additional step here to notify all active plugins that
+ shutdown is requested to allow plugins to deinitialize in parallel.
+ */
+ while (reap_needed && (count= plugin_array.elements))
+ {
+ reap_plugins();
+ for (i= free_slots= 0; i < count; i++)
+ {
+ plugin= dynamic_element(&plugin_array, i, struct st_plugin_int *);
+ switch (plugin->state) {
+ case PLUGIN_IS_READY:
+ plugin->state= PLUGIN_IS_DELETED;
+ reap_needed= true;
+ break;
+ case PLUGIN_IS_FREED:
+ case PLUGIN_IS_UNINITIALIZED:
+ free_slots++;
+ break;
+ }
+ }
+ if (!reap_needed)
+ {
+ /*
+ release any plugin references held.
+ */
+ unlock_variables(NULL, &global_system_variables);
+ unlock_variables(NULL, &max_system_variables);
+ }
+ }
+
+ if (count > free_slots)
+ sql_print_warning("Forcing shutdown of %d plugins", count - free_slots);
+
+ plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));
+
+ /*
+ If we have any plugins which did not die cleanly, we force shutdown
+ */
+ for (i= 0; i < count; i++)
+ {
+ plugins[i]= dynamic_element(&plugin_array, i, struct st_plugin_int *);
+ /* change the state to ensure no reaping races */
+ if (plugins[i]->state == PLUGIN_IS_DELETED)
+ plugins[i]->state= PLUGIN_IS_DYING;
+ }
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ /*
+ We loop through all plugins and call deinit() if they have one.
+ */
+ for (i= 0; i < count; i++)
+ if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED)))
+ {
+ sql_print_information("Plugin '%s' will be forced to shutdown",
+ plugins[i]->name.str);
+ /*
+ We are forcing deinit on plugins so we don't want to do a ref_count
+ check until we have processed all the plugins.
+ */
+ plugin_deinitialize(plugins[i], false);
+ }
+
+ /*
+ It's perfectly safe not to lock LOCK_plugin, as there're no
+ concurrent threads anymore. But some functions called from here
+ use safe_mutex_assert_owner(), so we lock the mutex to satisfy it
+ */
+ pthread_mutex_lock(&LOCK_plugin);
+ /*
+ We defer checking ref_counts until after all plugins are deinitialized
+ as some may have worker threads holding on to plugin references.
+ */
+ for (i= 0; i < count; i++)
+ {
+ if (plugins[i]->ref_count)
+ sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
+ plugins[i]->name.str, plugins[i]->ref_count);
+ if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED)
+ plugin_del(plugins[i]);
+ }
+
+ /*
+ Now we can deallocate all memory.
+ */
+
+ cleanup_variables(NULL, &global_system_variables);
+ cleanup_variables(NULL, &max_system_variables);
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ initialized= 0;
+ pthread_mutex_destroy(&LOCK_plugin);
+
+ my_afree(plugins);
}
+ /* Dispose of the memory */
+
for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
hash_free(&plugin_hash[i]);
delete_dynamic(&plugin_array);
+
+ count= plugin_dl_array.elements;
+ dl= (struct st_plugin_dl **)my_alloca(sizeof(void*) * count);
+ for (i= 0; i < count; i++)
+ dl[i]= dynamic_element(&plugin_dl_array, i, struct st_plugin_dl *);
for (i= 0; i < plugin_dl_array.elements; i++)
- {
- struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
- struct st_plugin_dl *);
- free_plugin_mem(tmp);
- }
+ free_plugin_mem(dl[i]);
+ my_afree(dl);
delete_dynamic(&plugin_dl_array);
- if (initialized)
- {
- initialized= 0;
- rwlock_destroy(&THR_LOCK_plugin);
- }
+
+ hash_free(&bookmark_hash);
+ free_root(&plugin_mem_root, MYF(0));
+
+ global_variables_dynamic_size= 0;
+
DBUG_VOID_RETURN;
}
-my_bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl)
+bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl)
{
TABLE_LIST tables;
TABLE *table;
- int error;
+ int error, argc;
+ char *argv[2];
struct st_plugin_int *tmp;
DBUG_ENTER("mysql_install_plugin");
@@ -840,14 +1586,21 @@ my_bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING
if (check_table_access(thd, INSERT_ACL, &tables, 0))
DBUG_RETURN(TRUE);
- /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
+ /* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table = open_ltable(thd, &tables, TL_WRITE)))
DBUG_RETURN(TRUE);
- rw_wrlock(&THR_LOCK_plugin);
- if (plugin_add(name, dl, REPORT_TO_USER))
+ pthread_mutex_lock(&LOCK_plugin);
+ rw_wrlock(&LOCK_system_variables_hash);
+ /* handle_options() assumes arg0 (program name) always exists */
+ argv[0]= const_cast<char*>(""); // without a cast gcc emits a warning
+ argv[1]= 0;
+ argc= 1;
+ error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
+ rw_unlock(&LOCK_system_variables_hash);
+
+ if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
goto err;
- tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
if (plugin_initialize(tmp))
{
@@ -867,18 +1620,19 @@ my_bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING
goto deinit;
}
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(FALSE);
deinit:
- plugin_deinitialize(tmp);
- plugin_del(tmp);
+ tmp->state= PLUGIN_IS_DELETED;
+ reap_needed= true;
+ reap_plugins();
err:
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE);
}
-my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
+bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
{
TABLE *table;
TABLE_LIST tables;
@@ -889,11 +1643,11 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
tables.db= (char *)"mysql";
tables.table_name= tables.alias= (char *)"plugin";
- /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
+ /* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
DBUG_RETURN(TRUE);
- rw_wrlock(&THR_LOCK_plugin);
+ pthread_mutex_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
@@ -907,40 +1661,36 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
goto err;
}
+ plugin->state= PLUGIN_IS_DELETED;
if (plugin->ref_count)
- {
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"Plugin is busy and will be uninstalled on shutdown");
- plugin->state= PLUGIN_IS_DELETED;
- }
else
- {
- plugin_deinitialize(plugin);
- plugin_del(plugin);
- }
+ reap_needed= true;
+ reap_plugins();
+ pthread_mutex_unlock(&LOCK_plugin);
table->use_all_columns();
table->field[0]->store(name->str, name->length, system_charset_info);
if (! table->file->index_read_idx(table->record[0], 0,
- (byte *)table->field[0]->ptr,
- table->key_info[0].key_length,
+ (uchar *)table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
int error;
if ((error= table->file->ha_delete_row(table->record[0])))
{
table->file->print_error(error, MYF(0));
- goto err;
+ DBUG_RETURN(TRUE);
}
}
- rw_unlock(&THR_LOCK_plugin);
DBUG_RETURN(FALSE);
err:
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(TRUE);
}
-my_bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
+
+bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int type, uint state_mask, void *arg)
{
uint idx, total;
@@ -948,48 +1698,51 @@ my_bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int version=plugin_array_version;
DBUG_ENTER("plugin_foreach_with_mask");
+ if (!initialized)
+ DBUG_RETURN(FALSE);
+
state_mask= ~state_mask; // do it only once
- rw_rdlock(&THR_LOCK_plugin);
+ pthread_mutex_lock(&LOCK_plugin);
+ total= type == MYSQL_ANY_PLUGIN ? plugin_array.elements
+ : plugin_hash[type].records;
+ /*
+ Do the alloca out here in case we do have a working alloca:
+ leaving the nested stack frame invalidates alloca allocation.
+ */
+ plugins=(struct st_plugin_int **)my_alloca(total*sizeof(plugin));
if (type == MYSQL_ANY_PLUGIN)
{
- total=plugin_array.elements;
- plugins=(struct st_plugin_int **)my_alloca(total*sizeof(*plugins));
for (idx= 0; idx < total; idx++)
{
plugin= dynamic_element(&plugin_array, idx, struct st_plugin_int *);
- if (plugin->state & state_mask)
- continue;
- plugins[idx]= plugin;
+ plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
}
}
else
{
- HASH *hash= &plugin_hash[type];
- total=hash->records;
- plugins=(struct st_plugin_int **)my_alloca(total*sizeof(*plugins));
+ HASH *hash= plugin_hash + type;
for (idx= 0; idx < total; idx++)
{
plugin= (struct st_plugin_int *) hash_element(hash, idx);
- if (plugin->state & state_mask)
- continue;
- plugins[idx]= plugin;
+ plugins[idx]= !(plugin->state & state_mask) ? plugin : NULL;
}
}
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
for (idx= 0; idx < total; idx++)
{
if (unlikely(version != plugin_array_version))
{
- rw_rdlock(&THR_LOCK_plugin);
+ pthread_mutex_lock(&LOCK_plugin);
for (uint i=idx; i < total; i++)
- if (plugins[i]->state & state_mask)
+ if (plugins[i] && plugins[i]->state & state_mask)
plugins[i]=0;
- rw_unlock(&THR_LOCK_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
}
plugin= plugins[idx];
- if (plugin && func(thd, plugin, arg))
+ /* It will stop iterating on first engine error when "func" returns TRUE */
+ if (plugin && func(thd, plugin_int_to_ref(plugin), arg))
goto err;
}
@@ -1000,3 +1753,1417 @@ err:
DBUG_RETURN(TRUE);
}
+
+/****************************************************************************
+ Internal type declarations for variables support
+****************************************************************************/
+
+#undef MYSQL_SYSVAR_NAME
+#define MYSQL_SYSVAR_NAME(name) name
+#define PLUGIN_VAR_TYPEMASK 0x007f
+
+#define EXTRA_OPTIONS 3 /* options for: 'foo', 'plugin-foo' and NULL */
+
+typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_bool_t, my_bool);
+typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_bool_t, my_bool);
+typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_str_t, char *);
+typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_str_t, char *);
+
+typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
+typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
+typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_set_t, ulonglong);
+typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_set_t, ulonglong);
+
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_int_t, int);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_long_t, long);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_longlong_t, longlong);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong);
+typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulonglong_t, ulonglong);
+
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_longlong_t, longlong);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong);
+typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong);
+
+#define SET_PLUGIN_VAR_RESOLVE(opt)\
+ *(mysql_sys_var_ptr_p*)&((opt)->resolve)= mysql_sys_var_ptr
+typedef uchar *(*mysql_sys_var_ptr_p)(void* a_thd, int offset);
+
+
+/****************************************************************************
+ default variable data check and update functions
+****************************************************************************/
+
+static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ const char *strvalue= "NULL", *str;
+ int result, length;
+ long long tmp;
+
+ if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
+ {
+ length= sizeof(buff);
+ if (!(str= value->val_str(value, buff, &length)) ||
+ (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
+ {
+ if (str)
+ strvalue= str;
+ goto err;
+ }
+ }
+ else
+ {
+ if (value->val_int(value, &tmp) < 0)
+ goto err;
+ if (tmp > 1)
+ {
+ llstr(tmp, buff);
+ strvalue= buff;
+ goto err;
+ }
+ result= (int) tmp;
+ }
+ *(int*)save= -result;
+ return 0;
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
+ return 1;
+}
+
+
+static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ long long tmp;
+ struct my_option options;
+ value->val_int(value, &tmp);
+ plugin_opt_set_limits(&options, var);
+ *(int *)save= (int) getopt_ull_limit_value(tmp, &options);
+ return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
+ (*(int *)save != (int) tmp);
+}
+
+
+static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ long long tmp;
+ struct my_option options;
+ value->val_int(value, &tmp);
+ plugin_opt_set_limits(&options, var);
+ *(long *)save= (long) getopt_ull_limit_value(tmp, &options);
+ return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
+ (*(long *)save != (long) tmp);
+}
+
+
+static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ long long tmp;
+ struct my_option options;
+ value->val_int(value, &tmp);
+ plugin_opt_set_limits(&options, var);
+ *(ulonglong *)save= getopt_ull_limit_value(tmp, &options);
+ return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
+ (*(long long *)save != tmp);
+}
+
+static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ const char *str;
+ int length;
+
+ length= sizeof(buff);
+ if ((str= value->val_str(value, buff, &length)))
+ str= thd->strmake(str, length);
+ *(const char**)save= str;
+ return 0;
+}
+
+
+static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ const char *strvalue= "NULL", *str;
+ TYPELIB *typelib;
+ long long tmp;
+ long result;
+ int length;
+
+ if (var->flags & PLUGIN_VAR_THDLOCAL)
+ typelib= ((thdvar_enum_t*) var)->typelib;
+ else
+ typelib= ((sysvar_enum_t*) var)->typelib;
+
+ if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
+ {
+ length= sizeof(buff);
+ if (!(str= value->val_str(value, buff, &length)))
+ goto err;
+ if ((result= find_type(typelib, str, length, 1)-1) < 0)
+ {
+ strvalue= str;
+ goto err;
+ }
+ }
+ else
+ {
+ if (value->val_int(value, &tmp))
+ goto err;
+ if (tmp >= typelib->count)
+ {
+ llstr(tmp, buff);
+ strvalue= buff;
+ goto err;
+ }
+ result= (long) tmp;
+ }
+ *(long*)save= result;
+ return 0;
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
+ return 1;
+}
+
+
+static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
+ void *save, st_mysql_value *value)
+{
+ char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
+ const char *strvalue= "NULL", *str;
+ TYPELIB *typelib;
+ ulonglong result;
+ uint error_len;
+ bool not_used;
+ int length;
+
+ if (var->flags & PLUGIN_VAR_THDLOCAL)
+ typelib= ((thdvar_set_t*) var)->typelib;
+ else
+ typelib= ((sysvar_set_t*)var)->typelib;
+
+ if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
+ {
+ length= sizeof(buff);
+ if (!(str= value->val_str(value, buff, &length)))
+ goto err;
+ result= find_set(typelib, str, length, NULL,
+ &error, &error_len, &not_used);
+ if (error_len)
+ {
+ strmake(buff, error, min(sizeof(buff), error_len));
+ strvalue= buff;
+ goto err;
+ }
+ }
+ else
+ {
+ if (value->val_int(value, (long long *)&result))
+ goto err;
+ if (unlikely((result >= (ULL(1) << typelib->count)) &&
+ (typelib->count < sizeof(long)*8)))
+ {
+ llstr(result, buff);
+ strvalue= buff;
+ goto err;
+ }
+ }
+ *(ulonglong*)save= result;
+ return 0;
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->name, strvalue);
+ return 1;
+}
+
+
+static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, void *save)
+{
+ *(my_bool *) tgt= *(int *) save ? 1 : 0;
+}
+
+
+static void update_func_int(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, void *save)
+{
+ *(int *)tgt= *(int *) save;
+}
+
+
+static void update_func_long(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, void *save)
+{
+ *(long *)tgt= *(long *) save;
+}
+
+
+static void update_func_longlong(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, void *save)
+{
+ *(longlong *)tgt= *(ulonglong *) save;
+}
+
+
+static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
+ void *tgt, void *save)
+{
+ char *old= *(char **) tgt;
+ *(char **)tgt= *(char **) save;
+ if (var->flags & PLUGIN_VAR_MEMALLOC)
+ {
+ *(char **)tgt= my_strdup(*(char **) save, MYF(0));
+ my_free(old, MYF(0));
+ }
+}
+
+
+/****************************************************************************
+ System Variables support
+****************************************************************************/
+
+
+sys_var *find_sys_var(THD *thd, const char *str, uint length)
+{
+ sys_var *var;
+ sys_var_pluginvar *pi= NULL;
+ plugin_ref plugin;
+ DBUG_ENTER("find_sys_var");
+
+ pthread_mutex_lock(&LOCK_plugin);
+ rw_rdlock(&LOCK_system_variables_hash);
+ if ((var= intern_find_sys_var(str, length, false)) &&
+ (pi= var->cast_pluginvar()))
+ {
+ rw_unlock(&LOCK_system_variables_hash);
+ LEX *lex= thd ? thd->lex : 0;
+ if (!(plugin= my_intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
+ var= NULL; /* failed to lock it, it must be uninstalling */
+ else
+ if (!(plugin_state(plugin) & PLUGIN_IS_READY))
+ {
+ /* initialization not completed */
+ var= NULL;
+ intern_plugin_unlock(lex, plugin);
+ }
+ }
+ else
+ rw_unlock(&LOCK_system_variables_hash);
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ /*
+ If the variable exists but the plugin it is associated with is not ready
+ then the intern_plugin_lock did not raise an error, so we do it here.
+ */
+ if (pi && !var)
+ my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (char*) str);
+ DBUG_RETURN(var);
+}
+
+
+/*
+ called by register_var, construct_options and test_plugin_options.
+ Returns the 'bookmark' for the named variable.
+ LOCK_system_variables_hash should be at least read locked
+*/
+static st_bookmark *find_bookmark(const char *plugin, const char *name,
+ int flags)
+{
+ st_bookmark *result= NULL;
+ uint namelen, length, pluginlen= 0;
+ char *varname, *p;
+
+ if (!(flags & PLUGIN_VAR_THDLOCAL))
+ return NULL;
+
+ namelen= strlen(name);
+ if (plugin)
+ pluginlen= strlen(plugin) + 1;
+ length= namelen + pluginlen + 2;
+ varname= (char*) my_alloca(length);
+
+ if (plugin)
+ {
+ strxmov(varname + 1, plugin, "_", name, NullS);
+ for (p= varname + 1; *p; p++)
+ if (*p == '-')
+ *p= '_';
+ }
+ else
+ memcpy(varname + 1, name, namelen + 1);
+
+ varname[0]= flags & PLUGIN_VAR_TYPEMASK;
+
+ result= (st_bookmark*) hash_search(&bookmark_hash,
+ (const uchar*) varname, length - 1);
+
+ my_afree(varname);
+ return result;
+}
+
+
+/*
+ returns a bookmark for thd-local variables, creating if neccessary.
+ returns null for non thd-local variables.
+ Requires that a write lock is obtained on LOCK_system_variables_hash
+*/
+static st_bookmark *register_var(const char *plugin, const char *name,
+ int flags)
+{
+ uint length= strlen(plugin) + strlen(name) + 3, size= 0, offset, new_size;
+ st_bookmark *result;
+ char *varname, *p;
+
+ if (!(flags & PLUGIN_VAR_THDLOCAL))
+ return NULL;
+
+ switch (flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL:
+ size= sizeof(my_bool);
+ break;
+ case PLUGIN_VAR_INT:
+ size= sizeof(int);
+ break;
+ case PLUGIN_VAR_LONG:
+ size= sizeof(long);
+ break;
+ case PLUGIN_VAR_LONGLONG:
+ size= sizeof(ulonglong);
+ break;
+ case PLUGIN_VAR_STR:
+ size= sizeof(char*);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ return NULL;
+ };
+
+ varname= ((char*) my_alloca(length));
+ strxmov(varname + 1, plugin, "_", name, NullS);
+ for (p= varname + 1; *p; p++)
+ if (*p == '-')
+ *p= '_';
+
+ if (!(result= find_bookmark(NULL, varname + 1, flags)))
+ {
+ result= (st_bookmark*) alloc_root(&plugin_mem_root,
+ sizeof(struct st_bookmark) + length-1);
+ varname[0]= flags & PLUGIN_VAR_TYPEMASK;
+ memcpy(result->key, varname, length);
+ result->name_len= length - 2;
+ result->offset= -1;
+
+ DBUG_ASSERT(size && !(size & (size-1))); /* must be power of 2 */
+
+ offset= global_system_variables.dynamic_variables_size;
+ offset= (offset + size - 1) & ~(size - 1);
+ result->offset= (int) offset;
+
+ new_size= (offset + size + 63) & ~63;
+
+ if (new_size > global_variables_dynamic_size)
+ {
+ global_system_variables.dynamic_variables_ptr= (char*)
+ my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
+ MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ max_system_variables.dynamic_variables_ptr= (char*)
+ my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
+ MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ /*
+ Clear the new variable value space. This is required for string
+ variables. If their value is non-NULL, it must point to a valid
+ string.
+ */
+ bzero(global_system_variables.dynamic_variables_ptr +
+ global_variables_dynamic_size,
+ new_size - global_variables_dynamic_size);
+ bzero(max_system_variables.dynamic_variables_ptr +
+ global_variables_dynamic_size,
+ new_size - global_variables_dynamic_size);
+ global_variables_dynamic_size= new_size;
+ }
+
+ global_system_variables.dynamic_variables_head= offset;
+ max_system_variables.dynamic_variables_head= offset;
+ global_system_variables.dynamic_variables_size= offset + size;
+ max_system_variables.dynamic_variables_size= offset + size;
+ global_system_variables.dynamic_variables_version++;
+ max_system_variables.dynamic_variables_version++;
+
+ result->version= global_system_variables.dynamic_variables_version;
+
+ /* this should succeed because we have already checked if a dup exists */
+ if (my_hash_insert(&bookmark_hash, (uchar*) result))
+ {
+ fprintf(stderr, "failed to add placeholder to hash");
+ DBUG_ASSERT(0);
+ }
+ }
+ my_afree(varname);
+ return result;
+}
+
+
+/*
+ returns a pointer to the memory which holds the thd-local variable or
+ a pointer to the global variable if thd==null.
+ If required, will sync with global variables if the requested variable
+ has not yet been allocated in the current thread.
+*/
+static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
+{
+ DBUG_ASSERT(offset >= 0);
+ DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);
+
+ if (!thd)
+ return (uchar*) global_system_variables.dynamic_variables_ptr + offset;
+
+ /*
+ dynamic_variables_head points to the largest valid offset
+ */
+ if (!thd->variables.dynamic_variables_ptr ||
+ (uint)offset > thd->variables.dynamic_variables_head)
+ {
+ uint idx;
+
+ rw_rdlock(&LOCK_system_variables_hash);
+
+ thd->variables.dynamic_variables_ptr= (char*)
+ my_realloc(thd->variables.dynamic_variables_ptr,
+ global_variables_dynamic_size,
+ MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+
+ if (global_lock)
+ pthread_mutex_lock(&LOCK_global_system_variables);
+
+ safe_mutex_assert_owner(&LOCK_global_system_variables);
+
+ memcpy(thd->variables.dynamic_variables_ptr +
+ thd->variables.dynamic_variables_size,
+ global_system_variables.dynamic_variables_ptr +
+ thd->variables.dynamic_variables_size,
+ global_system_variables.dynamic_variables_size -
+ thd->variables.dynamic_variables_size);
+
+ /*
+ now we need to iterate through any newly copied 'defaults'
+ and if it is a string type with MEMALLOC flag, we need to strdup
+ */
+ for (idx= 0; idx < bookmark_hash.records; idx++)
+ {
+ sys_var_pluginvar *pi;
+ sys_var *var;
+ st_bookmark *v= (st_bookmark*) hash_element(&bookmark_hash,idx);
+
+ if (v->version <= thd->variables.dynamic_variables_version ||
+ !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
+ !(pi= var->cast_pluginvar()) ||
+ v->key[0] != (pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
+ continue;
+
+ /* Here we do anything special that may be required of the data types */
+
+ if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
+ pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC)
+ {
+ char **pp= (char**) (thd->variables.dynamic_variables_ptr +
+ *(int*)(pi->plugin_var + 1));
+ if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr +
+ *(int*)(pi->plugin_var + 1))))
+ *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
+ }
+ }
+
+ if (global_lock)
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+
+ thd->variables.dynamic_variables_version=
+ global_system_variables.dynamic_variables_version;
+ thd->variables.dynamic_variables_head=
+ global_system_variables.dynamic_variables_head;
+ thd->variables.dynamic_variables_size=
+ global_system_variables.dynamic_variables_size;
+
+ rw_unlock(&LOCK_system_variables_hash);
+ }
+ return (uchar*)thd->variables.dynamic_variables_ptr + offset;
+}
+
+static uchar *mysql_sys_var_ptr(void* a_thd, int offset)
+{
+ return intern_sys_var_ptr((THD *)a_thd, offset, true);
+}
+
+
+void plugin_thdvar_init(THD *thd)
+{
+ plugin_ref old_table_plugin= thd->variables.table_plugin;
+ DBUG_ENTER("plugin_thdvar_init");
+
+ thd->variables.table_plugin= NULL;
+ cleanup_variables(thd, &thd->variables);
+
+ thd->variables= global_system_variables;
+ thd->variables.table_plugin= NULL;
+
+ /* we are going to allocate these lazily */
+ thd->variables.dynamic_variables_version= 0;
+ thd->variables.dynamic_variables_size= 0;
+ thd->variables.dynamic_variables_ptr= 0;
+
+ pthread_mutex_lock(&LOCK_plugin);
+ thd->variables.table_plugin=
+ my_intern_plugin_lock(NULL, global_system_variables.table_plugin);
+ intern_plugin_unlock(NULL, old_table_plugin);
+ pthread_mutex_unlock(&LOCK_plugin);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unlocks all system variables which hold a reference
+*/
+static void unlock_variables(THD *thd, struct system_variables *vars)
+{
+ intern_plugin_unlock(NULL, vars->table_plugin);
+ vars->table_plugin= NULL;
+}
+
+
+/*
+ Frees memory used by system variables
+
+ Unlike plugin_vars_free_values() it frees all variables of all plugins,
+ it's used on shutdown.
+*/
+static void cleanup_variables(THD *thd, struct system_variables *vars)
+{
+ st_bookmark *v;
+ sys_var_pluginvar *pivar;
+ sys_var *var;
+ int flags;
+ uint idx;
+
+ rw_rdlock(&LOCK_system_variables_hash);
+ for (idx= 0; idx < bookmark_hash.records; idx++)
+ {
+ v= (st_bookmark*) hash_element(&bookmark_hash, idx);
+ if (v->version > vars->dynamic_variables_version ||
+ !(var= intern_find_sys_var(v->key + 1, v->name_len, true)) ||
+ !(pivar= var->cast_pluginvar()) ||
+ v->key[0] != (pivar->plugin_var->flags & PLUGIN_VAR_TYPEMASK))
+ continue;
+
+ flags= pivar->plugin_var->flags;
+
+ if ((flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
+ flags & PLUGIN_VAR_THDLOCAL && flags & PLUGIN_VAR_MEMALLOC)
+ {
+ char **ptr= (char**) pivar->real_value_ptr(thd, OPT_SESSION);
+ my_free(*ptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ *ptr= NULL;
+ }
+ }
+ rw_unlock(&LOCK_system_variables_hash);
+
+ DBUG_ASSERT(vars->table_plugin == NULL);
+
+ my_free(vars->dynamic_variables_ptr, MYF(MY_ALLOW_ZERO_PTR));
+ vars->dynamic_variables_ptr= NULL;
+ vars->dynamic_variables_size= 0;
+ vars->dynamic_variables_version= 0;
+}
+
+
+void plugin_thdvar_cleanup(THD *thd)
+{
+ uint idx;
+ plugin_ref *list;
+ DBUG_ENTER("plugin_thdvar_cleanup");
+
+ pthread_mutex_lock(&LOCK_plugin);
+
+ unlock_variables(thd, &thd->variables);
+ cleanup_variables(thd, &thd->variables);
+
+ if ((idx= thd->lex->plugins.elements))
+ {
+ list= ((plugin_ref*) thd->lex->plugins.buffer) + idx - 1;
+ DBUG_PRINT("info",("unlocking %d plugins", idx));
+ while ((uchar*) list >= thd->lex->plugins.buffer)
+ intern_plugin_unlock(NULL, *list--);
+ }
+
+ reap_plugins();
+ pthread_mutex_unlock(&LOCK_plugin);
+
+ reset_dynamic(&thd->lex->plugins);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Free values of thread variables of a plugin.
+
+ @detail This must be called before a plugin is deleted. Otherwise its
+ variables are no longer accessible and the value space is lost. Note
+ that only string values with PLUGIN_VAR_MEMALLOC are allocated and
+ must be freed.
+
+ @param[in] vars Chain of system variables of a plugin
+*/
+
+static void plugin_vars_free_values(sys_var *vars)
+{
+ DBUG_ENTER("plugin_vars_free_values");
+
+ for (sys_var *var= vars; var; var= var->next)
+ {
+ sys_var_pluginvar *piv= var->cast_pluginvar();
+ if (piv &&
+ ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
+ (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
+ {
+ /* Free the string from global_system_variables. */
+ char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
+ DBUG_PRINT("plugin", ("freeing value for: '%s' addr: 0x%lx",
+ var->name, (long) valptr));
+ my_free(*valptr, MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
+ *valptr= NULL;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+bool sys_var_pluginvar::check_update_type(Item_result type)
+{
+ if (is_readonly())
+ return 1;
+ switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_INT:
+ case PLUGIN_VAR_LONG:
+ case PLUGIN_VAR_LONGLONG:
+ return type != INT_RESULT;
+ case PLUGIN_VAR_STR:
+ return type != STRING_RESULT;
+ default:
+ return 0;
+ }
+}
+
+
+SHOW_TYPE sys_var_pluginvar::show_type()
+{
+ switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL:
+ return SHOW_MY_BOOL;
+ case PLUGIN_VAR_INT:
+ return SHOW_INT;
+ case PLUGIN_VAR_LONG:
+ return SHOW_LONG;
+ case PLUGIN_VAR_LONGLONG:
+ return SHOW_LONGLONG;
+ case PLUGIN_VAR_STR:
+ return SHOW_CHAR_PTR;
+ case PLUGIN_VAR_ENUM:
+ case PLUGIN_VAR_SET:
+ return SHOW_CHAR;
+ default:
+ DBUG_ASSERT(0);
+ return SHOW_UNDEF;
+ }
+}
+
+
+uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
+{
+ DBUG_ASSERT(thd || (type == OPT_GLOBAL));
+ if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
+ {
+ if (type == OPT_GLOBAL)
+ thd= NULL;
+
+ return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
+ }
+ return *(uchar**) (plugin_var+1);
+}
+
+
+TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
+{
+ switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
+ case PLUGIN_VAR_ENUM:
+ return ((sysvar_enum_t *)plugin_var)->typelib;
+ case PLUGIN_VAR_SET:
+ return ((sysvar_set_t *)plugin_var)->typelib;
+ case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
+ return ((thdvar_enum_t *)plugin_var)->typelib;
+ case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
+ return ((thdvar_set_t *)plugin_var)->typelib;
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+
+uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ uchar* result;
+
+ result= real_value_ptr(thd, type);
+
+ if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
+ result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
+ else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
+ {
+ char buffer[STRING_BUFFER_USUAL_SIZE];
+ String str(buffer, sizeof(buffer), system_charset_info);
+ TYPELIB *typelib= plugin_var_typelib();
+ ulonglong mask= 1, value= *(ulonglong*) result;
+ uint i;
+
+ str.length(0);
+ for (i= 0; i < typelib->count; i++, mask<<=1)
+ {
+ if (!(value & mask))
+ continue;
+ str.append(typelib->type_names[i], typelib->type_lengths[i]);
+ str.append(',');
+ }
+
+ result= (uchar*) "";
+ if (str.length())
+ result= (uchar*) thd->strmake(str.ptr(), str.length()-1);
+ }
+ return result;
+}
+
+
+bool sys_var_pluginvar::check(THD *thd, set_var *var)
+{
+ st_item_value_holder value;
+ DBUG_ASSERT(is_readonly() || plugin_var->check);
+
+ value.value_type= item_value_type;
+ value.val_str= item_val_str;
+ value.val_int= item_val_int;
+ value.val_real= item_val_real;
+ value.item= var->value;
+
+ return is_readonly() ||
+ plugin_var->check(thd, plugin_var, &var->save_result, &value);
+}
+
+
+void sys_var_pluginvar::set_default(THD *thd, enum_var_type type)
+{
+ void *tgt, *src;
+
+ DBUG_ASSERT(is_readonly() || plugin_var->update);
+
+ if (is_readonly())
+ return;
+
+ tgt= real_value_ptr(thd, type);
+ src= ((void **) (plugin_var + 1) + 1);
+
+ if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
+ {
+ src= ((int*) (plugin_var + 1) + 1);
+ if (type != OPT_GLOBAL)
+ src= real_value_ptr(thd, OPT_GLOBAL);
+ }
+
+ /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
+ DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
+ thd == current_thd);
+
+ if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || type == OPT_GLOBAL)
+ {
+ pthread_mutex_lock(&LOCK_plugin);
+ plugin_var->update(thd, plugin_var, tgt, src);
+ pthread_mutex_unlock(&LOCK_plugin);
+ }
+ else
+ plugin_var->update(thd, plugin_var, tgt, src);
+}
+
+
+bool sys_var_pluginvar::update(THD *thd, set_var *var)
+{
+ void *tgt;
+
+ DBUG_ASSERT(is_readonly() || plugin_var->update);
+
+ /* thd must equal current_thd if PLUGIN_VAR_THDLOCAL flag is set */
+ DBUG_ASSERT(!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ||
+ thd == current_thd);
+
+ if (is_readonly())
+ return 1;
+
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ tgt= real_value_ptr(thd, var->type);
+
+ if (!(plugin_var->flags & PLUGIN_VAR_THDLOCAL) || var->type == OPT_GLOBAL)
+ {
+ /* variable we are updating has global scope, so we unlock after updating */
+ plugin_var->update(thd, plugin_var, tgt, &var->save_result);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ }
+ else
+ {
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ plugin_var->update(thd, plugin_var, tgt, &var->save_result);
+ }
+ return 0;
+}
+
+
+#define OPTION_SET_LIMITS(type, options, opt) \
+ options->var_type= type; \
+ options->def_value= (opt)->def_val; \
+ options->min_value= (opt)->min_val; \
+ options->max_value= (opt)->max_val; \
+ options->block_size= (long) (opt)->blk_sz
+
+
+static void plugin_opt_set_limits(struct my_option *options,
+ const struct st_mysql_sys_var *opt)
+{
+ switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
+ PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
+ /* global system variables */
+ case PLUGIN_VAR_INT:
+ OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
+ break;
+ case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
+ OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
+ break;
+ case PLUGIN_VAR_LONG:
+ OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
+ break;
+ case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
+ OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
+ break;
+ case PLUGIN_VAR_LONGLONG:
+ OPTION_SET_LIMITS(GET_LL, options, (sysvar_longlong_t*) opt);
+ break;
+ case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
+ OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
+ break;
+ case PLUGIN_VAR_ENUM:
+ options->var_type= GET_ENUM;
+ options->typelib= ((sysvar_enum_t*) opt)->typelib;
+ options->def_value= *(ulong*) ((int*) (opt + 1) + 1);
+ options->min_value= options->block_size= 0;
+ options->max_value= options->typelib->count - 1;
+ break;
+ case PLUGIN_VAR_SET:
+ options->var_type= GET_SET;
+ options->typelib= ((sysvar_set_t*) opt)->typelib;
+ options->def_value= *(ulonglong*) ((int*) (opt + 1) + 1);
+ options->min_value= options->block_size= 0;
+ options->max_value= (ULL(1) << options->typelib->count) - 1;
+ break;
+ case PLUGIN_VAR_BOOL:
+ options->var_type= GET_BOOL;
+ options->def_value= *(my_bool*) ((void**)(opt + 1) + 1);
+ break;
+ case PLUGIN_VAR_STR:
+ options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
+ GET_STR_ALLOC : GET_STR);
+ options->def_value= (ulonglong)(intptr) *((char**) ((void**) (opt + 1) + 1));
+ break;
+ /* threadlocal variables */
+ case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
+ break;
+ case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
+ break;
+ case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
+ break;
+ case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
+ break;
+ case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_LL, options, (thdvar_longlong_t*) opt);
+ break;
+ case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
+ OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
+ break;
+ case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
+ options->var_type= GET_ENUM;
+ options->typelib= ((thdvar_enum_t*) opt)->typelib;
+ options->def_value= *(ulong*) ((int*) (opt + 1) + 1);
+ options->min_value= options->block_size= 0;
+ options->max_value= options->typelib->count - 1;
+ break;
+ case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
+ options->var_type= GET_SET;
+ options->typelib= ((thdvar_set_t*) opt)->typelib;
+ options->def_value= *(ulonglong*) ((int*) (opt + 1) + 1);
+ options->min_value= options->block_size= 0;
+ options->max_value= (ULL(1) << options->typelib->count) - 1;
+ break;
+ case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
+ options->var_type= GET_BOOL;
+ options->def_value= *(my_bool*) ((int*) (opt + 1) + 1);
+ break;
+ case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
+ options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
+ GET_STR_ALLOC : GET_STR);
+ options->def_value= (intptr) *((char**) ((void**) (opt + 1) + 1));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ options->arg_type= REQUIRED_ARG;
+ if (opt->flags & PLUGIN_VAR_NOCMDARG)
+ options->arg_type= NO_ARG;
+ if (opt->flags & PLUGIN_VAR_OPCMDARG)
+ options->arg_type= OPT_ARG;
+}
+
+
+static my_bool get_one_option(int optid __attribute__((unused)),
+ const struct my_option *opt,
+ char *argument)
+{
+ return 0;
+}
+
+
+static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
+ my_option *options, my_bool **enabled,
+ bool can_disable)
+{
+ const char *plugin_name= tmp->plugin->name;
+ uint namelen= strlen(plugin_name), optnamelen;
+ uint buffer_length= namelen * 4 + (can_disable ? 75 : 10);
+ char *name= (char*) alloc_root(mem_root, buffer_length) + 1;
+ char *optname, *p;
+ int index= 0, offset= 0;
+ st_mysql_sys_var *opt, **plugin_option;
+ st_bookmark *v;
+ DBUG_ENTER("construct_options");
+ DBUG_PRINT("plugin", ("plugin: '%s' enabled: %d can_disable: %d",
+ plugin_name, **enabled, can_disable));
+
+ /* support --skip-plugin-foo syntax */
+ memcpy(name, plugin_name, namelen + 1);
+ my_casedn_str(&my_charset_latin1, name);
+ strxmov(name + namelen + 1, "plugin-", name, NullS);
+ /* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
+
+ for (p= name + namelen*2 + 8; p > name; p--)
+ if (*p == '_')
+ *p= '-';
+
+ if (can_disable)
+ {
+ strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
+ "Disable with --skip-", name," (will save memory).", NullS);
+ /*
+ Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
+ 20 + namelen + 20 + 1 == namelen * 4 + 67.
+ */
+
+ options[0].comment= name + namelen*2 + 10;
+ }
+
+ /*
+ NOTE: 'name' is one char above the allocated buffer!
+ NOTE: This code assumes that 'my_bool' and 'char' are of same size.
+ */
+ *((my_bool *)(name -1))= **enabled;
+ *enabled= (my_bool *)(name - 1);
+
+
+ options[1].name= (options[0].name= name) + namelen + 1;
+ options[0].id= options[1].id= 256; /* must be >255. dup id ok */
+ options[0].var_type= options[1].var_type= GET_BOOL;
+ options[0].arg_type= options[1].arg_type= NO_ARG;
+ options[0].def_value= options[1].def_value= **enabled;
+ options[0].value= options[0].u_max_value=
+ options[1].value= options[1].u_max_value= (uchar**) (name - 1);
+ options+= 2;
+
+ /*
+ Two passes as the 2nd pass will take pointer addresses for use
+ by my_getopt and register_var() in the first pass uses realloc
+ */
+
+ for (plugin_option= tmp->plugin->system_vars;
+ plugin_option && *plugin_option; plugin_option++, index++)
+ {
+ opt= *plugin_option;
+ if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
+ continue;
+ if (!(register_var(name, opt->name, opt->flags)))
+ continue;
+ switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_bool_t *) opt);
+ break;
+ case PLUGIN_VAR_INT:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_int_t *) opt);
+ break;
+ case PLUGIN_VAR_LONG:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_long_t *) opt);
+ break;
+ case PLUGIN_VAR_LONGLONG:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_longlong_t *) opt);
+ break;
+ case PLUGIN_VAR_STR:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_str_t *) opt);
+ break;
+ case PLUGIN_VAR_ENUM:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_enum_t *) opt);
+ break;
+ case PLUGIN_VAR_SET:
+ SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt);
+ break;
+ default:
+ sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
+ opt->flags, plugin_name);
+ DBUG_RETURN(-1);
+ };
+ }
+
+ for (plugin_option= tmp->plugin->system_vars;
+ plugin_option && *plugin_option; plugin_option++, index++)
+ {
+ switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
+ case PLUGIN_VAR_BOOL:
+ if (!opt->check)
+ opt->check= check_func_bool;
+ if (!opt->update)
+ opt->update= update_func_bool;
+ break;
+ case PLUGIN_VAR_INT:
+ if (!opt->check)
+ opt->check= check_func_int;
+ if (!opt->update)
+ opt->update= update_func_int;
+ break;
+ case PLUGIN_VAR_LONG:
+ if (!opt->check)
+ opt->check= check_func_long;
+ if (!opt->update)
+ opt->update= update_func_long;
+ break;
+ case PLUGIN_VAR_LONGLONG:
+ if (!opt->check)
+ opt->check= check_func_longlong;
+ if (!opt->update)
+ opt->update= update_func_longlong;
+ break;
+ case PLUGIN_VAR_STR:
+ if (!opt->check)
+ opt->check= check_func_str;
+ if (!opt->update)
+ {
+ opt->update= update_func_str;
+ if (!(opt->flags & PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY))
+ {
+ opt->flags|= PLUGIN_VAR_READONLY;
+ sql_print_warning("Server variable %s of plugin %s was forced "
+ "to be read-only: string variable without "
+ "update_func and PLUGIN_VAR_MEMALLOC flag",
+ opt->name, plugin_name);
+ }
+ }
+ break;
+ case PLUGIN_VAR_ENUM:
+ if (!opt->check)
+ opt->check= check_func_enum;
+ if (!opt->update)
+ opt->update= update_func_long;
+ break;
+ case PLUGIN_VAR_SET:
+ if (!opt->check)
+ opt->check= check_func_set;
+ if (!opt->update)
+ opt->update= update_func_longlong;
+ break;
+ default:
+ sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
+ opt->flags, plugin_name);
+ DBUG_RETURN(-1);
+ }
+
+ if (opt->flags & PLUGIN_VAR_NOCMDOPT)
+ continue;
+
+ if (!opt->name)
+ {
+ sql_print_error("Missing variable name in plugin '%s'.",
+ plugin_name);
+ DBUG_RETURN(-1);
+ }
+
+ if (!(v= find_bookmark(name, opt->name, opt->flags)))
+ {
+ optnamelen= strlen(opt->name);
+ optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
+ strxmov(optname, name, "-", opt->name, NullS);
+ optnamelen= namelen + optnamelen + 1;
+ }
+ else
+ optname= (char*) memdup_root(mem_root, v->key + 1, (optnamelen= v->name_len) + 1);
+
+ /* convert '_' to '-' */
+ for (p= optname; *p; p++)
+ if (*p == '_')
+ *p= '-';
+
+ options->name= optname;
+ options->comment= opt->comment;
+ options->app_type= opt;
+ options->id= (options-1)->id + 1;
+
+ if (opt->flags & PLUGIN_VAR_THDLOCAL)
+ *(int*)(opt + 1)= offset= v->offset;
+
+ plugin_opt_set_limits(options, opt);
+
+ if ((opt->flags & PLUGIN_VAR_TYPEMASK) != PLUGIN_VAR_ENUM &&
+ (opt->flags & PLUGIN_VAR_TYPEMASK) != PLUGIN_VAR_SET)
+ {
+ if (opt->flags & PLUGIN_VAR_THDLOCAL)
+ options->value= options->u_max_value= (uchar**)
+ (global_system_variables.dynamic_variables_ptr + offset);
+ else
+ options->value= options->u_max_value= *(uchar***) (opt + 1);
+ }
+
+ options[1]= options[0];
+ options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
+ options[1].comment= 0; // hidden
+ strxmov(p, "plugin-", optname, NullS);
+
+ options+= 2;
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+static my_option *construct_help_options(MEM_ROOT *mem_root,
+ struct st_plugin_int *p)
+{
+ st_mysql_sys_var **opt;
+ my_option *opts;
+ my_bool dummy, can_disable;
+ my_bool *dummy2= &dummy;
+ uint count= EXTRA_OPTIONS;
+ DBUG_ENTER("construct_help_options");
+
+ for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2);
+
+ if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
+ DBUG_RETURN(NULL);
+
+ bzero(opts, sizeof(my_option) * count);
+
+ dummy= TRUE; /* plugin is enabled. */
+
+ can_disable=
+ my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
+ my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
+
+ if (construct_options(mem_root, p, opts, &dummy2, can_disable))
+ DBUG_RETURN(NULL);
+
+ DBUG_RETURN(opts);
+}
+
+
+/*
+ SYNOPSIS
+ test_plugin_options()
+ tmp_root temporary scratch space
+ plugin internal plugin structure
+ argc user supplied arguments
+ argv user supplied arguments
+ default_enabled default plugin enable status
+ RETURNS:
+ 0 SUCCESS - plugin should be enabled/loaded
+ NOTE:
+ Requires that a write-lock is held on LOCK_system_variables_hash
+*/
+static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
+ int *argc, char **argv, my_bool default_enabled)
+{
+ struct sys_var_chain chain= { NULL, NULL };
+ my_bool enabled_saved= default_enabled, can_disable;
+ my_bool *enabled= &default_enabled;
+ MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
+ &tmp->mem_root : &plugin_mem_root;
+ st_mysql_sys_var **opt;
+ my_option *opts;
+ char *p, *varname;
+ int error;
+ st_mysql_sys_var *o;
+ sys_var *v;
+ struct st_bookmark *var;
+ uint len, count= EXTRA_OPTIONS;
+ DBUG_ENTER("test_plugin_options");
+ DBUG_ASSERT(tmp->plugin && tmp->name.str);
+
+ for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
+ count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
+
+ can_disable=
+ my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
+ my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
+
+ if (count > EXTRA_OPTIONS || (*argc > 1))
+ {
+ if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
+ {
+ sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
+ DBUG_RETURN(-1);
+ }
+ bzero(opts, sizeof(my_option) * count);
+
+ if (construct_options(tmp_root, tmp, opts, &enabled, can_disable))
+ {
+ sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
+ DBUG_RETURN(-1);
+ }
+
+ error= handle_options(argc, &argv, opts, get_one_option);
+ (*argc)++; /* add back one for the program name */
+
+ if (error)
+ {
+ sql_print_error("Parsing options for plugin '%s' failed.",
+ tmp->name.str);
+ DBUG_RETURN(error);
+ }
+ }
+
+ if (!*enabled && !can_disable)
+ {
+ sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
+ *enabled= TRUE;
+ }
+
+ if (*enabled)
+ {
+ for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
+ {
+ if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
+ continue;
+
+ if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
+ v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
+ else
+ {
+ len= tmp->name.length + strlen(o->name) + 2;
+ varname= (char*) alloc_root(mem_root, len);
+ strxmov(varname, tmp->name.str, "-", o->name, NullS);
+ my_casedn_str(&my_charset_latin1, varname);
+
+ for (p= varname; *p; p++)
+ if (*p == '-')
+ *p= '_';
+
+ v= new (mem_root) sys_var_pluginvar(varname, o);
+ }
+ DBUG_ASSERT(v); /* check that an object was actually constructed */
+
+ /*
+ Add to the chain of variables.
+ Done like this for easier debugging so that the
+ pointer to v is not lost on optimized builds.
+ */
+ v->chain_sys_var(&chain);
+ }
+ if (chain.first)
+ {
+ chain.last->next = NULL;
+ if (mysql_add_sys_var_chain(chain.first, NULL))
+ {
+ sql_print_error("Plugin '%s' has conflicting system variables",
+ tmp->name.str);
+ DBUG_RETURN(1);
+ }
+ tmp->system_vars= chain.first;
+ }
+ DBUG_RETURN(0);
+ }
+
+ if (enabled_saved)
+ sql_print_information("Plugin '%s' disabled by command line option",
+ tmp->name.str);
+ DBUG_RETURN(1);
+}
+
+
+/****************************************************************************
+ Help Verbose text with Plugin System Variables
+****************************************************************************/
+
+static int option_cmp(my_option *a, my_option *b)
+{
+ return my_strcasecmp(&my_charset_latin1, a->name, b->name);
+}
+
+
+void my_print_help_inc_plugins(my_option *main_options, uint size)
+{
+ DYNAMIC_ARRAY all_options;
+ struct st_plugin_int *p;
+ MEM_ROOT mem_root;
+ my_option *opt;
+
+ init_alloc_root(&mem_root, 4096, 4096);
+ my_init_dynamic_array(&all_options, sizeof(my_option), size, size/4);
+
+ if (initialized)
+ for (uint idx= 0; idx < plugin_array.elements; idx++)
+ {
+ p= dynamic_element(&plugin_array, idx, struct st_plugin_int *);
+
+ if (!p->plugin->system_vars ||
+ !(opt= construct_help_options(&mem_root, p)))
+ continue;
+
+ /* Only options with a non-NULL comment are displayed in help text */
+ for (;opt->id; opt++)
+ if (opt->comment)
+ insert_dynamic(&all_options, (uchar*) opt);
+ }
+
+ for (;main_options->id; main_options++)
+ insert_dynamic(&all_options, (uchar*) main_options);
+
+ sort_dynamic(&all_options, (qsort_cmp) option_cmp);
+
+ /* main_options now points to the empty option terminator */
+ insert_dynamic(&all_options, (uchar*) main_options);
+
+ my_print_help((my_option*) all_options.buffer);
+ my_print_variables((my_option*) all_options.buffer);
+
+ delete_dynamic(&all_options);
+ free_root(&mem_root, MYF(0));
+}
+
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index fa3440f7f68..70ce21a64da 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,6 +16,17 @@
#ifndef _sql_plugin_h
#define _sql_plugin_h
+class sys_var;
+
+/*
+ the following flags are valid for plugin_init()
+*/
+#define PLUGIN_INIT_SKIP_DYNAMIC_LOADING 1
+#define PLUGIN_INIT_SKIP_PLUGIN_TABLE 2
+#define PLUGIN_INIT_SKIP_INITIALIZATION 4
+
+#define INITIAL_LEX_PLUGIN_LIST_SIZE 16
+
/*
the following #define adds server-only members to enum_mysql_show_type,
that is defined in plugin.h
@@ -42,6 +52,7 @@ typedef struct st_mysql_show_var SHOW_VAR;
#define PLUGIN_IS_DELETED 2
#define PLUGIN_IS_UNINITIALIZED 4
#define PLUGIN_IS_READY 8
+#define PLUGIN_IS_DYING 16
/* A handle for the dynamic library containing a plugin or plugins. */
@@ -64,25 +75,64 @@ struct st_plugin_int
uint state;
uint ref_count; /* number of threads using the plugin */
void *data; /* plugin type specific, e.g. handlerton */
+ MEM_ROOT mem_root; /* memory for dynamic plugin structures */
+ sys_var *system_vars; /* server variables for this plugin */
};
+
+/*
+ See intern_plugin_lock() for the explanation for the
+ conditionally defined plugin_ref type
+*/
+#ifdef DBUG_OFF
+typedef struct st_plugin_int *plugin_ref;
+#define plugin_decl(pi) ((pi)->plugin)
+#define plugin_dlib(pi) ((pi)->plugin_dl)
+#define plugin_data(pi,cast) ((cast)((pi)->data))
+#define plugin_name(pi) (&((pi)->name))
+#define plugin_state(pi) ((pi)->state)
+#define plugin_equals(p1,p2) ((p1) == (p2))
+#else
+typedef struct st_plugin_int **plugin_ref;
+#define plugin_decl(pi) ((pi)[0]->plugin)
+#define plugin_dlib(pi) ((pi)[0]->plugin_dl)
+#define plugin_data(pi,cast) ((cast)((pi)[0]->data))
+#define plugin_name(pi) (&((pi)[0]->name))
+#define plugin_state(pi) ((pi)[0]->state)
+#define plugin_equals(p1,p2) ((p1) && (p2) && (p1)[0] == (p2)[0])
+#endif
+
typedef int (*plugin_type_init)(struct st_plugin_int *);
+extern char *opt_plugin_load;
extern char *opt_plugin_dir_ptr;
extern char opt_plugin_dir[FN_REFLEN];
extern const LEX_STRING plugin_type_names[];
-extern int plugin_init(int);
+
+extern int plugin_init(int *argc, char **argv, int init_flags);
extern void plugin_shutdown(void);
-extern my_bool plugin_is_ready(const LEX_STRING *name, int type);
-extern st_plugin_int *plugin_lock(const LEX_STRING *name, int type);
-extern void plugin_unlock(struct st_plugin_int *plugin);
-extern my_bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl);
-extern my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name);
+extern void my_print_help_inc_plugins(struct my_option *options, uint size);
+extern bool plugin_is_ready(const LEX_STRING *name, int type);
+#define my_plugin_lock_by_name(A,B,C) plugin_lock_by_name(A,B,C CALLER_INFO)
+#define my_plugin_lock_by_name_ci(A,B,C) plugin_lock_by_name(A,B,C ORIG_CALLER_INFO)
+#define my_plugin_lock(A,B) plugin_lock(A,B CALLER_INFO)
+#define my_plugin_lock_ci(A,B) plugin_lock(A,B ORIG_CALLER_INFO)
+extern plugin_ref plugin_lock(THD *thd, plugin_ref *ptr CALLER_INFO_PROTO);
+extern plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name,
+ int type CALLER_INFO_PROTO);
+extern void plugin_unlock(THD *thd, plugin_ref plugin);
+extern void plugin_unlock_list(THD *thd, plugin_ref *list, uint count);
+extern bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
+ const LEX_STRING *dl);
+extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name);
+extern bool plugin_register_builtin(struct st_mysql_plugin *plugin);
+extern void plugin_thdvar_init(THD *thd);
+extern void plugin_thdvar_cleanup(THD *thd);
typedef my_bool (plugin_foreach_func)(THD *thd,
- st_plugin_int *plugin,
+ plugin_ref plugin,
void *arg);
#define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
-extern my_bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
- int type, uint state_mask, void *arg);
+extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
+ int type, uint state_mask, void *arg);
#endif
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 6f810f13d9c..c54b2358b37 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,6 +34,12 @@ When one prepares a statement:
[Params meta info (stubs only for now)] (if Param_count > 0)
[Columns meta info] (if Column_count > 0)
+ During prepare the tables used in a statement are opened, but no
+ locks are acquired. Table opening will block any DDL during the
+ operation, and we do not need any locks as we neither read nor
+ modify any data during prepare. Tables are closed after prepare
+ finishes.
+
When one executes a statement:
- Server gets the command 'COM_STMT_EXECUTE' to execute the
@@ -54,6 +59,10 @@ When one executes a statement:
- Execute the query without re-parsing and send back the results
to client
+ During execution of prepared statement tables are opened and locked
+ the same way they would for normal (non-prepared) statement
+ execution. Tables are unlocked and closed after the execution.
+
When one supplies long data for a placeholder:
- Server gets the long data in pieces with command type
@@ -84,11 +93,11 @@ When one supplies long data for a placeholder:
/* A result class used to send cursor rows using the binary protocol. */
-class Select_fetch_protocol_prep: public select_send
+class Select_fetch_protocol_binary: public select_send
{
- Protocol_prep protocol;
+ Protocol_binary protocol;
public:
- Select_fetch_protocol_prep(THD *thd);
+ Select_fetch_protocol_binary(THD *thd);
virtual bool send_fields(List<Item> &list, uint flags);
virtual bool send_data(List<Item> &items);
virtual bool send_eof();
@@ -100,9 +109,12 @@ public:
#endif
};
-/******************************************************************************
- Prepared_statement: a statement that can contain placeholders
-******************************************************************************/
+/****************************************************************************/
+
+/**
+ @class Prepared_statement
+ @brief Prepared_statement: a statement that can contain placeholders
+*/
class Prepared_statement: public Statement
{
@@ -113,7 +125,7 @@ public:
};
THD *thd;
- Select_fetch_protocol_prep result;
+ Select_fetch_protocol_binary result;
Protocol *protocol;
Item_param **param_array;
uint param_count;
@@ -142,6 +154,16 @@ public:
bool execute(String *expanded_query, bool open_cursor);
/* Destroy this statement */
bool deallocate();
+private:
+ /**
+ Store the parsed tree of a prepared statement here.
+ */
+ LEX main_lex;
+ /**
+ The memory root to allocate parsed tree elements (instances of Item,
+ SELECT_LEX and other classes).
+ */
+ MEM_ROOT main_mem_root;
};
@@ -207,7 +229,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where)
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
{
NET *net= &stmt->thd->net;
- char buff[12];
+ uchar buff[12];
uint tmp;
DBUG_ENTER("send_prep_stmt");
@@ -225,9 +247,9 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
*/
DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
(stmt->param_count &&
- stmt->thd->protocol_simple.send_fields((List<Item> *)
- &stmt->lex->param_list,
- Protocol::SEND_EOF)));
+ stmt->thd->protocol_text.send_fields((List<Item> *)
+ &stmt->lex->param_list,
+ Protocol::SEND_EOF)));
}
#else
static bool send_prep_stmt(Prepared_statement *stmt,
@@ -669,7 +691,7 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
and generate a valid query for logging.
NOTES
- This function, along with other _withlog functions is called when one of
+ This function, along with other _with_log functions is called when one of
binary, slow or general logs is open. Logging of prepared statements in
all cases is performed by means of conventional queries: if parameter
data was supplied from C API, each placeholder in the query is
@@ -693,9 +715,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
0 if success, 1 otherwise
*/
-static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
- uchar *read_pos, uchar *data_end,
- String *query)
+static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
+ uchar *read_pos, uchar *data_end,
+ String *query)
{
THD *thd= stmt->thd;
Item_param **begin= stmt->param_array;
@@ -703,7 +725,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
uint32 length= 0;
String str;
const String *res;
- DBUG_ENTER("insert_params_withlog");
+ DBUG_ENTER("insert_params_with_log");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
@@ -847,7 +869,8 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
}
-static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
+static bool emb_insert_params_with_log(Prepared_statement *stmt,
+ String *query)
{
THD *thd= stmt->thd;
Item_param **it= stmt->param_array;
@@ -858,7 +881,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
const String *res;
uint32 length= 0;
- DBUG_ENTER("emb_insert_params_withlog");
+ DBUG_ENTER("emb_insert_params_with_log");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
DBUG_RETURN(1);
@@ -923,7 +946,7 @@ static bool insert_params_from_vars(Prepared_statement *stmt,
Item_param *param= *it;
varname= var_it++;
entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
- (byte*) varname->str,
+ (uchar*) varname->str,
varname->length);
if (param->set_from_user_var(stmt->thd, entry) ||
param->convert_str_value(stmt->thd))
@@ -977,19 +1000,19 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
/* Insert @'escaped-varname' instead of parameter in the query */
if (entry)
{
- char *begin, *ptr;
+ char *start, *ptr;
buf.length(0);
if (buf.reserve(entry->name.length*2+3))
DBUG_RETURN(1);
- begin= ptr= buf.c_ptr_quick();
+ start= ptr= buf.c_ptr_quick();
*ptr++= '@';
*ptr++= '\'';
ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci,
ptr, 0, entry->name.str,
entry->name.length);
*ptr++= '\'';
- buf.length(ptr - begin);
+ buf.length(ptr - start);
val= &buf;
}
else
@@ -1027,7 +1050,6 @@ static bool mysql_test_insert(Prepared_statement *stmt,
enum_duplicates duplic)
{
THD *thd= stmt->thd;
- LEX *lex= stmt->lex;
List_iterator_fast<List_item> its(values_list);
List_item *values;
DBUG_ENTER("mysql_test_insert");
@@ -1055,12 +1077,12 @@ static bool mysql_test_insert(Prepared_statement *stmt,
if (table_list->table)
{
// don't allocate insert_values
- table_list->table->insert_values=(byte *)1;
+ table_list->table->insert_values=(uchar *)1;
}
if (mysql_prepare_insert(thd, table_list, table_list->table,
fields, values, update_fields, update_values,
- duplic, &unused_conds, FALSE))
+ duplic, &unused_conds, FALSE, FALSE, FALSE))
goto error;
value_count= values->elements;
@@ -1118,32 +1140,20 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
- bool need_reopen;
DBUG_ENTER("mysql_test_update");
- if (update_precheck(thd, table_list))
+ if (update_precheck(thd, table_list) ||
+ open_tables(thd, &table_list, &table_count, 0))
goto error;
- for ( ; ; )
+ if (table_list->multitable_view)
{
- if (open_tables(thd, &table_list, &table_count, 0))
- goto error;
-
- if (table_list->multitable_view)
- {
- DBUG_ASSERT(table_list->view != 0);
- DBUG_PRINT("info", ("Switch to multi-update"));
- /* pass counter value */
- thd->lex->table_count= table_count;
- /* convert to multiupdate */
- DBUG_RETURN(2);
- }
-
- if (!lock_tables(thd, table_list, table_count, &need_reopen))
- break;
- if (!need_reopen)
- goto error;
- close_tables_for_reopen(thd, &table_list);
+ DBUG_ASSERT(table_list->view != 0);
+ DBUG_PRINT("info", ("Switch to multi-update"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ DBUG_RETURN(2);
}
/*
@@ -1154,8 +1164,9 @@ static int mysql_test_update(Prepared_statement *stmt,
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* TABLE_LIST contain right privilages request */
- want_privilege= table_list->grant.want_privilege;
+ /* Force privilege re-checking for views after they have been opened. */
+ want_privilege= (table_list->view ? UPDATE_ACL :
+ table_list->grant.want_privilege);
#endif
if (mysql_prepare_update(thd, table_list, &select->where,
@@ -1210,7 +1221,7 @@ static bool mysql_test_delete(Prepared_statement *stmt,
DBUG_ENTER("mysql_test_delete");
if (delete_precheck(thd, table_list) ||
- open_and_lock_tables(thd, table_list))
+ open_normal_and_derived_tables(thd, table_list, 0))
goto error;
if (!table_list->table)
@@ -1254,7 +1265,6 @@ static int mysql_test_select(Prepared_statement *stmt,
lex->select_lex.context.resolve_in_select_list= TRUE;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (tables)
{
@@ -1263,7 +1273,6 @@ static int mysql_test_select(Prepared_statement *stmt,
}
else if (check_access(thd, privilege, any_db,0,0,0,0))
goto error;
-#endif
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
{
@@ -1271,7 +1280,7 @@ static int mysql_test_select(Prepared_statement *stmt,
goto error;
}
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
goto error;
thd->used_tables= 0; // Updated by setup_fields
@@ -1332,7 +1341,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt,
if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
DBUG_RETURN(TRUE);
- if (open_and_lock_tables(thd, tables))
+ if (open_normal_and_derived_tables(thd, tables, 0))
DBUG_RETURN(TRUE);
DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
}
@@ -1362,7 +1371,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
set_var_base *var;
if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
- open_and_lock_tables(thd, tables))
+ open_normal_and_derived_tables(thd, tables, 0))
goto error;
while ((var= it++))
@@ -1388,7 +1397,7 @@ error:
NOTE
This function won't directly open tables used in select. They should
be opened either by calling function (and in this case you probably
- should use select_like_stmt_test_with_open_n_lock()) or by
+ should use select_like_stmt_test_with_open()) or by
"specific_prepare" call (like this happens in case of multi-update).
RETURN VALUE
@@ -1416,14 +1425,14 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
}
/*
- Check internal SELECT of the prepared command (with opening and
- locking of used tables).
+ Check internal SELECT of the prepared command (with opening of used
+ tables).
SYNOPSIS
- select_like_stmt_test_with_open_n_lock()
+ select_like_stmt_test_with_open()
stmt prepared statement
- tables list of tables to be opened and locked
- before calling specific_prepare function
+ tables list of tables to be opened before calling
+ specific_prepare function
specific_prepare function of command specific prepare
setup_tables_done_option options to be passed to LEX::unit.prepare()
@@ -1433,19 +1442,20 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
*/
static bool
-select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
- TABLE_LIST *tables,
- bool (*specific_prepare)(THD *thd),
- ulong setup_tables_done_option)
+select_like_stmt_test_with_open(Prepared_statement *stmt,
+ TABLE_LIST *tables,
+ bool (*specific_prepare)(THD *thd),
+ ulong setup_tables_done_option)
{
- DBUG_ENTER("select_like_stmt_test_with_open_n_lock");
+ DBUG_ENTER("select_like_stmt_test_with_open");
/*
- We should not call LEX::unit.cleanup() after this open_and_lock_tables()
- call because we don't allow prepared EXPLAIN yet so derived tables will
- clean up after themself.
+ We should not call LEX::unit.cleanup() after this
+ open_normal_and_derived_tables() call because we don't allow
+ prepared EXPLAIN yet so derived tables will clean up after
+ themself.
*/
- if (open_and_lock_tables(stmt->thd, tables))
+ if (open_normal_and_derived_tables(stmt->thd, tables, 0))
DBUG_RETURN(TRUE);
DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
@@ -1483,8 +1493,21 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
if (select_lex->item_list.elements)
{
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ lex->link_first_table_back(create_table, link_to_local);
+ create_table->create= TRUE;
+ }
+
+ if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
+ DBUG_RETURN(TRUE);
+
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
+ create_table= lex->unlink_first_table(&link_to_local);
+
select_lex->context.resolve_in_select_list= TRUE;
- res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
+
+ res= select_like_stmt_test(stmt, 0, 0);
}
/* put tables back for PS rexecuting */
@@ -1544,9 +1567,9 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
}
if (multi_delete_precheck(stmt->thd, tables) ||
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_multi_delete_prepare,
- OPTION_SETUP_TABLES_DONE))
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_multi_delete_prepare,
+ OPTION_SETUP_TABLES_DONE))
goto error;
if (!tables->table)
{
@@ -1562,34 +1585,30 @@ error:
/*
Wrapper for mysql_insert_select_prepare, to make change of local tables
- after open_and_lock_tables() call.
+ after open_normal_and_derived_tables() call.
SYNOPSIS
mysql_insert_select_prepare_tester()
thd thread handle
NOTE
- We need to remove the first local table after open_and_lock_tables,
- because mysql_handle_derived uses local tables lists.
+ We need to remove the first local table after
+ open_normal_and_derived_tables(), because mysql_handle_derived
+ uses local tables lists.
*/
static bool mysql_insert_select_prepare_tester(THD *thd)
{
- TABLE_LIST *first;
- bool res;
SELECT_LEX *first_select= &thd->lex->select_lex;
+ TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)->
+ next_local;
+
/* Skip first table, which is the table we are inserting in */
- first_select->table_list.first= (byte*)(first=
- ((TABLE_LIST*)first_select->
- table_list.first)->next_local);
- res= mysql_insert_select_prepare(thd);
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- thd->lex->select_lex.context.resolve_in_select_list= TRUE;
- thd->lex->select_lex.context.table_list= first;
- return res;
+ first_select->table_list.first= (uchar *) second_table;
+ thd->lex->select_lex.context.table_list=
+ thd->lex->select_lex.context.first_name_resolution_table= second_table;
+
+ return mysql_insert_select_prepare(thd);
}
@@ -1616,7 +1635,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
if (tables->table)
{
// don't allocate insert_values
- tables->table->insert_values=(byte *)1;
+ tables->table->insert_values=(uchar *)1;
}
if (insert_precheck(stmt->thd, tables))
@@ -1627,11 +1646,11 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
DBUG_ASSERT(first_local_table != 0);
res=
- select_like_stmt_test_with_open_n_lock(stmt, tables,
- &mysql_insert_select_prepare_tester,
- OPTION_SETUP_TABLES_DONE);
+ select_like_stmt_test_with_open(stmt, tables,
+ &mysql_insert_select_prepare_tester,
+ OPTION_SETUP_TABLES_DONE);
/* revert changes made by mysql_insert_select_prepare_tester */
- lex->select_lex.table_list.first= (byte*) first_local_table;
+ lex->select_lex.table_list.first= (uchar*) first_local_table;
return res;
}
@@ -1665,7 +1684,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
enum enum_sql_command sql_command= lex->sql_command;
int res= 0;
DBUG_ENTER("check_prepared_statement");
- DBUG_PRINT("enter",("command: %d, param_count: %u",
+ DBUG_PRINT("enter",("command: %d param_count: %u",
sql_command, stmt->param_count));
lex->first_lists_tables_same();
@@ -1680,7 +1699,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_INSERT:
res= mysql_test_insert(stmt, tables, lex->field_list,
lex->many_values,
- select_lex->item_list, lex->value_list,
+ lex->update_list, lex->value_list,
lex->duplicates);
break;
@@ -1789,6 +1808,9 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_KILL:
break;
+ case SQLCOM_PREPARE:
+ case SQLCOM_EXECUTE:
+ case SQLCOM_DEALLOCATE_PREPARE:
default:
/*
Trivial check of all status commands. This is easier than having
@@ -1885,7 +1907,7 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep)))
+ if (! (stmt= new Prepared_statement(thd, &thd->protocol_binary)))
DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
if (thd->stmt_map.insert(thd, stmt))
@@ -1965,7 +1987,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
*/
if ((entry=
(user_var_entry*)hash_search(&thd->user_vars,
- (byte*)lex->prepared_stmt_code.str,
+ (uchar*)lex->prepared_stmt_code.str,
lex->prepared_stmt_code.length))
&& entry->value)
{
@@ -1994,7 +2016,7 @@ static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
var_value->length());
- if (!(query_str= alloc_root(thd->mem_root, len+1)))
+ if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
goto end;
if (needs_conversion)
@@ -2057,7 +2079,8 @@ void mysql_sql_stmt_prepare(THD *thd)
const char *query;
uint query_len;
DBUG_ENTER("mysql_sql_stmt_prepare");
- DBUG_ASSERT(thd->protocol == &thd->protocol_simple);
+ LINT_INIT(query_len);
+ DBUG_ASSERT(thd->protocol == &thd->protocol_text);
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2070,7 +2093,7 @@ void mysql_sql_stmt_prepare(THD *thd)
}
if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
- ! (stmt= new Prepared_statement(thd, &thd->protocol_simple)))
+ ! (stmt= new Prepared_statement(thd, &thd->protocol_text)))
{
DBUG_VOID_RETURN; /* out of memory */
}
@@ -2081,6 +2104,7 @@ void mysql_sql_stmt_prepare(THD *thd)
delete stmt;
DBUG_VOID_RETURN;
}
+
if (thd->stmt_map.insert(thd, stmt))
{
/* The statement is deleted and an error is set if insert fails */
@@ -2246,11 +2270,11 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
ulong stmt_id= uint4korr(packet);
- ulong flags= (ulong) ((uchar) packet[4]);
+ ulong flags= (ulong) packet[4];
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
#ifndef EMBEDDED_LIBRARY
- uchar *packet_end= (uchar *) packet + packet_length - 1;
+ uchar *packet_end= packet + packet_length - 1;
#endif
Prepared_statement *stmt;
bool error;
@@ -2273,9 +2297,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
- uchar *null_array= (uchar *) packet;
- if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
- stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
+ uchar *null_array= packet;
+ if (setup_conversion_functions(stmt, &packet, packet_end) ||
+ stmt->set_params(stmt, null_array, packet, packet_end,
&expanded_query))
goto set_params_data_err;
}
@@ -2345,7 +2369,7 @@ void mysql_sql_stmt_execute(THD *thd)
/* Query text for binary, general or slow log, if any of them is open */
String expanded_query;
DBUG_ENTER("mysql_sql_stmt_execute");
- DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str));
+ DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2406,7 +2430,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_fetch);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
DBUG_VOID_RETURN;
@@ -2470,7 +2494,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
- statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_reset);
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
DBUG_VOID_RETURN;
@@ -2533,7 +2557,8 @@ void mysql_sql_stmt_close(THD *thd)
{
Prepared_statement* stmt;
LEX_STRING *name= &thd->lex->prepared_stmt_name;
- DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name->length, name->str));
+ DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
+ name->str));
if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
{
@@ -2569,10 +2594,12 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
uint param_number;
Prepared_statement *stmt;
Item_param *param;
+#ifndef EMBEDDED_LIBRARY
char *packet_end= packet + packet_length - 1;
+#endif
DBUG_ENTER("mysql_stmt_get_longdata");
- statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_send_long_data);
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if (packet_length <= MYSQL_LONG_DATA_HEADER)
@@ -2620,14 +2647,14 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
/***************************************************************************
- Select_fetch_protocol_prep
+ Select_fetch_protocol_binary
****************************************************************************/
-Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd)
- :protocol(thd)
+Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
+ :protocol(thd_arg)
{}
-bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
+bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
{
bool rc;
Protocol *save_protocol= thd->protocol;
@@ -2645,7 +2672,7 @@ bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
return rc;
}
-bool Select_fetch_protocol_prep::send_eof()
+bool Select_fetch_protocol_binary::send_eof()
{
Protocol *save_protocol= thd->protocol;
@@ -2657,7 +2684,7 @@ bool Select_fetch_protocol_prep::send_eof()
bool
-Select_fetch_protocol_prep::send_data(List<Item> &fields)
+Select_fetch_protocol_binary::send_data(List<Item> &fields)
{
Protocol *save_protocol= thd->protocol;
bool rc;
@@ -2673,32 +2700,44 @@ Select_fetch_protocol_prep::send_data(List<Item> &fields)
****************************************************************************/
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
- :Statement(INITIALIZED, ++thd_arg->statement_id_counter,
- thd_arg->variables.query_alloc_block_size,
- thd_arg->variables.query_prealloc_size),
+ :Statement(&main_lex, &main_mem_root,
+ INITIALIZED, ++thd_arg->statement_id_counter),
thd(thd_arg),
result(thd_arg),
protocol(protocol_arg),
param_array(0),
param_count(0),
last_errno(0),
- flags((uint) IS_IN_USE)
+ flags((uint) IS_IN_USE)
{
+ init_alloc_root(&main_mem_root, thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size);
*last_error= '\0';
}
void Prepared_statement::setup_set_params()
{
- /* Setup binary logging */
+ /*
+ Note: BUG#25843 applies here too (query cache lookup uses thd->db, not
+ db from "prepare" time).
+ */
+ if (query_cache_maybe_disabled(thd)) // we won't expand the query
+ lex->safe_to_cache_query= FALSE; // so don't cache it at Execution
+
+ /*
+ Decide if we have to expand the query (because we must write it to logs or
+ because we want to look it up in the query cache) or not.
+ */
if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
- opt_log || opt_slow_log)
+ opt_log || opt_slow_log ||
+ query_cache_is_cacheable_query(lex))
{
set_params_from_vars= insert_params_from_vars_with_log;
#ifndef EMBEDDED_LIBRARY
- set_params= insert_params_withlog;
+ set_params= insert_params_with_log;
#else
- set_params_data= emb_insert_params_withlog;
+ set_params_data= emb_insert_params_with_log;
#endif
}
else
@@ -2733,6 +2772,7 @@ Prepared_statement::~Prepared_statement()
*/
free_items();
delete lex->result;
+ free_root(&main_mem_root, MYF(0));
DBUG_VOID_RETURN;
}
@@ -2748,6 +2788,7 @@ void Prepared_statement::cleanup_stmt()
DBUG_ENTER("Prepared_statement::cleanup_stmt");
DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
+ DBUG_ASSERT(lex->sphead == 0);
/* The order is important */
lex->unit.cleanup();
cleanup_items(free_list);
@@ -2762,7 +2803,7 @@ void Prepared_statement::cleanup_stmt()
bool Prepared_statement::set_name(LEX_STRING *name_arg)
{
name.length= name_arg->length;
- name.str= memdup_root(mem_root, (char*) name_arg->str, name_arg->length);
+ name.str= (char*) memdup_root(mem_root, name_arg->str, name_arg->length);
return name.str == 0;
}
@@ -2809,7 +2850,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
However, it seems handy if com_stmt_prepare is increased always,
no matter what kind of prepare is processed.
*/
- statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_prepare);
/*
alloc_query() uses thd->memroot && thd->query, so we should call
@@ -2827,23 +2868,15 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
old_stmt_arena= thd->stmt_arena;
thd->stmt_arena= this;
- lex_start(thd, (uchar*) thd->query, thd->query_length);
- lex->stmt_prepare_mode= TRUE;
-
- error= MYSQLparse((void *)thd) || thd->is_fatal_error ||
- thd->net.report_error || init_param_array(this);
- /*
- The first thing we do after parse error is freeing sp_head to
- ensure that we have restored original memroot.
- */
- if (error && lex->sphead)
- {
- delete lex->sphead;
- lex->sphead= NULL;
- }
+ Lex_input_stream lip(thd, thd->query, thd->query_length);
+ lip.stmt_prepare_mode= TRUE;
+ thd->m_lip= &lip;
+ lex_start(thd);
+ int err= MYSQLparse((void *)thd);
- lex->safe_to_cache_query= FALSE;
+ error= err || thd->is_fatal_error ||
+ thd->net.report_error || init_param_array(this);
/*
While doing context analysis of the query (in check_prepared_statement)
@@ -2870,17 +2903,35 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (error == 0)
error= check_prepared_statement(this, name.str != 0);
- /* Free sp_head if check_prepared_statement() failed. */
- if (error && lex->sphead)
+ /*
+ Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared
+ statements: ensure we have no memory leak here if by someone tries
+ to PREPARE stmt FROM "CREATE PROCEDURE ..."
+ */
+ DBUG_ASSERT(lex->sphead == NULL || error != 0);
+ if (lex->sphead)
{
delete lex->sphead;
lex->sphead= NULL;
}
+
lex_end(lex);
cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
thd->stmt_arena= old_stmt_arena;
+ if ((protocol->type() == Protocol::PROTOCOL_TEXT) && (param_count > 0))
+ {
+ /*
+ This is a mysql_sql_stmt_prepare(); query expansion will insert user
+ variable references, and user variables are uncacheable, thus we have to
+ mark this statement as uncacheable.
+ This has to be done before setup_set_params(), as it may make expansion
+ unneeded.
+ */
+ lex->safe_to_cache_query= FALSE;
+ }
+
if (error == 0)
{
setup_set_params();
@@ -2922,7 +2973,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Query_arena *old_stmt_arena;
bool error= TRUE;
- statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_execute);
/* Check if we got an error when sending long data */
if (state == Query_arena::ERROR)
@@ -2946,10 +2997,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
in INSERT ... SELECT and similar commands.
*/
- if (open_cursor && lex->result && !lex->result->simple_select())
+ if (open_cursor && lex->result && lex->result->check_simple_select())
{
DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
- my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
return TRUE;
}
@@ -2998,11 +3048,26 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
reinit_stmt_before_use(thd, lex);
thd->protocol= protocol; /* activate stmt protocol */
- error= (open_cursor ?
- mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
- &result, &cursor) :
- mysql_execute_command(thd));
- thd->protocol= &thd->protocol_simple; /* use normal protocol */
+
+ if (open_cursor)
+ error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
+ &result, &cursor);
+ else
+ {
+ /*
+ Try to find it in the query cache, if not, execute it.
+ Note that multi-statements cannot exist here (they are not supported in
+ prepared statements).
+ */
+ if (query_cache_send_result_to_client(thd, thd->query,
+ thd->query_length) <= 0)
+ {
+ error= mysql_execute_command(thd);
+ query_cache_end_of_result(thd);
+ }
+ }
+
+ thd->protocol= &thd->protocol_text; /* use normal protocol */
/* Assert that if an error, no cursor is open */
DBUG_ASSERT(! (error && cursor));
@@ -3030,7 +3095,7 @@ error:
bool Prepared_statement::deallocate()
{
/* We account deallocate in the same manner as mysql_stmt_close */
- statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
+ status_var_increment(thd->status_var.com_stmt_close);
if (flags & (uint) IS_IN_USE)
{
my_error(ER_PS_NO_RECURSION, MYF(0));
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index c37227e7d28..f34ec83b29c 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 6238a801b9b..d638a6718c0 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
+/* Copyright (C) 2000-2006 MySQL AB & Sasha
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,6 +16,7 @@
#include "mysql_priv.h"
#ifdef HAVE_REPLICATION
+#include "rpl_mi.h"
#include "sql_repl.h"
#include "log_event.h"
#include "rpl_filter.h"
@@ -24,7 +24,9 @@
int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
+#ifndef DBUG_OFF
static int binlog_dump_count = 0;
+#endif
/*
fake_rotate_event() builds a fake (=which does not exist physically in any
@@ -70,7 +72,7 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
int8store(buf+R_POS_OFFSET,position);
packet->append(buf, ROTATE_HEADER_LEN);
packet->append(p,ident_len);
- if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
{
*errmsg = "failed on my_net_write()";
DBUG_RETURN(-1);
@@ -81,20 +83,21 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
static int send_file(THD *thd)
{
NET* net = &thd->net;
- int fd = -1,bytes, error = 1;
+ int fd = -1, error = 1;
+ size_t bytes;
char fname[FN_REFLEN+1];
const char *errmsg = 0;
int old_timeout;
unsigned long packet_len;
- char buf[IO_SIZE]; // It's safe to alloc this
+ uchar buf[IO_SIZE]; // It's safe to alloc this
DBUG_ENTER("send_file");
/*
The client might be slow loading the data, give him wait_timeout to do
the job
*/
- old_timeout = thd->net.read_timeout;
- thd->net.read_timeout = thd->variables.net_wait_timeout;
+ old_timeout= net->read_timeout;
+ net_set_read_timeout(net, thd->variables.net_wait_timeout);
/*
We need net_flush here because the client will not know it needs to send
@@ -119,7 +122,7 @@ static int send_file(THD *thd)
goto err;
}
- while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, MYF(0))) > 0)
+ while ((long) (bytes= my_read(fd, buf, IO_SIZE, MYF(0))) > 0)
{
if (my_net_write(net, buf, bytes))
{
@@ -129,7 +132,7 @@ static int send_file(THD *thd)
}
end:
- if (my_net_write(net, "", 0) || net_flush(net) ||
+ if (my_net_write(net, (uchar*) "", 0) || net_flush(net) ||
(my_net_read(net) == packet_error))
{
errmsg = "while negotiating file transfer close";
@@ -138,7 +141,7 @@ static int send_file(THD *thd)
error = 0;
err:
- thd->net.read_timeout = old_timeout;
+ net_set_read_timeout(net, old_timeout);
if (fd >= 0)
(void) my_close(fd, MYF(0));
if (errmsg)
@@ -215,7 +218,8 @@ bool log_in_use(const char* log_name)
if ((linfo = tmp->current_linfo))
{
pthread_mutex_lock(&linfo->lock);
- result = !bcmp(log_name, linfo->log_file_name, log_name_len);
+ result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
+ log_name_len);
pthread_mutex_unlock(&linfo->lock);
if (result)
break;
@@ -478,7 +482,7 @@ impossible position";
int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
ST_CREATED_OFFSET+1, (ulong) 0);
/* send it */
- if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
{
errmsg = "Failed on my_net_write()";
my_errno= ER_UNKNOWN_ERROR;
@@ -536,7 +540,7 @@ impossible position";
else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT)
binlog_can_be_corrupted= FALSE;
- if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
{
errmsg = "Failed on my_net_write()";
my_errno= ER_UNKNOWN_ERROR;
@@ -649,7 +653,7 @@ impossible position";
if (read_packet)
{
thd->proc_info = "Sending binlog event to slave";
- if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
+ if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
my_errno= ER_UNKNOWN_ERROR;
@@ -885,12 +889,14 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
+ DBUG_ENTER("stop_slave");
+
int slave_errno;
if (!thd)
thd = current_thd;
if (check_access(thd, SUPER_ACL, any_db,0,0,0,0))
- return 1;
+ DBUG_RETURN(1);
thd->proc_info = "Killing slave";
int thread_mask;
lock_slave_threads(mi);
@@ -924,12 +930,12 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
if (net_report)
my_message(slave_errno, ER(slave_errno), MYF(0));
- return 1;
+ DBUG_RETURN(1);
}
else if (net_report)
send_ok(thd);
- return 0;
+ DBUG_RETURN(0);
}
@@ -1127,6 +1133,11 @@ bool change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED)
mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE);
+
+ if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::SSL_UNCHANGED)
+ mi->ssl_verify_server_cert=
+ (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::SSL_ENABLE);
+
if (lex_mi->ssl_ca)
strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
if (lex_mi->ssl_capath)
@@ -1139,7 +1150,8 @@ bool change_master(THD* thd, MASTER_INFO* mi)
strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1);
#ifndef HAVE_OPENSSL
if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
- lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key )
+ lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ||
+ lex_mi->ssl_verify_server_cert )
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS));
#endif
@@ -1597,6 +1609,149 @@ int log_loaded_block(IO_CACHE* file)
return 0;
}
+/*
+ Replication System Variables
+*/
+
+class sys_var_slave_skip_counter :public sys_var
+{
+public:
+ sys_var_slave_skip_counter(sys_var_chain *chain, const char *name_arg)
+ :sys_var(name_arg)
+ { chain_sys_var(chain); }
+ bool check(THD *thd, set_var *var);
+ bool update(THD *thd, set_var *var);
+ bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
+ /*
+ We can't retrieve the value of this, so we don't have to define
+ type() or value_ptr()
+ */
+};
+
+class sys_var_sync_binlog_period :public sys_var_long_ptr
+{
+public:
+ sys_var_sync_binlog_period(sys_var_chain *chain, const char *name_arg,
+ ulong *value_ptr)
+ :sys_var_long_ptr(chain, name_arg,value_ptr) {}
+ bool update(THD *thd, set_var *var);
+};
+
+static sys_var_chain vars = { NULL, NULL };
+
+static sys_var_bool_ptr sys_relay_log_purge(&vars, "relay_log_purge",
+ &relay_log_purge);
+static sys_var_long_ptr sys_slave_net_timeout(&vars, "slave_net_timeout",
+ &slave_net_timeout);
+static sys_var_long_ptr sys_slave_trans_retries(&vars, "slave_transaction_retries",
+ &slave_trans_retries);
+static sys_var_sync_binlog_period sys_sync_binlog_period(&vars, "sync_binlog", &sync_binlog_period);
+static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter");
+
+static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff);
+
+
+static SHOW_VAR fixed_vars[]= {
+ {"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL},
+ {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG},
+ {"slave_load_tmpdir", (char*) &slave_load_tmpdir, SHOW_CHAR_PTR},
+ {"slave_skip_errors", (char*) &show_slave_skip_errors, SHOW_FUNC},
+};
+
+static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type=SHOW_CHAR;
+ var->value= buff;
+ if (!use_slave_mask || bitmap_is_clear_all(&slave_error_mask))
+ {
+ var->value= const_cast<char *>("OFF");
+ }
+ else if (bitmap_is_set_all(&slave_error_mask))
+ {
+ var->value= const_cast<char *>("ALL");
+ }
+ else
+ {
+ /* 10 is enough assuming errors are max 4 digits */
+ int i;
+ var->value= buff;
+ for (i= 1;
+ i < MAX_SLAVE_ERROR &&
+ (buff - var->value) < SHOW_VAR_FUNC_BUFF_SIZE;
+ i++)
+ {
+ if (bitmap_is_set(&slave_error_mask, i))
+ {
+ buff= int10_to_str(i, buff, 10);
+ *buff++= ',';
+ }
+ }
+ if (var->value != buff)
+ buff--; // Remove last ','
+ if (i < MAX_SLAVE_ERROR)
+ buff= strmov(buff, "..."); // Couldn't show all errors
+ *buff=0;
+ }
+ return 0;
+}
+
+bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
+{
+ int result= 0;
+ pthread_mutex_lock(&LOCK_active_mi);
+ pthread_mutex_lock(&active_mi->rli.run_lock);
+ if (active_mi->rli.slave_running)
+ {
+ my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
+ result=1;
+ }
+ pthread_mutex_unlock(&active_mi->rli.run_lock);
+ pthread_mutex_unlock(&LOCK_active_mi);
+ var->save_result.ulong_value= (ulong) var->value->val_int();
+ return result;
+}
+
+
+bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
+{
+ pthread_mutex_lock(&LOCK_active_mi);
+ pthread_mutex_lock(&active_mi->rli.run_lock);
+ /*
+ The following test should normally never be true as we test this
+ in the check function; To be safe against multiple
+ SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
+ */
+ if (!active_mi->rli.slave_running)
+ {
+ pthread_mutex_lock(&active_mi->rli.data_lock);
+ active_mi->rli.slave_skip_counter= var->save_result.ulong_value;
+ pthread_mutex_unlock(&active_mi->rli.data_lock);
+ }
+ pthread_mutex_unlock(&active_mi->rli.run_lock);
+ pthread_mutex_unlock(&LOCK_active_mi);
+ return 0;
+}
+
+
+bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
+{
+ sync_binlog_period= (ulong) var->save_result.ulonglong_value;
+ return 0;
+}
+
+int init_replication_sys_vars()
+{
+ mysql_append_static_vars(fixed_vars, sizeof(fixed_vars) / sizeof(SHOW_VAR));
+
+ if (mysql_add_sys_var_chain(vars.first, my_long_options))
+ {
+ /* should not happen */
+ fprintf(stderr, "failed to initialize replication system variables");
+ unireg_abort(1);
+ }
+ return 0;
+}
+
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 789de64da85..da50d47c60d 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB & Sasha
+/* Copyright (C) 2000-2006 MySQL AB & Sasha
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -68,6 +67,7 @@ typedef struct st_load_file_info
} LOAD_FILE_INFO;
int log_loaded_block(IO_CACHE* file);
+int init_replication_sys_vars();
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 9a64055f2e3..bdd70de35d8 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000-2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -50,15 +49,15 @@ static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
table_map used_tables);
-static void choose_plan(JOIN *join,table_map join_tables);
+static bool choose_plan(JOIN *join,table_map join_tables);
static void best_access_path(JOIN *join, JOIN_TAB *s, THD *thd,
table_map remaining_tables, uint idx,
double record_count, double read_time);
static void optimize_straight_join(JOIN *join, table_map join_tables);
-static void greedy_search(JOIN *join, table_map remaining_tables,
+static bool greedy_search(JOIN *join, table_map remaining_tables,
uint depth, uint prune_level);
-static void best_extension_by_limited_search(JOIN *join,
+static bool best_extension_by_limited_search(JOIN *join,
table_map remaining_tables,
uint idx, double record_count,
double read_time, uint depth,
@@ -70,14 +69,14 @@ static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
TODO: 'find_best' is here only temporarily until 'greedy_search' is
tested and approved.
*/
-static void find_best(JOIN *join,table_map rest_tables,uint index,
+static bool find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join, uint idx, table_map found_ref);
static bool get_best_combination(JOIN *join);
static store_key *get_store_key(THD *thd,
KEYUSE *keyuse, table_map used_tables,
- KEY_PART_INFO *key_part, char *key_buff,
+ KEY_PART_INFO *key_part, uchar *key_buff,
uint maybe_null);
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
static void make_outerjoin_info(JOIN *join);
@@ -110,7 +109,6 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
static COND *optimize_cond(JOIN *join, COND *conds,
List<TABLE_LIST> *join_list,
Item::cond_result *cond_value);
-static bool resolve_nested_join (TABLE_LIST *table);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
@@ -165,13 +163,15 @@ static COND *make_cond_for_table(COND *cond,table_map table,
static Item* part_of_refkey(TABLE *form,Field *field);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
- ha_rows select_limit, bool no_changes);
+ ha_rows select_limit, bool no_changes,
+ key_map *map);
static bool list_contains_unique_index(TABLE *table,
bool (*find_func) (Field *, void *), void *data);
static bool find_field_in_item_list (Field *field, void *data);
static bool find_field_in_order_list (Field *field, void *data);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
- ha_rows filesort_limit, ha_rows select_limit);
+ ha_rows filesort_limit, ha_rows select_limit,
+ bool is_order_by);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
@@ -231,7 +231,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
- if (select_lex->next_select() || select_lex->master_unit()->fake_select_lex)
+ if (select_lex->master_unit()->is_union() ||
+ select_lex->master_unit()->fake_select_lex)
res= mysql_union(thd, lex, result, &lex->unit, setup_tables_done_option);
else
{
@@ -270,6 +271,116 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
/*
+ Fix fields referenced from inner selects.
+
+ SYNOPSIS
+ fix_inner_refs()
+ thd Thread handle
+ all_fields List of all fields used in select
+ select Current select
+ ref_pointer_array Array of references to Items used in current select
+
+ DESCRIPTION
+ The function serves 3 purposes - adds fields referenced from inner
+ selects to the current select list, resolves which class to use
+ to access referenced item (Item_ref of Item_direct_ref) and fixes
+ references (Item_ref objects) to these fields.
+
+ If a field isn't already in the select list and the ref_pointer_array
+ is provided then it is added to the all_fields list and the pointer to
+ it is saved in the ref_pointer_array.
+
+ The class to access the outer field is determined by the following rules:
+ 1. If the outer field isn't used under an aggregate function
+ then the Item_ref class should be used.
+ 2. If the outer field is used under an aggregate function and this
+ function is aggregated in the select where the outer field was
+ resolved or in some more inner select then the Item_direct_ref
+ class should be used.
+ The resolution is done here and not at the fix_fields() stage as
+ it can be done only after sum functions are fixed and pulled up to
+ selects where they are have to be aggregated.
+ When the class is chosen it substitutes the original field in the
+ Item_outer_ref object.
+
+ After this we proceed with fixing references (Item_outer_ref objects) to
+ this field from inner subqueries.
+
+ RETURN
+ TRUE an error occured
+ FALSE ok
+*/
+
+bool
+fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
+ Item **ref_pointer_array)
+{
+ Item_outer_ref *ref;
+ bool res= FALSE;
+ bool direct_ref= FALSE;
+
+ List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
+ while ((ref= ref_it++))
+ {
+ Item *item= ref->outer_ref;
+ Item **item_ref= ref->ref;
+ Item_ref *new_ref;
+ /*
+ TODO: this field item already might be present in the select list.
+ In this case instead of adding new field item we could use an
+ existing one. The change will lead to less operations for copying fields,
+ smaller temporary tables and less data passed through filesort.
+ */
+ if (ref_pointer_array && !ref->found_in_select_list)
+ {
+ int el= all_fields.elements;
+ ref_pointer_array[el]= item;
+ /* Add the field item to the select list of the current select. */
+ all_fields.push_front(item);
+ /*
+ If it's needed reset each Item_ref item that refers this field with
+ a new reference taken from ref_pointer_array.
+ */
+ item_ref= ref_pointer_array + el;
+ }
+
+ if (ref->in_sum_func)
+ {
+ Item_sum *sum_func;
+ if (ref->in_sum_func->nest_level > select->nest_level)
+ direct_ref= TRUE;
+ else
+ {
+ for (sum_func= ref->in_sum_func; sum_func &&
+ sum_func->aggr_level >= select->nest_level;
+ sum_func= sum_func->in_sum_func)
+ {
+ if (sum_func->aggr_level == select->nest_level)
+ {
+ direct_ref= TRUE;
+ break;
+ }
+ }
+ }
+ }
+ new_ref= direct_ref ?
+ new Item_direct_ref(ref->context, item_ref, ref->field_name,
+ ref->table_name, ref->alias_name_used) :
+ new Item_ref(ref->context, item_ref, ref->field_name,
+ ref->table_name, ref->alias_name_used);
+ if (!new_ref)
+ return TRUE;
+ ref->outer_ref= new_ref;
+ ref->ref= &ref->outer_ref;
+
+ if (!ref->fixed && ref->fix_fields(thd, 0))
+ return TRUE;
+ thd->used_tables|= item->used_tables();
+ }
+ return res;
+}
+
+/*
Function to setup clauses without sum functions
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
@@ -332,8 +443,9 @@ JOIN::prepare(Item ***rref_pointer_array,
select_lex= select_lex_arg;
select_lex->join= this;
join_list= &select_lex->top_join_list;
- union_part= (unit_arg->first_select()->next_select() != 0);
+ union_part= unit_arg->is_union();
+ thd->lex->current_select->is_item_list_lookup= 1;
/*
If we have already executed SELECT, then it have not sense to prevent
its table from update (see unique_table())
@@ -343,12 +455,19 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
- if ((!(select_options & OPTION_SETUP_TABLES_DONE) &&
- setup_tables_and_check_access(thd, &select_lex->context, join_list,
- tables_list,
- &select_lex->leaf_tables, FALSE,
- SELECT_ACL, SELECT_ACL)) ||
- setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
+ if (!(select_options & OPTION_SETUP_TABLES_DONE) &&
+ setup_tables_and_check_access(thd, &select_lex->context, join_list,
+ tables_list, &select_lex->leaf_tables,
+ FALSE, SELECT_ACL, SELECT_ACL))
+ DBUG_RETURN(-1);
+
+ TABLE_LIST *table_ptr;
+ for (table_ptr= select_lex->leaf_tables;
+ table_ptr;
+ table_ptr= table_ptr->next_leaf)
+ tables++;
+
+ if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
&all_fields, 1) ||
@@ -393,6 +512,17 @@ JOIN::prepare(Item ***rref_pointer_array,
select_lex->fix_prepare_information(thd, &conds, &having);
+ if (order)
+ {
+ ORDER *ord;
+ for (ord= order; ord; ord= ord->next)
+ {
+ Item *item= *ord->item;
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ item->split_sum_func(thd, ref_pointer_array, all_fields);
+ }
+ }
+
if (having && having->with_sum_func)
having->split_sum_func2(thd, ref_pointer_array, all_fields,
&having, TRUE);
@@ -408,6 +538,10 @@ JOIN::prepare(Item ***rref_pointer_array,
} while (item_sum != end);
}
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
@@ -438,11 +572,6 @@ JOIN::prepare(Item ***rref_pointer_array,
DBUG_RETURN(-1);
}
}
- TABLE_LIST *table_ptr;
- for (table_ptr= select_lex->leaf_tables;
- table_ptr;
- table_ptr= table_ptr->next_leaf)
- tables++;
}
{
/* Caclulate the number of groups */
@@ -476,6 +605,9 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
+ goto err; /* purecov: inspected */
+
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
@@ -489,9 +621,6 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- if (!procedure && result && result->prepare(fields_list, unit_arg))
- goto err; /* purecov: inspected */
-
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
goto err;
if (alloc_func_list())
@@ -507,72 +636,88 @@ err:
/*
- test if it is known for optimisation IN subquery
+ Remove the predicates pushed down into the subquery
SYNOPSIS
- JOIN::test_in_subselect()
- where - pointer for variable in which conditions should be
- stored if subquery is known
+ JOIN::remove_subq_pushed_predicates()
+ where IN Must be NULL
+ OUT The remaining WHERE condition, or NULL
- RETURN
- 1 - known
- 0 - unknown
+ DESCRIPTION
+ Given that this join will be executed using (unique|index)_subquery,
+ without "checking NULL", remove the predicates that were pushed down
+ into the subquery.
+
+ We can remove the equalities that will be guaranteed to be true by the
+ fact that subquery engine will be using index lookup.
+
+ If the subquery compares scalar values, we can remove the condition that
+ was wrapped into trig_cond (it will be checked when needed by the subquery
+ engine)
+
+ If the subquery compares row values, we need to keep the wrapped
+ equalities in the WHERE clause: when the left (outer) tuple has both NULL
+ and non-NULL values, we'll do a full table scan and will rely on the
+ equalities corresponding to non-NULL parts of left tuple to filter out
+ non-matching records.
*/
-bool JOIN::test_in_subselect(Item **where)
+void JOIN::remove_subq_pushed_predicates(Item **where)
{
if (conds->type() == Item::FUNC_ITEM &&
((Item_func *)this->conds)->functype() == Item_func::EQ_FUNC &&
((Item_func *)conds)->arguments()[0]->type() == Item::REF_ITEM &&
((Item_func *)conds)->arguments()[1]->type() == Item::FIELD_ITEM)
{
- join_tab->info= "Using index";
*where= 0;
- return 1;
+ return;
}
if (conds->type() == Item::COND_ITEM &&
((class Item_func *)this->conds)->functype() ==
Item_func::COND_AND_FUNC)
{
- if ((*where= remove_additional_cond(conds)))
- join_tab->info= "Using index; Using where";
- else
- join_tab->info= "Using index";
- return 1;
+ *where= remove_additional_cond(conds);
}
- return 0;
}
/*
- Check if the passed HAVING clause is a clause added by subquery optimizer
+ Index lookup-based subquery: save some flags for EXPLAIN output
SYNOPSIS
- is_having_subq_predicates()
- having Having clause
+ save_index_subquery_explain_info()
+ join_tab Subquery's join tab (there is only one as index lookup is
+ only used for subqueries that are single-table SELECTs)
+ where Subquery's WHERE clause
- RETURN
- TRUE The passed HAVING clause was added by the subquery optimizer
- FALSE Otherwise
+ DESCRIPTION
+ For index lookup-based subquery (i.e. one executed with
+ subselect_uniquesubquery_engine or subselect_indexsubquery_engine),
+ check its EXPLAIN output row should contain
+ "Using index" (TAB_INFO_FULL_SCAN_ON_NULL)
+ "Using Where" (TAB_INFO_USING_WHERE)
+ "Full scan on NULL key" (TAB_INFO_FULL_SCAN_ON_NULL)
+ and set appropriate flags in join_tab->packed_info.
*/
-bool is_having_subq_predicates(Item *having)
+static void save_index_subquery_explain_info(JOIN_TAB *join_tab, Item* where)
{
- if (having->type() == Item::FUNC_ITEM)
+ join_tab->packed_info= TAB_INFO_HAVE_VALUE;
+ if (join_tab->table->covering_keys.is_set(join_tab->ref.key))
+ join_tab->packed_info |= TAB_INFO_USING_INDEX;
+ if (where)
+ join_tab->packed_info |= TAB_INFO_USING_WHERE;
+ for (uint i = 0; i < join_tab->ref.key_parts; i++)
{
- if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC)
- return TRUE;
- if (((Item_func *) having)->functype() == Item_func::TRIG_COND_FUNC)
+ if (join_tab->ref.cond_guards[i])
{
- having= ((Item_func*)having)->arguments()[0];
- if (((Item_func *) having)->functype() == Item_func::ISNOTNULLTEST_FUNC)
- return TRUE;
+ join_tab->packed_info |= TAB_INFO_FULL_SCAN_ON_NULL;
+ break;
}
- return TRUE;
}
- return FALSE;
}
+
/*
global select optimisation.
return 0 - success
@@ -656,7 +801,6 @@ JOIN::optimize()
}
{
- Item::cond_result having_value;
having= optimize_cond(this, having, join_list, &having_value);
if (thd->net.report_error)
{
@@ -664,6 +808,10 @@ JOIN::optimize()
DBUG_PRINT("error",("Error from optimize_cond"));
DBUG_RETURN(1);
}
+ if (select_lex->where)
+ select_lex->cond_value= cond_value;
+ if (select_lex->having)
+ select_lex->having_value= having_value;
if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
@@ -702,11 +850,20 @@ JOIN::optimize()
{
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_...
+ opt_sum_query() returns HA_ERR_KEY_NOT_FOUND 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(select_lex->leaf_tables, all_fields, conds)))
{
+ if (res == HA_ERR_KEY_NOT_FOUND)
+ {
+ DBUG_PRINT("info",("No matching min/max row"));
+ zero_result_cause= "No matching min/max row";
+ error=0;
+ DBUG_RETURN(0);
+ }
if (res > 1)
{
thd->fatal_error();
@@ -714,13 +871,6 @@ JOIN::optimize()
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
}
- if (res < 0)
- {
- DBUG_PRINT("info",("No matching min/max row"));
- zero_result_cause= "No matching min/max row";
- error=0;
- DBUG_RETURN(0);
- }
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
@@ -822,6 +972,7 @@ JOIN::optimize()
conds->update_used_tables();
DBUG_EXECUTE("where", print_where(conds, "after substitute_best_equal"););
}
+
/*
Permorm the the optimization on fields evaluation mentioned above
for all on expressions.
@@ -837,6 +988,12 @@ JOIN::optimize()
}
}
+ if (conds &&!outer_join && const_table_map != found_const_table_map &&
+ (select_options & SELECT_DESCRIBE) &&
+ select_lex->master_unit() == &thd->lex->unit) // upper level SELECT
+ {
+ conds=new Item_int((longlong) 0,1); // Always false
+ }
if (make_join_select(this, select, conds))
{
zero_result_cause=
@@ -850,6 +1007,13 @@ JOIN::optimize()
{
ORDER *org_order= order;
order=remove_const(this, order,conds,1, &simple_order);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
+
/*
If we are using ORDER BY NULL or ORDER BY const_expression,
return result in any order (even if we are using a GROUP BY)
@@ -859,10 +1023,11 @@ JOIN::optimize()
}
/*
Check if we can optimize away GROUP BY/DISTINCT.
- We can do that if there are no aggregate functions and the
+ We can do that if there are no aggregate functions, the
fields in DISTINCT clause (if present) and/or columns in GROUP BY
(if present) contain direct references to all key parts of
- an unique index (in whatever order).
+ an unique index (in whatever order) and if the key parts of the
+ unique index cannot contain NULLs.
Note that the unique keys for DISTINCT and GROUP BY should not
be the same (as long as they are unique).
@@ -916,14 +1081,15 @@ JOIN::optimize()
JOIN_TAB *tab= &join_tab[const_tables];
bool all_order_fields_used;
if (order)
- skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
+ skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1,
+ &tab->table->keys_in_use_for_order_by);
if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array,
order, fields_list,
&all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
- test_if_skip_sort_order(tab, group_list, select_limit,
- 1) != 0);
+ test_if_skip_sort_order(tab, group_list, select_limit, 1,
+ &tab->table->keys_in_use_for_group_by) != 0);
if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR ||
(order && !skip_sort_order))
@@ -957,6 +1123,12 @@ JOIN::optimize()
group_list= remove_const(this, (old_group_list= group_list), conds,
rollup.state == ROLLUP::STATE_NONE,
&simple_group);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
if (old_group_list && !group_list)
select_distinct= 0;
}
@@ -973,6 +1145,12 @@ JOIN::optimize()
{
group_list= procedure->group= remove_const(this, procedure->group, conds,
1, &simple_group);
+ if (thd->net.report_error)
+ {
+ error= 1;
+ DBUG_PRINT("error",("Error from remove_const"));
+ DBUG_RETURN(1);
+ }
calc_group_buffer(this, group_list);
}
@@ -1020,7 +1198,7 @@ JOIN::optimize()
if (!group_list && !order &&
unit->item && unit->item->substype() == Item_subselect::IN_SUBS &&
tables == 1 && conds &&
- !unit->first_select()->next_select())
+ !unit->is_union())
{
if (!having)
{
@@ -1028,51 +1206,47 @@ JOIN::optimize()
if (join_tab[0].type == JT_EQ_REF &&
join_tab[0].ref.items[0]->name == in_left_expr_name)
{
- if (test_in_subselect(&where))
- {
- join_tab[0].type= JT_UNIQUE_SUBQUERY;
- error= 0;
- DBUG_RETURN(unit->item->
- change_engine(new
- subselect_uniquesubquery_engine(thd,
- join_tab,
- unit->item,
- where)));
- }
+ remove_subq_pushed_predicates(&where);
+ save_index_subquery_explain_info(join_tab, where);
+ join_tab[0].type= JT_UNIQUE_SUBQUERY;
+ error= 0;
+ DBUG_RETURN(unit->item->
+ change_engine(new
+ subselect_uniquesubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where)));
}
else if (join_tab[0].type == JT_REF &&
join_tab[0].ref.items[0]->name == in_left_expr_name)
{
- if (test_in_subselect(&where))
- {
- join_tab[0].type= JT_INDEX_SUBQUERY;
- error= 0;
- DBUG_RETURN(unit->item->
- change_engine(new
- subselect_indexsubquery_engine(thd,
- join_tab,
- unit->item,
- where,
- 0)));
- }
+ remove_subq_pushed_predicates(&where);
+ save_index_subquery_explain_info(join_tab, where);
+ join_tab[0].type= JT_INDEX_SUBQUERY;
+ error= 0;
+ DBUG_RETURN(unit->item->
+ change_engine(new
+ subselect_indexsubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where,
+ NULL,
+ 0)));
}
} else if (join_tab[0].type == JT_REF_OR_NULL &&
join_tab[0].ref.items[0]->name == in_left_expr_name &&
- is_having_subq_predicates(having))
+ having->name == in_having_cond)
{
join_tab[0].type= JT_INDEX_SUBQUERY;
error= 0;
-
- if ((conds= remove_additional_cond(conds)))
- join_tab->info= "Using index; Using where";
- else
- join_tab->info= "Using index";
-
+ conds= remove_additional_cond(conds);
+ save_index_subquery_explain_info(join_tab, conds);
DBUG_RETURN(unit->item->
change_engine(new subselect_indexsubquery_engine(thd,
join_tab,
unit->item,
conds,
+ having,
1)));
}
@@ -1113,7 +1287,9 @@ JOIN::optimize()
((group_list &&
(!simple_group ||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
- unit->select_limit_cnt, 0))) ||
+ unit->select_limit_cnt, 0,
+ &join_tab[const_tables].table->
+ keys_in_use_for_group_by))) ||
select_distinct) &&
tmp_table_param.quick_group && !procedure)
{
@@ -1128,7 +1304,7 @@ JOIN::optimize()
for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next)
{
Item *item= *tmp_order->item;
- if (item->walk(&Item::is_expensive_processor, 0, (byte*)0))
+ if (item->walk(&Item::is_expensive_processor, 0, (uchar*)0))
{
/* Force tmp table without sort */
need_tmp=1; simple_order=simple_group=0;
@@ -1215,7 +1391,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
if (create_sort_index(thd, this, group_list,
- HA_POS_ERROR, HA_POS_ERROR) ||
+ HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
setup_sum_funcs(thd, sum_funcs))
@@ -1232,7 +1408,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
if (create_sort_index(thd, this, order,
- HA_POS_ERROR, HA_POS_ERROR))
+ HA_POS_ERROR, HA_POS_ERROR, TRUE))
DBUG_RETURN(1);
order=0;
}
@@ -1259,19 +1435,20 @@ JOIN::optimize()
{
/* Should always succeed */
if (test_if_skip_sort_order(&join_tab[const_tables],
- order, unit->select_limit_cnt, 0))
+ order, unit->select_limit_cnt, 0,
+ &join_tab[const_tables].table->
+ keys_in_use_for_order_by))
order=0;
}
}
- if (select_lex->uncacheable && !is_top_level_join())
- {
- /* If this join belongs to an uncacheable subquery */
- if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
- DBUG_RETURN(-1);
- error= 0; // Ensure that tmp_join.error= 0
- restore_tmp();
- }
+ /*
+ If this join belongs to an uncacheable subquery save
+ the original join
+ */
+ if (select_lex->uncacheable && !is_top_level_join() &&
+ init_save_join_tab())
+ DBUG_RETURN(-1); /* purecov: inspected */
}
error= 0;
@@ -1333,13 +1510,34 @@ JOIN::reinit()
DBUG_RETURN(0);
}
+/**
+ @brief Save the original join layout
+
+ @details Saves the original join layout so it can be reused in
+ re-execution and for EXPLAIN.
+
+ @return Operation status
+ @retval 0 success.
+ @retval 1 error occurred.
+*/
+
+bool
+JOIN::init_save_join_tab()
+{
+ if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
+ return 1; /* purecov: inspected */
+ error= 0; // Ensure that tmp_join.error= 0
+ restore_tmp();
+ return 0;
+}
+
bool
JOIN::save_join_tab()
{
if (!join_tab_save && select_lex->master_unit()->uncacheable)
{
- if (!(join_tab_save= (JOIN_TAB*)thd->memdup((gptr) join_tab,
+ if (!(join_tab_save= (JOIN_TAB*)thd->memdup((uchar*) join_tab,
sizeof(JOIN_TAB) * tables)))
return 1;
}
@@ -1452,7 +1650,9 @@ JOIN::exec()
(const_tables == tables ||
((simple_order || skip_sort_order) &&
test_if_skip_sort_order(&join_tab[const_tables], order,
- select_limit, 0))))
+ select_limit, 0,
+ &join_tab[const_tables].table->
+ keys_in_use_for_order_by))))
order=0;
having= tmp_having;
select_describe(this, need_tmp,
@@ -1475,7 +1675,7 @@ JOIN::exec()
if ((curr_join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe &&
- get_schema_tables_result(curr_join))
+ get_schema_tables_result(curr_join, PROCESSED_BY_JOIN_EXEC))
{
DBUG_VOID_RETURN;
}
@@ -1628,7 +1828,7 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
if (create_sort_index(thd, curr_join, curr_join->group_list,
- HA_POS_ERROR, HA_POS_ERROR) ||
+ HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
make_group_fields(this, curr_join))
{
DBUG_VOID_RETURN;
@@ -1844,7 +2044,8 @@ JOIN::exec()
curr_join->group_list : curr_join->order,
curr_join->select_limit,
(select_options & OPTION_FOUND_ROWS ?
- HA_POS_ERROR : unit->select_limit_cnt)))
+ HA_POS_ERROR : unit->select_limit_cnt),
+ curr_join->group_list ? TRUE : FALSE))
DBUG_VOID_RETURN;
sortorder= curr_join->sortorder;
if (curr_join->const_tables != curr_join->tables &&
@@ -1903,6 +2104,17 @@ JOIN::exec()
thd->examined_row_count+= curr_join->examined_rows;
DBUG_PRINT("counts", ("thd->examined_row_count: %lu",
(ulong) thd->examined_row_count));
+
+ /*
+ With EXPLAIN EXTENDED we have to restore original ref_array
+ for a derived table which is always materialized.
+ Otherwise we would not be able to print the query correctly.
+ */
+ if (items0 &&
+ (thd->lex->describe & DESCRIBE_EXTENDED) &&
+ select_lex->linkage == DERIVED_TABLE_TYPE)
+ set_items_ref_array(items0);
+
DBUG_VOID_RETURN;
}
@@ -2198,7 +2410,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
s->key_dependent= 0;
if (tables->schema_table)
table->file->stats.records= 2;
- table->quick_condition_rows= table->file->records();
+ table->quick_condition_rows= table->file->stats.records;
s->on_expr_ref= &tables->on_expr;
if (*s->on_expr_ref)
@@ -2334,8 +2546,18 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
substitution of a const table the key value happens to be null
then we can state that there are no matches for this equi-join.
*/
- if ((keyuse= s->keyuse) && *s->on_expr_ref)
+ if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map)
{
+ /*
+ When performing an outer join operation if there are no matching rows
+ for the single row of the outer table all the inner tables are to be
+ null complemented and thus considered as constant tables.
+ Here we apply this consideration to the case of outer join operations
+ with a single inner table only because the case with nested tables
+ would require a more thorough analysis.
+ TODO. Apply single row substitution to null complemented inner tables
+ for nested outer join operations.
+ */
while (keyuse->table == table)
{
if (!(keyuse->val->used_tables() & ~join->const_table_map) &&
@@ -2448,14 +2670,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
for( ; sargables->field ; sargables++)
{
Field *field= sargables->field;
- JOIN_TAB *stat= field->table->reginfo.join_tab;
+ JOIN_TAB *join_tab= field->table->reginfo.join_tab;
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
bool is_const= 1;
- for (uint i=0; i< sargables->num_values; i++)
- is_const&= sargables->arg_value[i]->const_item();
+ for (uint j=0; j < sargables->num_values; j++)
+ is_const&= sargables->arg_value[j]->const_item();
if (is_const)
- stat[0].const_keys.merge(possible_keys);
+ join_tab[0].const_keys.merge(possible_keys);
}
}
@@ -2544,11 +2766,12 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
if (join->const_tables != join->tables)
{
optimize_keyuse(join, keyuse_array);
- choose_plan(join, all_table_map & ~join->const_table_map);
+ if (choose_plan(join, all_table_map & ~join->const_table_map))
+ DBUG_RETURN(TRUE);
}
else
{
- memcpy((gptr) join->best_positions,(gptr) join->positions,
+ memcpy((uchar*) join->best_positions,(uchar*) join->positions,
sizeof(POSITION)*join->const_tables);
join->best_read=1.0;
}
@@ -2576,9 +2799,7 @@ typedef struct key_field_t { // Used when finding key fields
when val IS NULL.
*/
bool null_rejecting;
-
- /* TRUE<=> This ref access is an outer subquery reference access */
- bool outer_ref;
+ bool *cond_guard; /* See KEYUSE::cond_guard */
} KEY_FIELD;
/* Values in optimize */
@@ -2844,15 +3065,9 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
-
- We also cannot use index on a text column, as the column may
- contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
- 'x' when searching for WHERE col='x '
*/
if (field->cmp_type() == STRING_RESULT &&
- (((Field_str*)field)->charset() != cond->compare_collation() ||
- ((*value)->type() != Item::NULL_ITEM &&
- (field->flags & BLOB_FLAG) && !field->binary())))
+ ((Field_str*)field)->charset() != cond->compare_collation())
return;
}
}
@@ -2880,7 +3095,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond,
cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
((*value)->type() == Item::FIELD_ITEM) &&
((Item_field*)*value)->field->maybe_null());
- (*key_fields)->outer_ref= FALSE;
+ (*key_fields)->cond_guard= NULL;
(*key_fields)++;
}
@@ -2977,25 +3192,26 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
}
/*
- Subquery optimization: check if the encountered condition is one
- added by condition push down into subquery.
+ Subquery optimization: Conditions that are pushed down into subqueries
+ are wrapped into Item_func_trig_cond. We process the wrapped condition
+ but need to set cond_guard for KEYUSE elements generated from it.
*/
{
if (cond->type() == Item::FUNC_ITEM &&
((Item_func*)cond)->functype() == Item_func::TRIG_COND_FUNC)
{
- cond= ((Item_func*)cond)->arguments()[0];
+ Item *cond_arg= ((Item_func*)cond)->arguments()[0];
if (!join->group_list && !join->order &&
join->unit->item &&
join->unit->item->substype() == Item_subselect::IN_SUBS &&
- !join->unit->first_select()->next_select())
+ !join->unit->is_union())
{
KEY_FIELD *save= *key_fields;
- add_key_fields(join, key_fields, and_level, cond, usable_tables,
+ add_key_fields(join, key_fields, and_level, cond_arg, usable_tables,
sargables);
// Indicate that this ref access candidate is for subquery lookup:
for (; save != *key_fields; save++)
- save->outer_ref= TRUE;
+ save->cond_guard= ((Item_func_trig_cond*)cond)->get_trig_var();
}
return;
}
@@ -3175,8 +3391,8 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
keyuse.used_tables=key_field->val->used_tables();
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
keyuse.null_rejecting= key_field->null_rejecting;
- keyuse.outer_ref= key_field->outer_ref;
- VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
+ keyuse.cond_guard= key_field->cond_guard;
+ VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
}
}
}
@@ -3243,7 +3459,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
keyuse.used_tables=cond_func->key_item()->used_tables();
keyuse.optimize= 0;
keyuse.keypart_map= 0;
- VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
+ VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
}
@@ -3452,16 +3668,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
*/
if (keyuse->elements)
{
- KEYUSE end,*prev,*save_pos,*use;
+ KEYUSE key_end,*prev,*save_pos,*use;
qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE),
(qsort_cmp) sort_keyuse);
- bzero((char*) &end,sizeof(end)); /* Add for easy testing */
- VOID(insert_dynamic(keyuse,(gptr) &end));
+ bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */
+ VOID(insert_dynamic(keyuse,(uchar*) &key_end));
use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
- prev=&end;
+ prev= &key_end;
found_eq_constant=0;
for (i=0 ; i < keyuse->elements-1 ; i++,use++)
{
@@ -3479,7 +3695,11 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
continue;
}
- *save_pos= *use;
+#ifdef HAVE_purify
+ /* Valgrind complains about overlapped memcpy when save_pos==use. */
+ if (save_pos != use)
+#endif
+ *save_pos= *use;
prev=use;
found_eq_constant= !use->used_tables;
/* Save ptr to first use */
@@ -3489,7 +3709,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
- VOID(set_dynamic(keyuse,(gptr) &end,i));
+ VOID(set_dynamic(keyuse,(uchar*) &key_end,i));
keyuse->elements=i;
}
return FALSE;
@@ -3570,7 +3790,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
{ /* Collect all query fields referenced in the GROUP clause. */
for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
(*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
- (byte*) &indexed_fields);
+ (uchar*) &indexed_fields);
}
else if (join->select_distinct)
{ /* Collect all query fields referenced in the SELECT clause. */
@@ -3579,7 +3799,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
Item *item;
while ((item= select_items_it++))
item->walk(&Item::collect_item_field_processor, 0,
- (byte*) &indexed_fields);
+ (uchar*) &indexed_fields);
}
else
return;
@@ -3674,7 +3894,6 @@ best_access_path(JOIN *join,
table_map best_ref_depends_map= 0;
double tmp;
ha_rows rec;
-
DBUG_ENTER("best_access_path");
if (s->keyuse)
@@ -3722,12 +3941,12 @@ best_access_path(JOIN *join,
if (!(keyuse->used_tables & ~join->const_table_map))
const_part|= keyuse->keypart_map;
- double tmp= prev_record_reads(join, idx, (found_ref |
+ double tmp2= prev_record_reads(join, idx, (found_ref |
keyuse->used_tables));
- if (tmp < best_prev_record_reads)
+ if (tmp2 < best_prev_record_reads)
{
best_part_found_ref= keyuse->used_tables & ~join->const_table_map;
- best_prev_record_reads= tmp;
+ best_prev_record_reads= tmp2;
}
if (rec > keyuse->ref_table_rows)
rec= keyuse->ref_table_rows;
@@ -3842,7 +4061,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys.is_set(key))
+ if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@@ -4009,7 +4228,7 @@ best_access_path(JOIN *join,
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
- if (table->used_keys.is_set(key))
+ if (table->covering_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->stats.block_size/2/
@@ -4068,7 +4287,7 @@ best_access_path(JOIN *join,
!(s->quick && best_key && s->quick->index == best_key->key && // (2)
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&// (2)
!((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) && // (3)
- ! s->table->used_keys.is_clear_all() && best_key) && // (3)
+ ! s->table->covering_keys.is_clear_all() && best_key && !s->quick) &&// (3)
!(s->table->force_index && best_key && !s->quick)) // (4)
{ // Check full join
ha_rows rnd_records= s->found_records;
@@ -4197,11 +4416,12 @@ best_access_path(JOIN *join,
the array 'join->best_positions', and the cost of the plan in
'join->best_read'.
- RETURN
- None
+ RETURN VALUES
+ FALSE ok
+ TRUE Fatal error
*/
-static void
+static bool
choose_plan(JOIN *join, table_map join_tables)
{
uint search_depth= join->thd->variables.optimizer_search_depth;
@@ -4234,14 +4454,16 @@ choose_plan(JOIN *join, table_map join_tables)
the greedy version. Will be removed when greedy_search is approved.
*/
join->best_read= DBL_MAX;
- find_best(join, join_tables, join->const_tables, 1.0, 0.0);
+ if (find_best(join, join_tables, join->const_tables, 1.0, 0.0))
+ DBUG_RETURN(TRUE);
}
else
{
if (search_depth == 0)
/* Automatically determine a reasonable value for 'search_depth' */
search_depth= determine_search_depth(join);
- greedy_search(join, join_tables, search_depth, prune_level);
+ if (greedy_search(join, join_tables, search_depth, prune_level))
+ DBUG_RETURN(TRUE);
}
}
@@ -4249,7 +4471,7 @@ choose_plan(JOIN *join, table_map join_tables)
Store the cost of this query into a user variable
*/
join->thd->status_var.last_query_cost= join->best_read;
- DBUG_VOID_RETURN;
+ DBUG_RETURN(FALSE);
}
@@ -4401,7 +4623,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
if (join->sort_by_table &&
join->sort_by_table != join->positions[join->const_tables].table->table)
read_time+= record_count; // We have to make a temp table
- memcpy((gptr) join->best_positions, (gptr) join->positions,
+ memcpy((uchar*) join->best_positions, (uchar*) join->positions,
sizeof(POSITION)*idx);
join->best_read= read_time;
}
@@ -4477,11 +4699,12 @@ optimize_straight_join(JOIN *join, table_map join_tables)
In the future, 'greedy_search' might be extended to support other
implementations of 'best_extension', e.g. some simpler quadratic procedure.
- RETURN
- None
+ RETURN VALUES
+ FALSE ok
+ TRUE Fatal error
*/
-static void
+static bool
greedy_search(JOIN *join,
table_map remaining_tables,
uint search_depth,
@@ -4503,8 +4726,9 @@ greedy_search(JOIN *join,
do {
/* Find the extension of the current QEP with the lowest cost */
join->best_read= DBL_MAX;
- best_extension_by_limited_search(join, remaining_tables, idx, record_count,
- read_time, search_depth, prune_level);
+ if (best_extension_by_limited_search(join, remaining_tables, idx, record_count,
+ read_time, search_depth, prune_level))
+ DBUG_RETURN(TRUE);
if (size_remain <= search_depth)
{
@@ -4515,7 +4739,7 @@ greedy_search(JOIN *join,
DBUG_EXECUTE("opt", print_plan(join, join->tables,
record_count, read_time, read_time,
"optimal"););
- DBUG_VOID_RETURN;
+ DBUG_RETURN(FALSE);
}
/* select the first table in the optimal extension as most promising */
@@ -4660,11 +4884,12 @@ greedy_search(JOIN *join,
The parameter 'search_depth' provides control over the recursion
depth, and thus the size of the resulting optimal plan.
- RETURN
- None
+ RETURN VALUES
+ FALSE ok
+ TRUE Fatal error
*/
-static void
+static bool
best_extension_by_limited_search(JOIN *join,
table_map remaining_tables,
uint idx,
@@ -4673,11 +4898,12 @@ best_extension_by_limited_search(JOIN *join,
uint search_depth,
uint prune_level)
{
+ DBUG_ENTER("best_extension_by_limited_search");
+
THD *thd= join->thd;
if (thd->killed) // Abort
- return;
+ DBUG_RETURN(TRUE);
- DBUG_ENTER("best_extension_by_limited_search");
DBUG_EXECUTE("opt", print_plan(join, idx, read_time, record_count, idx,
"SOFAR:"););
@@ -4759,15 +4985,14 @@ best_extension_by_limited_search(JOIN *join,
if ( (search_depth > 1) && (remaining_tables & ~real_table_bit) )
{ /* Recursively expand the current partial plan */
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
- best_extension_by_limited_search(join,
- remaining_tables & ~real_table_bit,
- idx + 1,
- current_record_count,
- current_read_time,
- search_depth - 1,
- prune_level);
- if (thd->killed)
- DBUG_VOID_RETURN;
+ if (best_extension_by_limited_search(join,
+ remaining_tables & ~real_table_bit,
+ idx + 1,
+ current_record_count,
+ current_read_time,
+ search_depth - 1,
+ prune_level))
+ DBUG_RETURN(TRUE);
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
}
else
@@ -4783,7 +5008,7 @@ best_extension_by_limited_search(JOIN *join,
current_read_time+= current_record_count;
if ((search_depth == 1) || (current_read_time < join->best_read))
{
- memcpy((gptr) join->best_positions, (gptr) join->positions,
+ memcpy((uchar*) join->best_positions, (uchar*) join->positions,
sizeof(POSITION) * (idx + 1));
join->best_read= current_read_time - 0.001;
}
@@ -4796,19 +5021,26 @@ best_extension_by_limited_search(JOIN *join,
restore_prev_nj_state(s);
}
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(FALSE);
}
/*
TODO: this function is here only temporarily until 'greedy_search' is
tested and accepted.
+
+ RETURN VALUES
+ FALSE ok
+ TRUE Fatal error
*/
-static void
+static bool
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double read_time)
{
+ DBUG_ENTER("find_best");
THD *thd= join->thd;
+ if (thd->killed)
+ DBUG_RETURN(TRUE);
if (!rest_tables)
{
DBUG_PRINT("best",("read_time: %g record_count: %g",read_time,
@@ -4821,14 +5053,14 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
read_time+=record_count; // We have to make a temp table
if (read_time < join->best_read)
{
- memcpy((gptr) join->best_positions,(gptr) join->positions,
+ memcpy((uchar*) join->best_positions,(uchar*) join->positions,
sizeof(POSITION)*idx);
join->best_read= read_time - 0.001;
}
- return;
+ DBUG_RETURN(FALSE);
}
if (read_time+record_count/(double) TIME_FOR_COMPARE >= join->best_read)
- return; /* Found better before */
+ DBUG_RETURN(FALSE); /* Found better before */
JOIN_TAB *s;
double best_record_count=DBL_MAX,best_read_time=DBL_MAX;
@@ -4861,10 +5093,9 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
best_read_time=current_read_time;
}
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
- find_best(join,rest_tables & ~real_table_bit,idx+1,
- current_record_count,current_read_time);
- if (thd->killed)
- return;
+ if (find_best(join,rest_tables & ~real_table_bit,idx+1,
+ current_record_count,current_read_time))
+ DBUG_RETURN(TRUE);
swap_variables(JOIN_TAB*, join->best_ref[idx], *pos);
}
restore_prev_nj_state(s);
@@ -4872,6 +5103,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
break; // Don't test all combinations
}
}
+ DBUG_RETURN(FALSE);
}
@@ -5132,10 +5364,11 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
j->ref.key_parts=keyparts;
j->ref.key_length=length;
j->ref.key=(int) key;
- if (!(j->ref.key_buff= (byte*) thd->calloc(ALIGN_SIZE(length)*2)) ||
+ if (!(j->ref.key_buff= (uchar*) thd->calloc(ALIGN_SIZE(length)*2)) ||
!(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
(keyparts+1)))) ||
- !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)))
+ !(j->ref.items= (Item**) thd->alloc(sizeof(Item*)*keyparts)) ||
+ !(j->ref.cond_guards= (bool**) thd->alloc(sizeof(uint*)*keyparts)))
{
DBUG_RETURN(TRUE);
}
@@ -5145,11 +5378,13 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
keyuse=org_keyuse;
store_key **ref_key= j->ref.key_copy;
- byte *key_buff=j->ref.key_buff, *null_ref_key= 0;
+ uchar *key_buff=j->ref.key_buff, *null_ref_key= 0;
bool keyuse_uses_no_tables= TRUE;
if (ftkey)
{
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
+ /* Predicates pushed down into subquery can't be used FT access */
+ j->ref.cond_guards[0]= NULL;
if (keyuse->used_tables)
DBUG_RETURN(TRUE); // not supported yet. SerG
@@ -5166,6 +5401,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
uint maybe_null= test(keyinfo->key_part[i].null_bit);
j->ref.items[i]=keyuse->val; // Save for cond removal
+ j->ref.cond_guards[i]= keyuse->cond_guard;
if (keyuse->null_rejecting)
j->ref.null_rejecting |= 1 << i;
keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
@@ -5173,8 +5409,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
!(join->select_options & SELECT_DESCRIBE))
{ // Compare against constant
store_key_item tmp(thd, keyinfo->key_part[i].field,
- (char*)key_buff + maybe_null,
- maybe_null ? (char*) key_buff : 0,
+ key_buff + maybe_null,
+ maybe_null ? key_buff : 0,
keyinfo->key_part[i].length, keyuse->val);
if (thd->is_fatal_error)
DBUG_RETURN(TRUE);
@@ -5184,7 +5420,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
*ref_key++= get_store_key(thd,
keyuse,join->const_table_map,
&keyinfo->key_part[i],
- (char*) key_buff,maybe_null);
+ key_buff, maybe_null);
/*
Remember if we are going to use REF_OR_NULL
But only if field _really_ can be null i.e. we force JT_REF
@@ -5228,7 +5464,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
static store_key *
get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
- KEY_PART_INFO *key_part, char *key_buff, uint maybe_null)
+ KEY_PART_INFO *key_part, uchar *key_buff, uint maybe_null)
{
if (!((~used_tables) & keyuse->used_tables)) // if const item
{
@@ -5239,13 +5475,17 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
key_part->length,
keyuse->val);
}
- else if (keyuse->val->type() == Item::FIELD_ITEM)
+ else if (keyuse->val->type() == Item::FIELD_ITEM ||
+ (keyuse->val->type() == Item::REF_ITEM &&
+ ((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
+ (*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
+ Item_ref::DIRECT_REF) )
return new store_key_field(thd,
key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
- ((Item_field*) keyuse->val)->field,
+ ((Item_field*) keyuse->val->real_item())->field,
keyuse->val->full_name());
return new store_key_item(thd,
key_part->field,
@@ -5426,8 +5666,9 @@ static void add_not_null_conds(JOIN *join)
for (uint i=join->const_tables ; i < join->tables ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
- if ((tab->type == JT_REF || tab->type == JT_REF_OR_NULL) &&
- !tab->table->maybe_null)
+ if ((tab->type == JT_REF || tab->type == JT_EQ_REF ||
+ tab->type == JT_REF_OR_NULL) &&
+ !tab->table->maybe_null)
{
for (uint keypart= 0; keypart < tab->ref.key_parts; keypart++)
{
@@ -5683,6 +5924,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->ref.key= -1;
tab->ref.key_parts=0; // Don't use ref key.
join->best_positions[i].records_read= rows2double(tab->quick->records);
+ /*
+ We will use join cache here : prevent sorting of the first
+ table only and sort at the end.
+ */
+ if (i != join->const_tables && join->tables > join->const_tables + 1)
+ join->full_join= 1;
}
tmp= NULL;
@@ -5716,7 +5963,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
DBUG_EXECUTE("where",print_where(tmp,tab->table->alias););
SQL_SELECT *sel= tab->select= ((SQL_SELECT*)
- thd->memdup((gptr) select,
+ thd->memdup((uchar*) select,
sizeof(*select)));
if (!sel)
DBUG_RETURN(1); // End of memory
@@ -5868,7 +6115,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
DBUG_EXECUTE("where",print_where(tmp,"cache"););
tab->cache.select=(SQL_SELECT*)
- thd->memdup((gptr) sel, sizeof(SQL_SELECT));
+ thd->memdup((uchar*) sel, sizeof(SQL_SELECT));
tab->cache.select->cond=tmp;
tab->cache.select->read_tables=join->const_table_map;
}
@@ -5877,13 +6124,39 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
/*
- Push down all predicates from on expressions.
- Each of these predicated are guarded by a variable
+ Push down conditions from all on expressions.
+ Each of these conditions are guarded by a variable
that turns if off just before null complemented row for
- outer joins is formed. Thus, the predicates from an
+ outer joins is formed. Thus, the condition from an
'on expression' are guaranteed not to be checked for
the null complemented row.
*/
+
+ /* First push down constant conditions from on expressions */
+ for (JOIN_TAB *join_tab= join->join_tab+join->const_tables;
+ join_tab < join->join_tab+join->tables ; join_tab++)
+ {
+ if (*join_tab->on_expr_ref)
+ {
+ JOIN_TAB *cond_tab= join_tab->first_inner;
+ COND *tmp= make_cond_for_table(*join_tab->on_expr_ref,
+ join->const_table_map,
+ (table_map) 0);
+ if (!tmp)
+ continue;
+ tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
+ if (!tmp)
+ DBUG_RETURN(1);
+ tmp->quick_fix_field();
+ cond_tab->select_cond= !cond_tab->select_cond ? tmp :
+ new Item_cond_and(cond_tab->select_cond,tmp);
+ if (!cond_tab->select_cond)
+ DBUG_RETURN(1);
+ cond_tab->select_cond->quick_fix_field();
+ }
+ }
+
+ /* Push down non-constant conditions from on expressions */
JOIN_TAB *last_tab= tab;
while (first_inner_tab && first_inner_tab->last_inner == last_tab)
{
@@ -5893,37 +6166,42 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
*/
COND *on_expr= *first_inner_tab->on_expr_ref;
- table_map used_tables= join->const_table_map |
- OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
+ table_map used_tables2= (join->const_table_map |
+ OUTER_REF_TABLE_BIT | RAND_TABLE_BIT);
for (tab= join->join_tab+join->const_tables; tab <= last_tab ; tab++)
{
current_map= tab->table->map;
- used_tables|= current_map;
- COND *tmp= make_cond_for_table(on_expr, used_tables, current_map);
- if (tmp)
+ used_tables2|= current_map;
+ COND *tmp_cond= make_cond_for_table(on_expr, used_tables2,
+ current_map);
+ if (tmp_cond)
{
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
/*
First add the guards for match variables of
all embedding outer join operations.
*/
- if (!(tmp= add_found_match_trig_cond(cond_tab->first_inner,
- tmp, first_inner_tab)))
+ if (!(tmp_cond= add_found_match_trig_cond(cond_tab->first_inner,
+ tmp_cond,
+ first_inner_tab)))
DBUG_RETURN(1);
/*
Now add the guard turning the predicate off for
the null complemented row.
*/
DBUG_PRINT("info", ("Item_func_trig_cond"));
- tmp= new Item_func_trig_cond(tmp,
- &first_inner_tab->not_null_compl);
- DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
- if (tmp)
- tmp->quick_fix_field();
+ tmp_cond= new Item_func_trig_cond(tmp_cond,
+ &first_inner_tab->
+ not_null_compl);
+ DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx",
+ (ulong) tmp_cond));
+ if (tmp_cond)
+ tmp_cond->quick_fix_field();
/* Add the predicate to other pushed down predicates */
DBUG_PRINT("info", ("Item_cond_and"));
- cond_tab->select_cond= !cond_tab->select_cond ? tmp :
- new Item_cond_and(cond_tab->select_cond,tmp);
+ cond_tab->select_cond= !cond_tab->select_cond ? tmp_cond :
+ new Item_cond_and(cond_tab->select_cond,
+ tmp_cond);
DBUG_PRINT("info", ("Item_cond_and 0x%lx",
(ulong)cond_tab->select_cond));
if (!cond_tab->select_cond)
@@ -5960,14 +6238,14 @@ make_join_readinfo(JOIN *join, ulonglong options)
disable join cache because it will change the ordering of the results.
Code handles sort table that is at any location (not only first after
the const tables) despite the fact that it's currently prohibited.
+ We must disable join cache if the first non-const table alone is
+ ordered. If there is a temp table the ordering is done as a last
+ operation and doesn't prevent join cache usage.
*/
- if (!ordered_set &&
- (table == join->sort_by_table &&
- (!join->order || join->skip_sort_order ||
- test_if_skip_sort_order(tab, join->order, join->select_limit,
- 1))
- ) ||
- (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))
+ if (!ordered_set && !join->need_tmp &&
+ ((table == join->sort_by_table &&
+ (!join->order || join->skip_sort_order)) ||
+ (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)))
ordered_set= 1;
tab->sorted= sorted;
@@ -5982,7 +6260,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
table->status=STATUS_NO_RECORD;
tab->read_first_record= join_read_const;
tab->read_record.read_record= join_no_more_records;
- if (table->used_keys.is_set(tab->ref.key) &&
+ if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -6000,7 +6278,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
tab->quick=0;
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
- if (table->used_keys.is_set(tab->ref.key) &&
+ if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -6017,7 +6295,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
}
delete tab->quick;
tab->quick=0;
- if (table->used_keys.is_set(tab->ref.key) &&
+ if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@@ -6061,8 +6339,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED;
tab->read_first_record= join_init_quick_read_record;
if (statistics)
- statistic_increment(join->thd->status_var.select_range_check_count,
- &LOCK_status);
+ status_var_increment(join->thd->status_var.select_range_check_count);
}
else
{
@@ -6072,15 +6349,13 @@ make_join_readinfo(JOIN *join, ulonglong options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(join->thd->status_var.select_range_count,
- &LOCK_status);
+ status_var_increment(join->thd->status_var.select_range_count);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(join->thd->status_var.select_scan_count,
- &LOCK_status);
+ status_var_increment(join->thd->status_var.select_scan_count);
}
}
else
@@ -6088,30 +6363,28 @@ make_join_readinfo(JOIN *join, ulonglong options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(join->thd->status_var.select_full_range_join_count,
- &LOCK_status);
+ status_var_increment(join->thd->status_var.select_full_range_join_count);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(join->thd->status_var.select_full_join_count,
- &LOCK_status);
+ status_var_increment(join->thd->status_var.select_full_join_count);
}
}
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && //not index_merge
- table->used_keys.is_set(tab->select->quick->index))
+ table->covering_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
- else if (!table->used_keys.is_clear_all() &&
+ else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
- tab->index=find_shortest_key(table, & table->used_keys);
+ tab->index=find_shortest_key(table, & table->covering_keys);
tab->read_first_record= join_read_first;
tab->type=JT_NEXT; // Read with index_first / index_next
}
@@ -6242,7 +6515,7 @@ void JOIN_TAB::cleanup()
void JOIN::join_free()
{
- SELECT_LEX_UNIT *unit;
+ SELECT_LEX_UNIT *tmp_unit;
SELECT_LEX *sl;
/*
Optimization: if not EXPLAIN and we are done with the JOIN,
@@ -6254,8 +6527,10 @@ void JOIN::join_free()
cleanup(full);
- for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit())
- for (sl= unit->first_select(); sl; sl= sl->next_select())
+ for (tmp_unit= select_lex->first_inner_unit();
+ tmp_unit;
+ tmp_unit= tmp_unit->next_unit())
+ for (sl= tmp_unit->first_select(); sl; sl= sl->next_select())
{
Item_subselect *subselect= sl->master_unit()->item;
bool full_local= full && (!subselect || subselect->is_evaluated());
@@ -6329,7 +6604,6 @@ void JOIN::cleanup(bool full)
for (tab= join_tab, end= tab+tables; tab != end; tab++)
tab->cleanup();
table= 0;
- tables= 0;
}
else
{
@@ -6493,7 +6767,8 @@ static void update_depend_map(JOIN *join, ORDER *order)
order->item[0]->update_used_tables();
order->depend_map=depend_map=order->item[0]->used_tables();
// Not item_sum(), RAND() and no reference to table outside of sub select
- if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)))
+ if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT))
+ && !order->item[0]->with_sum_func)
{
for (JOIN_TAB **tab=join->map2table;
depend_map ;
@@ -6554,6 +6829,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
+ if (order->item[0]->with_subselect)
+ order->item[0]->val_str(&order->item[0]->str_value);
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
continue; // skip const item
}
@@ -6891,9 +7168,9 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
else
{
/* None of the fields was found in multiple equalities */
- Item_equal *item= new Item_equal((Item_field *) left_item,
- (Item_field *) right_item);
- cond_equal->current_level.push_back(item);
+ Item_equal *item_equal= new Item_equal((Item_field *) left_item,
+ (Item_field *) right_item);
+ cond_equal->current_level.push_back(item_equal);
}
}
return TRUE;
@@ -6973,6 +7250,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
SYNOPSIS
check_row_equality()
+ thd thread handle
left_row left term of the row equality to be processed
right_row right term of the row equality to be processed
cond_equal multiple equalities that must hold together with the predicate
@@ -6993,24 +7271,32 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
FALSE otherwise
*/
-static bool check_row_equality(Item *left_row, Item_row *right_row,
+static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
COND_EQUAL *cond_equal, List<Item>* eq_list)
{
uint n= left_row->cols();
for (uint i= 0 ; i < n; i++)
{
bool is_converted;
- Item *left_item= left_row->el(i);
- Item *right_item= right_row->el(i);
+ Item *left_item= left_row->element_index(i);
+ Item *right_item= right_row->element_index(i);
if (left_item->type() == Item::ROW_ITEM &&
right_item->type() == Item::ROW_ITEM)
- is_converted= check_row_equality((Item_row *) left_item,
- (Item_row *) right_item,
- cond_equal, eq_list);
- else
+ {
+ is_converted= check_row_equality(thd,
+ (Item_row *) left_item,
+ (Item_row *) right_item,
+ cond_equal, eq_list);
+ if (!is_converted)
+ thd->lex->current_select->cond_count++;
+ }
+ else
+ {
is_converted= check_simple_equality(left_item, right_item, 0, cond_equal);
-
- if (!is_converted)
+ thd->lex->current_select->cond_count++;
+ }
+
+ if (!is_converted)
{
Item_func_eq *eq_item;
if (!(eq_item= new Item_func_eq(left_item, right_item)))
@@ -7029,6 +7315,7 @@ static bool check_row_equality(Item *left_row, Item_row *right_row,
SYNOPSIS
check_equality()
+ thd thread handle
item predicate to process
cond_equal multiple equalities that must hold together with the predicate
eq_list results of conversions of row equalities that are not simple
@@ -7053,7 +7340,7 @@ static bool check_row_equality(Item *left_row, Item_row *right_row,
or, if the procedure fails by a fatal error.
*/
-static bool check_equality(Item *item, COND_EQUAL *cond_equal,
+static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
List<Item> *eq_list)
{
if (item->type() == Item::FUNC_ITEM &&
@@ -7064,9 +7351,13 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal,
if (left_item->type() == Item::ROW_ITEM &&
right_item->type() == Item::ROW_ITEM)
- return check_row_equality((Item_row *) left_item,
+ {
+ thd->lex->current_select->cond_count--;
+ return check_row_equality(thd,
+ (Item_row *) left_item,
(Item_row *) right_item,
cond_equal, eq_list);
+ }
else
return check_simple_equality(left_item, right_item, item, cond_equal);
}
@@ -7079,6 +7370,7 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal,
SYNOPSIS
build_equal_items_for_cond()
+ thd thread handle
cond condition(expression) where to make replacement
inherited path to all inherited multiple equality items
@@ -7141,7 +7433,7 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal,
pointer to the transformed condition
*/
-static COND *build_equal_items_for_cond(COND *cond,
+static COND *build_equal_items_for_cond(THD *thd, COND *cond,
COND_EQUAL *inherited)
{
Item_equal *item_equal;
@@ -7174,7 +7466,7 @@ static COND *build_equal_items_for_cond(COND *cond,
structure here because it's restored before each
re-execution of any prepared statement/stored procedure.
*/
- if (check_equality(item, &cond_equal, &eq_list))
+ if (check_equality(thd, item, &cond_equal, &eq_list))
li.remove();
}
@@ -7209,7 +7501,7 @@ static COND *build_equal_items_for_cond(COND *cond,
while ((item= li++))
{
Item *new_item;
- if ((new_item = build_equal_items_for_cond(item, inherited))!= item)
+ if ((new_item= build_equal_items_for_cond(thd, item, inherited)) != item)
{
/* This replacement happens only for standalone equalities */
/*
@@ -7239,7 +7531,7 @@ static COND *build_equal_items_for_cond(COND *cond,
for WHERE a=b AND c=d AND (b=c OR d=5)
b=c is replaced by =(a,b,c,d).
*/
- if (check_equality(cond, &cond_equal, &eq_list))
+ if (check_equality(thd, cond, &cond_equal, &eq_list))
{
int n= cond_equal.current_level.elements + eq_list.elements;
if (n == 0)
@@ -7285,11 +7577,11 @@ static COND *build_equal_items_for_cond(COND *cond,
as soon the field is not of a string type or the field reference is
an argument of a comparison predicate.
*/
- byte *is_subst_valid= (byte *) 1;
+ uchar *is_subst_valid= (uchar *) 1;
cond= cond->compile(&Item::subst_argument_checker,
&is_subst_valid,
&Item::equal_fields_propagator,
- (byte *) inherited);
+ (uchar *) inherited);
cond->update_used_tables();
}
return cond;
@@ -7302,7 +7594,7 @@ static COND *build_equal_items_for_cond(COND *cond,
SYNOPSIS
build_equal_items()
- thd Thread handler
+ thd thread handle
cond condition to build the multiple equalities for
inherited path to all inherited multiple equality items
join_list list of join tables to which the condition refers to
@@ -7363,7 +7655,7 @@ static COND *build_equal_items(THD *thd, COND *cond,
if (cond)
{
- cond= build_equal_items_for_cond(cond, inherited);
+ cond= build_equal_items_for_cond(thd, cond, inherited);
cond->update_used_tables();
if (cond->type() == Item::COND_ITEM &&
((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
@@ -7391,14 +7683,15 @@ static COND *build_equal_items(THD *thd, COND *cond,
{
if (table->on_expr)
{
- List<TABLE_LIST> *join_list= table->nested_join ?
- &table->nested_join->join_list : NULL;
+ List<TABLE_LIST> *nested_join_list= table->nested_join ?
+ &table->nested_join->join_list : NULL;
/*
We can modify table->on_expr because its old value will
be restored before re-execution of PS/SP.
*/
table->on_expr= build_equal_items(thd, table->on_expr, inherited,
- join_list, &table->cond_equal);
+ nested_join_list,
+ &table->cond_equal);
}
}
}
@@ -7650,6 +7943,10 @@ static COND* substitute_for_best_equal_field(COND *cond,
break;
}
}
+ if (cond->type() == Item::COND_ITEM &&
+ !((Item_cond*)cond)->argument_list()->elements)
+ cond= new Item_int((int32)cond->val_bool());
+
}
else if (cond->type() == Item::FUNC_ITEM &&
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
@@ -7713,6 +8010,22 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
stat[0].const_keys.merge(possible_keys);
+
+ /*
+ For each field in the multiple equality (for which we know that it
+ is a constant) we have to find its corresponding key part, and set
+ that key part in const_key_parts.
+ */
+ if (!possible_keys.is_clear_all())
+ {
+ TABLE *tab= field->table;
+ KEYUSE *use;
+ for (use= stat->keyuse; use && use->table == tab; use++)
+ if (possible_keys.is_set(use->key) &&
+ tab->key_info[use->key].key_part[use->keypart].field ==
+ field)
+ tab->const_key_parts[use->key]|= use->keypart_map;
+ }
}
}
}
@@ -7755,7 +8068,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
value->result_type() != STRING_RESULT ||
left_item->collation.collation == value->collation.collation))
{
- Item *tmp=value->new_item();
+ Item *tmp=value->clone_item();
tmp->collation.set(right_item->collation);
if (tmp)
@@ -7779,7 +8092,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
value->result_type() != STRING_RESULT ||
right_item->collation.collation == value->collation.collation))
{
- Item *tmp=value->new_item();
+ Item *tmp= value->clone_item();
tmp->collation.set(left_item->collation);
if (tmp)
@@ -7807,7 +8120,7 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
SYNOPSIS
remove_additional_cond()
- conds - condition for processing
+ conds Condition for processing
RETURN VALUES
new conditions
@@ -8028,9 +8341,14 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
*/
expr= simplify_joins(join, &nested_join->join_list,
expr, FALSE);
- table->on_expr= expr;
- if (!table->prep_on_expr)
+
+ if (!table->prep_on_expr || expr != table->on_expr)
+ {
+ DBUG_ASSERT(expr);
+
+ table->on_expr= expr;
table->prep_on_expr= expr->copy_andor_structure(join->thd);
+ }
}
nested_join->used_tables= (table_map) 0;
nested_join->not_null_tables=(table_map) 0;
@@ -8040,7 +8358,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
else
{
- if (!(table->prep_on_expr))
+ if (!table->prep_on_expr)
table->prep_on_expr= table->on_expr;
used_tables= table->table->map;
if (conds)
@@ -8190,7 +8508,7 @@ static uint build_bitmap_for_nested_joins(List<TABLE_LIST> *join_list,
*/
if (nested_join->join_list.elements != 1)
{
- nested_join->nj_map= 1 << first_unused++;
+ nested_join->nj_map= (nested_join_map) 1 << first_unused++;
first_unused= build_bitmap_for_nested_joins(&nested_join->join_list,
first_unused);
}
@@ -8400,7 +8718,6 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
Item::cond_result *cond_value)
{
THD *thd= join->thd;
- SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
if (!conds)
@@ -8533,7 +8850,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
thd->read_first_successful_insert_id_in_prev_stmt(),
- 21))))
+ MY_INT64_NUM_DECIMAL_DIGITS))))
{
cond=new_cond;
/*
@@ -8550,8 +8867,8 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
thd->substitute_null_with_insert_id= FALSE;
}
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
- else if (((field->type() == FIELD_TYPE_DATE) ||
- (field->type() == FIELD_TYPE_DATETIME)) &&
+ else if (((field->type() == MYSQL_TYPE_DATE) ||
+ (field->type() == MYSQL_TYPE_DATETIME)) &&
(field->flags & NOT_NULL_FLAG) &&
!field->table->maybe_null)
{
@@ -8594,6 +8911,42 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
return cond; // Point at next and level
}
+/*
+ Check if equality can be used in removing components of GROUP BY/DISTINCT
+
+ SYNOPSIS
+ test_if_equality_guarantees_uniqueness()
+ l the left comparison argument (a field if any)
+ r the right comparison argument (a const of any)
+
+ DESCRIPTION
+ Checks if an equality predicate can be used to take away
+ DISTINCT/GROUP BY because it is known to be true for exactly one
+ distinct value (e.g. <expr> == <const>).
+ Arguments must be of the same type because e.g.
+ <string_field> = <int_const> may match more than 1 distinct value from
+ the column.
+ We must take into consideration and the optimization done for various
+ string constants when compared to dates etc (see Item_int_with_ref) as
+ well as the collation of the arguments.
+
+ RETURN VALUE
+ TRUE can be used
+ FALSE cannot be used
+*/
+static bool
+test_if_equality_guarantees_uniqueness(Item *l, Item *r)
+{
+ return r->const_item() &&
+ /* elements must be compared as dates */
+ (Arg_comparator::can_compare_as_dates(l, r, 0) ||
+ /* or of the same result type */
+ (r->result_type() == l->result_type() &&
+ /* and must have the same collation if compared as strings */
+ (l->result_type() != STRING_RESULT ||
+ l->collation.collation == r->collation.collation)));
+}
+
/*
Return 1 if the item is a const value in all the WHERE clause
*/
@@ -8630,7 +8983,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
Item *right_item= ((Item_func*) cond)->arguments()[1];
if (left_item->eq(comp_item,1))
{
- if (right_item->const_item())
+ if (test_if_equality_guarantees_uniqueness (left_item, right_item))
{
if (*const_item)
return right_item->eq(*const_item, 1);
@@ -8640,7 +8993,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
}
else if (right_item->eq(comp_item,1))
{
- if (left_item->const_item())
+ if (test_if_equality_guarantees_uniqueness (right_item, left_item))
{
if (*const_item)
return left_item->eq(*const_item, 1);
@@ -8689,7 +9042,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
Make sure that the blob fits into a Field_varstring which has
2-byte lenght.
*/
- if (convert_blob_length && convert_blob_length < UINT_MAX16 &&
+ if (convert_blob_length && convert_blob_length <= Field_varstring::MAX_SIZE &&
(org_field->flags & BLOB_FLAG))
new_field= new Field_varstring(convert_blob_length,
org_field->maybe_null(),
@@ -8712,6 +9065,8 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
org_field->type() == MYSQL_TYPE_VARCHAR)
table->s->db_create_options|= HA_OPTION_PACK_RECORD;
+ else if (org_field->type() == FIELD_TYPE_DOUBLE)
+ ((Field_double *) new_field)->not_fixed= TRUE;
}
return new_field;
}
@@ -8752,11 +9107,16 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
switch (item->result_type()) {
case REAL_RESULT:
new_field= new Field_double(item->max_length, maybe_null,
- item->name, item->decimals);
+ item->name, item->decimals, TRUE);
break;
case INT_RESULT:
- /* Select an integer type with the minimal fit precision */
- if (item->max_length > 11)
+ /*
+ Select an integer type with the minimal fit precision.
+ MY_INT32_NUM_DECIMAL_DIGITS is sign inclusive, don't consider the sign.
+ Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
+ Field_long : make them Field_longlong.
+ */
+ if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1))
new_field=new Field_longlong(item->max_length, maybe_null,
item->name, item->unsigned_flag);
else
@@ -8768,19 +9128,20 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
enum enum_field_types type;
/*
- DATE/TIME fields have STRING_RESULT result type. To preserve
- type they needed to be handled separately.
+ DATE/TIME and GEOMETRY fields have STRING_RESULT result type.
+ To preserve type they needed to be handled separately.
*/
if ((type= item->field_type()) == MYSQL_TYPE_DATETIME ||
- type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE)
+ type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_GEOMETRY)
new_field= item->tmp_table_field_from_field_type(table, 1);
/*
Make sure that the blob fits into a Field_varstring which has
2-byte lenght.
*/
else if (item->max_length/item->collation.collation->mbmaxlen > 255 &&
- item->max_length/item->collation.collation->mbmaxlen < UINT_MAX16
- && convert_blob_length)
+ convert_blob_length <= Field_varstring::MAX_SIZE &&
+ convert_blob_length)
new_field= new Field_varstring(convert_blob_length, maybe_null,
item->name, table->s,
item->collation.collation);
@@ -8829,8 +9190,7 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table)
if (item->field_type() == MYSQL_TYPE_VARCHAR)
{
Field *field;
- if (item->max_length > MAX_FIELD_VARCHARLENGTH /
- item->collation.collation->mbmaxlen)
+ if (item->max_length > MAX_FIELD_VARCHARLENGTH)
field= new Field_blob(item->max_length, item->maybe_null,
item->name, item->collation.collation);
else
@@ -8888,9 +9248,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item *orig_item= 0;
if (type != Item::FIELD_ITEM &&
- item->real_item()->type() == Item::FIELD_ITEM &&
- (item->type() != Item::REF_ITEM ||
- !((Item_ref *) item)->depended_from))
+ item->real_item()->type() == Item::FIELD_ITEM)
{
orig_item= item;
item= item->real_item();
@@ -8926,7 +9284,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
field->result_field= result;
}
else if (table_cant_handle_bit_fields && field->field->type() ==
- FIELD_TYPE_BIT)
+ MYSQL_TYPE_BIT)
{
*from_field= field->field;
result= create_tmp_field_from_item(thd, item, table, copy_func,
@@ -8988,7 +9346,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
a tmp_set bitmap to be used by things like filesort.
*/
-void setup_tmp_table_column_bitmaps(TABLE *table, byte *bitmaps)
+void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
{
uint field_count= table->s->fields;
bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
@@ -9052,12 +9410,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
uint blob_count,group_null_items, string_count;
uint temp_pool_slot=MY_BIT_NONE;
- ulong reclength, string_total_length, fieldnr= 0;
+ uint fieldnr= 0;
+ ulong reclength, string_total_length;
bool using_unique_constraint= 0;
bool use_packed_rows= 0;
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
char *tmpname,path[FN_REFLEN];
- byte *pos, *group_buff, *bitmaps;
+ uchar *pos, *group_buff, *bitmaps;
uchar *null_flags;
Field **reg_field, **from_field, **default_field;
uint *blob_field;
@@ -9074,7 +9433,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(int) distinct, (int) save_sum_fields,
(ulong) rows_limit,test(group)));
- statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
+ status_var_increment(thd->status_var.created_tmp_tables);
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
temp_pool_slot = bitmap_lock_set_next(&temp_pool);
@@ -9179,7 +9538,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->copy_blobs= 1;
table->in_use= thd;
table->quick_keys.init();
- table->used_keys.init();
+ table->covering_keys.init();
table->keys_in_use_for_query.init();
table->s= share;
@@ -9208,13 +9567,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
{
- /*
- Mark that the we have ignored an item that refers to a summary
- function. We need to know this if someone is going to use
- DISTINCT on the result.
- */
- param->using_indirect_summary_function=1;
- continue;
+ if (item->used_tables() & OUTER_REF_TABLE_BIT)
+ item->update_used_tables();
+ if (type == Item::SUBSELECT_ITEM ||
+ (item->used_tables() & ~OUTER_REF_TABLE_BIT))
+ {
+ /*
+ Mark that the we have ignored an item that refers to a summary
+ function. We need to know this if someone is going to use
+ DISTINCT on the result.
+ */
+ param->using_indirect_summary_function=1;
+ continue;
+ }
}
if (item->const_item() && (int) hidden_field_count <= 0)
continue; // We don't have to store this
@@ -9243,7 +9608,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field++= fieldnr;
blob_count++;
}
- if (new_field->type() == FIELD_TYPE_BIT)
+ if (new_field->type() == MYSQL_TYPE_BIT)
total_uneven_bit_length+= new_field->field_length & 7;
*(reg_field++)= new_field;
if (new_field->real_type() == MYSQL_TYPE_STRING ||
@@ -9305,7 +9670,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
reclength+=new_field->pack_length();
if (!(new_field->flags & NOT_NULL_FLAG))
null_count++;
- if (new_field->type() == FIELD_TYPE_BIT)
+ if (new_field->type() == MYSQL_TYPE_BIT)
total_uneven_bit_length+= new_field->field_length & 7;
if (new_field->flags & BLOB_FLAG)
{
@@ -9343,12 +9708,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
share->fields= field_count;
/* If result table is small; use a heap */
+ /* future: storage engine selection can be made dynamic? */
if (blob_count || using_unique_constraint ||
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM))
{
+ share->db_plugin= ha_lock_engine(0, myisam_hton);
table->file= get_new_handler(share, &table->mem_root,
- share->db_type= myisam_hton);
+ share->db_type());
if (group &&
(param->group_parts > table->file->max_key_parts() ||
param->group_length > table->file->max_key_length()))
@@ -9356,8 +9723,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
+ share->db_plugin= ha_lock_engine(0, heap_hton);
table->file= get_new_handler(share, &table->mem_root,
- share->db_type= heap_hton);
+ share->db_type());
}
if (!table->file)
goto err;
@@ -9392,13 +9760,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
share->rec_buff_length= alloc_length;
- if (!(table->record[0]= (byte*)
+ if (!(table->record[0]= (uchar*)
alloc_root(&table->mem_root, alloc_length*3)))
goto err;
table->record[1]= table->record[0]+alloc_length;
share->default_values= table->record[1]+alloc_length;
}
copy_func[0]=0; // End marker
+ param->func_count= copy_func - param->items_to_copy;
setup_tmp_table_column_bitmaps(table, bitmaps);
@@ -9407,7 +9776,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
pos=table->record[0]+ null_pack_length;
if (null_pack_length)
{
- bzero((byte*) recinfo,sizeof(*recinfo));
+ bzero((uchar*) recinfo,sizeof(*recinfo));
recinfo->type=FIELD_NORMAL;
recinfo->length=null_pack_length;
recinfo++;
@@ -9423,7 +9792,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
Field *field= *reg_field;
uint length;
- bzero((byte*) recinfo,sizeof(*recinfo));
+ bzero((uchar*) recinfo,sizeof(*recinfo));
if (!(field->flags & NOT_NULL_FLAG))
{
@@ -9437,20 +9806,20 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
recinfo->length=1;
recinfo->type=FIELD_NORMAL;
recinfo++;
- bzero((byte*) recinfo,sizeof(*recinfo));
+ bzero((uchar*) recinfo,sizeof(*recinfo));
}
else
{
recinfo->null_bit= 1 << (null_count & 7);
recinfo->null_pos= null_count/8;
}
- field->move_field((char*) pos,null_flags+null_count/8,
+ field->move_field(pos,null_flags+null_count/8,
1 << (null_count & 7));
null_count++;
}
else
- field->move_field((char*) pos,(uchar*) 0,0);
- if (field->type() == FIELD_TYPE_BIT)
+ field->move_field(pos,(uchar*) 0,0);
+ if (field->type() == MYSQL_TYPE_BIT)
{
/* We have to reserve place for extra bits among null bits */
((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8,
@@ -9518,7 +9887,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (thd->variables.tmp_table_size == ~ (ulonglong) 0) // No limit
share->max_rows= ~(ha_rows) 0;
else
- share->max_rows= (ha_rows) (((share->db_type == heap_hton) ?
+ share->max_rows= (ha_rows) (((share->db_type() == heap_hton) ?
min(thd->variables.tmp_table_size,
thd->variables.max_heap_table_size) :
thd->variables.tmp_table_size) /
@@ -9567,10 +9936,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
cur_group->buff=(char*) group_buff;
if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
- (char*) group_buff +
- test(maybe_null),
- field->null_ptr,
- field->null_bit)))
+ group_buff +
+ test(maybe_null),
+ field->null_ptr,
+ field->null_bit)))
goto err; /* purecov: inspected */
if (maybe_null)
{
@@ -9632,7 +10001,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
key_part_info->null_bit=0;
key_part_info->offset=hidden_null_pack_length;
key_part_info->length=null_pack_length;
- key_part_info->field= new Field_string((char*) table->record[0],
+ key_part_info->field= new Field_string(table->record[0],
(uint32) key_part_info->length,
(uchar*) 0,
(uint) 0,
@@ -9666,7 +10035,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (thd->is_fatal_error) // If end of memory
goto err; /* purecov: inspected */
share->db_record_offset= 1;
- if (share->db_type == myisam_hton)
+ if (share->db_type() == myisam_hton)
{
if (create_myisam_tmp_table(table,param,select_options))
goto err;
@@ -9721,7 +10090,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
uint null_count= 0; /* number of columns which may be null */
uint null_pack_length; /* NULL representation array length */
uint *blob_field;
- byte *bitmaps;
+ uchar *bitmaps;
TABLE *table;
TABLE_SHARE *share;
@@ -9772,7 +10141,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
null_pack_length= (null_count + 7)/8;
share->reclength= record_length + null_pack_length;
share->rec_buff_length= ALIGN_SIZE(share->reclength + 1);
- table->record[0]= (byte*) thd->alloc(share->rec_buff_length);
+ table->record[0]= (uchar*) thd->alloc(share->rec_buff_length);
if (!table->record[0])
goto error;
@@ -9786,18 +10155,18 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
table->in_use= thd; /* field->reset() may access table->in_use */
{
/* Set up field pointers */
- byte *null_pos= table->record[0];
- byte *field_pos= null_pos + share->null_bytes;
+ uchar *null_pos= table->record[0];
+ uchar *field_pos= null_pos + share->null_bytes;
uint null_bit= 1;
for (field= table->field; *field; ++field)
{
Field *cur_field= *field;
if ((cur_field->flags & NOT_NULL_FLAG))
- cur_field->move_field((char*) field_pos);
+ cur_field->move_field(field_pos);
else
{
- cur_field->move_field((char*) field_pos, (uchar*) null_pos, null_bit);
+ cur_field->move_field(field_pos, (uchar*) null_pos, null_bit);
null_bit<<= 1;
if (null_bit == (1 << 8))
{
@@ -9866,7 +10235,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
uniquedef.null_are_equal=1;
/* Create extra column for hash value */
- bzero((byte*) param->recinfo,sizeof(*param->recinfo));
+ bzero((uchar*) param->recinfo,sizeof(*param->recinfo));
param->recinfo->type= FIELD_CHECK;
param->recinfo->length=MI_UNIQUE_HASH_LENGTH;
param->recinfo++;
@@ -9936,8 +10305,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
table->db_stat=0;
goto err;
}
- statistic_increment(table->in_use->status_var.created_tmp_disk_tables,
- &LOCK_status);
+ status_var_increment(table->in_use->status_var.created_tmp_disk_tables);
share->db_record_offset= 1;
DBUG_RETURN(0);
err:
@@ -9973,6 +10341,8 @@ free_tmp_table(THD *thd, TABLE *entry)
if (entry->temp_pool_slot != MY_BIT_NONE)
bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot);
+ plugin_unlock(0, entry->s->db_plugin);
+
free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
thd->proc_info=save_proc_info;
@@ -9992,7 +10362,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int write_err;
DBUG_ENTER("create_myisam_from_heap");
- if (table->s->db_type != heap_hton ||
+ if (table->s->db_type() != heap_hton ||
error != HA_ERR_RECORD_FILE_FULL)
{
table->file->print_error(error,MYF(0));
@@ -10001,9 +10371,9 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table= *table;
share= *table->s;
new_table.s= &share;
- new_table.s->db_type= myisam_hton;
+ new_table.s->db_plugin= ha_lock_engine(thd, myisam_hton);
if (!(new_table.file= get_new_handler(&share, &new_table.mem_root,
- myisam_hton)))
+ new_table.s->db_type())))
DBUG_RETURN(1); // End of memory
save_proc_info=thd->proc_info;
@@ -10061,9 +10431,12 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
(void) table->file->delete_table(table->s->table_name.str);
delete table->file;
table->file=0;
+ plugin_unlock(0, table->s->db_plugin);
+ share.db_plugin= my_plugin_lock(0, &share.db_plugin);
new_table.s= table->s; // Keep old share
*table= new_table;
*table->s= share;
+
table->file->change_table_ptr(table, table->s);
table->use_all_columns();
if (save_proc_info)
@@ -10218,7 +10591,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
else
{
DBUG_ASSERT(join->tables);
- DBUG_ASSERT(join_tab);
error= sub_select(join,join_tab,0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
@@ -10488,7 +10860,6 @@ static enum_nested_loop_state
evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
int error, my_bool *report_error)
{
- bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize;
bool not_used_in_distinct=join_tab->not_used_in_distinct;
ha_rows found_records=join->found_records;
COND *select_cond= join_tab->select_cond;
@@ -10525,6 +10896,8 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
first_unmatched->found= 1;
for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
+ if (tab->table->reginfo.not_exists_optimize)
+ return NESTED_LOOP_NO_MORE_ROWS;
/* Check all predicates that has just been activated. */
/*
Actually all predicates non-guarded by first_unmatched->found
@@ -10570,8 +10943,6 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
if (found)
{
enum enum_nested_loop_state rc;
- if (not_exists_optimize)
- return NESTED_LOOP_NO_MORE_ROWS;
/* A match from join_tab is found for the current partial join. */
rc= (*join_tab->next_select)(join, join_tab+1, 0);
if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
@@ -10597,6 +10968,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
*/
join->examined_rows++;
join->thd->row_count++;
+ join_tab->read_record.file->unlock_row();
}
return NESTED_LOOP_OK;
}
@@ -10774,7 +11146,8 @@ int safe_index_read(JOIN_TAB *tab)
TABLE *table= tab->table;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
- tab->ref.key_length, HA_READ_KEY_EXACT)))
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT)))
return report_error(table, error);
return 0;
}
@@ -10804,7 +11177,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
else
{
- if (!table->key_read && table->used_keys.is_set(tab->ref.key) &&
+ if (!table->key_read && table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread &&
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
{
@@ -10911,8 +11284,9 @@ join_read_const(JOIN_TAB *tab)
else
{
error=table->file->index_read_idx(table->record[0],tab->ref.key,
- (byte*) tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
+ (uchar*) tab->ref.key_buff,
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT);
}
if (error)
{
@@ -10955,7 +11329,8 @@ join_read_key(JOIN_TAB *tab)
}
error=table->file->index_read(table->record[0],
tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
}
@@ -10983,7 +11358,8 @@ join_read_always_key(JOIN_TAB *tab)
return -1;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT)))
+ make_prev_keypart_map(tab->ref.key_parts),
+ HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@@ -11009,8 +11385,7 @@ join_read_last_key(JOIN_TAB *tab)
if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref))
return -1;
if ((error=table->file->index_read_last(table->record[0],
- tab->ref.key_buff,
- tab->ref.key_length)))
+ tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts))))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@@ -11080,7 +11455,9 @@ int rr_sequential(READ_RECORD *info);
int init_read_record_seq(JOIN_TAB *tab)
{
tab->read_record.read_record= rr_sequential;
- return tab->read_record.file->ha_rnd_init(1);
+ if (tab->read_record.file->ha_rnd_init(1))
+ return 1;
+ return (*tab->read_record.read_record)(&tab->read_record);
}
static int
@@ -11109,7 +11486,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
- if (!table->key_read && table->used_keys.is_set(tab->index) &&
+ if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -11148,7 +11525,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
- if (!table->key_read && table->used_keys.is_set(tab->index) &&
+ if (!table->key_read && table->covering_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@@ -11484,7 +11861,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (item->maybe_null)
{
Field *field=item->get_tmp_table_field();
- field->ptr[-1]= (byte) (field->is_null() ? 1 : 0);
+ field->ptr[-1]= (uchar) (field->is_null() ? 1 : 0);
}
}
}
@@ -11549,7 +11926,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
group->buff[-1]= (char) group->field->is_null();
}
if (!table->file->index_read(table->record[1],
- join->tmp_table_param.group_buff,0,
+ join->tmp_table_param.group_buff, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{ /* Update old record */
restore_record(table,record[1]);
@@ -11746,7 +12123,7 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
if (field->binary() &&
field->real_type() != MYSQL_TYPE_STRING &&
field->real_type() != MYSQL_TYPE_VARCHAR &&
- (field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0))
+ (field->type() != MYSQL_TYPE_FLOAT || field->decimals() == 0))
{
return !store_val_in_field(field, right_item, CHECK_FIELD_WARN);
}
@@ -12025,7 +12402,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
/*
- Check if GROUP BY/DISTINCT can be optimized away because the set is
+ Check if GROUP BY/DISTINCT can be optimized away because the set is
already known to be distinct.
SYNOPSIS
@@ -12033,7 +12410,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
table The table to operate on.
find_func function to iterate over the list and search
for a field
-
+
DESCRIPTION
Used in removing the GROUP BY/DISTINCT of the following types of
statements:
@@ -12044,12 +12421,13 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
then <any combination of a,b,c>,{whatever} is also distinct
This function checks if all the key parts of any of the unique keys
- of the table are referenced by a list : either the select list
+ of the table are referenced by a list : either the select list
through find_field_in_item_list or GROUP BY list through
find_field_in_order_list.
- If the above holds then we can safely remove the GROUP BY/DISTINCT,
+ If the above holds and the key parts cannot contain NULLs then we
+ can safely remove the GROUP BY/DISTINCT,
as no result set can be more distinct than an unique key.
-
+
RETURN VALUE
1 found
0 not found.
@@ -12072,7 +12450,8 @@ list_contains_unique_index(TABLE *table,
key_part < key_part_end;
key_part++)
{
- if (!find_func(key_part->field, data))
+ if (key_part->field->maybe_null() ||
+ !find_func(key_part->field, data))
break;
}
if (key_part == key_part_end)
@@ -12170,7 +12549,7 @@ find_field_in_item_list (Field *field, void *data)
static bool
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
- bool no_changes)
+ bool no_changes, key_map *map)
{
int ref_key;
uint ref_key_parts;
@@ -12181,12 +12560,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
LINT_INIT(ref_key_parts);
/*
- Check which keys can be used to resolve ORDER BY.
- We must not try to use disabled keys.
+ Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
+ been taken into account.
*/
- usable_keys= table->s->keys_in_use;
- /* we must not consider keys that are disabled by IGNORE INDEX */
- usable_keys.intersect(table->keys_in_use_for_query);
+ usable_keys= *map;
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
@@ -12244,8 +12621,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
- if (table->used_keys.is_set(ref_key))
- usable_keys.intersect(table->used_keys);
+ if (table->covering_keys.is_set(ref_key))
+ usable_keys.intersect(table->covering_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
&usable_keys)) < MAX_KEY)
{
@@ -12352,6 +12729,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
uint nr;
key_map keys;
+ /*
+ filesort() and join cache are usually faster than reading in
+ index order and not using join cache
+ */
+ if (tab->type == JT_ALL && tab->join->tables > tab->join->const_tables + 1)
+ DBUG_RETURN(0);
/*
If not used with LIMIT, only use keys if the whole query can be
resolved with a key; This is because filesort() is usually faster than
@@ -12360,7 +12743,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if (select_limit >= table->file->stats.records)
{
keys= *table->file->keys_to_use_for_scanning();
- keys.merge(table->used_keys);
+ keys.merge(table->covering_keys);
/*
We are adding here also the index specified in FORCE INDEX clause,
@@ -12388,7 +12771,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tab->read_first_record= (flag > 0 ? join_read_first:
join_read_last);
tab->type=JT_NEXT; // Read with index_first(), index_next()
- if (table->used_keys.is_set(nr))
+ if (table->covering_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@@ -12414,6 +12797,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
filesort_limit Max number of rows that needs to be sorted
select_limit Max number of rows in final output
Used to decide if we should use index or not
+ is_order_by true if we are sorting on ORDER BY, false if GROUP BY
+ Used to decide if we should use index or not
IMPLEMENTATION
@@ -12432,9 +12817,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
- ha_rows filesort_limit, ha_rows select_limit)
+ ha_rows filesort_limit, ha_rows select_limit,
+ bool is_order_by)
{
- uint length;
+ uint length= 0;
ha_rows examined_rows;
TABLE *table;
SQL_SELECT *select;
@@ -12453,10 +12839,14 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
*/
if ((order != join->group_list ||
!(join->select_options & SELECT_BIG_RESULT)) &&
- test_if_skip_sort_order(tab,order,select_limit,0))
+ test_if_skip_sort_order(tab,order,select_limit,0,
+ is_order_by ? &table->keys_in_use_for_order_by :
+ &table->keys_in_use_for_group_by))
DBUG_RETURN(0);
+ for (ORDER *ord= join->order; ord; ord= ord->next)
+ length++;
if (!(join->sortorder=
- make_unireg_sortorder(order,&length,join->sortorder)))
+ make_unireg_sortorder(order, &length, join->sortorder)))
goto err; /* purecov: inspected */
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
@@ -12499,7 +12889,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
/* Fill schema tables with data before filesort if it's necessary */
if ((join->select_lex->options & OPTION_SCHEMA_TABLE) &&
!thd->lex->describe &&
- get_schema_tables_result(join))
+ get_schema_tables_result(join, PROCESSED_BY_CREATE_SORT_INDEX))
goto err;
if (table->s->tmp_table)
@@ -12639,7 +13029,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
free_io_cache(entry); // Safety
entry->file->info(HA_STATUS_VARIABLE);
- if (entry->s->db_type == heap_hton ||
+ if (entry->s->db_type() == heap_hton ||
(!entry->s->blob_fields &&
((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->stats.records <
thd->variables.sortbuff_size)))
@@ -12660,7 +13050,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
{
handler *file=table->file;
char *org_record,*new_record;
- byte *record;
+ uchar *record;
int error;
ulong reclength= table->s->reclength-offset;
DBUG_ENTER("remove_dup_with_compare");
@@ -12751,7 +13141,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
ulong key_length,
Item *having)
{
- byte *key_buffer, *key_pos, *record=table->record[0];
+ uchar *key_buffer, *key_pos, *record=table->record[0];
int error;
handler *file= table->file;
ulong extra_length= ALIGN_SIZE(key_length)-key_length;
@@ -12795,7 +13185,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
key_pos=key_buffer;
for (;;)
{
- byte *org_key_pos;
+ uchar *org_key_pos;
if (thd->killed)
{
thd->send_kill_message();
@@ -12822,7 +13212,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
field_length=field_lengths;
for (Field **ptr= first_field ; *ptr ; ptr++)
{
- (*ptr)->sort_string((char*) key_pos,*field_length);
+ (*ptr)->sort_string(key_pos,*field_length);
key_pos+= *field_length++;
}
/* Check if it exists before */
@@ -12864,22 +13254,24 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
for (ORDER *tmp = order; tmp; tmp=tmp->next)
count++;
if (!sortorder)
- sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
- pos=sort=sortorder;
+ sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD) *
+ (max(count, *length) + 1));
+ pos= sort= sortorder;
+
if (!pos)
return 0;
for (;order;order=order->next,pos++)
{
- pos->field=0; pos->item=0;
- if (order->item[0]->type() == Item::FIELD_ITEM)
- pos->field= ((Item_field*) (*order->item))->field;
- else if (order->item[0]->type() == Item::SUM_FUNC_ITEM &&
- !order->item[0]->const_item())
- pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field();
- else if (order->item[0]->type() == Item::COPY_STR_ITEM)
+ Item *item= order->item[0]->real_item();
+ pos->field= 0; pos->item= 0;
+ if (item->type() == Item::FIELD_ITEM)
+ pos->field= ((Item_field*) item)->field;
+ else if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
+ pos->field= ((Item_sum*) item)->get_tmp_table_field();
+ else if (item->type() == Item::COPY_STR_ITEM)
{ // Blob patch
- pos->item= ((Item_copy_string*) (*order->item))->item;
+ pos->item= ((Item_copy_string*) item)->item;
}
else
pos->item= *order->item;
@@ -12923,7 +13315,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
sizeof(CACHE_FIELD*))))
{
- my_free((gptr) cache->buff,MYF(0)); /* purecov: inspected */
+ my_free((uchar*) cache->buff,MYF(0)); /* purecov: inspected */
cache->buff=0; /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -12956,7 +13348,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
/* Copy null bits from table */
if (null_fields && tables[i].table->s->null_fields)
{ /* must copy null bits */
- copy->str=(char*) tables[i].table->null_flags;
+ copy->str= tables[i].table->null_flags;
copy->length= tables[i].table->s->null_bytes;
copy->strip=0;
copy->blob_field=0;
@@ -12967,7 +13359,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
/* If outer join table, copy null_row flag */
if (tables[i].table->maybe_null)
{
- copy->str= (char*) &tables[i].table->null_row;
+ copy->str= (uchar*) &tables[i].table->null_row;
copy->length=sizeof(tables[i].table->null_row);
copy->strip=0;
copy->blob_field=0;
@@ -13030,13 +13422,13 @@ store_record_in_cache(JOIN_CACHE *cache)
{
if (last_record)
{
- copy->blob_field->get_image((char*) pos,copy->length+sizeof(char*),
+ copy->blob_field->get_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
- copy->blob_field->get_image((char*) pos,copy->length, // blob length
+ copy->blob_field->get_image(pos, copy->length, // blob length
copy->blob_field->charset());
memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
pos+=copy->length+copy->blob_length;
@@ -13046,7 +13438,7 @@ store_record_in_cache(JOIN_CACHE *cache)
{
if (copy->strip)
{
- char *str,*end;
+ uchar *str,*end;
for (str=copy->str,end= str+copy->length;
end > str && end[-1] == ' ' ;
end--) ;
@@ -13102,13 +13494,13 @@ read_cached_record(JOIN_TAB *tab)
{
if (last_record)
{
- copy->blob_field->set_image((char*) pos,copy->length+sizeof(char*),
+ copy->blob_field->set_image(pos, copy->length+sizeof(char*),
copy->blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
- copy->blob_field->set_ptr((char*) pos,(char*) pos+copy->length);
+ copy->blob_field->set_ptr(pos, pos+copy->length);
pos+=copy->length+copy->blob_field->get_length();
}
}
@@ -13219,7 +13611,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **select_item; /* The corresponding item from the SELECT clause. */
Field *from_field; /* The corresponding field from the FROM clause. */
uint counter;
- bool unaliased;
+ enum_resolution_type resolution;
/*
Local SP variables may be int but are expressions, not positions.
@@ -13242,7 +13634,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
select_item= find_item_in_list(order_item, fields, &counter,
- REPORT_EXCEPT_NOT_FOUND, &unaliased);
+ REPORT_EXCEPT_NOT_FOUND, &resolution);
if (!select_item)
return TRUE; /* The item is not unique, or some other error occured. */
@@ -13256,7 +13648,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
original field name, we should additionaly check if we have conflict
for this name (in case if we would perform lookup in all tables).
*/
- if (unaliased && !order_item->fixed &&
+ if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed &&
order_item->fix_fields(thd, order->item))
return TRUE;
@@ -13326,16 +13718,11 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
*/
- thd->lex->current_select->is_item_list_lookup= 1;
if (!order_item->fixed &&
(order_item->fix_fields(thd, order->item) ||
(order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
- {
- thd->lex->current_select->is_item_list_lookup= 0;
return TRUE; /* Wrong field. */
- }
- thd->lex->current_select->is_item_list_lookup= 0;
uint el= all_fields.elements;
all_fields.push_front(order_item); /* Add new field to field list. */
@@ -13393,49 +13780,83 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
bool *hidden_group_fields)
{
*hidden_group_fields=0;
+ ORDER *ord;
+
if (!order)
return 0; /* Everything is ok */
- if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
- {
- Item *item;
- List_iterator<Item> li(fields);
- while ((item=li++))
- item->marker=0; /* Marker that field is not used */
- }
uint org_fields=all_fields.elements;
thd->where="group statement";
- for (; order; order=order->next)
+ for (ord= order; ord; ord= ord->next)
{
- if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
+ if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
all_fields, TRUE))
return 1;
- (*order->item)->marker=1; /* Mark found */
- if ((*order->item)->with_sum_func)
+ (*ord->item)->marker= UNDEF_POS; /* Mark found */
+ if ((*ord->item)->with_sum_func)
{
- my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*order->item)->full_name());
+ my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
return 1;
}
}
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
{
- /* Don't allow one to use fields that is not used in GROUP BY */
+ /*
+ Don't allow one to use fields that is not used in GROUP BY
+ For each select a list of field references that aren't under an
+ aggregate function is created. Each field in this list keeps the
+ position of the select list expression which it belongs to.
+
+ First we check an expression from the select list against the GROUP BY
+ list. If it's found there then it's ok. It's also ok if this expression
+ is a constant or an aggregate function. Otherwise we scan the list
+ of non-aggregated fields and if we'll find at least one field reference
+ that belongs to this expression and doesn't occur in the GROUP BY list
+ we throw an error. If there are no fields in the created list for a
+ select list expression this means that all fields in it are used under
+ aggregate functions.
+ */
Item *item;
+ Item_field *field;
+ int cur_pos_in_select_list= 0;
List_iterator<Item> li(fields);
+ List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields);
- while ((item=li++))
+ field= naf_it++;
+ while (field && (item=li++))
{
- if (item->type() != Item::SUM_FUNC_ITEM && !item->marker &&
- !item->const_item())
+ if (item->type() != Item::SUM_FUNC_ITEM && item->marker >= 0 &&
+ !item->const_item() &&
+ !(item->real_item()->type() == Item::FIELD_ITEM &&
+ item->used_tables() & OUTER_REF_TABLE_BIT))
{
- /*
- TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
- ER_NON_GROUPING_FIELD_USED
- */
- my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), item->full_name());
- return 1;
+ while (field)
+ {
+ /* Skip fields from previous expressions. */
+ if (field->marker < cur_pos_in_select_list)
+ goto next_field;
+ /* Found a field from the next expression. */
+ if (field->marker > cur_pos_in_select_list)
+ break;
+ /*
+ Check whether the field occur in the GROUP BY list.
+ Throw the error later if the field isn't found.
+ */
+ for (ord= order; ord; ord= ord->next)
+ if ((*ord->item)->eq((Item*)field, 0))
+ goto next_field;
+ /*
+ TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
+ ER_NON_GROUPING_FIELD_USED
+ */
+ my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), field->full_name());
+ return 1;
+next_field:
+ field= naf_it++;
+ }
}
+ cur_pos_in_select_list++;
}
}
if (org_fields != all_fields.elements)
@@ -13453,7 +13874,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
{
Item **item;
uint counter;
- bool not_used;
+ enum_resolution_type not_used;
DBUG_ENTER("setup_new_fields");
thd->mark_used_columns= MARK_COLUMNS_READ; // Not really needed, but...
@@ -13521,9 +13942,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *ord_iter;
for (ord_iter= group; ord_iter; ord_iter= ord_iter->next)
if ((*ord_iter->item)->eq(item, 1))
- break;
- if (ord_iter)
- continue;
+ goto next_item;
ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord)
@@ -13538,6 +13957,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array,
*prev=ord;
prev= &ord->next;
}
+next_item:
ref_pointer_array++;
}
*prev=0;
@@ -13561,10 +13981,10 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
param->quick_group=1;
while ((field=li++))
{
- Item::Type type=field->real_item()->type();
- if (type == Item::FIELD_ITEM)
+ Item::Type real_type= field->real_item()->type();
+ if (real_type == Item::FIELD_ITEM)
param->field_count++;
- else if (type == Item::SUM_FUNC_ITEM)
+ else if (real_type == Item::SUM_FUNC_ITEM)
{
if (! field->const_item())
{
@@ -13572,6 +13992,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
if (!sum_item->quick_group)
param->quick_group=0; // UDF SUM function
param->sum_func_count++;
+ param->func_count++;
for (uint i=0 ; i < sum_item->arg_count ; i++)
{
@@ -13661,11 +14082,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
if (field)
{
enum_field_types type;
- if ((type= field->type()) == FIELD_TYPE_BLOB)
+ if ((type= field->type()) == MYSQL_TYPE_BLOB)
key_length+=MAX_BLOB_WIDTH; // Can't be used as a key
else if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING)
key_length+= field->field_length + HA_KEY_BLOB_LENGTH;
- else if (type == FIELD_TYPE_BIT)
+ else if (type == MYSQL_TYPE_BIT)
{
/* Bit is usually stored as a longlong key for group fields */
key_length+= 8; // Big enough
@@ -13829,7 +14250,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
for (i= 0; (pos= li++); i++)
{
Field *field;
- char *tmp;
+ uchar *tmp;
Item *real_pos= pos->real_item();
if (real_pos->type() == Item::FIELD_ITEM)
{
@@ -13874,8 +14295,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
another extra byte to not get warnings from purify in
Field_string::val_int
*/
- tmp= (char*) sql_alloc(field->pack_length()+2);
- if (!tmp)
+ if (!(tmp= (uchar*) sql_alloc(field->pack_length()+2)))
goto err;
if (copy)
{
@@ -14480,7 +14900,7 @@ bool JOIN::rollup_init()
for (j=0 ; j < fields_list.elements ; j++)
rollup.fields[i].push_back(rollup.null_items[i]);
}
- List_iterator_fast<Item> it(all_fields);
+ List_iterator<Item> it(all_fields);
Item *item;
while ((item= it++))
{
@@ -14493,6 +14913,32 @@ bool JOIN::rollup_init()
{
item->maybe_null= 1;
found_in_group= 1;
+ if (item->const_item())
+ {
+ /*
+ For ROLLUP queries each constant item referenced in GROUP BY list
+ is wrapped up into an Item_func object yielding the same value
+ as the constant item. The objects of the wrapper class are never
+ considered as constant items and besides they inherit all
+ properties of the Item_result_field class.
+ This wrapping allows us to ensure writing constant items
+ into temporary tables whenever the result of the ROLLUP
+ operation has to be written into a temporary table, e.g. when
+ ROLLUP is used together with DISTINCT in the SELECT list.
+ Usually when creating temporary tables for a intermidiate
+ result we do not include fields for constant expressions.
+ */
+ Item* new_item= new Item_func_rollup_const(item);
+ if (!new_item)
+ return 1;
+ new_item->fix_fields(thd, (Item **) 0);
+ thd->change_item_tree(it.ref(), new_item);
+ for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next)
+ {
+ if (*tmp->item == item)
+ thd->change_item_tree(tmp->item, new_item);
+ }
+ }
}
}
if (item->type() == Item::FUNC_ITEM && !found_in_group)
@@ -14702,7 +15148,7 @@ int JOIN::rollup_send_data(uint idx)
1 if write_data_failed()
*/
-int JOIN::rollup_write_data(uint idx, TABLE *table)
+int JOIN::rollup_write_data(uint idx, TABLE *table_arg)
{
uint i;
for (i= send_group_parts ; i-- > idx ; )
@@ -14713,7 +15159,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table)
ref_pointer_array_size);
if ((!having || having->val_int()))
{
- int error;
+ int write_error;
Item *item;
List_iterator_fast<Item> it(rollup.fields[i]);
while ((item= it++))
@@ -14722,10 +15168,10 @@ int JOIN::rollup_write_data(uint idx, TABLE *table)
item->save_in_result_field(1);
}
copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
- if ((error= table->file->write_row(table->record[0])))
+ if ((write_error= table_arg->file->write_row(table_arg->record[0])))
{
- if (create_myisam_from_heap(thd, table, &tmp_table_param,
- error, 0))
+ if (create_myisam_from_heap(thd, table_arg, &tmp_table_param,
+ write_error, 0))
return 1;
}
}
@@ -14921,9 +15367,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
else
{
- TABLE_LIST *tab=table->pos_in_table_list;
- item_list.push_back(new Item_string(tab->alias,
- strlen(tab->alias),
+ TABLE_LIST *real_table= table->pos_in_table_list;
+ item_list.push_back(new Item_string(real_table->alias,
+ strlen(real_table->alias),
cs));
}
/* "partitions" column */
@@ -15028,7 +15474,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
examined_rows=(ha_rows)join->best_positions[i].records_read;
item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows,
- 21));
+ MY_INT64_NUM_DECIMAL_DIGITS));
/* Add "filtered" field to item_list. */
if (join->thd->lex->describe & DESCRIBE_EXTENDED)
@@ -15036,7 +15482,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Item_float *filtered;
float f;
if (examined_rows)
- f= 100.0 * join->best_positions[i].records_read / examined_rows;
+ f= (float) (100.0 * join->best_positions[i].records_read /
+ examined_rows);
else
f= 0.0;
item_list.push_back((filtered= new Item_float(f)));
@@ -15047,7 +15494,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* Build "Extra" field and add it to item_list. */
my_bool key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
- table->used_keys.is_set(tab->index))
+ table->covering_keys.is_set(tab->index))
key_read=1;
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT &&
!((QUICK_ROR_INTERSECT_SELECT*)tab->select->quick)->need_to_fetch_row)
@@ -15055,6 +15502,24 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (tab->info)
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
+ else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
+ {
+ if (tab->packed_info & TAB_INFO_USING_INDEX)
+ extra.append(STRING_WITH_LEN("; Using index"));
+ if (tab->packed_info & TAB_INFO_USING_WHERE)
+ extra.append(STRING_WITH_LEN("; Using where"));
+ if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
+ extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
+ /* Skip initial "; "*/
+ const char *str= extra.ptr();
+ uint32 len= extra.length();
+ if (len)
+ {
+ str += 2;
+ len -= 2;
+ }
+ item_list.push_back(new Item_string(str, len, cs));
+ }
else
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
@@ -15113,6 +15578,17 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
if (distinct & test_all_bits(used_tables,thd->used_tables))
extra.append(STRING_WITH_LEN("; Distinct"));
+
+ for (uint part= 0; part < tab->ref.key_parts; part++)
+ {
+ if (tab->ref.cond_guards[part])
+ {
+ extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
+ break;
+ }
+ }
+ if (i > 0 && tab[-1].next_select == sub_select_cache)
+ extra.append(STRING_WITH_LEN("; Using join buffer"));
/* Skip initial "; "*/
const char *str= extra.ptr();
@@ -15169,7 +15645,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
"UNION")));
sl->options|= SELECT_DESCRIBE;
}
- if (first->next_select())
+ if (unit->is_union())
{
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
@@ -15385,10 +15861,13 @@ void st_select_lex::print(THD *thd, String *str)
Item *cur_where= where;
if (join)
cur_where= join->conds;
- if (cur_where)
+ if (cur_where || cond_value != Item::COND_UNDEF)
{
str->append(STRING_WITH_LEN(" where "));
- cur_where->print(str);
+ if (cur_where)
+ cur_where->print(str);
+ else
+ str->append(cond_value != Item::COND_FALSE ? "1" : "0");
}
// group by & olap
@@ -15414,10 +15893,13 @@ void st_select_lex::print(THD *thd, String *str)
if (join)
cur_having= join->having;
- if (cur_having)
+ if (cur_having || having_value != Item::COND_UNDEF)
{
str->append(STRING_WITH_LEN(" having "));
- cur_having->print(str);
+ if (cur_having)
+ cur_having->print(str);
+ else
+ str->append(having_value != Item::COND_FALSE ? "1" : "0");
}
if (order_list.elements)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 323df568271..290a0f5d992 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,8 +35,17 @@ typedef struct keyuse_t {
satisfied if val has NULL 'value'.
*/
bool null_rejecting;
- /* TRUE<=> This ref access is an outer subquery reference access */
- bool outer_ref;
+ /*
+ !NULL - This KEYUSE was created from an equality that was wrapped into
+ an Item_func_trig_cond. This means the equality (and validity of
+ this KEYUSE element) can be turned on and off. The on/off state
+ is indicted by the pointed value:
+ *cond_guard == TRUE <=> equality condition is on
+ *cond_guard == FALSE <=> equality condition is off
+
+ NULL - Otherwise (the source equality can't be turned off)
+ */
+ bool *cond_guard;
} KEYUSE;
class store_key;
@@ -48,10 +56,22 @@ typedef struct st_table_ref
uint key_parts; // num of ...
uint key_length; // length of key_buff
int key; // key no
- byte *key_buff; // value to look for with key
- byte *key_buff2; // key_buff+key_length
+ uchar *key_buff; // value to look for with key
+ uchar *key_buff2; // key_buff+key_length
store_key **key_copy; //
Item **items; // val()'s for each keypart
+ /*
+ Array of pointers to trigger variables. Some/all of the pointers may be
+ NULL. The ref access can be used iff
+
+ for each used key part i, (!cond_guards[i] || *cond_guards[i])
+
+ This array is used by subquery code. The subquery code may inject
+ triggered conditions, i.e. conditions that can be 'switched off'. A ref
+ access created from such condition is not valid when at least one of the
+ underlying conditions is switched off (see subquery code for more details)
+ */
+ bool **cond_guards;
/*
(null_rejecting & (1<<i)) means the condition is '=' and no matching
rows will be produced if items[i] IS NULL (see add_not_null_conds())
@@ -59,7 +79,7 @@ typedef struct st_table_ref
key_part_map null_rejecting;
table_map depend_map; // Table depends on these tables.
/* null byte position in the key_buf. Used for REF_OR_NULL optimization */
- byte *null_ref_key;
+ uchar *null_ref_key;
} TABLE_REF;
@@ -69,8 +89,8 @@ typedef struct st_table_ref
*/
typedef struct st_cache_field {
- char *str;
- uint length,blob_length;
+ uchar *str;
+ uint length, blob_length;
Field_blob *blob_field;
bool strip;
} CACHE_FIELD;
@@ -100,6 +120,13 @@ enum enum_nested_loop_state
NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4
};
+
+/* Values for JOIN_TAB::packed_info */
+#define TAB_INFO_HAVE_VALUE 1
+#define TAB_INFO_USING_INDEX 2
+#define TAB_INFO_USING_WHERE 4
+#define TAB_INFO_FULL_SCAN_ON_NULL 8
+
typedef enum_nested_loop_state
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
typedef int (*Read_record_func)(struct st_join_table *tab);
@@ -121,10 +148,25 @@ typedef struct st_join_table {
st_join_table *last_inner; /* last table table for embedding outer join */
st_join_table *first_upper; /* first inner table for embedding outer join */
st_join_table *first_unmatched; /* used for optimization purposes only */
+
+ /* Special content for EXPLAIN 'Extra' column or NULL if none */
const char *info;
+ /*
+ Bitmap of TAB_INFO_* bits that encodes special line for EXPLAIN 'Extra'
+ column, or 0 if there is no info.
+ */
+ uint packed_info;
+
Read_record_func read_first_record;
Next_select_func next_select;
READ_RECORD read_record;
+ /*
+ Currently the following two fields are used only for a [NOT] IN subquery
+ if it is executed by an alternative full table scan when the left operand of
+ the subquery predicate is evaluated to NULL.
+ */
+ Read_record_func save_read_first_record;/* to save read_first_record */
+ int (*save_read_record) (READ_RECORD *);/* to save read_record.read_record */
double worst_seeks;
key_map const_keys; /* Keys with constant part */
key_map checked_keys; /* Keys checked in find_best */
@@ -157,7 +199,7 @@ typedef struct st_join_table {
JOIN *join;
/* Bitmap of nested joins this table is part of */
nested_join_map embedding_map;
-
+
void cleanup();
inline bool is_using_loose_index_scan()
{
@@ -296,7 +338,7 @@ public:
bool need_tmp, hidden_group_fields;
DYNAMIC_ARRAY keyuse;
- Item::cond_result cond_value;
+ Item::cond_result cond_value, having_value;
List<Item> all_fields; // to store all fields that used in query
//Above list changed to use temporary table
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
@@ -426,7 +468,7 @@ public:
Item_sum ***func);
int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
- bool test_in_subselect(Item **where);
+ void remove_subq_pushed_predicates(Item **where);
/*
Release memory and, if possible, the open tables held by this execution
plan (and nested plans). It's used to release some tables before
@@ -438,6 +480,7 @@ public:
void cleanup(bool full);
void clear();
bool save_join_tab();
+ bool init_save_join_tab();
bool send_row_on_empty_set()
{
return (do_send_rows && tmp_table_param.sum_func_count != 0 &&
@@ -492,31 +535,54 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
class store_key :public Sql_alloc
{
- protected:
- Field *to_field; // Store data here
- char *null_ptr;
- char err;
public:
bool null_key; /* TRUE <=> the value of the key has a null part */
enum store_key_result { STORE_KEY_OK, STORE_KEY_FATAL, STORE_KEY_CONV };
- store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
- :null_ptr(null), err(0), null_key(0)
+ store_key(THD *thd, Field *field_arg, uchar *ptr, uchar *null, uint length)
+ :null_key(0), null_ptr(null), err(0)
{
- if (field_arg->type() == FIELD_TYPE_BLOB)
+ if (field_arg->type() == MYSQL_TYPE_BLOB)
{
/* Key segments are always packed with a 2 byte length prefix */
- to_field= new Field_varstring(ptr, length, 2, (uchar*) null, 1,
+ to_field= new Field_varstring(ptr, length, 2, null, 1,
Field::NONE, field_arg->field_name,
field_arg->table->s, field_arg->charset());
to_field->init(field_arg->table);
}
else
to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
- ptr, (uchar*) null, 1);
+ ptr, null, 1);
}
virtual ~store_key() {} /* Not actually needed */
- virtual enum store_key_result copy()=0;
virtual const char *name() const=0;
+
+ /**
+ @brief sets ignore truncation warnings mode and calls the real copy method
+
+ @details this function makes sure truncation warnings when preparing the
+ key buffers don't end up as errors (because of an enclosing INSERT/UPDATE).
+ */
+ enum store_key_result copy()
+ {
+ enum store_key_result result;
+ enum_check_fields saved_count_cuted_fields=
+ to_field->table->in_use->count_cuted_fields;
+
+ to_field->table->in_use->count_cuted_fields= CHECK_FIELD_IGNORE;
+
+ result= copy_inner();
+
+ to_field->table->in_use->count_cuted_fields= saved_count_cuted_fields;
+
+ return result;
+ }
+
+ protected:
+ Field *to_field; // Store data here
+ uchar *null_ptr;
+ uchar err;
+
+ virtual enum store_key_result copy_inner()=0;
};
@@ -525,18 +591,22 @@ class store_key_field: public store_key
Copy_field copy_field;
const char *field_name;
public:
- store_key_field(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ store_key_field(THD *thd, Field *to_field_arg, uchar *ptr,
+ uchar *null_ptr_arg,
uint length, Field *from_field, const char *name_arg)
:store_key(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
- : NullS,length), field_name(name_arg)
+ : (uchar*) 0, length), field_name(name_arg)
{
if (to_field)
{
copy_field.set(to_field,from_field,0);
}
}
- enum store_key_result copy()
+ const char *name() const { return field_name; }
+
+ protected:
+ enum store_key_result copy_inner()
{
TABLE *table= copy_field.to_field->table;
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
@@ -546,7 +616,6 @@ class store_key_field: public store_key
null_key= to_field->is_null();
return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK;
}
- const char *name() const { return field_name; }
};
@@ -555,13 +624,16 @@ class store_key_item :public store_key
protected:
Item *item;
public:
- store_key_item(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
- uint length, Item *item_arg)
- :store_key(thd, to_field_arg,ptr,
+ store_key_item(THD *thd, Field *to_field_arg, uchar *ptr,
+ uchar *null_ptr_arg, uint length, Item *item_arg)
+ :store_key(thd, to_field_arg, ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
- &err : NullS, length), item(item_arg)
+ &err : (uchar*) 0, length), item(item_arg)
{}
- enum store_key_result copy()
+ const char *name() const { return "func"; }
+
+ protected:
+ enum store_key_result copy_inner()
{
TABLE *table= to_field->table;
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
@@ -571,7 +643,6 @@ public:
null_key= to_field->is_null() || item->null_value;
return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res);
}
- const char *name() const { return "func"; }
};
@@ -579,15 +650,18 @@ class store_key_const_item :public store_key_item
{
bool inited;
public:
- store_key_const_item(THD *thd, Field *to_field_arg, char *ptr,
- char *null_ptr_arg, uint length,
+ store_key_const_item(THD *thd, Field *to_field_arg, uchar *ptr,
+ uchar *null_ptr_arg, uint length,
Item *item_arg)
:store_key_item(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
- &err : NullS, length, item_arg), inited(0)
+ &err : (uchar*) 0, length, item_arg), inited(0)
{
}
- enum store_key_result copy()
+ const char *name() const { return "const"; }
+
+protected:
+ enum store_key_result copy_inner()
{
int res;
if (!inited)
@@ -602,7 +676,6 @@ public:
null_key= to_field->is_null() || item->null_value;
return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
}
- const char *name() const { return "const"; }
};
bool cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref);
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
new file mode 100644
index 00000000000..195e6743a72
--- /dev/null
+++ b/sql/sql_servers.cc
@@ -0,0 +1,1278 @@
+/* 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; version 2 of the License.
+
+ 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 */
+
+
+/*
+ The servers are saved in the system table "servers"
+
+ Currently, when the user performs an ALTER SERVER or a DROP SERVER
+ operation, it will cause all open tables which refer to the named
+ server connection to be flushed. This may cause some undesirable
+ behaviour with regard to currently running transactions. It is
+ expected that the DBA knows what s/he is doing when s/he performs
+ the ALTER SERVER or DROP SERVER operation.
+
+ TODO:
+ It is desirable for us to implement a callback mechanism instead where
+ callbacks can be registered for specific server protocols. The callback
+ will be fired when such a server name has been created/altered/dropped
+ or when statistics are to be gathered such as how many actual connections.
+ Storage engines etc will be able to make use of the callback so that
+ currently running transactions etc will not be disrupted.
+*/
+
+#include "mysql_priv.h"
+#include "hash_filo.h"
+#include <m_ctype.h>
+#include <stdarg.h>
+#include "sp_head.h"
+#include "sp.h"
+
+/*
+ We only use 1 mutex to guard the data structures - THR_LOCK_servers.
+ Read locked when only reading data and write-locked for all other access.
+*/
+
+static HASH servers_cache;
+static MEM_ROOT mem;
+static rw_lock_t THR_LOCK_servers;
+
+static bool get_server_from_table_to_cache(TABLE *table);
+
+/* insert functions */
+static int insert_server(THD *thd, FOREIGN_SERVER *server_options);
+static int insert_server_record(TABLE *table, FOREIGN_SERVER *server);
+static int insert_server_record_into_cache(FOREIGN_SERVER *server);
+static void prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
+ FOREIGN_SERVER *server);
+/* drop functions */
+static int delete_server_record(TABLE *table,
+ char *server_name,
+ int server_name_length);
+static int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options);
+
+/* update functions */
+static void prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
+ FOREIGN_SERVER *existing,
+ FOREIGN_SERVER *altered);
+static int update_server(THD *thd, FOREIGN_SERVER *existing,
+ FOREIGN_SERVER *altered);
+static int update_server_record(TABLE *table, FOREIGN_SERVER *server);
+static int update_server_record_in_cache(FOREIGN_SERVER *existing,
+ FOREIGN_SERVER *altered);
+/* utility functions */
+static void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to);
+
+
+
+static uchar *servers_cache_get_key(FOREIGN_SERVER *server, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ DBUG_ENTER("servers_cache_get_key");
+ DBUG_PRINT("info", ("server_name_length %d server_name %s",
+ server->server_name_length,
+ server->server_name));
+
+ *length= (uint) server->server_name_length;
+ DBUG_RETURN((uchar*) server->server_name);
+}
+
+
+/*
+ Initialize structures responsible for servers used in federated
+ server scheme information for them from the server
+ table in the 'mysql' database.
+
+ SYNOPSIS
+ servers_init()
+ dont_read_server_table TRUE if we want to skip loading data from
+ server table and disable privilege checking.
+
+ NOTES
+ This function is mostly responsible for preparatory steps, main work
+ on initialization and grants loading is done in servers_reload().
+
+ RETURN VALUES
+ 0 ok
+ 1 Could not initialize servers
+*/
+
+bool servers_init(bool dont_read_servers_table)
+{
+ THD *thd;
+ bool return_val= FALSE;
+ DBUG_ENTER("servers_init");
+
+ /* init the mutex */
+ if (my_rwlock_init(&THR_LOCK_servers, NULL))
+ DBUG_RETURN(TRUE);
+
+ /* initialise our servers cache */
+ if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
+ (hash_get_key) servers_cache_get_key, 0, 0))
+ {
+ return_val= TRUE; /* we failed, out of memory? */
+ goto end;
+ }
+
+ /* Initialize the mem root for data */
+ init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
+
+ if (dont_read_servers_table)
+ goto end;
+
+ /*
+ To be able to run this from boot, we allocate a temporary THD
+ */
+ if (!(thd=new THD))
+ DBUG_RETURN(TRUE);
+ thd->thread_stack= (char*) &thd;
+ thd->store_globals();
+ /*
+ It is safe to call servers_reload() since servers_* arrays and hashes which
+ will be freed there are global static objects and thus are initialized
+ by zeros at startup.
+ */
+ return_val= servers_reload(thd);
+ delete thd;
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+
+end:
+ DBUG_RETURN(return_val);
+}
+
+/*
+ Initialize server structures
+
+ SYNOPSIS
+ servers_load()
+ thd Current thread
+ tables List containing open "mysql.servers"
+
+ RETURN VALUES
+ FALSE Success
+ TRUE Error
+*/
+
+static bool servers_load(THD *thd, TABLE_LIST *tables)
+{
+ TABLE *table;
+ READ_RECORD read_record_info;
+ bool return_val= TRUE;
+ DBUG_ENTER("servers_load");
+
+ /* first, send all cached rows to sleep with the fishes, oblivion!
+ I expect this crappy comment replaced */
+ free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
+ my_hash_reset(&servers_cache);
+
+ init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0);
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ /* return_val is already TRUE, so no need to set */
+ if ((get_server_from_table_to_cache(table)))
+ goto end;
+ }
+
+ return_val= FALSE;
+
+end:
+ end_read_record(&read_record_info);
+ DBUG_RETURN(return_val);
+}
+
+
+/*
+ Forget current servers cache and read new servers
+ from the conneciton table.
+
+ SYNOPSIS
+ servers_reload()
+ thd Current thread
+
+ NOTE
+ All tables of calling thread which were open and locked by LOCK TABLES
+ statement will be unlocked and closed.
+ This function is also used for initialization of structures responsible
+ for user/db-level privilege checking.
+
+ RETURN VALUE
+ FALSE Success
+ TRUE Failure
+*/
+
+bool servers_reload(THD *thd)
+{
+ TABLE_LIST tables[1];
+ bool return_val= TRUE;
+ DBUG_ENTER("servers_reload");
+
+ if (thd->locked_tables)
+ { // Can't have locked tables here
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0;
+ close_thread_tables(thd);
+ }
+
+ DBUG_PRINT("info", ("locking servers_cache"));
+ rw_wrlock(&THR_LOCK_servers);
+
+ bzero((char*) tables, sizeof(tables));
+ tables[0].alias= tables[0].table_name= (char*) "servers";
+ tables[0].db= (char*) "mysql";
+ tables[0].lock_type= TL_READ;
+
+ if (simple_open_n_lock_tables(thd, tables))
+ {
+ sql_print_error("Can't open and lock privilege tables: %s",
+ thd->net.last_error);
+ goto end;
+ }
+
+ if ((return_val= servers_load(thd, tables)))
+ { // Error. Revert to old list
+ /* blast, for now, we have no servers, discuss later way to preserve */
+
+ DBUG_PRINT("error",("Reverting to old privileges"));
+ servers_free();
+ }
+
+end:
+ close_thread_tables(thd);
+ DBUG_PRINT("info", ("unlocking servers_cache"));
+ rw_unlock(&THR_LOCK_servers);
+ DBUG_RETURN(return_val);
+}
+
+
+/*
+ Initialize structures responsible for servers used in federated
+ server scheme information for them from the server
+ table in the 'mysql' database.
+
+ SYNOPSIS
+ get_server_from_table_to_cache()
+ TABLE *table open table pointer
+
+
+ NOTES
+ This function takes a TABLE pointer (pointing to an opened
+ table). With this open table, a FOREIGN_SERVER struct pointer
+ is allocated into root memory, then each member of the FOREIGN_SERVER
+ struct is populated. A char pointer takes the return value of get_field
+ for each column we're interested in obtaining, and if that pointer
+ isn't 0x0, the FOREIGN_SERVER member is set to that value, otherwise,
+ is set to the value of an empty string, since get_field would set it to
+ 0x0 if the column's value is empty, even if the default value for that
+ column is NOT NULL.
+
+ RETURN VALUES
+ 0 ok
+ 1 could not insert server struct into global servers cache
+*/
+
+static bool
+get_server_from_table_to_cache(TABLE *table)
+{
+ /* alloc a server struct */
+ char *ptr;
+ char *blank= (char*)"";
+ FOREIGN_SERVER *server= (FOREIGN_SERVER *)alloc_root(&mem,
+ sizeof(FOREIGN_SERVER));
+ DBUG_ENTER("get_server_from_table_to_cache");
+ table->use_all_columns();
+
+ /* get each field into the server struct ptr */
+ server->server_name= get_field(&mem, table->field[0]);
+ server->server_name_length= strlen(server->server_name);
+ ptr= get_field(&mem, table->field[1]);
+ server->host= ptr ? ptr : blank;
+ ptr= get_field(&mem, table->field[2]);
+ server->db= ptr ? ptr : blank;
+ ptr= get_field(&mem, table->field[3]);
+ server->username= ptr ? ptr : blank;
+ ptr= get_field(&mem, table->field[4]);
+ server->password= ptr ? ptr : blank;
+ ptr= get_field(&mem, table->field[5]);
+ server->sport= ptr ? ptr : blank;
+
+ server->port= server->sport ? atoi(server->sport) : 0;
+
+ ptr= get_field(&mem, table->field[6]);
+ server->socket= ptr && strlen(ptr) ? ptr : NULL;
+ ptr= get_field(&mem, table->field[7]);
+ server->scheme= ptr ? ptr : blank;
+ ptr= get_field(&mem, table->field[8]);
+ server->owner= ptr ? ptr : blank;
+ DBUG_PRINT("info", ("server->server_name %s", server->server_name));
+ DBUG_PRINT("info", ("server->host %s", server->host));
+ DBUG_PRINT("info", ("server->db %s", server->db));
+ DBUG_PRINT("info", ("server->username %s", server->username));
+ DBUG_PRINT("info", ("server->password %s", server->password));
+ DBUG_PRINT("info", ("server->socket %s", server->socket));
+ if (my_hash_insert(&servers_cache, (uchar*) server))
+ {
+ DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
+ server->server_name, (long unsigned int) server));
+ // error handling needed here
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ SYNOPSIS
+ insert_server()
+ THD *thd - thread pointer
+ FOREIGN_SERVER *server - pointer to prepared FOREIGN_SERVER struct
+
+ NOTES
+ This function takes a server object that is has all members properly
+ prepared, ready to be inserted both into the mysql.servers table and
+ the servers cache.
+
+ THR_LOCK_servers must be write locked.
+
+ RETURN VALUES
+ 0 - no error
+ other - error code
+*/
+
+static int
+insert_server(THD *thd, FOREIGN_SERVER *server)
+{
+ int error= -1;
+ TABLE_LIST tables;
+ TABLE *table;
+
+ DBUG_ENTER("insert_server");
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.alias= tables.table_name= (char*) "servers";
+
+ /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
+ if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+ goto end;
+
+ /* insert the server into the table */
+ if ((error= insert_server_record(table, server)))
+ goto end;
+
+ /* insert the server into the cache */
+ if ((error= insert_server_record_into_cache(server)))
+ goto end;
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+/*
+ SYNOPSIS
+ int insert_server_record_into_cache()
+ FOREIGN_SERVER *server
+
+ NOTES
+ This function takes a FOREIGN_SERVER pointer to an allocated (root mem)
+ and inserts it into the global servers cache
+
+ THR_LOCK_servers must be write locked.
+
+ RETURN VALUE
+ 0 - no error
+ >0 - error code
+
+*/
+
+static int
+insert_server_record_into_cache(FOREIGN_SERVER *server)
+{
+ int error=0;
+ DBUG_ENTER("insert_server_record_into_cache");
+ /*
+ We succeded in insertion of the server to the table, now insert
+ the server to the cache
+ */
+ DBUG_PRINT("info", ("inserting server %s at %lx, length %d",
+ server->server_name, (long unsigned int) server,
+ server->server_name_length));
+ if (my_hash_insert(&servers_cache, (uchar*) server))
+ {
+ DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
+ server->server_name, (long unsigned int) server));
+ // error handling needed here
+ error= 1;
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*
+ SYNOPSIS
+ store_server_fields()
+ TABLE *table
+ FOREIGN_SERVER *server
+
+ NOTES
+ This function takes an opened table object, and a pointer to an
+ allocated FOREIGN_SERVER struct, and then stores each member of
+ the FOREIGN_SERVER to the appropriate fields in the table, in
+ advance of insertion into the mysql.servers table
+
+ RETURN VALUE
+ VOID
+
+*/
+
+static void
+store_server_fields(TABLE *table, FOREIGN_SERVER *server)
+{
+
+ table->use_all_columns();
+ /*
+ "server" has already been prepped by prepare_server_struct_for_<>
+ so, all we need to do is check if the value is set (> -1 for port)
+
+ If this happens to be an update, only the server members that
+ have changed will be set. If an insert, then all will be set,
+ even if with empty strings
+ */
+ if (server->host)
+ table->field[1]->store(server->host,
+ (uint) strlen(server->host), system_charset_info);
+ if (server->db)
+ table->field[2]->store(server->db,
+ (uint) strlen(server->db), system_charset_info);
+ if (server->username)
+ table->field[3]->store(server->username,
+ (uint) strlen(server->username), system_charset_info);
+ if (server->password)
+ table->field[4]->store(server->password,
+ (uint) strlen(server->password), system_charset_info);
+ if (server->port > -1)
+ table->field[5]->store(server->port);
+
+ if (server->socket)
+ table->field[6]->store(server->socket,
+ (uint) strlen(server->socket), system_charset_info);
+ if (server->scheme)
+ table->field[7]->store(server->scheme,
+ (uint) strlen(server->scheme), system_charset_info);
+ if (server->owner)
+ table->field[8]->store(server->owner,
+ (uint) strlen(server->owner), system_charset_info);
+}
+
+/*
+ SYNOPSIS
+ insert_server_record()
+ TABLE *table
+ FOREIGN_SERVER *server
+
+ NOTES
+ This function takes the arguments of an open table object and a pointer
+ to an allocated FOREIGN_SERVER struct. It stores the server_name into
+ the first field of the table (the primary key, server_name column). With
+ this, index_read_idx is called, if the record is found, an error is set
+ to ER_FOREIGN_SERVER_EXISTS (the server with that server name exists in the
+ table), if not, then store_server_fields stores all fields of the
+ FOREIGN_SERVER to the table, then ha_write_row is inserted. If an error
+ is encountered in either index_read_idx or ha_write_row, then that error
+ is returned
+
+ RETURN VALUE
+ 0 - no errors
+ >0 - error code
+
+ */
+
+static
+int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
+{
+ int error;
+ DBUG_ENTER("insert_server_record");
+ table->use_all_columns();
+
+ empty_record(table);
+
+ /* set the field that's the PK to the value we're looking for */
+ table->field[0]->store(server->server_name,
+ server->server_name_length,
+ system_charset_info);
+
+ /* read index until record is that specified in server_name */
+ if ((error= table->file->index_read_idx(table->record[0], 0,
+ (uchar *)table->field[0]->ptr, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT)))
+ {
+ /* if not found, err */
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
+ {
+ table->file->print_error(error, MYF(0));
+ error= 1;
+ }
+ /* store each field to be inserted */
+ store_server_fields(table, server);
+
+ DBUG_PRINT("info",("record for server '%s' not found!",
+ server->server_name));
+ /* write/insert the new server */
+ if ((error=table->file->ha_write_row(table->record[0])))
+ {
+ table->file->print_error(error, MYF(0));
+ }
+ else
+ error= 0;
+ }
+ else
+ error= ER_FOREIGN_SERVER_EXISTS;
+ DBUG_RETURN(error);
+}
+
+/*
+ SYNOPSIS
+ drop_server()
+ THD *thd
+ LEX_SERVER_OPTIONS *server_options
+
+ NOTES
+ This function takes as its arguments a THD object pointer and a pointer
+ to a LEX_SERVER_OPTIONS struct from the parser. The member 'server_name'
+ of this LEX_SERVER_OPTIONS struct contains the value of the server to be
+ deleted. The mysql.servers table is opened via open_ltable, a table object
+ returned, the servers cache mutex locked, then delete_server_record is
+ called with this table object and LEX_SERVER_OPTIONS server_name and
+ server_name_length passed, containing the name of the server to be
+ dropped/deleted, then delete_server_record_in_cache is called to delete
+ the server from the servers cache.
+
+ RETURN VALUE
+ 0 - no error
+ > 0 - error code
+*/
+
+int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
+{
+ int error;
+ TABLE_LIST tables;
+ TABLE *table;
+ LEX_STRING name= { server_options->server_name,
+ server_options->server_name_length };
+
+ DBUG_ENTER("drop_server");
+ DBUG_PRINT("info", ("server name server->server_name %s",
+ server_options->server_name));
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.alias= tables.table_name= (char*) "servers";
+
+ rw_wrlock(&THR_LOCK_servers);
+
+ /* hit the memory hit first */
+ if ((error= delete_server_record_in_cache(server_options)))
+ goto end;
+
+ if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+ {
+ error= my_errno;
+ goto end;
+ }
+
+ error= delete_server_record(table, name.str, name.length);
+
+ /* close the servers table before we call closed_cached_connection_tables */
+ close_thread_tables(thd);
+
+ if (close_cached_connection_tables(thd, TRUE, &name))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR, "Server connection in use");
+ }
+
+end:
+ rw_unlock(&THR_LOCK_servers);
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ delete_server_record_in_cache()
+ LEX_SERVER_OPTIONS *server_options
+
+ NOTES
+ This function's argument is a LEX_SERVER_OPTIONS struct pointer. This
+ function uses the "server_name" and "server_name_length" members of the
+ lex->server_options to search for the server in the servers_cache. Upon
+ returned the server (pointer to a FOREIGN_SERVER struct), it then deletes
+ that server from the servers_cache hash.
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+static int
+delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
+{
+ int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
+ FOREIGN_SERVER *server;
+ DBUG_ENTER("delete_server_record_in_cache");
+
+ DBUG_PRINT("info",("trying to obtain server name %s length %d",
+ server_options->server_name,
+ server_options->server_name_length));
+
+
+ if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
+ (uchar*) server_options->server_name,
+ server_options->server_name_length)))
+ {
+ DBUG_PRINT("info", ("server_name %s length %d not found!",
+ server_options->server_name,
+ server_options->server_name_length));
+ goto end;
+ }
+ /*
+ We succeded in deletion of the server to the table, now delete
+ the server from the cache
+ */
+ DBUG_PRINT("info",("deleting server %s length %d",
+ server->server_name,
+ server->server_name_length));
+
+ VOID(hash_delete(&servers_cache, (uchar*) server));
+
+ error= 0;
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ update_server()
+ THD *thd
+ FOREIGN_SERVER *existing
+ FOREIGN_SERVER *altered
+
+ NOTES
+ This function takes as arguments a THD object pointer, and two pointers,
+ one pointing to the existing FOREIGN_SERVER struct "existing" (which is
+ the current record as it is) and another pointer pointing to the
+ FOREIGN_SERVER struct with the members containing the modified/altered
+ values that need to be updated in both the mysql.servers table and the
+ servers_cache. It opens a table, passes the table and the altered
+ FOREIGN_SERVER pointer, which will be used to update the mysql.servers
+ table for the particular server via the call to update_server_record,
+ and in the servers_cache via update_server_record_in_cache.
+
+ THR_LOCK_servers must be write locked.
+
+ RETURN VALUE
+ 0 - no error
+ >0 - error code
+
+*/
+
+int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
+{
+ int error;
+ TABLE *table;
+ TABLE_LIST tables;
+ DBUG_ENTER("update_server");
+
+ bzero((char*) &tables, sizeof(tables));
+ tables.db= (char*)"mysql";
+ tables.alias= tables.table_name= (char*)"servers";
+
+ if (!(table= open_ltable(thd, &tables, TL_WRITE)))
+ {
+ error= my_errno;
+ goto end;
+ }
+
+ if ((error= update_server_record(table, altered)))
+ goto end;
+
+ error= update_server_record_in_cache(existing, altered);
+
+ /*
+ Perform a reload so we don't have a 'hole' in our mem_root
+ */
+ servers_load(thd, &tables);
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ update_server_record_in_cache()
+ FOREIGN_SERVER *existing
+ FOREIGN_SERVER *altered
+
+ NOTES
+ This function takes as an argument the FOREIGN_SERVER structi pointer
+ for the existing server and the FOREIGN_SERVER struct populated with only
+ the members which have been updated. It then "merges" the "altered" struct
+ members to the existing server, the existing server then represents an
+ updated server. Then, the existing record is deleted from the servers_cache
+ HASH, then the updated record inserted, in essence replacing the old
+ record.
+
+ THR_LOCK_servers must be write locked.
+
+ RETURN VALUE
+ 0 - no error
+ 1 - error
+
+*/
+
+int update_server_record_in_cache(FOREIGN_SERVER *existing,
+ FOREIGN_SERVER *altered)
+{
+ int error= 0;
+ DBUG_ENTER("update_server_record_in_cache");
+
+ /*
+ update the members that haven't been change in the altered server struct
+ with the values of the existing server struct
+ */
+ merge_server_struct(existing, altered);
+
+ /*
+ delete the existing server struct from the server cache
+ */
+ VOID(hash_delete(&servers_cache, (uchar*)existing));
+
+ /*
+ Insert the altered server struct into the server cache
+ */
+ if (my_hash_insert(&servers_cache, (uchar*)altered))
+ {
+ DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
+ altered->server_name, (long unsigned int) altered));
+ error= ER_OUT_OF_RESOURCES;
+ }
+
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ merge_server_struct()
+ FOREIGN_SERVER *from
+ FOREIGN_SERVER *to
+
+ NOTES
+ This function takes as its arguments two pointers each to an allocated
+ FOREIGN_SERVER struct. The first FOREIGN_SERVER struct represents the struct
+ that we will obtain values from (hence the name "from"), the second
+ FOREIGN_SERVER struct represents which FOREIGN_SERVER struct we will be
+ "copying" any members that have a value to (hence the name "to")
+
+ RETURN VALUE
+ VOID
+
+*/
+
+void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to)
+{
+ DBUG_ENTER("merge_server_struct");
+ if (!to->host)
+ to->host= strdup_root(&mem, from->host);
+ if (!to->db)
+ to->db= strdup_root(&mem, from->db);
+ if (!to->username)
+ to->username= strdup_root(&mem, from->username);
+ if (!to->password)
+ to->password= strdup_root(&mem, from->password);
+ if (to->port == -1)
+ to->port= from->port;
+ if (!to->socket && from->socket)
+ to->socket= strdup_root(&mem, from->socket);
+ if (!to->scheme && from->scheme)
+ to->scheme= strdup_root(&mem, from->scheme);
+ if (!to->owner)
+ to->owner= strdup_root(&mem, from->owner);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+
+ SYNOPSIS
+ update_server_record()
+ TABLE *table
+ FOREIGN_SERVER *server
+
+ NOTES
+ This function takes as its arguments an open TABLE pointer, and a pointer
+ to an allocated FOREIGN_SERVER structure representing an updated record
+ which needs to be inserted. The primary key, server_name is stored to field
+ 0, then index_read_idx is called to read the index to that record, the
+ record then being ready to be updated, if found. If not found an error is
+ set and error message printed. If the record is found, store_record is
+ called, then store_server_fields stores each field from the the members of
+ the updated FOREIGN_SERVER struct.
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+
+static int
+update_server_record(TABLE *table, FOREIGN_SERVER *server)
+{
+ int error=0;
+ DBUG_ENTER("update_server_record");
+ table->use_all_columns();
+ /* set the field that's the PK to the value we're looking for */
+ table->field[0]->store(server->server_name,
+ server->server_name_length,
+ system_charset_info);
+
+ if ((error= table->file->index_read_idx(table->record[0], 0,
+ (uchar *)table->field[0]->ptr, ~(longlong)0,
+ HA_READ_KEY_EXACT)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
+ table->file->print_error(error, MYF(0));
+ DBUG_PRINT("info",("server not found!"));
+ error= ER_FOREIGN_SERVER_DOESNT_EXIST;
+ }
+ else
+ {
+ /* ok, so we can update since the record exists in the table */
+ store_record(table,record[1]);
+ store_server_fields(table, server);
+ if ((error=table->file->ha_update_row(table->record[1],table->record[0])))
+ {
+ DBUG_PRINT("info",("problems with ha_update_row %d", error));
+ goto end;
+ }
+ }
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ delete_server_record()
+ TABLE *table
+ char *server_name
+ int server_name_length
+
+ NOTES
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+static int
+delete_server_record(TABLE *table,
+ char *server_name, int server_name_length)
+{
+ int error;
+ DBUG_ENTER("delete_server_record");
+ table->use_all_columns();
+
+ /* set the field that's the PK to the value we're looking for */
+ table->field[0]->store(server_name, server_name_length, system_charset_info);
+
+ if ((error= table->file->index_read_idx(table->record[0], 0,
+ (uchar *)table->field[0]->ptr, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
+ table->file->print_error(error, MYF(0));
+ DBUG_PRINT("info",("server not found!"));
+ error= ER_FOREIGN_SERVER_DOESNT_EXIST;
+ }
+ else
+ {
+ if ((error= table->file->ha_delete_row(table->record[0])))
+ table->file->print_error(error, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+}
+
+/*
+
+ SYNOPSIS
+ create_server()
+ THD *thd
+ LEX_SERVER_OPTIONS *server_options
+
+ NOTES
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
+{
+ int error= ER_FOREIGN_SERVER_EXISTS;
+ FOREIGN_SERVER *server;
+
+ DBUG_ENTER("create_server");
+ DBUG_PRINT("info", ("server_options->server_name %s",
+ server_options->server_name));
+
+ rw_wrlock(&THR_LOCK_servers);
+
+ /* hit the memory first */
+ if (hash_search(&servers_cache, (uchar*) server_options->server_name,
+ server_options->server_name_length))
+ goto end;
+
+ server= (FOREIGN_SERVER *)alloc_root(&mem,
+ sizeof(FOREIGN_SERVER));
+
+ prepare_server_struct_for_insert(server_options, server);
+
+ error= insert_server(thd, server);
+
+ DBUG_PRINT("info", ("error returned %d", error));
+
+end:
+ rw_unlock(&THR_LOCK_servers);
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ alter_server()
+ THD *thd
+ LEX_SERVER_OPTIONS *server_options
+
+ NOTES
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
+{
+ int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
+ FOREIGN_SERVER *altered, *existing;
+ LEX_STRING name= { server_options->server_name,
+ server_options->server_name_length };
+ DBUG_ENTER("alter_server");
+ DBUG_PRINT("info", ("server_options->server_name %s",
+ server_options->server_name));
+
+ rw_wrlock(&THR_LOCK_servers);
+
+ if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache,
+ (uchar*) name.str,
+ name.length)))
+ goto end;
+
+ altered= (FOREIGN_SERVER *)alloc_root(&mem,
+ sizeof(FOREIGN_SERVER));
+
+ prepare_server_struct_for_update(server_options, existing, altered);
+
+ error= update_server(thd, existing, altered);
+
+ /* close the servers table before we call closed_cached_connection_tables */
+ close_thread_tables(thd);
+
+ if (close_cached_connection_tables(thd, FALSE, &name))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR, "Server connection in use");
+ }
+
+end:
+ DBUG_PRINT("info", ("error returned %d", error));
+ rw_unlock(&THR_LOCK_servers);
+ DBUG_RETURN(error);
+}
+
+
+/*
+
+ SYNOPSIS
+ prepare_server_struct_for_insert()
+ LEX_SERVER_OPTIONS *server_options
+ FOREIGN_SERVER *server
+
+ NOTES
+
+ RETURN VALUE
+ none
+
+*/
+
+static void
+prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
+ FOREIGN_SERVER *server)
+{
+ char *unset_ptr= (char*)"";
+ DBUG_ENTER("prepare_server_struct");
+
+ /* these two MUST be set */
+ server->server_name= strdup_root(&mem, server_options->server_name);
+ server->server_name_length= server_options->server_name_length;
+
+ server->host= server_options->host ?
+ strdup_root(&mem, server_options->host) : unset_ptr;
+
+ server->db= server_options->db ?
+ strdup_root(&mem, server_options->db) : unset_ptr;
+
+ server->username= server_options->username ?
+ strdup_root(&mem, server_options->username) : unset_ptr;
+
+ server->password= server_options->password ?
+ strdup_root(&mem, server_options->password) : unset_ptr;
+
+ /* set to 0 if not specified */
+ server->port= server_options->port > -1 ?
+ server_options->port : 0;
+
+ server->socket= server_options->socket ?
+ strdup_root(&mem, server_options->socket) : unset_ptr;
+
+ server->scheme= server_options->scheme ?
+ strdup_root(&mem, server_options->scheme) : unset_ptr;
+
+ server->owner= server_options->owner ?
+ strdup_root(&mem, server_options->owner) : unset_ptr;
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+
+ SYNOPSIS
+ prepare_server_struct_for_update()
+ LEX_SERVER_OPTIONS *server_options
+
+ NOTES
+
+ RETURN VALUE
+ 0 - no error
+
+*/
+
+static void
+prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
+ FOREIGN_SERVER *existing,
+ FOREIGN_SERVER *altered)
+{
+ DBUG_ENTER("prepare_server_struct_for_update");
+
+ altered->server_name= strdup_root(&mem, server_options->server_name);
+ altered->server_name_length= server_options->server_name_length;
+ DBUG_PRINT("info", ("existing name %s altered name %s",
+ existing->server_name, altered->server_name));
+
+ /*
+ The logic here is this: is this value set AND is it different
+ than the existing value?
+ */
+ altered->host=
+ (server_options->host && (strcmp(server_options->host, existing->host))) ?
+ strdup_root(&mem, server_options->host) : 0;
+
+ altered->db=
+ (server_options->db && (strcmp(server_options->db, existing->db))) ?
+ strdup_root(&mem, server_options->db) : 0;
+
+ altered->username=
+ (server_options->username &&
+ (strcmp(server_options->username, existing->username))) ?
+ strdup_root(&mem, server_options->username) : 0;
+
+ altered->password=
+ (server_options->password &&
+ (strcmp(server_options->password, existing->password))) ?
+ strdup_root(&mem, server_options->password) : 0;
+
+ /*
+ port is initialised to -1, so if unset, it will be -1
+ */
+ altered->port= (server_options->port > -1 &&
+ server_options->port != existing->port) ?
+ server_options->port : -1;
+
+ altered->socket=
+ (server_options->socket &&
+ (strcmp(server_options->socket, existing->socket))) ?
+ strdup_root(&mem, server_options->socket) : 0;
+
+ altered->scheme=
+ (server_options->scheme &&
+ (strcmp(server_options->scheme, existing->scheme))) ?
+ strdup_root(&mem, server_options->scheme) : 0;
+
+ altered->owner=
+ (server_options->owner &&
+ (strcmp(server_options->owner, existing->owner))) ?
+ strdup_root(&mem, server_options->owner) : 0;
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+
+ SYNOPSIS
+ servers_free()
+ bool end
+
+ NOTES
+
+ RETURN VALUE
+ void
+
+*/
+
+void servers_free(bool end)
+{
+ DBUG_ENTER("servers_free");
+ if (!hash_inited(&servers_cache))
+ DBUG_VOID_RETURN;
+ if (!end)
+ {
+ free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
+ my_hash_reset(&servers_cache);
+ DBUG_VOID_RETURN;
+ }
+ rwlock_destroy(&THR_LOCK_servers);
+ free_root(&mem,MYF(0));
+ hash_free(&servers_cache);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ SYNOPSIS
+
+ clone_server(MEM_ROOT *mem_root, FOREIGN_SERVER *orig, FOREIGN_SERVER *buff)
+
+ Create a clone of FOREIGN_SERVER. If the supplied mem_root is of
+ thd->mem_root then the copy is automatically disposed at end of statement.
+
+ NOTES
+
+ ARGS
+ MEM_ROOT pointer (strings are copied into this mem root)
+ FOREIGN_SERVER pointer (made a copy of)
+ FOREIGN_SERVER buffer (if not-NULL, this pointer is returned)
+
+ RETURN VALUE
+ FOREIGN_SEVER pointer (copy of one supplied FOREIGN_SERVER)
+*/
+
+static FOREIGN_SERVER *clone_server(MEM_ROOT *mem, const FOREIGN_SERVER *server,
+ FOREIGN_SERVER *buffer)
+{
+ DBUG_ENTER("sql_server.cc:clone_server");
+
+ if (!buffer)
+ buffer= (FOREIGN_SERVER *) alloc_root(mem, sizeof(FOREIGN_SERVER));
+
+ buffer->server_name= strmake_root(mem, server->server_name,
+ server->server_name_length);
+ buffer->port= server->port;
+ buffer->server_name_length= server->server_name_length;
+
+ /* TODO: We need to examine which of these can really be NULL */
+ buffer->db= server->db ? strdup_root(mem, server->db) : NULL;
+ buffer->scheme= server->scheme ? strdup_root(mem, server->scheme) : NULL;
+ buffer->username= server->username? strdup_root(mem, server->username): NULL;
+ buffer->password= server->password? strdup_root(mem, server->password): NULL;
+ buffer->socket= server->socket ? strdup_root(mem, server->socket) : NULL;
+ buffer->owner= server->owner ? strdup_root(mem, server->owner) : NULL;
+ buffer->host= server->host ? strdup_root(mem, server->host) : NULL;
+
+ DBUG_RETURN(buffer);
+}
+
+
+/*
+
+ SYNOPSIS
+ get_server_by_name()
+ const char *server_name
+
+ NOTES
+
+ RETURN VALUE
+ FOREIGN_SERVER *
+
+*/
+
+FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
+ FOREIGN_SERVER *buff)
+{
+ uint server_name_length;
+ FOREIGN_SERVER *server;
+ DBUG_ENTER("get_server_by_name");
+ DBUG_PRINT("info", ("server_name %s", server_name));
+
+ server_name_length= strlen(server_name);
+
+ if (! server_name || !strlen(server_name))
+ {
+ DBUG_PRINT("info", ("server_name not defined!"));
+ DBUG_RETURN((FOREIGN_SERVER *)NULL);
+ }
+
+ DBUG_PRINT("info", ("locking servers_cache"));
+ rw_rdlock(&THR_LOCK_servers);
+ if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
+ (uchar*) server_name,
+ server_name_length)))
+ {
+ DBUG_PRINT("info", ("server_name %s length %d not found!",
+ server_name, server_name_length));
+ server= (FOREIGN_SERVER *) NULL;
+ }
+ /* otherwise, make copy of server */
+ else
+ server= clone_server(mem, server, buff);
+
+ DBUG_PRINT("info", ("unlocking servers_cache"));
+ rw_unlock(&THR_LOCK_servers);
+ DBUG_RETURN(server);
+
+}
diff --git a/sql/sql_servers.h b/sql/sql_servers.h
new file mode 100644
index 00000000000..63c691893d1
--- /dev/null
+++ b/sql/sql_servers.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2006 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; version 2 of the License.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "slave.h" // for tables_ok(), rpl_filter
+
+/* structs */
+typedef struct st_federated_server
+{
+ char *server_name;
+ long port;
+ uint server_name_length;
+ char *db, *scheme, *username, *password, *socket, *owner, *host, *sport;
+} FOREIGN_SERVER;
+
+/* cache handlers */
+bool servers_init(bool dont_read_server_table);
+bool servers_reload(THD *thd);
+void servers_free(bool end=0);
+
+/* insert functions */
+int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options);
+
+/* drop functions */
+int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options);
+
+/* update functions */
+int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options);
+
+/* lookup functions */
+FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
+ FOREIGN_SERVER *server_buffer);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 0ebccba43ca..9aa444aa4c0 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,13 +32,13 @@
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
-
enum enum_i_s_events_fields
{
ISE_EVENT_CATALOG= 0,
ISE_EVENT_SCHEMA,
ISE_EVENT_NAME,
ISE_DEFINER,
+ ISE_TIME_ZONE,
ISE_EVENT_BODY,
ISE_EVENT_DEFINITION,
ISE_EVENT_TYPE,
@@ -54,15 +53,16 @@ enum enum_i_s_events_fields
ISE_CREATED,
ISE_LAST_ALTERED,
ISE_LAST_EXECUTED,
- ISE_EVENT_COMMENT
+ ISE_EVENT_COMMENT,
+ ISE_ORIGINATOR
};
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
static const char *grant_names[]={
"select","insert","update","delete","create","drop","reload","shutdown",
"process","file","grant","references","index","alter"};
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **),
"grant_types",
grant_names, NULL};
@@ -79,24 +79,24 @@ append_algorithm(TABLE_LIST *table, String *buff);
** List all table types supported
***************************************************************************/
-static my_bool show_handlerton(THD *thd, st_plugin_int *plugin,
+static my_bool show_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
handlerton *default_type= (handlerton *) arg;
Protocol *protocol= thd->protocol;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if (!(hton->flags & HTON_HIDDEN))
{
protocol->prepare_for_resend();
- protocol->store(plugin->name.str, plugin->name.length,
+ protocol->store(plugin_name(plugin)->str, plugin_name(plugin)->length,
system_charset_info);
const char *option_name= show_comp_option_name[(int) hton->state];
if (hton->state == SHOW_OPTION_YES && default_type == hton)
option_name= "DEFAULT";
protocol->store(option_name, system_charset_info);
- protocol->store(plugin->plugin->descr, system_charset_info);
+ protocol->store(plugin_decl(plugin)->descr, system_charset_info);
protocol->store(hton->commit ? "YES" : "NO", system_charset_info);
protocol->store(hton->prepare ? "YES" : "NO", system_charset_info);
protocol->store(hton->savepoint_set ? "YES" : "NO", system_charset_info);
@@ -124,7 +124,7 @@ bool mysqld_show_storage_engines(THD *thd)
DBUG_RETURN(TRUE);
if (plugin_foreach(thd, show_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN, thd->variables.table_type))
+ MYSQL_STORAGE_ENGINE_PLUGIN, ha_default_handlerton(thd)))
DBUG_RETURN(TRUE);
send_eof(thd);
@@ -136,26 +136,26 @@ static int make_version_string(char *buf, int buf_length, uint version)
return my_snprintf(buf, buf_length, "%d.%d", version>>8,version&0xff);
}
-static my_bool show_plugins(THD *thd, st_plugin_int *plugin,
+static my_bool show_plugins(THD *thd, plugin_ref plugin,
void *arg)
{
TABLE *table= (TABLE*) arg;
- struct st_mysql_plugin *plug= plugin->plugin;
- Protocol *protocol= thd->protocol;
+ struct st_mysql_plugin *plug= plugin_decl(plugin);
+ struct st_plugin_dl *plugin_dl= plugin_dlib(plugin);
CHARSET_INFO *cs= system_charset_info;
char version_buf[20];
restore_record(table, s->default_values);
- table->field[0]->store(plugin->name.str, plugin->name.length, cs);
+ table->field[0]->store(plugin_name(plugin)->str,
+ plugin_name(plugin)->length, cs);
table->field[1]->store(version_buf,
make_version_string(version_buf, sizeof(version_buf), plug->version),
cs);
- switch (plugin->state)
- {
+ switch (plugin_state(plugin)) {
/* case PLUGIN_IS_FREED: does not happen */
case PLUGIN_IS_DELETED:
table->field[2]->store(STRING_WITH_LEN("DELETED"), cs);
@@ -177,14 +177,13 @@ static my_bool show_plugins(THD *thd, st_plugin_int *plugin,
make_version_string(version_buf, sizeof(version_buf),
*(uint *)plug->info), cs);
- if (plugin->plugin_dl)
+ if (plugin_dl)
{
- table->field[5]->store(plugin->plugin_dl->dl.str,
- plugin->plugin_dl->dl.length, cs);
+ table->field[5]->store(plugin_dl->dl.str, plugin_dl->dl.length, cs);
table->field[5]->set_notnull();
table->field[6]->store(version_buf,
make_version_string(version_buf, sizeof(version_buf),
- plugin->plugin_dl->version),
+ plugin_dl->version),
cs);
table->field[6]->set_notnull();
}
@@ -364,7 +363,7 @@ bool mysqld_show_privileges(THD *thd)
field_list.push_back(new Item_empty_string("Privilege",10));
field_list.push_back(new Item_empty_string("Context",15));
- field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -428,7 +427,8 @@ bool mysqld_show_column_types(THD *thd)
DBUG_ENTER("mysqld_show_column_types");
field_list.push_back(new Item_empty_string("Type",30));
- field_list.push_back(new Item_int("Size",(longlong) 1,21));
+ field_list.push_back(new Item_int("Size",(longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("Min_Value",20));
field_list.push_back(new Item_empty_string("Max_Value",20));
field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
@@ -439,8 +439,8 @@ bool mysqld_show_column_types(THD *thd)
field_list.push_back(new Item_empty_string("Zerofill",4));
field_list.push_back(new Item_empty_string("Searchable",4));
field_list.push_back(new Item_empty_string("Case_Sensitive",4));
- field_list.push_back(new Item_empty_string("Default",NAME_LEN));
- field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Default",NAME_CHAR_LEN));
+ field_list.push_back(new Item_empty_string("Comment",NAME_CHAR_LEN));
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -522,7 +522,7 @@ find_files(THD *thd, List<char> *files, const char *db,
for (i=0 ; i < (uint) dirp->number_off_files ; i++)
{
- char uname[NAME_LEN*3+1]; /* Unencoded name */
+ char uname[NAME_LEN + 1]; /* Unencoded name */
file=dirp->dir_entry+i;
if (dir)
{ /* Return databases */
@@ -652,13 +652,13 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
List<Item> field_list;
if (table_list->view)
{
- field_list.push_back(new Item_empty_string("View",NAME_LEN));
+ field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN));
field_list.push_back(new Item_empty_string("Create View",
max(buffer.length(),1024)));
}
else
{
- field_list.push_back(new Item_empty_string("Table",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Table",NAME_CHAR_LEN));
// 1024 is for not to confuse old clients
field_list.push_back(new Item_empty_string("Create Table",
max(buffer.length(),1024)));
@@ -689,10 +689,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
bool mysqld_show_create_db(THD *thd, char *dbname,
HA_CREATE_INFO *create_info)
{
- Security_context *sctx= thd->security_ctx;
char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *sctx= thd->security_ctx;
uint db_access;
#endif
HA_CREATE_INFO create;
@@ -706,7 +706,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
else
db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
sctx->master_access);
- if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname))
{
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->host_or_ip, dbname);
@@ -716,9 +716,9 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
}
#endif
if (!my_strcasecmp(system_charset_info, dbname,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
- dbname= information_schema_name.str;
+ dbname= INFORMATION_SCHEMA_NAME.str;
create.default_table_charset= system_charset_info;
}
else
@@ -732,7 +732,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
load_db_opt_by_name(thd, dbname, &create);
}
List<Item> field_list;
- field_list.push_back(new Item_empty_string("Database",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN));
field_list.push_back(new Item_empty_string("Create Database",1024));
if (protocol->send_fields(&field_list,
@@ -831,7 +831,7 @@ mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd)
}
else
{
- if (my_write(fd, (const byte*) packet->ptr(), packet->length(),
+ if (my_write(fd, (const uchar*) packet->ptr(), packet->length(),
MYF(MY_WME)))
DBUG_RETURN(-1);
}
@@ -1021,7 +1021,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
HA_CREATE_INFO *create_info_arg)
{
List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128];
const char *alias;
String type(tmp, sizeof(tmp), system_charset_info);
Field **ptr,*field;
@@ -1116,7 +1116,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (flags & NOT_NULL_FLAG)
packet->append(STRING_WITH_LEN(" NOT NULL"));
- else if (field->type() == FIELD_TYPE_TIMESTAMP)
+ else if (field->type() == MYSQL_TYPE_TIMESTAMP)
{
/*
TIMESTAMP field require explicit NULL flag, because unlike
@@ -1132,7 +1132,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
has_now_default= table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_UN_FIELD;
- has_default= (field->type() != FIELD_TYPE_BLOB &&
+ has_default= (field->type() != MYSQL_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER &&
!((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
@@ -1225,7 +1225,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (key_part->field &&
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
- !(key_info->flags & HA_FULLTEXT)))
+ !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
{
char *end;
buff[0] = '(';
@@ -1240,9 +1240,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
store_key_options(thd, packet, table, key_info);
if (key_info->parser)
{
+ LEX_STRING *parser_name= plugin_name(key_info->parser);
packet->append(STRING_WITH_LEN(" /*!50100 WITH PARSER "));
- append_identifier(thd, packet, key_info->parser->name.str,
- key_info->parser->name.length);
+ append_identifier(thd, packet, parser_name->str, parser_name->length);
packet->append(STRING_WITH_LEN(" */ "));
}
}
@@ -1267,7 +1267,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
to the CREATE TABLE statement
*/
- if ((for_str= file->get_tablespace_name(thd)))
+ if ((for_str= file->get_tablespace_name(thd,0,0)))
{
packet->append(STRING_WITH_LEN(" /*!50100 TABLESPACE "));
packet->append(for_str, strlen(for_str));
@@ -1308,8 +1308,9 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
but may extrapolate its existence from that of an AUTO_INCREMENT column.
*/
- if(create_info.auto_increment_value > 1)
+ if (create_info.auto_increment_value > 1)
{
+ char *end;
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
end= longlong10_to_str(create_info.auto_increment_value, buff,10);
packet->append(buff, (uint) (end - buff));
@@ -1339,6 +1340,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->min_rows)
{
+ char *end;
packet->append(STRING_WITH_LEN(" MIN_ROWS="));
end= longlong10_to_str(share->min_rows, buff, 10);
packet->append(buff, (uint) (end- buff));
@@ -1346,6 +1348,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->max_rows && !table_list->schema_table)
{
+ char *end;
packet->append(STRING_WITH_LEN(" MAX_ROWS="));
end= longlong10_to_str(share->max_rows, buff, 10);
packet->append(buff, (uint) (end - buff));
@@ -1353,6 +1356,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
if (share->avg_row_length)
{
+ char *end;
packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
end= longlong10_to_str(share->avg_row_length, buff,10);
packet->append(buff, (uint) (end - buff));
@@ -1373,6 +1377,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
if (table->s->key_block_size)
{
+ char *end;
packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
end= longlong10_to_str(table->s->key_block_size, buff, 10);
packet->append(buff, (uint) (end - buff));
@@ -1619,13 +1624,13 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_list_processes");
- field_list.push_back(new Item_int("Id",0,11));
+ field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("User",16));
field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
- field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
+ field_list.push_back(field=new Item_empty_string("db",NAME_CHAR_LEN));
field->maybe_null=1;
field_list.push_back(new Item_empty_string("Command",16));
- field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Time",7, MYSQL_TYPE_LONG));
field_list.push_back(field=new Item_empty_string("State",30));
field->maybe_null=1;
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
@@ -1655,7 +1660,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
thd->security_ctx->host_or_ip[0])
{
- if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
+ if ((thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)))
my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
}
@@ -1686,10 +1691,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (mysys_var)
pthread_mutex_unlock(&mysys_var->mutex);
-#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
- if (pthread_kill(tmp->real_id,0))
- tmp->proc_info="*** DEAD ***"; // This shouldn't happen
-#endif
#ifdef EXTRA_DEBUG
thd_info->start_time= tmp->time_after_lock;
#else
@@ -1800,7 +1801,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
else
table->field[4]->store(command_name[tmp->command].str,
command_name[tmp->command].length, cs);
- /* TIME */
+ /* MYSQL_TIME */
table->field[5]->store((uint32)(tmp->start_time ?
now - tmp->start_time : 0), TRUE);
/* STATE */
@@ -1911,8 +1912,8 @@ int add_status_vars(SHOW_VAR *list)
goto err;
}
while (list->name)
- res|= insert_dynamic(&all_status_vars, (gptr)list++);
- res|= insert_dynamic(&all_status_vars, (gptr)list); // appending NULL-element
+ res|= insert_dynamic(&all_status_vars, (uchar*)list++);
+ res|= insert_dynamic(&all_status_vars, (uchar*)list); // appending NULL-element
all_status_vars.elements--; // but next insert_dynamic should overwite it
if (status_vars_inited)
sort_dynamic(&all_status_vars, show_var_cmp);
@@ -1936,6 +1937,18 @@ void init_status_vars()
sort_dynamic(&all_status_vars, show_var_cmp);
}
+void reset_status_vars()
+{
+ SHOW_VAR *ptr= (SHOW_VAR*) all_status_vars.buffer;
+ SHOW_VAR *last= ptr + all_status_vars.elements;
+ for (; ptr < last; ptr++)
+ {
+ /* Note that SHOW_LONG_NOFLUSH variables are not reset */
+ if (ptr->type == SHOW_LONG)
+ *(ulong*) ptr->value= 0;
+ }
+}
+
/*
catch-all cleanup function, cleans up everything no matter what
@@ -2066,9 +2079,11 @@ static bool show_status_array(THD *thd, const char *wild,
char *value=var->value;
const char *pos, *end; // We assign a lot of const's
+ pthread_mutex_lock(&LOCK_global_system_variables);
+
if (show_type == SHOW_SYS)
{
- show_type= ((sys_var*) value)->type();
+ show_type= ((sys_var*) value)->show_type();
value= (char*) ((sys_var*) value)->value_ptr(thd, value_type,
&null_lex_str);
}
@@ -2121,7 +2136,7 @@ static bool show_status_array(THD *thd, const char *wild,
end= strend(pos);
break;
}
- case SHOW_CHAR_PTR:
+ case SHOW_CHAR_PTR:
{
if (!(pos= *(char**) value))
pos= "";
@@ -2148,6 +2163,9 @@ static bool show_status_array(THD *thd, const char *wild,
system_charset_info);
table->field[1]->store(pos, (uint32) (end - pos), system_charset_info);
table->field[1]->set_notnull();
+
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+
if (schema_table_store_record(thd, table))
DBUG_RETURN(TRUE);
}
@@ -2197,7 +2215,7 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
/* INFORMATION_SCHEMA name */
-LEX_STRING information_schema_name= { C_STRING_WITH_LEN("information_schema")};
+LEX_STRING INFORMATION_SCHEMA_NAME= { C_STRING_WITH_LEN("information_schema")};
/* This is only used internally, but we need it here as a forward reference */
extern ST_SCHEMA_TABLE schema_tables[];
@@ -2269,8 +2287,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
ident_table.length= strlen(table);
table_ident= new Table_ident(thd, ident_db, ident_table, 1);
sel->init_query();
- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
- (List<String> *) 0, (List<String> *) 0))
+ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
return 1;
return 0;
}
@@ -2414,11 +2431,11 @@ int make_db_list(THD *thd, List<char> *files,
*/
if (!idx_field_vals->db_value ||
!wild_case_compare(system_charset_info,
- information_schema_name.str,
+ INFORMATION_SCHEMA_NAME.str,
idx_field_vals->db_value))
{
*with_i_schema= 1;
- if (files->push_back(thd->strdup(information_schema_name.str)))
+ if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
return 1;
}
return (find_files(thd, files, NullS, mysql_data_home,
@@ -2432,11 +2449,11 @@ int make_db_list(THD *thd, List<char> *files,
*/
if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)
{
- if (!my_strcasecmp(system_charset_info, information_schema_name.str,
+ if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str,
idx_field_vals->db_value))
{
*with_i_schema= 1;
- return files->push_back(thd->strdup(information_schema_name.str));
+ return files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str));
}
return files->push_back(thd->strdup(idx_field_vals->db_value));
}
@@ -2445,17 +2462,55 @@ int make_db_list(THD *thd, List<char> *files,
Create list of existing databases. It is used in case
of select from information schema table
*/
- if (files->push_back(thd->strdup(information_schema_name.str)))
+ if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
return 1;
*with_i_schema= 1;
return (find_files(thd, files, NullS,
mysql_data_home, NullS, 1) != FIND_FILES_OK);
}
+struct st_add_schema_table
+{
+ List<char> *files;
+ const char *wild;
+};
+
+static my_bool add_schema_table(THD *thd, plugin_ref plugin,
+ void* p_data)
+{
+ st_add_schema_table *data= (st_add_schema_table *)p_data;
+ List<char> *file_list= data->files;
+ const char *wild= data->wild;
+ ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
+ DBUG_ENTER("add_schema_table");
+
+ if (schema_table->hidden)
+ DBUG_RETURN(0);
+ if (wild)
+ {
+ if (lower_case_table_names)
+ {
+ if (wild_case_compare(files_charset_info,
+ schema_table->table_name,
+ wild))
+ DBUG_RETURN(0);
+ }
+ else if (wild_compare(schema_table->table_name, wild, 0))
+ DBUG_RETURN(0);
+ }
+
+ if (file_list->push_back(thd->strdup(schema_table->table_name)))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
int schema_tables_add(THD *thd, List<char> *files, const char *wild)
{
ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
+ st_add_schema_table add_data;
+ DBUG_ENTER("schema_tables_add");
+
for (; tmp_schema_table->table_name; tmp_schema_table++)
{
if (tmp_schema_table->hidden)
@@ -2473,9 +2528,16 @@ int schema_tables_add(THD *thd, List<char> *files, const char *wild)
continue;
}
if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
- return 1;
+ DBUG_RETURN(1);
}
- return 0;
+
+ add_data.files= files;
+ add_data.wild= wild;
+ if (plugin_foreach(thd, add_schema_table,
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
}
@@ -2490,26 +2552,27 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
ST_SCHEMA_TABLE *schema_table= tables->schema_table;
SELECT_LEX sel;
INDEX_FIELD_VALUES idx_field_vals;
- char path[FN_REFLEN], *end, *base_name, *orig_base_name, *file_name;
+ char path[FN_REFLEN], *base_name, *orig_base_name, *file_name;
uint len;
bool with_i_schema;
enum enum_schema_tables schema_table_idx;
List<char> bases;
List_iterator_fast<char> it(bases);
COND *partial_cond;
- Security_context *sctx= thd->security_ctx;
uint derived_tables= lex->derived_tables;
int error= 1;
enum legacy_db_type not_used;
Open_tables_state open_tables_state_backup;
bool save_view_prepare_mode= lex->view_prepare_mode;
Query_tables_list query_tables_list_backup;
- lex->view_prepare_mode= TRUE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *sctx= thd->security_ctx;
+#endif
DBUG_ENTER("get_all_tables");
- LINT_INIT(end);
LINT_INIT(len);
+ lex->view_prepare_mode= TRUE;
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
/*
@@ -2519,7 +2582,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
- if (lsel)
+ if (lsel && lsel->table_list.first)
{
TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
bool res;
@@ -2586,7 +2649,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
&thd->col_access, 0, 1, with_i_schema) ||
sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) ||
- (grant_option && !check_grant_db(thd, base_name)))
+ !check_grant_db(thd, base_name))
#endif
{
List<char> files;
@@ -2598,7 +2661,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
len= build_table_filename(path, sizeof(path), base_name, "", "", 0);
- end= path + len;
len= FN_LEN - len;
find_files_result res= find_files(thd, &files, base_name,
path, idx_field_vals.table_value, 0);
@@ -2648,7 +2710,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- my_snprintf(end, len, "/%s%s", file_name, reg_ext);
+ build_table_filename(path, sizeof(path),
+ base_name, file_name, reg_ext, 0);
+
switch (mysql_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
table->field[3]->store(STRING_WITH_LEN("ERROR"),
@@ -2687,18 +2751,32 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
res= open_normal_and_derived_tables(thd, show_table_list,
MYSQL_LOCK_IGNORE_FLUSH);
lex->sql_command= save_sql_command;
- /*
- We should use show_table_list->alias instead of
- show_table_list->table_name because table_name
- could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case.
+ /*
+ They can drop table after table names list creation and
+ before table opening. We open non existing table and
+ get ER_NO_SUCH_TABLE error. In this case we do not store
+ the record into I_S table and clear error.
*/
- res= schema_table->process_table(thd, show_table_list, table,
- res, orig_base_name,
- show_table_list->alias);
- close_tables_for_reopen(thd, &show_table_list);
- DBUG_ASSERT(!lex->query_tables_own_last);
+ if (thd->net.last_errno == ER_NO_SUCH_TABLE)
+ {
+ res= 0;
+ thd->clear_error();
+ }
+ else
+ {
+ /*
+ We should use show_table_list->alias instead of
+ show_table_list->table_name because table_name
+ could be changed during opening of I_S tables. It's safe
+ to use alias because alias contains original table name
+ in this case.
+ */
+ res= schema_table->process_table(thd, show_table_list, table,
+ res, orig_base_name,
+ show_table_list->alias);
+ close_tables_for_reopen(thd, &show_table_list);
+ DBUG_ASSERT(!lex->query_tables_own_last);
+ }
if (res)
goto err;
}
@@ -2748,7 +2826,9 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
bool with_i_schema;
HA_CREATE_INFO create;
TABLE *table= tables->table;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
+#endif
DBUG_ENTER("fill_schema_shemata");
if (make_db_list(thd, &files, &idx_field_vals,
@@ -2769,7 +2849,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) ||
- (grant_option && !check_grant_db(thd, file_name)))
+ !check_grant_db(thd, file_name))
#endif
{
load_db_opt_by_name(thd, file_name, &create);
@@ -2789,7 +2869,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
const char *file_name)
{
const char *tmp_buff;
- TIME time;
+ MYSQL_TIME time;
CHARSET_INFO *cs= system_charset_info;
DBUG_ENTER("get_schema_tables_record");
@@ -2892,20 +2972,21 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
if (file->stats.create_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->stats.create_time);
+ (my_time_t) file->stats.create_time);
table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[14]->set_notnull();
}
if (file->stats.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- file->stats.update_time);
+ (my_time_t) file->stats.update_time);
table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[15]->set_notnull();
}
if (file->stats.check_time)
{
- thd->variables.time_zone->gmt_sec_to_TIME(&time, file->stats.check_time);
+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
+ (my_time_t) file->stats.check_time);
table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[16]->set_notnull();
}
@@ -2948,7 +3029,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables,
ha_row_type[(uint) share->row_type],
NullS);
#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (show_table->s->db_type == partition_hton &&
+ if (show_table->s->db_type() == partition_hton &&
show_table->part_info != NULL &&
show_table->part_info->no_parts > 0)
ptr= strmov(ptr, " partitioned");
@@ -3017,7 +3098,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
for (ptr=show_table->field; (field= *ptr) ; ptr++)
{
const char *tmp_buff;
- byte *pos;
+ uchar *pos;
bool is_blob;
uint flags=field->flags;
char tmp[MAX_FIELD_WIDTH];
@@ -3095,15 +3176,15 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
table->field[5]->store("",0, cs);
table->field[5]->set_notnull();
}
- pos=(byte*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
+ pos=(uchar*) ((flags & NOT_NULL_FLAG) ? "NO" : "YES");
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
- is_blob= (field->type() == FIELD_TYPE_BLOB);
+ is_blob= (field->type() == MYSQL_TYPE_BLOB);
if (field->has_charset() || is_blob ||
field->real_type() == MYSQL_TYPE_VARCHAR || // For varbinary type
field->real_type() == MYSQL_TYPE_STRING) // For binary type
{
- uint32 octet_max_length= field->max_length();
+ uint32 octet_max_length= field->max_display_length();
if (is_blob && octet_max_length != (uint32) 4294967295U)
octet_max_length /= field->charset()->mbmaxlen;
longlong char_max_len= is_blob ?
@@ -3122,25 +3203,25 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
decimals= field->decimals();
switch (field->type()) {
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
field_length= ((Field_new_decimal*) field)->precision;
break;
- case FIELD_TYPE_DECIMAL:
+ case MYSQL_TYPE_DECIMAL:
field_length= field->field_length - (decimals ? 2 : 1);
break;
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- field_length= field->max_length() - 1;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ field_length= field->max_display_length() - 1;
break;
- case FIELD_TYPE_BIT:
- field_length= field->max_length();
+ case MYSQL_TYPE_BIT:
+ field_length= field->max_display_length();
decimals= -1; // return NULL
break;
- case FIELD_TYPE_FLOAT:
- case FIELD_TYPE_DOUBLE:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
field_length= field->field_length;
if (decimals == NOT_FIXED_DEC)
decimals= -1; // return NULL
@@ -3163,16 +3244,16 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
if (field->has_charset())
{
- pos=(byte*) field->charset()->csname;
+ pos=(uchar*) field->charset()->csname;
table->field[12]->store((const char*) pos,
strlen((const char*) pos), cs);
table->field[12]->set_notnull();
- pos=(byte*) field->charset()->name;
+ pos=(uchar*) field->charset()->name;
table->field[13]->store((const char*) pos,
strlen((const char*) pos), cs);
table->field[13]->set_notnull();
}
- pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
+ pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
table->field[15]->store((const char*) pos,
@@ -3223,19 +3304,20 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
}
-static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin,
+static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
void *ptable)
{
TABLE *table= (TABLE *) ptable;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
DBUG_ENTER("iter_schema_engines");
if (!(hton->flags & HTON_HIDDEN))
{
+ LEX_STRING *name= plugin_name(plugin);
if (!(wild && wild[0] &&
- wild_case_compare(scs, plugin->name.str,wild)))
+ wild_case_compare(scs, name->str,wild)))
{
LEX_STRING state[2]= {{ C_STRING_WITH_LEN("ENABLED") },
{ C_STRING_WITH_LEN("DISABLED") }};
@@ -3244,11 +3326,11 @@ static my_bool iter_schema_engines(THD *thd, st_plugin_int *plugin,
LEX_STRING *tmp;
restore_record(table, s->default_values);
- table->field[0]->store(plugin->name.str, plugin->name.length, scs);
+ table->field[0]->store(name->str, name->length, scs);
tmp= &state[test(hton->state)];
table->field[1]->store(tmp->str, tmp->length, scs);
- table->field[2]->store(plugin->plugin->descr,
- strlen(plugin->plugin->descr), scs);
+ table->field[2]->store(plugin_decl(plugin)->descr,
+ strlen(plugin_decl(plugin)->descr), scs);
tmp= &yesno[test(hton->commit)];
table->field[3]->store(tmp->str, tmp->length, scs);
tmp= &yesno[test(hton->prepare)];
@@ -3347,7 +3429,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
{
String tmp_string;
String sp_db, sp_name, definer;
- TIME time;
+ MYSQL_TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
get_field(thd->mem_root, proc_table->field[0], &sp_db);
@@ -3464,7 +3546,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
err:
proc_table->file->ha_index_end();
- close_proc_table(thd, &open_tables_state_backup);
+ close_system_tables(thd, &open_tables_state_backup);
DBUG_RETURN(res);
}
@@ -3712,8 +3794,7 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db,
LEX_STRING *definer_buffer)
{
CHARSET_INFO *cs= system_charset_info;
- byte *sql_mode_str;
- ulong sql_mode_len;
+ LEX_STRING sql_mode_rep;
restore_record(table, s->default_values);
table->field[1]->store(db, strlen(db), cs);
@@ -3729,11 +3810,9 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db,
table->field[14]->store(STRING_WITH_LEN("OLD"), cs);
table->field[15]->store(STRING_WITH_LEN("NEW"), cs);
- sql_mode_str=
- sys_var_thd_sql_mode::symbolic_mode_representation(thd,
- sql_mode,
- &sql_mode_len);
- table->field[17]->store((const char*)sql_mode_str, sql_mode_len, cs);
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd, sql_mode,
+ &sql_mode_rep);
+ table->field[17]->store(sql_mode_rep.str, sql_mode_rep.length, cs);
table->field[18]->store((const char *)definer_buffer->str, definer_buffer->length, cs);
return schema_table_store_record(thd, table);
}
@@ -3855,8 +3934,8 @@ static int get_schema_key_column_usage_record(THD *thd,
show_table->file->get_foreign_key_list(thd, &f_key_list);
FOREIGN_KEY_INFO *f_key_info;
- List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
- while ((f_key_info= it++))
+ List_iterator_fast<FOREIGN_KEY_INFO> fkey_it(f_key_list);
+ while ((f_key_info= fkey_it++))
{
LEX_STRING *f_info;
LEX_STRING *r_info;
@@ -3895,6 +3974,7 @@ static int get_schema_key_column_usage_record(THD *thd,
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
static void collect_partition_expr(List<char> &field_list, String *str)
{
List_iterator<char> part_it(field_list);
@@ -3909,6 +3989,7 @@ static void collect_partition_expr(List<char> &field_list, String *str)
}
return;
}
+#endif
static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
@@ -3919,7 +4000,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
TABLE* table= schema_table;
CHARSET_INFO *cs= system_charset_info;
PARTITION_INFO stat_info;
- TIME time;
+ MYSQL_TIME time;
file->get_dynamic_partition_info(&stat_info, part_id);
table->field[12]->store((longlong) stat_info.records, TRUE);
table->field[13]->store((longlong) stat_info.mean_rec_length, TRUE);
@@ -3934,20 +4015,21 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
if (stat_info.create_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- stat_info.create_time);
+ (my_time_t)stat_info.create_time);
table->field[18]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[18]->set_notnull();
}
if (stat_info.update_time)
{
thd->variables.time_zone->gmt_sec_to_TIME(&time,
- stat_info.update_time);
+ (my_time_t)stat_info.update_time);
table->field[19]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[19]->set_notnull();
}
if (stat_info.check_time)
{
- thd->variables.time_zone->gmt_sec_to_TIME(&time, stat_info.check_time);
+ thd->variables.time_zone->gmt_sec_to_TIME(&time,
+ (my_time_t)stat_info.check_time);
table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[20]->set_notnull();
}
@@ -3974,7 +4056,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
strlen(part_elem->tablespace_name), cs);
else
{
- char *ts= showing_table->file->get_tablespace_name(thd);
+ char *ts= showing_table->file->get_tablespace_name(thd,0,0);
if(ts)
{
table->field[24]->store(ts, strlen(ts), cs);
@@ -4020,7 +4102,6 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
partition_element *part_elem;
List_iterator<partition_element> part_it(part_info->partitions);
uint part_pos= 0, part_id= 0;
- uint no_parts= part_info->no_parts;
restore_record(table, s->default_values);
table->field[1]->store(base_name, strlen(base_name), cs);
@@ -4190,6 +4271,7 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
}
+#ifdef NOT_USED
static interval_type get_real_interval_type(interval_type i_type)
{
switch (i_type) {
@@ -4233,6 +4315,8 @@ static interval_type get_real_interval_type(interval_type i_type)
return INTERVAL_SECOND;
}
+#endif
+
/*
Loads an event from mysql.event and copies it's data to a row of
@@ -4254,15 +4338,15 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
CHARSET_INFO *scs= system_charset_info;
- TIME time;
+ MYSQL_TIME time;
Event_timed et;
- DBUG_ENTER("fill_events_copy_to_schema_tab");
+ DBUG_ENTER("copy_event_to_schema_table");
restore_record(sch_table, s->default_values);
- if (et.load_from_row(event_table))
+ if (et.load_from_row(thd, event_table))
{
- my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
+ my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), event_table->alias);
DBUG_RETURN(1);
}
@@ -4287,6 +4371,9 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
store(et.name.str, et.name.length, scs);
sch_table->field[ISE_DEFINER]->
store(et.definer.str, et.definer.length, scs);
+ const String *tz_name= et.time_zone->get_name();
+ sch_table->field[ISE_TIME_ZONE]->
+ store(tz_name->ptr(), tz_name->length(), scs);
sch_table->field[ISE_EVENT_BODY]->
store(STRING_WITH_LEN("SQL"), scs);
sch_table->field[ISE_EVENT_DEFINITION]->
@@ -4294,15 +4381,15 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
/* SQL_MODE */
{
- byte *sql_mode_str;
- ulong sql_mode_len= 0;
- sql_mode_str=
- sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
- &sql_mode_len);
+ LEX_STRING sql_mode;
+ sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode,
+ &sql_mode);
sch_table->field[ISE_SQL_MODE]->
- store((const char*)sql_mode_str, sql_mode_len, scs);
+ store(sql_mode.str, sql_mode.length, scs);
}
+ int not_used=0;
+
if (et.expression)
{
String show_str;
@@ -4322,15 +4409,17 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[ISE_INTERVAL_FIELD]->store(ival->str, ival->length, scs);
/* starts & ends . STARTS is always set - see sql_yacc.yy */
+ et.time_zone->gmt_sec_to_TIME(&time, et.starts);
sch_table->field[ISE_STARTS]->set_notnull();
sch_table->field[ISE_STARTS]->
- store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
+ store_time(&time, MYSQL_TIMESTAMP_DATETIME);
if (!et.ends_null)
{
+ et.time_zone->gmt_sec_to_TIME(&time, et.ends);
sch_table->field[ISE_ENDS]->set_notnull();
sch_table->field[ISE_ENDS]->
- store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
+ store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
}
else
@@ -4338,16 +4427,30 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
/* type */
sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
+ et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
sch_table->field[ISE_EXECUTE_AT]->set_notnull();
sch_table->field[ISE_EXECUTE_AT]->
- store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
+ store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
/* status */
- if (et.status == Event_timed::ENABLED)
- sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
- else
- sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs);
+
+ switch (et.status)
+ {
+ case Event_timed::ENABLED:
+ sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
+ break;
+ case Event_timed::SLAVESIDE_DISABLED:
+ sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
+ scs);
+ break;
+ case Event_timed::DISABLED:
+ sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ sch_table->field[ISE_ORIGINATOR]->store(et.originator, TRUE);
/* on_completion */
if (et.on_completion == Event_timed::ON_COMPLETION_DROP)
@@ -4357,7 +4460,6 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[ISE_ON_COMPLETION]->
store(STRING_WITH_LEN("PRESERVE"), scs);
- int not_used=0;
number_to_datetime(et.created, &time, 0, &not_used);
DBUG_ASSERT(not_used==0);
sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
@@ -4367,11 +4469,12 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[ISE_LAST_ALTERED]->
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
- if (et.last_executed.year)
+ if (et.last_executed)
{
+ et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
sch_table->field[ISE_LAST_EXECUTED]->
- store_time(&et.last_executed, MYSQL_TIMESTAMP_DATETIME);
+ store_time(&time, MYSQL_TIMESTAMP_DATETIME);
}
sch_table->field[ISE_EVENT_COMMENT]->
@@ -4415,10 +4518,20 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond)
int res= 0;
LEX *lex= thd->lex;
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
- pthread_mutex_lock(&LOCK_global_system_variables);
- res= show_status_array(thd, wild, init_vars,
- lex->option_type, 0, "", tables->table, 0);
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ enum enum_schema_tables schema_table_idx=
+ get_schema_table_idx(tables->schema_table);
+ enum enum_var_type option_type= OPT_SESSION;
+ bool upper_case_names= (schema_table_idx != SCH_VARIABLES);
+ bool sorted_vars= (schema_table_idx == SCH_VARIABLES);
+
+ if (lex->option_type == OPT_GLOBAL ||
+ schema_table_idx == SCH_GLOBAL_VARIABLES)
+ option_type= OPT_GLOBAL;
+
+ rw_rdlock(&LOCK_system_variables_hash);
+ res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars),
+ option_type, NULL, "", tables->table, upper_case_names);
+ rw_unlock(&LOCK_system_variables_hash);
DBUG_RETURN(res);
}
@@ -4429,16 +4542,38 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
LEX *lex= thd->lex;
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
int res= 0;
- STATUS_VAR tmp;
+ STATUS_VAR *tmp1, tmp;
+ enum enum_schema_tables schema_table_idx=
+ get_schema_table_idx(tables->schema_table);
+ enum enum_var_type option_type;
+ bool upper_case_names= (schema_table_idx != SCH_STATUS);
+
+ if (schema_table_idx == SCH_STATUS)
+ {
+ option_type= lex->option_type;
+ if (option_type == OPT_GLOBAL)
+ tmp1= &tmp;
+ else
+ tmp1= thd->initial_status_var;
+ }
+ else if (schema_table_idx == SCH_GLOBAL_STATUS)
+ {
+ option_type= OPT_GLOBAL;
+ tmp1= &tmp;
+ }
+ else
+ {
+ option_type= OPT_SESSION;
+ tmp1= &thd->status_var;
+ }
+
pthread_mutex_lock(&LOCK_status);
- if (lex->option_type == OPT_GLOBAL)
+ if (option_type == OPT_GLOBAL)
calc_sum_of_all_status(&tmp);
res= show_status_array(thd, wild,
(SHOW_VAR *)all_status_vars.buffer,
- OPT_GLOBAL,
- (lex->option_type == OPT_GLOBAL ?
- &tmp: thd->initial_status_var),
- "", tables->table, 0);
+ option_type, tmp1, "", tables->table,
+ upper_case_names);
pthread_mutex_unlock(&LOCK_status);
DBUG_RETURN(res);
}
@@ -4498,8 +4633,10 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
f_key_info->forein_id->length, cs);
table->field[4]->store(f_key_info->referenced_db->str,
f_key_info->referenced_db->length, cs);
- table->field[5]->store(f_key_info->referenced_table->str,
+ table->field[10]->store(f_key_info->referenced_table->str,
f_key_info->referenced_table->length, cs);
+ table->field[5]->store(f_key_info->referenced_key_name->str,
+ f_key_info->referenced_key_name->length, cs);
table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
table->field[7]->store(f_key_info->update_method->str,
f_key_info->update_method->length, cs);
@@ -4512,6 +4649,44 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
DBUG_RETURN(0);
}
+struct schema_table_ref
+{
+ const char *table_name;
+ ST_SCHEMA_TABLE *schema_table;
+};
+
+
+/*
+ Find schema_tables elment by name
+
+ SYNOPSIS
+ find_schema_table_in_plugin()
+ thd thread handler
+ plugin plugin
+ table_name table name
+
+ RETURN
+ 0 table not found
+ 1 found the schema table
+*/
+static my_bool find_schema_table_in_plugin(THD *thd, plugin_ref plugin,
+ void* p_table)
+{
+ schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
+ const char* table_name= p_schema_table->table_name;
+ ST_SCHEMA_TABLE *schema_table= plugin_data(plugin, ST_SCHEMA_TABLE *);
+ DBUG_ENTER("find_schema_table_in_plugin");
+
+ if (!my_strcasecmp(system_charset_info,
+ schema_table->table_name,
+ table_name)) {
+ p_schema_table->schema_table= schema_table;
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
/*
Find schema_tables elment by name
@@ -4528,15 +4703,24 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
+ schema_table_ref schema_table_a;
ST_SCHEMA_TABLE *schema_table= schema_tables;
+ DBUG_ENTER("find_schema_table");
+
for (; schema_table->table_name; schema_table++)
{
if (!my_strcasecmp(system_charset_info,
schema_table->table_name,
table_name))
- return schema_table;
+ DBUG_RETURN(schema_table);
}
- return 0;
+
+ schema_table_a.table_name= table_name;
+ if (plugin_foreach(thd, find_schema_table_in_plugin,
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
+ DBUG_RETURN(schema_table_a.schema_table);
+
+ DBUG_RETURN(NULL);
}
@@ -4573,26 +4757,42 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
for (; fields_info->field_name; fields_info++)
{
switch (fields_info->field_type) {
+ case MYSQL_TYPE_TINY:
case MYSQL_TYPE_LONG:
- if (!(item= new Item_int(fields_info->field_name,
- fields_info->value,
- fields_info->field_length)))
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ if (!(item= new Item_return_int(fields_info->field_name,
+ fields_info->field_length,
+ fields_info->field_type,
+ fields_info->value)))
{
DBUG_RETURN(0);
}
+ item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
case MYSQL_TYPE_TIMESTAMP:
- if (!(item=new Item_datetime(fields_info->field_name)))
+ case MYSQL_TYPE_DATETIME:
+ if (!(item=new Item_return_date_time(fields_info->field_name,
+ fields_info->field_type)))
{
DBUG_RETURN(0);
}
break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC,
+ fields_info->field_length)) == NULL)
+ DBUG_RETURN(NULL);
+ break;
case MYSQL_TYPE_DECIMAL:
if (!(item= new Item_decimal((longlong) fields_info->value, false)))
{
DBUG_RETURN(0);
}
- item->unsigned_flag= (fields_info->field_length/10000)%10;
+ item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
item->decimals= fields_info->field_length%10;
item->max_length= (fields_info->field_length/100)%100;
if (item->unsigned_flag == 0)
@@ -4602,19 +4802,30 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
item->set_name(fields_info->field_name,
strlen(fields_info->field_name), cs);
break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ if (!(item= new Item_blob(fields_info->field_name,
+ fields_info->field_length)))
+ {
+ DBUG_RETURN(0);
+ }
+ break;
default:
- /* this should be changed when Item_empty_string is fixed(in 4.1) */
- if (!(item= new Item_empty_string("", 0, cs)))
+ /* Don't let unimplemented types pass through. Could be a grave error. */
+ DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);
+
+ if (!(item= new Item_empty_string("", fields_info->field_length, cs)))
{
DBUG_RETURN(0);
}
- item->max_length= fields_info->field_length * cs->mbmaxlen;
item->set_name(fields_info->field_name,
strlen(fields_info->field_name), cs);
break;
}
field_list.push_back(item);
- item->maybe_null= fields_info->maybe_null;
+ item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
field_count++;
}
TMP_TABLE_PARAM *tmp_table_param =
@@ -4837,9 +5048,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
TABLE *table;
DBUG_ENTER("mysql_schema_table");
if (!(table= table_list->schema_table->create_table(thd, table_list)))
- {
DBUG_RETURN(1);
- }
table->s->tmp_table= SYSTEM_TMP_TABLE;
table->grant.privilege= SELECT_ACL;
/*
@@ -4928,14 +5137,13 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
We have to make non const db_name & table_name
because of lower_case_table_names
*/
- make_lex_string(thd, &db, information_schema_name.str,
- information_schema_name.length, 0);
+ make_lex_string(thd, &db, INFORMATION_SCHEMA_NAME.str,
+ INFORMATION_SCHEMA_NAME.length, 0);
make_lex_string(thd, &table, schema_table->table_name,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
- 0, 0, TL_READ, (List<String> *) 0,
- (List<String> *) 0))
+ 0, 0, TL_READ))
{
DBUG_RETURN(1);
}
@@ -4949,13 +5157,15 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
SYNOPSIS
get_schema_tables_result()
join join which use schema tables
+ executed_place place where I_S table processed
RETURN
FALSE success
TRUE error
*/
-bool get_schema_tables_result(JOIN *join)
+bool get_schema_tables_result(JOIN *join,
+ enum enum_schema_table_state executed_place)
{
JOIN_TAB *tmp_join_tab= join->join_tab+join->tables;
THD *thd= join->thd;
@@ -4975,15 +5185,26 @@ bool get_schema_tables_result(JOIN *join)
bool is_subselect= (&lex->unit != lex->current_select->master_unit() &&
lex->current_select->master_unit()->item);
/*
- The schema table is already processed and
- the statement is not a subselect.
- So we don't need to handle this table again.
+ If schema table is already processed and
+ the statement is not a subselect then
+ we don't need to fill this table again.
+ If schema table is already processed and
+ schema_table_state != executed_place then
+ table is already processed and
+ we should skip second data processing.
*/
- if (table_list->is_schema_table_processed && !is_subselect)
+ if (table_list->schema_table_state &&
+ (!is_subselect || table_list->schema_table_state != executed_place))
continue;
- if (is_subselect) // is subselect
+ /*
+ if table is used in a subselect and
+ table has been processed earlier with the same
+ 'executed_place' value then we should refresh the table.
+ */
+ if (table_list->schema_table_state && is_subselect)
{
+ table_list->table->file->extra(HA_EXTRA_NO_CACHE);
table_list->table->file->extra(HA_EXTRA_RESET_STATE);
table_list->table->file->delete_all_rows();
free_io_cache(table_list->table);
@@ -4998,10 +5219,10 @@ bool get_schema_tables_result(JOIN *join)
{
result= 1;
join->error= 1;
- table_list->is_schema_table_processed= TRUE;
+ table_list->schema_table_state= executed_place;
break;
}
- table_list->is_schema_table_processed= TRUE;
+ table_list->schema_table_state= executed_place;
}
}
thd->no_warnings_for_error= 0;
@@ -5014,12 +5235,12 @@ struct run_hton_fill_schema_files_args
COND *cond;
};
-static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin,
+static my_bool run_hton_fill_schema_files(THD *thd, plugin_ref plugin,
void *arg)
{
struct run_hton_fill_schema_files_args *args=
(run_hton_fill_schema_files_args *) arg;
- handlerton *hton= (handlerton *)plugin->data;
+ handlerton *hton= plugin_data(plugin, handlerton *);
if(hton->fill_files_table && hton->state == SHOW_OPTION_YES)
hton->fill_files_table(hton, thd, args->tables, args->cond);
return false;
@@ -5027,7 +5248,6 @@ static my_bool run_hton_fill_schema_files(THD *thd, st_plugin_int *plugin,
int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
{
- TABLE *table= tables->table;
DBUG_ENTER("fill_schema_files");
struct run_hton_fill_schema_files_args args;
@@ -5040,177 +5260,11 @@ int fill_schema_files(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(0);
}
-int fill_schema_status(THD *thd, SHOW_VAR *variables,
- struct system_status_var *status_var,
- const char *prefix, TABLE *table)
-{
- SHOW_VAR tmp, *var;
- SHOW_TYPE show_type;
- LEX_STRING null_lex_str;
- char buff[SHOW_VAR_FUNC_BUFF_SIZE];
- char name_buf[64], *name_pos;
- int name_len;
- DBUG_ENTER("fill_schema_status");
-
- null_lex_str.str= 0;
- null_lex_str.length= 0;
-
- name_pos= strnmov(name_buf, prefix, sizeof(name_buf) - 1);
- if (*prefix)
- *name_pos++= '_';
- name_len= name_buf + sizeof(name_buf) - name_pos;
-
- for (; variables->name; variables++)
- {
- strnmov(name_pos, variables->name, name_len);
- name_buf[sizeof(name_buf) - 1]= 0;
- make_upper(name_buf);
-
- for (var= variables; var->type == SHOW_FUNC; var= &tmp)
- ((mysql_show_var_func)(var->value))(thd, &tmp, buff);
-
- show_type= var->type;
-
- if (show_type == SHOW_ARRAY)
- {
- fill_schema_status(thd, (SHOW_VAR*) var->value,
- status_var, name_buf, table);
- }
- else
- {
- char *value= var->value;
-
- restore_record(table, s->default_values);
- table->field[0]->store(name_buf, strlen(name_buf), system_charset_info);
-
- if (show_type == SHOW_SYS)
- {
- show_type= ((sys_var*) value)->type();
- value= (char*) ((sys_var*) value)->value_ptr(thd, OPT_GLOBAL,
- &null_lex_str);
- }
-
- switch (show_type)
- {
- case SHOW_DOUBLE_STATUS:
- value= (char*) status_var + (ulong) value;
- table->field[1]->store(*(double*) value);
- break;
- case SHOW_LONG_STATUS:
- value= (char*) status_var + (ulong) value;
- /* fall through */
- case SHOW_LONG:
- case SHOW_LONG_NOFLUSH: /* the difference lies in refresh_status() */
- table->field[1]->store((longlong) *(long*) value, false);
- break;
- case SHOW_LONGLONG:
- table->field[1]->store(*(longlong*) value, false);
- break;
- case SHOW_HA_ROWS:
- table->field[1]->store((longlong) *(ha_rows*) value, false);
- break;
- case SHOW_BOOL:
- table->field[1]->store((longlong) *(bool*) value, false);
- break;
- case SHOW_MY_BOOL:
- table->field[1]->store((longlong) *(my_bool*) value, false);
- break;
- case SHOW_INT:
- table->field[1]->store((longlong) *(uint32*) value, false);
- break;
- case SHOW_HAVE: /* always displayed as 0 */
- table->field[1]->store((longlong) 0, false);
- break;
- case SHOW_CHAR_PTR:
- value= *(char**) value;
- /* fall through */
- case SHOW_CHAR: /* always displayed as 0 */
- table->field[1]->store((longlong) 0, false);
- break;
- case SHOW_KEY_CACHE_LONG:
- value= (char*) dflt_key_cache + (ulong) value;
- table->field[1]->store((longlong) *(long*) value, false);
- break;
- case SHOW_KEY_CACHE_LONGLONG:
- value= (char*) dflt_key_cache + (ulong) value;
- table->field[1]->store(*(longlong*) value, false);
- break;
- case SHOW_UNDEF: /* always displayed as 0 */
- table->field[1]->store((longlong) 0, false);
- break;
- case SHOW_SYS: /* cannot happen */
- default:
- DBUG_ASSERT(0);
- break;
- }
-
- table->field[1]->set_notnull();
- if (schema_table_store_record(thd, table))
- DBUG_RETURN(1);
- }
- }
-
- DBUG_RETURN(0);
-}
-
-int fill_schema_global_status(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- STATUS_VAR tmp;
- int res= 0;
- DBUG_ENTER("fill_schema_global_status");
-
- pthread_mutex_lock(&LOCK_status);
- calc_sum_of_all_status(&tmp);
- res= fill_schema_status(thd, (SHOW_VAR*) all_status_vars.buffer,
- &tmp, "", tables->table);
- pthread_mutex_unlock(&LOCK_status);
-
- DBUG_RETURN(res);
-}
-
-int fill_schema_session_status(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- int res= 0;
- DBUG_ENTER("fill_schema_session_status");
-
- pthread_mutex_lock(&LOCK_status);
- res= fill_schema_status(thd, (SHOW_VAR*) all_status_vars.buffer,
- &thd->status_var, "", tables->table);
- pthread_mutex_unlock(&LOCK_status);
-
- DBUG_RETURN(res);
-}
-
-int fill_schema_global_variables(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- int res= 0;
- DBUG_ENTER("fill_schema_global_variables");
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- res= show_status_array(thd, "", init_vars, OPT_GLOBAL,
- NULL, "", tables->table, 1);
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- DBUG_RETURN(res);
-}
-
-int fill_schema_session_variables(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- int res= 0;
- DBUG_ENTER("fill_schema_session_variables");
-
- pthread_mutex_lock(&LOCK_global_system_variables);
- res= show_status_array(thd, "", init_vars, OPT_SESSION,
- NULL, "", tables->table, 1);
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
- DBUG_RETURN(res);
-}
ST_FIELD_INFO schema_fields_info[]=
{
{"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"SCHEMA_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
+ {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
{"DEFAULT_CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
{"DEFAULT_COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0},
{"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
@@ -5221,24 +5275,33 @@ ST_FIELD_INFO schema_fields_info[]=
ST_FIELD_INFO tables_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
- {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
- {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
+ {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version"},
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
- {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
- {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
- {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
- {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
+ {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows"},
+ {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length"},
+ {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length"},
+ {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length"},
+ {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length"},
+ {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free"},
+ {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment"},
+ {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time"},
+ {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time"},
+ {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time"},
{"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
+ {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum"},
{"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
{"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5248,17 +5311,23 @@ ST_FIELD_INFO tables_fields_info[]=
ST_FIELD_INFO columns_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
- {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
+ {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ MY_I_S_UNSIGNED, 0},
+ {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
+ 1, "Default"},
{"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
- {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+ 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
+ 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
+ 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
+ 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
{"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
@@ -5275,7 +5344,7 @@ ST_FIELD_INFO charsets_fields_info[]=
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
{"DEFAULT_COLLATE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Default collation"},
{"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description"},
- {"MAXLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Maxlen"},
+ {"MAXLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Maxlen"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5284,10 +5353,10 @@ ST_FIELD_INFO collation_fields_info[]=
{
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
- {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
+ {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Id"},
{"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
{"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
- {"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
+ {"SORTLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Sortlen"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5306,26 +5375,28 @@ ST_FIELD_INFO engines_fields_info[]=
ST_FIELD_INFO events_fields_info[]=
{
- {"EVENT_CATALOG", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"EVENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
- {"EVENT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
+ {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
{"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
+ {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone"},
{"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
{"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
{"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
- {"EXECUTE_AT", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Execute at"},
+ {"EXECUTE_AT", 0, MYSQL_TYPE_DATETIME, 0, 1, "Execute at"},
{"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value"},
{"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field"},
{"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
- {"STARTS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Starts"},
- {"ENDS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Ends"},
- {"STATUS", 8, MYSQL_TYPE_STRING, 0, 0, "Status"},
+ {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts"},
+ {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends"},
+ {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status"},
{"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0},
- {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0},
- {"LAST_EXECUTED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"EVENT_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+ {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0},
+ {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0},
+ {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5340,25 +5411,25 @@ ST_FIELD_INFO coll_charset_app_fields_info[]=
ST_FIELD_INFO proc_fields_info[]=
{
- {"SPECIFIC_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"ROUTINE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
- {"ROUTINE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
+ {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
{"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
- {"DTD_IDENTIFIER", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"DTD_IDENTIFIER", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
{"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
- {"EXTERNAL_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"EXTERNAL_LANGUAGE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"EXTERNAL_LANGUAGE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0},
- {"SQL_DATA_ACCESS", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"SQL_PATH", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"SQL_DATA_ACCESS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"SQL_PATH", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type"},
- {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Created"},
- {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, "Modified"},
+ {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created"},
+ {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified"},
{"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
- {"ROUTINE_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment"},
+ {"ROUTINE_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Comment"},
{"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5367,16 +5438,17 @@ ST_FIELD_INFO proc_fields_info[]=
ST_FIELD_INFO stat_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
- {"NON_UNIQUE", 1, MYSQL_TYPE_LONG, 0, 0, "Non_unique"},
- {"INDEX_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"INDEX_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name"},
- {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
- {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique"},
+ {"INDEX_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name"},
+ {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONGLONG, 0, 0, "Seq_in_index"},
+ {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
{"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
- {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
- {"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
+ {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
+ "Cardinality"},
+ {"SUB_PART", 3, MYSQL_TYPE_LONGLONG, 0, 1, "Sub_part"},
{"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
{"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
{"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type"},
@@ -5388,8 +5460,8 @@ ST_FIELD_INFO stat_fields_info[]=
ST_FIELD_INFO view_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
{"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
@@ -5403,7 +5475,7 @@ ST_FIELD_INFO user_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5413,8 +5485,8 @@ ST_FIELD_INFO schema_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5424,9 +5496,9 @@ ST_FIELD_INFO table_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5436,10 +5508,10 @@ ST_FIELD_INFO column_privileges_fields_info[]=
{
{"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"PRIVILEGE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5448,11 +5520,11 @@ ST_FIELD_INFO column_privileges_fields_info[]=
ST_FIELD_INFO table_constraints_fields_info[]=
{
{"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CONSTRAINT_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5460,17 +5532,17 @@ ST_FIELD_INFO table_constraints_fields_info[]=
ST_FIELD_INFO key_column_usage_fields_info[]=
{
{"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONG, 0, 0, 0},
- {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONG, 0, 1, 0},
- {"REFERENCED_TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"REFERENCED_COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONGLONG, 0, 0, 0},
+ {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"REFERENCED_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"REFERENCED_COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5478,19 +5550,19 @@ ST_FIELD_INFO key_column_usage_fields_info[]=
ST_FIELD_INFO table_names_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_"},
- {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type"},
+ {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Tables_in_"},
+ {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
ST_FIELD_INFO open_tables_fields_info[]=
{
- {"Database", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
- {"Table",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
- {"In_use", 1, MYSQL_TYPE_LONG, 0, 0, "In_use"},
- {"Name_locked", 4, MYSQL_TYPE_LONG, 0, 0, "Name_locked"},
+ {"Database", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database"},
+ {"Table",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"In_use", 1, MYSQL_TYPE_LONGLONG, 0, 0, "In_use"},
+ {"Name_locked", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Name_locked"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5498,22 +5570,22 @@ ST_FIELD_INFO open_tables_fields_info[]=
ST_FIELD_INFO triggers_fields_info[]=
{
{"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
+ {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
{"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"},
{"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
- {"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0},
+ {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0},
{"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"},
{"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0},
{"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"},
- {"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
{"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
+ {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 1, "Created"},
{"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 0, "sql_mode"},
{"DEFINER", 65535, MYSQL_TYPE_STRING, 0, 0, "Definer"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5523,66 +5595,54 @@ ST_FIELD_INFO triggers_fields_info[]=
ST_FIELD_INFO partitions_fields_info[]=
{
{"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"PARTITION_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"SUBPARTITION_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"SUBPARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
{"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0},
{"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0},
{"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
- {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0},
+ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0},
+ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0},
+ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0},
+ {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0},
+ {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
{"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0},
{"NODEGROUP", 12 , MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLESPACE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
ST_FIELD_INFO variables_fields_info[]=
{
- {"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
- {"Value", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, "Value"},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-};
-
-
-ST_FIELD_INFO status_fields_info[]=
-{
{"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
- {"VARIABLE_VALUE", 2207, MYSQL_TYPE_DECIMAL, 0, 0, "Value"},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
-};
-
-
-ST_FIELD_INFO system_variables_fields_info[]=
-{
- {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
- {"VARIABLE_VALUE", 65535, MYSQL_TYPE_STRING, 0, 1, "Value"},
+ {"VARIABLE_VALUE", 20480, MYSQL_TYPE_STRING, 0, 1, "Value"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
ST_FIELD_INFO processlist_fields_info[]=
{
- {"ID", 4, MYSQL_TYPE_LONG, 0, 0, "Id"},
+ {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id"},
{"USER", 16, MYSQL_TYPE_STRING, 0, 0, "User"},
{"HOST", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Host"},
- {"DB", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Db"},
+ {"DB", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Db"},
{"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command"},
- {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time"},
+ {"TIME", 7, MYSQL_TYPE_LONGLONG, 0, 0, "Time"},
{"STATE", 64, MYSQL_TYPE_STRING, 0, 1, "State"},
{"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5591,14 +5651,14 @@ ST_FIELD_INFO processlist_fields_info[]=
ST_FIELD_INFO plugin_fields_info[]=
{
- {"PLUGIN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
+ {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
{"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0},
{"PLUGIN_STATUS", 10, MYSQL_TYPE_STRING, 0, 0, "Status"},
{"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type"},
{"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0},
- {"PLUGIN_LIBRARY", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Library"},
+ {"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library"},
{"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0},
- {"PLUGIN_AUTHOR", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
{"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 1, "License"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5606,42 +5666,53 @@ ST_FIELD_INFO plugin_fields_info[]=
ST_FIELD_INFO files_fields_info[]=
{
- {"FILE_ID", 4, MYSQL_TYPE_LONG, 0, 0, 0},
- {"FILE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"FILE_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0},
+ {"FILE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLESPACE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_CATALOG", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"LOGFILE_GROUP_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"FULLTEXT_KEYS", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"DELETED_ROWS", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"UPDATE_COUNT", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"FREE_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"EXTENT_SIZE", 4, MYSQL_TYPE_LONG, 0, 0, 0},
- {"INITIAL_SIZE", 21, MYSQL_TYPE_LONG, 0, 1, 0},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONG, 0, 1, 0},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONG, 0, 1, 0},
- {"CREATION_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0},
- {"RECOVER_TIME", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONG, 0, 1, 0},
- {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
+ {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"FULLTEXT_KEYS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"DELETED_ROWS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"UPDATE_COUNT", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"FREE_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0},
+ {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0},
+ {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0},
+ {"RECOVER_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0},
+ {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version"},
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
- {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
- {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
- {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
+ {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows"},
+ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length"},
+ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length"},
+ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length"},
+ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length"},
+ {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free"},
+ {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time"},
+ {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time"},
+ {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time"},
+ {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
+ (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum"},
{"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0},
{"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5660,15 +5731,16 @@ void init_fill_schema_files_row(TABLE* table)
ST_FIELD_INFO referential_constraints_fields_info[]=
{
{"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
- {"UNIQUE_CONSTRAINT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"UNIQUE_CONSTRAINT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"MATCH_OPTION", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"UPDATE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"DELETE_RULE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
@@ -5698,10 +5770,10 @@ ST_SCHEMA_TABLE schema_tables[]=
Events::fill_schema_events, make_old_format, 0, -1, -1, 0},
{"FILES", files_fields_info, create_schema_table,
fill_schema_files, 0, 0, -1, -1, 0},
- {"GLOBAL_STATUS", status_fields_info, create_schema_table,
- fill_schema_global_status, make_old_format, 0, -1, -1, 0},
- {"GLOBAL_VARIABLES", system_variables_fields_info, create_schema_table,
- fill_schema_global_variables, make_old_format, 0, -1, -1, 0},
+ {"GLOBAL_STATUS", variables_fields_info, create_schema_table,
+ fill_status, make_old_format, 0, -1, -1, 0},
+ {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
+ fill_variables, make_old_format, 0, -1, -1, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0},
{"OPEN_TABLES", open_tables_fields_info, create_schema_table,
@@ -5721,10 +5793,10 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_schema_shemata, make_schemata_old_format, 0, 1, -1, 0},
{"SCHEMA_PRIVILEGES", schema_privileges_fields_info, create_schema_table,
fill_schema_schema_privileges, 0, 0, -1, -1, 0},
- {"SESSION_STATUS", status_fields_info, create_schema_table,
- fill_schema_session_status, make_old_format, 0, -1, -1, 0},
- {"SESSION_VARIABLES", system_variables_fields_info, create_schema_table,
- fill_schema_session_variables, make_old_format, 0, -1, -1, 0},
+ {"SESSION_STATUS", variables_fields_info, create_schema_table,
+ fill_status, make_old_format, 0, -1, -1, 0},
+ {"SESSION_VARIABLES", variables_fields_info, create_schema_table,
+ fill_variables, make_old_format, 0, -1, -1, 0},
{"STATISTICS", stat_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0},
{"STATUS", variables_fields_info, create_schema_table, fill_status,
@@ -5753,3 +5825,53 @@ ST_SCHEMA_TABLE schema_tables[]=
template class List_iterator_fast<char>;
template class List<char>;
#endif
+
+int initialize_schema_table(st_plugin_int *plugin)
+{
+ ST_SCHEMA_TABLE *schema_table;
+ DBUG_ENTER("initialize_schema_table");
+
+ if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(1);
+ /* Historical Requirement */
+ plugin->data= schema_table; // shortcut for the future
+ if (plugin->plugin->init)
+ {
+ schema_table->create_table= create_schema_table;
+ schema_table->old_format= make_old_format;
+ schema_table->idx_field1= -1,
+ schema_table->idx_field2= -1;
+
+ if (plugin->plugin->init(schema_table))
+ {
+ sql_print_error("Plugin '%s' init function returned error.",
+ plugin->name.str);
+ goto err;
+ }
+ schema_table->table_name= plugin->name.str;
+ }
+
+ DBUG_RETURN(0);
+err:
+ my_free(schema_table, MYF(0));
+ DBUG_RETURN(1);
+}
+
+int finalize_schema_table(st_plugin_int *plugin)
+{
+ ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
+ DBUG_ENTER("finalize_schema_table");
+
+ if (schema_table && plugin->plugin->deinit)
+ {
+ DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
+ if (plugin->plugin->deinit(NULL))
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ plugin->name.str));
+ }
+ my_free(schema_table, MYF(0));
+ }
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 29cd52eb9fd..d5c3f3bf675 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -1,3 +1,17 @@
+/* Copyright (C) 2006 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; version 2 of the License.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifndef SQL_SHOW_H
#define SQL_SHOW_H
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 1831c4a2f3d..da28ca07e2c 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_state.c b/sql/sql_state.c
index 355b847f239..511dc65917b 100644
--- a/sql/sql_state.c
+++ b/sql/sql_state.c
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 29b53560067..6c7dea6bf22 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -33,7 +32,7 @@
required by the string function
*/
-extern gptr sql_alloc(unsigned size);
+extern uchar* sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
#include "sql_string.h"
@@ -497,7 +496,7 @@ bool String::append(FILE* file, uint32 arg_length, myf my_flags)
{
if (realloc(str_length+arg_length))
return TRUE;
- if (my_fread(file, (byte*) Ptr + str_length, arg_length, my_flags))
+ if (my_fread(file, (uchar*) Ptr + str_length, arg_length, my_flags))
{
shrink(str_length);
return TRUE;
@@ -511,7 +510,7 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
{
if (realloc(str_length+arg_length))
return TRUE;
- if (my_b_read(file, (byte*) Ptr + str_length, arg_length))
+ if (my_b_read(file, (uchar*) Ptr + str_length, arg_length))
{
shrink(str_length);
return TRUE;
@@ -608,27 +607,26 @@ skip:
}
/*
-** replace substring with string
-** If wrong parameter or not enough memory, do nothing
+ Replace substring with string
+ If wrong parameter or not enough memory, do nothing
*/
-
bool String::replace(uint32 offset,uint32 arg_length,const String &to)
{
return replace(offset,arg_length,to.ptr(),to.length());
}
bool String::replace(uint32 offset,uint32 arg_length,
- const char *to,uint32 length)
+ const char *to, uint32 to_length)
{
- long diff = (long) length-(long) arg_length;
+ long diff = (long) to_length-(long) arg_length;
if (offset+arg_length <= str_length)
{
if (diff < 0)
{
- if (length)
- memcpy(Ptr+offset,to,length);
- bmove(Ptr+offset+length,Ptr+offset+arg_length,
+ if (to_length)
+ memcpy(Ptr+offset,to,to_length);
+ bmove(Ptr+offset+to_length,Ptr+offset+arg_length,
str_length-offset-arg_length);
}
else
@@ -637,11 +635,11 @@ bool String::replace(uint32 offset,uint32 arg_length,
{
if (realloc(str_length+(uint32) diff))
return TRUE;
- bmove_upp(Ptr+str_length+diff,Ptr+str_length,
+ bmove_upp((uchar*) Ptr+str_length+diff, (uchar*) Ptr+str_length,
str_length-offset-arg_length);
}
- if (length)
- memcpy(Ptr+offset,to,length);
+ if (to_length)
+ memcpy(Ptr+offset,to,to_length);
}
str_length+=(uint32) diff;
}
@@ -1023,8 +1021,8 @@ void String::print(String *str)
case '\r':
str->append(STRING_WITH_LEN("\\r"));
break;
- case 26: //Ctrl-Z
- str->append(STRING_WITH_LEN("\\z"));
+ case '\032': // Ctrl-Z
+ str->append(STRING_WITH_LEN("\\Z"));
break;
default:
str->append(c);
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 6481c20d042..128ed749b5f 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -85,7 +84,8 @@ public:
{ /* never called */ }
~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
+ inline void set_charset(CHARSET_INFO *charset_arg)
+ { str_charset= charset_arg; }
inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c8f6e09fecb..06c09cf4ebf 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -38,17 +37,22 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
List<create_field> &create, bool ignore,
uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted,
- enum enum_enable_or_disable keys_onoff);
+ enum enum_enable_or_disable keys_onoff,
+ bool error_if_not_empty);
static bool prepare_blob_field(THD *thd, create_field *sql_field);
-static bool check_engine(THD *thd, const char *table_name,
- HA_CREATE_INFO *create_info);
-static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
- List<create_field> *fields,
- List<Key> *keys, bool tmp_table,
- uint *db_options,
- handler *file, KEY **key_info_buffer,
- uint *key_count, int select_field_count);
+static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
+static bool
+mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ bool tmp_table,
+ uint *db_options,
+ handler *file, KEY **key_info_buffer,
+ uint *key_count, int select_field_count);
+static bool
+mysql_prepare_alter_table(THD *thd, TABLE *table,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info);
#define MYSQL50_TABLE_NAME_PREFIX "#mysql50#"
#define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9
@@ -183,8 +187,8 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db,
VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)));
VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff)));
- length= strxnmov(buff, bufflen, mysql_data_home, "/", dbbuff,
- "/", tbbuff, ext, NullS) - buff;
+ length= strxnmov(buff, bufflen, mysql_data_home, FN_ROOTDIR, dbbuff,
+ FN_ROOTDIR, tbbuff, ext, NullS) - buff;
DBUG_PRINT("exit", ("buff: '%s'", buff));
DBUG_RETURN(length);
}
@@ -210,125 +214,22 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db,
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
{
- uint length;
- char tmp_table_name[tmp_file_prefix_length+22+22+22+3];
DBUG_ENTER("build_tmptable_filename");
- my_snprintf(tmp_table_name, sizeof(tmp_table_name),
- "%s%lx_%lx_%x",
- tmp_file_prefix, current_pid,
- thd->thread_id, thd->tmp_table++);
-
- strxnmov(buff, bufflen, mysql_tmpdir, "/", tmp_table_name, reg_ext, NullS);
- length= unpack_filename(buff, buff);
- DBUG_PRINT("exit", ("buff: '%s'", buff));
- DBUG_RETURN(length);
-}
-
-/*
- Return values for compare_tables().
- If you make compare_tables() non-static, move them to a header file.
-*/
-#define ALTER_TABLE_DATA_CHANGED 1
-#define ALTER_TABLE_INDEX_CHANGED 2
-
-
-/*
- SYNOPSIS
- mysql_copy_create_list()
- orig_create_list Original list of created fields
- inout::new_create_list Copy of original list
-
- RETURN VALUES
- FALSE Success
- TRUE Memory allocation error
-
- DESCRIPTION
- mysql_prepare_table destroys the create_list and in some cases we need
- this lists for more purposes. Thus we copy it specifically for use
- by mysql_prepare_table
-*/
+ char *p= strnmov(buff, mysql_tmpdir, bufflen);
+ my_snprintf(p, bufflen - (p - buff), "/%s%lx_%lx_%x%s",
+ tmp_file_prefix, current_pid,
+ thd->thread_id, thd->tmp_table++, reg_ext);
-static int mysql_copy_create_list(List<create_field> *orig_create_list,
- List<create_field> *new_create_list)
-{
- List_iterator<create_field> prep_field_it(*orig_create_list);
- create_field *prep_field;
- DBUG_ENTER("mysql_copy_create_list");
-
- while ((prep_field= prep_field_it++))
+ if (lower_case_table_names)
{
- create_field *field= new create_field(*prep_field);
- if (!field || new_create_list->push_back(field))
- {
- mem_alloc_error(2);
- DBUG_RETURN(TRUE);
- }
+ /* Convert all except tmpdir to lower case */
+ my_casedn_str(files_charset_info, p);
}
- DBUG_RETURN(FALSE);
-}
-
-
-/*
- SYNOPSIS
- mysql_copy_key_list()
- orig_key Original list of keys
- inout::new_key Copy of original list
-
- RETURN VALUES
- FALSE Success
- TRUE Memory allocation error
-
- DESCRIPTION
- mysql_prepare_table destroys the key list and in some cases we need
- this lists for more purposes. Thus we copy it specifically for use
- by mysql_prepare_table
-*/
-
-static int mysql_copy_key_list(List<Key> *orig_key,
- List<Key> *new_key)
-{
- List_iterator<Key> prep_key_it(*orig_key);
- Key *prep_key;
- DBUG_ENTER("mysql_copy_key_list");
-
- while ((prep_key= prep_key_it++))
- {
- List<key_part_spec> prep_columns;
- List_iterator<key_part_spec> prep_col_it(prep_key->columns);
- key_part_spec *prep_col;
- Key *temp_key;
- while ((prep_col= prep_col_it++))
- {
- key_part_spec *prep_key_part;
-
- if (!(prep_key_part= new key_part_spec(*prep_col)))
- {
- mem_alloc_error(sizeof(key_part_spec));
- DBUG_RETURN(TRUE);
- }
- if (prep_columns.push_back(prep_key_part))
- {
- mem_alloc_error(2);
- DBUG_RETURN(TRUE);
- }
- }
- if (!(temp_key= new Key(prep_key->type, prep_key->name,
- &prep_key->key_create_info,
- prep_key->generated,
- prep_columns)))
- {
- mem_alloc_error(sizeof(Key));
- DBUG_RETURN(TRUE);
- }
- if (new_key->push_back(temp_key))
- {
- mem_alloc_error(2);
- DBUG_RETURN(TRUE);
- }
- }
- DBUG_RETURN(FALSE);
+ uint length= unpack_filename(buff, buff);
+ DBUG_PRINT("exit", ("buff: '%s'", buff));
+ DBUG_RETURN(length);
}
/*
@@ -407,11 +308,11 @@ static bool read_ddl_log_file_entry(uint entry_no)
{
bool error= FALSE;
File file_id= global_ddl_log.file_id;
- char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
+ uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
uint io_size= global_ddl_log.io_size;
DBUG_ENTER("read_ddl_log_file_entry");
- if (my_pread(file_id, (byte*)file_entry_buf, io_size, io_size * entry_no,
+ if (my_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
MYF(MY_WME)) != io_size)
error= TRUE;
DBUG_RETURN(error);
@@ -435,7 +336,7 @@ static bool write_ddl_log_file_entry(uint entry_no)
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
DBUG_ENTER("write_ddl_log_file_entry");
- if (my_pwrite(file_id, (byte*)file_entry_buf,
+ if (my_pwrite(file_id, (uchar*)file_entry_buf,
IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
error= TRUE;
DBUG_RETURN(error);
@@ -461,10 +362,10 @@ static bool write_ddl_log_header()
global_ddl_log.num_entries);
const_var= FN_LEN;
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
- const_var);
+ (ulong) const_var);
const_var= IO_SIZE;
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
- const_var);
+ (ulong) const_var);
if (write_ddl_log_file_entry(0UL))
{
sql_print_error("Error writing ddl log header");
@@ -599,7 +500,6 @@ bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
static bool init_ddl_log()
{
- bool error= FALSE;
char file_name[FN_REFLEN];
DBUG_ENTER("init_ddl_log");
@@ -649,7 +549,9 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
int error= TRUE;
char to_path[FN_REFLEN];
char from_path[FN_REFLEN];
+#ifdef WITH_PARTITION_STORAGE_ENGINE
char *par_ext= (char*)".par";
+#endif
handlerton *hton;
DBUG_ENTER("execute_ddl_log_action");
@@ -664,16 +566,14 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
frm_action= TRUE;
else
{
- TABLE_SHARE dummy;
-
- hton= ha_resolve_by_name(thd, &handler_name);
- if (!hton)
+ plugin_ref plugin= ha_resolve_by_name(thd, &handler_name);
+ if (!plugin)
{
my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name);
goto error;
}
- bzero(&dummy, sizeof(TABLE_SHARE));
- file= get_new_handler(&dummy, &mem_root, hton);
+ hton= plugin_data(plugin, handlerton*);
+ file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
if (!file)
{
mem_alloc_error(sizeof(handler));
@@ -1234,13 +1134,13 @@ void release_ddl_log()
while (used_list)
{
DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
- my_free((char*)used_list, MYF(0));
+ my_free(used_list, MYF(0));
used_list= tmp;
}
while (free_list)
{
DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
- my_free((char*)free_list, MYF(0));
+ my_free(free_list, MYF(0));
free_list= tmp;
}
close_ddl_log();
@@ -1306,19 +1206,14 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
if (flags & WFRM_WRITE_SHADOW)
{
- if (mysql_copy_create_list(lpt->create_list,
- &lpt->new_create_list) ||
- mysql_copy_key_list(lpt->key_list,
- &lpt->new_key_list) ||
- mysql_prepare_table(lpt->thd, lpt->create_info,
- &lpt->new_create_list,
- &lpt->new_key_list,
- /*tmp_table*/ 1,
- &lpt->db_options,
- lpt->table->file,
- &lpt->key_info_buffer,
- &lpt->key_count,
- /*select_field_count*/ 0))
+ if (mysql_prepare_create_table(lpt->thd, lpt->create_info,
+ lpt->alter_info,
+ /*tmp_table*/ 1,
+ &lpt->db_options,
+ lpt->table->file,
+ &lpt->key_info_buffer,
+ &lpt->key_count,
+ /*select_field_count*/ 0))
{
DBUG_RETURN(TRUE);
}
@@ -1345,7 +1240,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
lpt->create_info->table_options= lpt->db_options;
if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
lpt->table_name, lpt->create_info,
- lpt->new_create_list, lpt->key_count,
+ lpt->alter_info->create_list, lpt->key_count,
lpt->key_info_buffer, lpt->table->file)) ||
lpt->table->file->create_handler_files(shadow_path, NULL,
CHF_CREATE_FLAG,
@@ -1364,13 +1259,13 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
handlers that have the main version of the frm file stored in the
handler.
*/
- const void *data= 0;
- uint length= 0;
+ uchar *data;
+ size_t length;
if (readfrm(shadow_path, &data, &length) ||
packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
{
- my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)lpt->pack_frm_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(lpt->pack_frm_data, MYF(MY_ALLOW_ZERO_PTR));
mem_alloc_error(length);
error= 1;
goto end;
@@ -1637,7 +1532,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
TABLE_SHARE *share;
table->db_type= NULL;
if ((share= get_cached_table_share(table->db, table->table_name)))
- table->db_type= share->db_type;
+ table->db_type= share->db_type();
/* Disable drop of enabled log tables */
if (share && share->log_table &&
@@ -1924,22 +1819,25 @@ static int sort_keys(KEY *a, KEY *b)
set_or_name "SET" or "ENUM" string for warning message
name name of the checked column
typelib list of values for the column
+ dup_val_count returns count of duplicate elements
DESCRIPTION
This function prints an warning for each value in list
which has some duplicates on its right
RETURN VALUES
- void
+ 0 ok
+ 1 Error
*/
-void check_duplicates_in_interval(const char *set_or_name,
+bool check_duplicates_in_interval(const char *set_or_name,
const char *name, TYPELIB *typelib,
- CHARSET_INFO *cs)
+ CHARSET_INFO *cs, unsigned int *dup_val_count)
{
TYPELIB tmp= *typelib;
const char **cur_value= typelib->type_names;
unsigned int *cur_length= typelib->type_lengths;
+ *dup_val_count= 0;
for ( ; tmp.count > 1; cur_value++, cur_length++)
{
@@ -1948,12 +1846,21 @@ void check_duplicates_in_interval(const char *set_or_name,
tmp.count--;
if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
{
+ if ((current_thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
+ {
+ my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
+ name,*cur_value,set_or_name);
+ return 1;
+ }
push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_DUPLICATED_VALUE_IN_TYPE,
ER(ER_DUPLICATED_VALUE_IN_TYPE),
name,*cur_value,set_or_name);
+ (*dup_val_count)++;
}
}
+ return 0;
}
@@ -2015,19 +1922,20 @@ int prepare_create_field(create_field *sql_field,
int *timestamps, int *timestamps_with_niladic,
longlong table_flags)
{
+ unsigned int dup_val_count;
DBUG_ENTER("prepare_field");
/*
- This code came from mysql_prepare_table.
+ This code came from mysql_prepare_create_table.
Indent preserved to make patching easier
*/
DBUG_ASSERT(sql_field->charset);
switch (sql_field->sql_type) {
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
sql_field->pack_flag=FIELDFLAG_BLOB |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
@@ -2037,7 +1945,7 @@ int prepare_create_field(create_field *sql_field,
sql_field->unireg_check=Field::BLOB_FIELD;
(*blob_columns)++;
break;
- case FIELD_TYPE_GEOMETRY:
+ case MYSQL_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
if (!(table_flags & HA_CAN_GEOMETRY))
{
@@ -2077,44 +1985,53 @@ int prepare_create_field(create_field *sql_field,
}
#endif
/* fall through */
- case FIELD_TYPE_STRING:
+ case MYSQL_TYPE_STRING:
sql_field->pack_flag=0;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
break;
- case FIELD_TYPE_ENUM:
+ case MYSQL_TYPE_ENUM:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_INTERVAL;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::INTERVAL_FIELD;
- check_duplicates_in_interval("ENUM",sql_field->field_name,
- sql_field->interval,
- sql_field->charset);
+ if (check_duplicates_in_interval("ENUM",sql_field->field_name,
+ sql_field->interval,
+ sql_field->charset, &dup_val_count))
+ DBUG_RETURN(1);
break;
- case FIELD_TYPE_SET:
+ case MYSQL_TYPE_SET:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_BITFIELD;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::BIT_FIELD;
- check_duplicates_in_interval("SET",sql_field->field_name,
- sql_field->interval,
- sql_field->charset);
+ if (check_duplicates_in_interval("SET",sql_field->field_name,
+ sql_field->interval,
+ sql_field->charset, &dup_val_count))
+ DBUG_RETURN(1);
+ /* Check that count of unique members is not more then 64 */
+ if (sql_field->interval->count - dup_val_count > sizeof(longlong)*8)
+ {
+ my_error(ER_TOO_BIG_SET, MYF(0), sql_field->field_name);
+ DBUG_RETURN(1);
+ }
break;
- case FIELD_TYPE_DATE: // Rest of string types
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_NULL:
+ case MYSQL_TYPE_DATE: // Rest of string types
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
- case FIELD_TYPE_BIT:
+ case MYSQL_TYPE_BIT:
/*
- We have sql_field->pack_flag already set here, see mysql_prepare_table().
+ We have sql_field->pack_flag already set here, see
+ mysql_prepare_create_table().
*/
break;
- case FIELD_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
(sql_field->flags & UNSIGNED_FLAG ? 0 :
FIELDFLAG_DECIMAL) |
@@ -2122,7 +2039,7 @@ int prepare_create_field(create_field *sql_field,
FIELDFLAG_ZEROFILL : 0) |
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
- case FIELD_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP:
/* We should replace old TIMESTAMP fields with their newer analogs */
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
{
@@ -2160,11 +2077,10 @@ int prepare_create_field(create_field *sql_field,
Preparation for table creation
SYNOPSIS
- mysql_prepare_table()
+ mysql_prepare_create_table()
thd Thread object.
create_info Create information (like MAX_ROWS).
- fields List of fields to create.
- keys List of keys to create.
+ alter_info List of columns and indexes to create
tmp_table If a temporary table is to be created.
db_options INOUT Table options (like HA_OPTION_PACK_RECORD).
file The handler for the new table.
@@ -2179,16 +2095,17 @@ int prepare_create_field(create_field *sql_field,
sets create_info->varchar if the table has a varchar
RETURN VALUES
- 0 ok
- -1 error
+ FALSE OK
+ TRUE error
*/
-static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
- List<create_field> *fields,
- List<Key> *keys, bool tmp_table,
- uint *db_options,
- handler *file, KEY **key_info_buffer,
- uint *key_count, int select_field_count)
+static bool
+mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ bool tmp_table,
+ uint *db_options,
+ handler *file, KEY **key_info_buffer,
+ uint *key_count, int select_field_count)
{
const char *key_name;
create_field *sql_field,*dup_field;
@@ -2199,11 +2116,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
- List_iterator<create_field> it(*fields),it2(*fields);
+ List_iterator<create_field> it(alter_info->create_list);
+ List_iterator<create_field> it2(alter_info->create_list);
uint total_uneven_bit_length= 0;
- DBUG_ENTER("mysql_prepare_table");
+ DBUG_ENTER("mysql_prepare_create_table");
- select_field_pos= fields->elements - select_field_count;
+ select_field_pos= alter_info->create_list.elements - select_field_count;
null_fields=blob_columns=0;
create_info->varchar= 0;
max_key_length= file->max_key_length();
@@ -2238,7 +2156,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
STRING_WITH_LEN("_bin"));
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/*
@@ -2247,36 +2165,33 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
*/
if (sql_field->def &&
save_cs != sql_field->def->collation.collation &&
- (sql_field->sql_type == FIELD_TYPE_VAR_STRING ||
- sql_field->sql_type == FIELD_TYPE_STRING ||
- sql_field->sql_type == FIELD_TYPE_SET ||
- sql_field->sql_type == FIELD_TYPE_ENUM))
- {
- Query_arena backup_arena;
- bool need_to_change_arena= !thd->stmt_arena->is_conventional();
- if (need_to_change_arena)
- {
- /* Asser that we don't do that at every PS execute */
- DBUG_ASSERT(thd->stmt_arena->is_first_stmt_execute() ||
- thd->stmt_arena->is_first_sp_execute());
- thd->set_n_backup_active_arena(thd->stmt_arena, &backup_arena);
- }
-
+ (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
+ sql_field->sql_type == MYSQL_TYPE_STRING ||
+ sql_field->sql_type == MYSQL_TYPE_SET ||
+ sql_field->sql_type == MYSQL_TYPE_ENUM))
+ {
+ /*
+ Starting from 5.1 we work here with a copy of create_field
+ created by the caller, not with the instance that was
+ originally created during parsing. It's OK to create
+ a temporary item and initialize with it a member of the
+ copy -- this item will be thrown away along with the copy
+ at the end of execution, and thus not introduce a dangling
+ pointer in the parsed tree of a prepared statement or a
+ stored procedure statement.
+ */
sql_field->def= sql_field->def->safe_charset_converter(save_cs);
- if (need_to_change_arena)
- thd->restore_active_arena(thd->stmt_arena, &backup_arena);
-
if (sql_field->def == NULL)
{
/* Could not convert */
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
- if (sql_field->sql_type == FIELD_TYPE_SET ||
- sql_field->sql_type == FIELD_TYPE_ENUM)
+ if (sql_field->sql_type == MYSQL_TYPE_SET ||
+ sql_field->sql_type == MYSQL_TYPE_ENUM)
{
uint32 dummy;
CHARSET_INFO *cs= sql_field->charset;
@@ -2290,21 +2205,20 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!interval)
{
/*
- Create the typelib in prepared statement memory if we're
- executing one.
+ Create the typelib in runtime memory - we will free the
+ occupied memory at the same time when we free this
+ sql_field -- at the end of execution.
*/
- MEM_ROOT *stmt_root= thd->stmt_arena->mem_root;
-
- interval= sql_field->interval= typelib(stmt_root,
+ interval= sql_field->interval= typelib(thd->mem_root,
sql_field->interval_list);
- List_iterator<String> it(sql_field->interval_list);
+ List_iterator<String> int_it(sql_field->interval_list);
String conv, *tmp;
char comma_buf[2];
int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
(uchar*) comma_buf +
sizeof(comma_buf));
DBUG_ASSERT(comma_length > 0);
- for (uint i= 0; (tmp= it++); i++)
+ for (uint i= 0; (tmp= int_it++); i++)
{
uint lengthsp;
if (String::needs_conversion(tmp->length(), tmp->charset(),
@@ -2312,7 +2226,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
uint cnv_errs;
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
- interval->type_names[i]= strmake_root(stmt_root, conv.ptr(),
+ interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
conv.length());
interval->type_lengths[i]= conv.length();
}
@@ -2322,21 +2236,21 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
interval->type_lengths[i]);
interval->type_lengths[i]= lengthsp;
((uchar *)interval->type_names[i])[lengthsp]= '\0';
- if (sql_field->sql_type == FIELD_TYPE_SET)
+ if (sql_field->sql_type == MYSQL_TYPE_SET)
{
if (cs->coll->instr(cs, interval->type_names[i],
interval->type_lengths[i],
comma_buf, comma_length, NULL, 0))
{
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", tmp->ptr());
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
sql_field->interval_list.empty(); // Don't need interval_list anymore
}
- if (sql_field->sql_type == FIELD_TYPE_SET)
+ if (sql_field->sql_type == MYSQL_TYPE_SET)
{
uint32 field_length;
if (sql_field->def != NULL)
@@ -2350,7 +2264,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
{
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* else, NULL is an allowed value */
@@ -2366,16 +2280,16 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (not_found)
{
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
calculate_interval_lengths(cs, interval, &dummy, &field_length);
sql_field->length= field_length + (interval->count - 1);
}
- else /* FIELD_TYPE_ENUM */
+ else /* MYSQL_TYPE_ENUM */
{
uint32 field_length;
- DBUG_ASSERT(sql_field->sql_type == FIELD_TYPE_ENUM);
+ DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
if (sql_field->def != NULL)
{
String str, *def= sql_field->def->val_str(&str);
@@ -2384,7 +2298,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
{
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* else, the defaults yield the correct length for NULLs. */
@@ -2395,7 +2309,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
{
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -2405,7 +2319,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
}
- if (sql_field->sql_type == FIELD_TYPE_BIT)
+ if (sql_field->sql_type == MYSQL_TYPE_BIT)
{
sql_field->pack_flag= FIELDFLAG_NUMBER;
if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
@@ -2416,7 +2330,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->create_length_to_internal_length();
if (prepare_blob_field(thd, sql_field))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
@@ -2424,7 +2338,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (check_column_name(sql_field->field_name))
{
my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* Check if we have used the same field name before */
@@ -2441,7 +2355,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (field_no < select_field_pos || dup_no >= select_field_pos)
{
my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
else
{
@@ -2492,9 +2406,9 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (prepare_create_field(sql_field, &blob_columns,
&timestamps, &timestamps_with_niladic,
file->ha_table_flags()))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
- create_info->varchar= 1;
+ create_info->varchar= TRUE;
sql_field->offset= record_offset;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
@@ -2504,31 +2418,32 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (auto_increment > 1)
{
my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (auto_increment &&
(file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
{
my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
{
my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* Create keys */
- List_iterator<Key> key_iterator(*keys), key_iterator2(*keys);
+ List_iterator<Key> key_iterator(alter_info->key_list);
+ List_iterator<Key> key_iterator2(alter_info->key_list);
uint key_parts=0, fk_key_count=0;
bool primary_key=0,unique_key=0;
Key *key, *key2;
@@ -2543,6 +2458,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
DBUG_PRINT("info", ("key name: '%s' type: %d", key->name ? key->name :
"(none)" , key->type));
+ LEX_STRING key_name_str;
if (key->type == Key::FOREIGN_KEY)
{
fk_key_count++;
@@ -2553,7 +2469,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_WRONG_FK_DEF, MYF(0),
(fk_key->name ? fk_key->name : "foreign key without name"),
ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
continue;
}
@@ -2562,12 +2478,15 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->columns.elements > tmp)
{
my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
- if (key->name && strlen(key->name) > NAME_LEN)
+ key_name_str.str= (char*) key->name;
+ key_name_str.length= key->name ? strlen(key->name) : 0;
+ if (check_string_char_length(&key_name_str, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
{
my_error(ER_TOO_LONG_IDENT, MYF(0), key->name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
key_iterator2.rewind ();
if (key->type != Key::FOREIGN_KEY)
@@ -2607,20 +2526,20 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
!my_strcasecmp(system_charset_info,key->name,primary_key_name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
tmp=file->max_keys();
if (*key_count > tmp)
{
my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
(*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
if (!*key_info_buffer || ! key_part_info)
- DBUG_RETURN(-1); // Out of memory
+ DBUG_RETURN(TRUE); // Out of memory
key_iterator.rewind();
key_number=0;
@@ -2657,7 +2576,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
#endif
case Key::FOREIGN_KEY:
key_number--; // Skip this key
@@ -2680,7 +2599,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
/*
@@ -2698,12 +2617,12 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (key_info->key_parts != 1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
else if (key_info->algorithm == HA_KEY_ALG_RTREE)
@@ -2712,15 +2631,15 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if ((key_info->key_parts & 1) == 1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* TODO: To be deleted */
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_rtree.name, sym_group_rtree.needed_define);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
#endif
}
@@ -2753,7 +2672,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!sql_field)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
while ((dup_column= cols2++) != column)
{
@@ -2763,7 +2682,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
my_printf_error(ER_DUP_FIELDNAME,
ER(ER_DUP_FIELDNAME),MYF(0),
column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
cols2.rewind();
@@ -2793,13 +2712,19 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
column->length*= sql_field->charset->mbmaxlen;
+ if (key->type == Key::SPATIAL && column->length)
+ {
+ my_error(ER_WRONG_SUB_KEY, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
if (f_is_blob(sql_field->pack_flag) ||
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
{
if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
{
my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
Field::GEOM_POINT)
@@ -2807,7 +2732,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!column->length)
{
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
#ifdef HAVE_SPATIAL
@@ -2838,13 +2763,13 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
{
my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (key->type == Key::SPATIAL)
{
my_message(ER_SPATIAL_CANT_HAVE_NULL,
ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
@@ -2880,19 +2805,20 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
else
{
my_error(ER_TOO_LONG_KEY,MYF(0),length);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
}
else if (!f_is_geom(sql_field->pack_flag) &&
(column->length > length ||
+ !Field::type_can_have_key_part (sql_field->sql_type) ||
((f_is_packed(sql_field->pack_flag) ||
((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
column->length != length)))
{
my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
length=column->length;
@@ -2900,7 +2826,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
else if (length == 0)
{
my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
{
@@ -2919,7 +2845,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
else
{
my_error(ER_TOO_LONG_KEY,MYF(0),length);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
}
key_part_info->length=(uint16) length;
@@ -2948,7 +2874,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
key_name=primary_key_name;
primary_key=1;
@@ -2959,7 +2885,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
{
my_error(ER_DUP_KEYNAME, MYF(0), key_name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
key_info->name=(char*) key_name;
}
@@ -2967,7 +2893,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (!key_info->name || check_column_name(key_info->name))
{
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (!(key_info->flags & HA_NULL_PART_KEY))
unique_key=1;
@@ -2975,7 +2901,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
if (key_length > max_key_length && key->type != Key::FULLTEXT)
{
my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
key_info++;
}
@@ -2983,19 +2909,19 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
(file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
{
my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
if (auto_increment > 0)
{
my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
/* Sort keys in optimized order */
- qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
+ qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
(qsort_cmp) sort_keys);
create_info->null_bits= null_fields;
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -3061,7 +2987,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen);
DBUG_RETURN(1);
}
- sql_field->sql_type= FIELD_TYPE_BLOB;
+ sql_field->sql_type= MYSQL_TYPE_BLOB;
sql_field->flags|= BLOB_FLAG;
sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
(sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
@@ -3072,7 +2998,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
{
- if (sql_field->sql_type == FIELD_TYPE_BLOB)
+ if (sql_field->sql_type == MYSQL_TYPE_BLOB)
{
/* The user has given a length to the blob column */
sql_field->sql_type= get_blob_type_from_length(sql_field->length);
@@ -3086,7 +3012,8 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
/*
Preparation of create_field for SP function return values.
- Based on code used in the inner loop of mysql_prepare_table() above
+ Based on code used in the inner loop of mysql_prepare_create_table()
+ above.
SYNOPSIS
sp_prepare_create_field()
@@ -3100,11 +3027,11 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
void sp_prepare_create_field(THD *thd, create_field *sql_field)
{
- if (sql_field->sql_type == FIELD_TYPE_SET ||
- sql_field->sql_type == FIELD_TYPE_ENUM)
+ if (sql_field->sql_type == MYSQL_TYPE_SET ||
+ sql_field->sql_type == MYSQL_TYPE_ENUM)
{
uint32 field_length, dummy;
- if (sql_field->sql_type == FIELD_TYPE_SET)
+ if (sql_field->sql_type == MYSQL_TYPE_SET)
{
calculate_interval_lengths(sql_field->charset,
sql_field->interval, &dummy,
@@ -3112,7 +3039,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
sql_field->length= field_length +
(sql_field->interval->count - 1);
}
- else /* FIELD_TYPE_ENUM */
+ else /* MYSQL_TYPE_ENUM */
{
calculate_interval_lengths(sql_field->charset,
sql_field->interval,
@@ -3122,7 +3049,7 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
}
- if (sql_field->sql_type == FIELD_TYPE_BIT)
+ if (sql_field->sql_type == MYSQL_TYPE_BIT)
{
sql_field->pack_flag= FIELDFLAG_NUMBER |
FIELDFLAG_TREAT_BIT_AS_CHAR;
@@ -3135,51 +3062,28 @@ void sp_prepare_create_field(THD *thd, create_field *sql_field)
/*
- Copy HA_CREATE_INFO struct
- SYNOPSIS
- copy_create_info()
- lex_create_info The create_info struct setup by parser
- RETURN VALUES
- > 0 A pointer to a copy of the lex_create_info
- 0 Memory allocation error
- DESCRIPTION
- Allocate memory for copy of HA_CREATE_INFO structure from parser
- to ensure we can reuse the parser struct in stored procedures
- and prepared statements.
-*/
-
-static HA_CREATE_INFO *copy_create_info(HA_CREATE_INFO *lex_create_info)
-{
- HA_CREATE_INFO *create_info;
- if (!(create_info= (HA_CREATE_INFO*)sql_alloc(sizeof(HA_CREATE_INFO))))
- mem_alloc_error(sizeof(HA_CREATE_INFO));
- else
- memcpy((void*)create_info, (void*)lex_create_info, sizeof(HA_CREATE_INFO));
- return create_info;
-}
-
-
-/*
Create a table
SYNOPSIS
- mysql_create_table_internal()
+ mysql_create_table_no_lock()
thd Thread object
db Database
table_name Table name
- lex_create_info Create information (like MAX_ROWS)
+ create_info Create information (like MAX_ROWS)
fields List of fields to create
keys List of keys to create
internal_tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
- select_field_count
- use_copy_create_info Should we make a copy of create info (we do this
- when this is called from sql_parse.cc where we
- want to ensure lex object isn't manipulated.
+ select_field_count
DESCRIPTION
If one creates a temporary table, this is automatically opened
+ Note that this function assumes that caller already have taken
+ name-lock on table being created or used some other way to ensure
+ that concurrent operations won't intervene. mysql_create_table()
+ is a wrapper that can be used for this.
+
no_log is needed for the case of CREATE ... SELECT,
as the logging will be done later in sql_insert.cc
select_field_count is also used for CREATE ... SELECT,
@@ -3190,38 +3094,27 @@ static HA_CREATE_INFO *copy_create_info(HA_CREATE_INFO *lex_create_info)
TRUE error
*/
-bool mysql_create_table_internal(THD *thd,
+bool mysql_create_table_no_lock(THD *thd,
const char *db, const char *table_name,
- HA_CREATE_INFO *lex_create_info,
- List<create_field> &fields,
- List<Key> &keys,bool internal_tmp_table,
- uint select_field_count,
- bool use_copy_create_info)
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ bool internal_tmp_table,
+ uint select_field_count)
{
char path[FN_REFLEN];
uint path_length;
const char *alias;
uint db_options, key_count;
KEY *key_info_buffer;
- HA_CREATE_INFO *create_info;
handler *file;
bool error= TRUE;
- DBUG_ENTER("mysql_create_table_internal");
+ DBUG_ENTER("mysql_create_table_no_lock");
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
db, table_name, internal_tmp_table));
- if (use_copy_create_info)
- {
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
- }
- else
- create_info= lex_create_info;
-
+
/* Check for duplicate fields and check type of table to create */
- if (!fields.elements)
+ if (!alter_info->create_list.elements)
{
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
MYF(0));
@@ -3273,7 +3166,7 @@ bool mysql_create_table_internal(THD *thd,
Check that we don't use foreign keys in the table since it won't
work even with InnoDB beneath it.
*/
- List_iterator<Key> key_iterator(keys);
+ List_iterator<Key> key_iterator(alter_info->key_list);
Key *key;
handlerton *part_engine_type= create_info->db_type;
char *part_syntax_buf;
@@ -3400,34 +3293,28 @@ bool mysql_create_table_internal(THD *thd,
set_table_default_charset(thd, create_info, (char*) db);
- if (mysql_prepare_table(thd, create_info, &fields,
- &keys, internal_tmp_table, &db_options, file,
- &key_info_buffer, &key_count,
- select_field_count))
+ if (mysql_prepare_create_table(thd, create_info, alter_info,
+ internal_tmp_table,
+ &db_options, file,
+ &key_info_buffer, &key_count,
+ select_field_count))
goto err;
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
path_length= build_tmptable_filename(thd, path, sizeof(path));
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, path);
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
}
else
{
#ifdef FN_DEVCHAR
/* check if the table name contains FN_DEVCHAR when defined */
- const char *start= alias;
- while (*start != '\0')
+ if (strchr(alias, FN_DEVCHAR))
{
- if (*start == FN_DEVCHAR)
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
- DBUG_RETURN(TRUE);
- }
- start++;
- }
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
+ DBUG_RETURN(TRUE);
+ }
#endif
path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
internal_tmp_table ? FN_IS_TMP : 0);
@@ -3488,14 +3375,25 @@ bool mysql_create_table_internal(THD *thd,
{
bool create_if_not_exists =
create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
- if (ha_table_exists_in_engine(thd, db, table_name))
+ int retcode = ha_table_exists_in_engine(thd, db, table_name);
+ DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
+ switch (retcode)
{
- DBUG_PRINT("info", ("Table with same name already existed in handler"));
+ case HA_ERR_NO_SUCH_TABLE:
+ /* Normal case, no table exists. we can go and create it */
+ break;
+ case HA_ERR_TABLE_EXIST:
+ DBUG_PRINT("info", ("Table existed in handler"));
- if (create_if_not_exists)
- goto warn;
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto unlock_and_end;
+ if (create_if_not_exists)
+ goto warn;
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ goto unlock_and_end;
+ break;
+ default:
+ DBUG_PRINT("info", ("error: %u from storage engine", retcode));
+ my_error(retcode, MYF(0),table_name);
+ goto unlock_and_end;
}
}
@@ -3507,7 +3405,8 @@ bool mysql_create_table_internal(THD *thd,
create_info->table_options=db_options;
path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
- if (rea_create_table(thd, path, db, table_name, create_info, fields,
+ if (rea_create_table(thd, path, db, table_name,
+ create_info, alter_info->create_list,
key_count, key_info_buffer, file))
goto unlock_and_end;
@@ -3554,23 +3453,23 @@ warn:
/*
- Database locking aware wrapper for mysql_create_table_internal(),
+ Database and name-locking aware wrapper for mysql_create_table_no_lock(),
*/
bool mysql_create_table(THD *thd, const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
- List<create_field> &fields,
- List<Key> &keys,bool internal_tmp_table,
- uint select_field_count,
- bool use_copy_create_info)
+ Alter_info *alter_info,
+ bool internal_tmp_table,
+ uint select_field_count)
{
+ TABLE *name_lock= 0;
bool result;
DBUG_ENTER("mysql_create_table");
/* Wait for any database locks */
pthread_mutex_lock(&LOCK_lock_db);
while (!thd->killed &&
- hash_search(&lock_db_cache,(byte*) db, strlen(db)))
+ hash_search(&lock_db_cache,(uchar*) db, strlen(db)))
{
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
pthread_mutex_lock(&LOCK_lock_db);
@@ -3584,11 +3483,44 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name,
creating_table++;
pthread_mutex_unlock(&LOCK_lock_db);
- result= mysql_create_table_internal(thd, db, table_name, create_info,
- fields, keys, internal_tmp_table,
- select_field_count,
- use_copy_create_info);
+ if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ {
+ if (lock_table_name_if_not_cached(thd, db, table_name, &name_lock))
+ {
+ result= TRUE;
+ goto unlock;
+ }
+ if (!name_lock)
+ {
+ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
+ table_name);
+ create_info->table_existed= 1;
+ result= FALSE;
+ }
+ else
+ {
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ result= TRUE;
+ }
+ goto unlock;
+ }
+ }
+
+ result= mysql_create_table_no_lock(thd, db, table_name, create_info,
+ alter_info,
+ internal_tmp_table,
+ select_field_count);
+unlock:
+ if (name_lock)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ unlink_open_table(thd, name_lock, FALSE);
+ pthread_mutex_unlock(&LOCK_open);
+ }
pthread_mutex_lock(&LOCK_lock_db);
if (!--creating_table && creating_database)
pthread_cond_signal(&COND_refresh);
@@ -3791,7 +3723,7 @@ void close_cached_table(THD *thd, TABLE *table)
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);
+ unlink_open_table(thd, table, TRUE);
/* When lock on LOCK_open is freed other threads can continue */
broadcast_refresh();
@@ -3867,7 +3799,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
to finish the restore in the handler later on
*/
pthread_mutex_lock(&LOCK_open);
- if (reopen_name_locked_table(thd, table))
+ if (reopen_name_locked_table(thd, table, TRUE))
{
unlock_table_name(thd, table);
pthread_mutex_unlock(&LOCK_open);
@@ -3938,7 +3870,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
/*
Check if this is a table type that stores index and data separately,
- like ISAM or MyISAM
+ like ISAM or MyISAM. We assume fixed order of engine file name
+ extentions array. First element of engine file name extentions array
+ is meta/index file extention. Second element - data file extention.
*/
ext= table->file->bas_ext();
if (!ext[0] || !ext[1])
@@ -3997,7 +3931,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
to finish the repair in the handler later on.
*/
pthread_mutex_lock(&LOCK_open);
- if (reopen_name_locked_table(thd, table_list))
+ if (reopen_name_locked_table(thd, table_list, TRUE))
{
unlock_table_name(thd, table_list);
pthread_mutex_unlock(&LOCK_open);
@@ -4038,7 +3972,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT *),
int (view_operator_func)(THD *, TABLE_LIST*))
{
- TABLE_LIST *table, *save_next_global, *save_next_local;
+ TABLE_LIST *table;
SELECT_LEX *select= &thd->lex->select_lex;
List<Item> field_list;
Item *item;
@@ -4049,7 +3983,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (end_active_trans(thd))
DBUG_RETURN(1);
- field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
+ field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN*2));
item->maybe_null = 1;
field_list.push_back(item = new Item_empty_string("Op", 10));
item->maybe_null = 1;
@@ -4072,46 +4006,48 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
thd->open_options|= extra_open_options;
table->lock_type= lock_type;
/* open only one table from local list of command */
- save_next_global= table->next_global;
- table->next_global= 0;
- save_next_local= table->next_local;
- table->next_local= 0;
- select->table_list.first= (byte*)table;
- /*
- Time zone tables and SP tables can be add to lex->query_tables list,
- so it have to be prepared.
- TODO: Investigate if we can put extra tables into argument instead of
- using lex->query_tables
- */
- lex->query_tables= table;
- lex->query_tables_last= &table->next_global;
- lex->query_tables_own_last= 0;
- thd->no_warnings_for_error= no_warnings_for_error;
- if (view_operator_func == NULL)
- table->required_type=FRMTYPE_TABLE;
-
- /*
- If we want to perform an admin operation on the log table
- (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable
- log tables
- */
-
- if (check_if_log_table(table->db_length, table->db,
- table->table_name_length,
- table->table_name, 1) &&
- lock_type >= TL_READ_NO_INSERT)
{
- disable_logs= 1;
- logger.lock();
- logger.tmp_close_log_tables(thd);
- }
+ TABLE_LIST *save_next_global, *save_next_local;
+ save_next_global= table->next_global;
+ table->next_global= 0;
+ save_next_local= table->next_local;
+ table->next_local= 0;
+ select->table_list.first= (uchar*)table;
+ /*
+ Time zone tables and SP tables can be add to lex->query_tables list,
+ so it have to be prepared.
+ TODO: Investigate if we can put extra tables into argument instead of
+ using lex->query_tables
+ */
+ lex->query_tables= table;
+ lex->query_tables_last= &table->next_global;
+ lex->query_tables_own_last= 0;
+ thd->no_warnings_for_error= no_warnings_for_error;
+ if (view_operator_func == NULL)
+ table->required_type=FRMTYPE_TABLE;
- open_and_lock_tables(thd, table);
- thd->no_warnings_for_error= 0;
- table->next_global= save_next_global;
- table->next_local= save_next_local;
- thd->open_options&= ~extra_open_options;
+ /*
+ If we want to perform an admin operation on the log table
+ (E.g. rename) and lock_type >= TL_READ_NO_INSERT disable
+ log tables
+ */
+
+ if (check_if_log_table(table->db_length, table->db,
+ table->table_name_length,
+ table->table_name, 1) &&
+ lock_type >= TL_READ_NO_INSERT)
+ {
+ disable_logs= 1;
+ logger.lock();
+ logger.tmp_close_log_tables(thd);
+ }
+ open_and_lock_tables(thd, table);
+ thd->no_warnings_for_error= 0;
+ table->next_global= save_next_global;
+ table->next_local= save_next_local;
+ thd->open_options&= ~extra_open_options;
+ }
if (prepare_func)
{
switch ((*prepare_func)(thd, table, check_opt)) {
@@ -4230,10 +4166,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
(table->table->file->ha_check_for_upgrade(check_opt) ==
HA_ADMIN_NEEDS_ALTER))
{
+ my_bool save_no_send_ok= thd->net.no_send_ok;
ha_autocommit_or_rollback(thd, 1);
close_thread_tables(thd);
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table, 0);
+ thd->net.no_send_ok= TRUE;
+ result_code= mysql_recreate_table(thd, table);
+ thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
goto send_result;
}
@@ -4312,6 +4251,7 @@ send_result_message:
case HA_ADMIN_TRY_ALTER:
{
+ my_bool save_no_send_ok= thd->net.no_send_ok;
/*
This is currently used only by InnoDB. ha_innobase::optimize() answers
"try with alter", so here we close the table, do an ALTER TABLE,
@@ -4323,7 +4263,9 @@ send_result_message:
*save_next_global= table->next_global;
table->next_local= table->next_global= 0;
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
- result_code= mysql_recreate_table(thd, table, 0);
+ thd->net.no_send_ok= TRUE;
+ result_code= mysql_recreate_table(thd, table);
+ thd->net.no_send_ok= save_no_send_ok;
reenable_binlog(thd);
ha_autocommit_or_rollback(thd, 0);
close_thread_tables(thd);
@@ -4576,8 +4518,13 @@ int reassign_keycache_tables(THD *thd, KEY_CACHE *src_cache,
bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
{
DBUG_ENTER("mysql_preload_keys");
+ /*
+ We cannot allow concurrent inserts. The storage engine reads
+ directly from the index file, bypassing the cache. It could read
+ outdated information if parallel inserts into cache blocks happen.
+ */
DBUG_RETURN(mysql_admin_table(thd, tables, 0,
- "preload_keys", TL_READ, 0, 0, 0, 0,
+ "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
&handler::preload_keys, 0));
}
@@ -4588,144 +4535,110 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
SYNOPSIS
mysql_create_like_table()
thd Thread object
- table Table list (one table only)
+ table Table list element for target table
+ src_table Table list element for source table
create_info Create info
- table_ident Src table_ident
RETURN VALUES
FALSE OK
TRUE error
*/
-bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
- HA_CREATE_INFO *lex_create_info,
- Table_ident *table_ident)
+bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
+ HA_CREATE_INFO *create_info)
{
- TABLE *tmp_table;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN], tmp_path[FN_REFLEN];
- char src_table_name_buff[FN_REFLEN], src_db_name_buff[FN_REFLEN];
+ TABLE *name_lock= 0;
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN];
uint dst_path_length;
char *db= table->db;
char *table_name= table->table_name;
- char *src_db;
- char *src_table= table_ident->table.str;
int err;
- bool res= TRUE, unlock_dst_table= FALSE;
- enum legacy_db_type not_used;
- HA_CREATE_INFO *create_info;
-
- TABLE_LIST src_tables_list, dst_tables_list;
+ bool res= TRUE;
+ uint not_used;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ char tmp_path[FN_REFLEN];
+#endif
+ char ts_name[FN_LEN];
DBUG_ENTER("mysql_create_like_table");
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
- DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
- src_db= table_ident->db.str;
+
+ /* CREATE TABLE ... LIKE is not allowed for views. */
+ src_table->required_type= FRMTYPE_TABLE;
/*
- Validate the source table
+ By opening source table we guarantee that it exists and no concurrent
+ DDL operation will mess with it. Later we also take an exclusive
+ name-lock on target table name, which makes copying of .frm file,
+ call to ha_create_table() and binlogging atomic against concurrent DML
+ and DDL operations on target table. Thus by holding both these "locks"
+ we ensure that our statement is properly isolated from all concurrent
+ operations which matter.
*/
- if (table_ident->table.length > NAME_LEN ||
- (table_ident->table.length &&
- check_table_name(src_table,table_ident->table.length)))
- {
- my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
+ if (open_tables(thd, &src_table, &not_used, 0))
DBUG_RETURN(TRUE);
- }
- if (!src_db || check_db_name(&table_ident->db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL");
- DBUG_RETURN(-1);
- }
- if ((tmp_table= find_temporary_table(thd, src_db, src_table)))
- strxmov(src_path, tmp_table->s->path.str, reg_ext, NullS);
- else
- {
- build_table_filename(src_path, sizeof(src_path),
- src_db, src_table, reg_ext, 0);
- /* Resolve symlinks (for windows) */
- unpack_filename(src_path, src_path);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, src_path);
- if (access(src_path, F_OK))
- {
- my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table);
- goto err;
- }
- }
-
- /*
- create like should be not allowed for Views, Triggers, ...
+ /*
+ For bug#25875, Newly created table through CREATE TABLE .. LIKE
+ has no ndb_dd attributes;
+ Add something to get possible tablespace info from src table,
+ it can get valid tablespace name only for disk-base ndb table
*/
- if (mysql_frm_type(thd, src_path, &not_used) != FRMTYPE_TABLE)
+ if ((src_table->table->file->get_tablespace_name(thd, ts_name, FN_LEN)))
{
- my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE");
- goto err;
+ create_info->tablespace= ts_name;
+ create_info->storage_media= HA_SM_DISK;
}
- if (lower_case_table_names)
- {
- if (src_db)
- {
- strmake(src_db_name_buff, src_db,
- min(sizeof(src_db_name_buff) - 1, table_ident->db.length));
- my_casedn_str(files_charset_info, src_db_name_buff);
- src_db= src_db_name_buff;
- }
- if (src_table)
- {
- strmake(src_table_name_buff, src_table,
- min(sizeof(src_table_name_buff) - 1, table_ident->table.length));
- my_casedn_str(files_charset_info, src_table_name_buff);
- src_table= src_table_name_buff;
- }
- }
-
- bzero((gptr)&src_tables_list, sizeof(src_tables_list));
- src_tables_list.db= src_db;
- src_tables_list.db_length= table_ident->db.length;
- src_tables_list.lock_type= TL_READ;
- src_tables_list.table_name= src_table;
- src_tables_list.alias= src_table;
+ strxmov(src_path, src_table->table->s->path.str, reg_ext, NullS);
- if (simple_open_n_lock_tables(thd, &src_tables_list))
- DBUG_RETURN(TRUE);
+ DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
/*
- Validate the destination table
-
- skip the destination table name checking as this is already
- validated.
+ Check that destination tables does not exist. Note that its name
+ was already checked when it was added to the table list.
*/
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
if (find_temporary_table(thd, db, table_name))
goto table_exists;
dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path));
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, dst_path);
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
}
else
{
+ if (lock_table_name_if_not_cached(thd, db, table_name, &name_lock))
+ goto err;
+ if (!name_lock)
+ goto table_exists;
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
db, table_name, reg_ext, 0);
if (!access(dst_path, F_OK))
goto table_exists;
}
+ DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
+
/*
Create a new table by copying from source table
+
+ Altough exclusive name-lock on target table protects us from concurrent
+ DML and DDL operations on it we still want to wrap .FRM creation and call
+ to ha_create_table() in critical section protected by LOCK_open in order
+ to provide minimal atomicity against operations which disregard name-locks,
+ like I_S implementation, for example. This is a temporary and should not
+ be copied. Instead we should fix our code to always honor name-locks.
+
+ Also some engines (e.g. NDB cluster) require that LOCK_open should be held
+ during the call to ha_create_table(). See bug #28614 for more info.
*/
+ VOID(pthread_mutex_lock(&LOCK_open));
if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
{
if (my_errno == ENOENT)
my_error(ER_BAD_DB_ERROR,MYF(0),db);
else
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
+ VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
@@ -4747,10 +4660,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
strmov(src_path, tmp_path);
my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE));
#endif
+
+ DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
+
dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
- pthread_mutex_lock(&LOCK_open);
err= ha_create_table(thd, dst_path, db, table_name, create_info, 1);
- pthread_mutex_unlock(&LOCK_open);
+ VOID(pthread_mutex_unlock(&LOCK_open));
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
if (err || !open_temporary_table(thd, dst_path, db, table_name, 1))
@@ -4767,6 +4682,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
goto err; /* purecov: inspected */
}
+ DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000););
+
/*
We have to write the query before we unlock the tables.
*/
@@ -4786,42 +4703,32 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
3 temporary normal Nothing
4 temporary temporary Nothing
==== ========= ========= ==============================
-
- The variable 'tmp_table' below is used to see if the source
- table is a temporary table: if it is set, then the source table
- was a temporary table and we can take apropriate actions.
*/
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
- if (tmp_table) // Case 2
+ if (src_table->table->s->tmp_table) // Case 2
{
char buf[2048];
String query(buf, sizeof(buf), system_charset_info);
query.length(0); // Have to zero it since constructor doesn't
- uint counter;
-
- /*
- Here we open the destination table. This is needed for
- store_create_info() to work. The table will be closed
- by close_thread_tables() at the end of the statement.
- */
- if (open_tables(thd, &table, &counter, 0))
- goto err;
-
- bzero((gptr)&dst_tables_list, sizeof(dst_tables_list));
- dst_tables_list.db= table->db;
- dst_tables_list.table_name= table->table_name;
/*
- lock destination table name, to make sure that nobody
- can drop/alter the table while we execute store_create_info()
+ Here we open the destination table, on which we already have
+ name-lock. This is needed for store_create_info() to work.
+ The table will be closed by unlink_open_table() at the end
+ of this function.
*/
- if (lock_and_wait_for_table_name(thd, &dst_tables_list))
+ table->table= name_lock;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (reopen_name_locked_table(thd, table, FALSE))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
- else
- unlock_dst_table= TRUE;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
- int result= store_create_info(thd, table, &query, create_info);
+ IF_DBUG(int result=) store_create_info(thd, table, &query,
+ create_info);
DBUG_ASSERT(result == 0); // store_create_info() always return 0
write_bin_log(thd, TRUE, query.ptr(), query.length());
@@ -4853,10 +4760,10 @@ table_exists:
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
err:
- if (unlock_dst_table)
+ if (name_lock)
{
pthread_mutex_lock(&LOCK_open);
- unlock_table_name(thd, &dst_tables_list);
+ unlink_open_table(thd, name_lock, FALSE);
pthread_mutex_unlock(&LOCK_open);
}
DBUG_RETURN(res);
@@ -4959,12 +4866,18 @@ err:
SYNOPSIS
compare_tables()
table The original table.
- create_list The fields for the new table.
- key_info_buffer An array of KEY structs for the new indexes.
- key_count The number of elements in the array.
+ alter_info Alter options, fields and keys for the new
+ table.
create_info Create options for the new table.
- alter_info Alter options.
order_num Number of order list elements.
+ need_copy_table OUT Result of the comparison. Undefined if error.
+ Otherwise is one of:
+ ALTER_TABLE_METADATA_ONLY No copy needed
+ ALTER_TABLE_DATA_CHANGED Data changes,
+ copy needed
+ ALTER_TABLE_INDEX_CHANGED Index changes,
+ copy might be needed
+ key_info_buffer OUT An array of KEY structs for new indexes
index_drop_buffer OUT An array of offsets into table->key_info.
index_drop_count OUT The number of elements in the array.
index_add_buffer OUT An array of offsets into key_info_buffer.
@@ -4986,27 +4899,69 @@ err:
that need to be dropped and/or (re-)created.
RETURN VALUES
- 0 No copy needed
- ALTER_TABLE_DATA_CHANGED Data changes, copy needed
- ALTER_TABLE_INDEX_CHANGED Index changes, copy might be needed
+ TRUE error
+ FALSE success
*/
-static uint compare_tables(TABLE *table, List<create_field> *create_list,
- KEY *key_info_buffer, uint key_count,
- HA_CREATE_INFO *create_info,
- ALTER_INFO *alter_info, uint order_num,
- uint *index_drop_buffer, uint *index_drop_count,
- uint *index_add_buffer, uint *index_add_count,
- bool varchar)
+static
+bool
+compare_tables(TABLE *table,
+ Alter_info *alter_info,
+ HA_CREATE_INFO *create_info,
+ uint order_num,
+ enum_alter_table_change_level *need_copy_table,
+ KEY **key_info_buffer,
+ uint **index_drop_buffer, uint *index_drop_count,
+ uint **index_add_buffer, uint *index_add_count)
{
Field **f_ptr, *field;
uint changes= 0, tmp;
- List_iterator_fast<create_field> new_field_it(*create_list);
+ uint key_count;
+ List_iterator_fast<create_field> new_field_it(alter_info->create_list);
create_field *new_field;
KEY_PART_INFO *key_part;
KEY_PART_INFO *end;
+ /*
+ Remember if the new definition has new VARCHAR column;
+ create_info->varchar will be reset in mysql_prepare_create_table.
+ */
+ bool varchar= create_info->varchar;
DBUG_ENTER("compare_tables");
+ {
+ THD *thd= table->in_use;
+ /*
+ Create a copy of alter_info.
+ To compare the new and old table definitions, we need to "prepare"
+ the new definition - transform it from parser output to a format
+ that describes the final table layout (all column defaults are
+ initialized, duplicate columns are removed). This is done by
+ mysql_prepare_create_table. Unfortunately,
+ mysql_prepare_create_table performs its transformations
+ "in-place", that is, modifies the argument. Since we would
+ like to keep compare_tables() idempotent (not altering any
+ of the arguments) we create a copy of alter_info here and
+ pass it to mysql_prepare_create_table, then use the result
+ to evaluate possibility of fast ALTER TABLE, and then
+ destroy the copy.
+ */
+ Alter_info tmp_alter_info(*alter_info, thd->mem_root);
+ uint db_options= 0; /* not used */
+ /* Create the prepared information. */
+ if (mysql_prepare_create_table(thd, create_info,
+ &tmp_alter_info,
+ (table->s->tmp_table != NO_TMP_TABLE),
+ &db_options,
+ table->file, key_info_buffer,
+ &key_count, 0))
+ DBUG_RETURN(1);
+ /* Allocate result buffers. */
+ if (! (*index_drop_buffer=
+ (uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
+ ! (*index_add_buffer=
+ (uint*) thd->alloc(sizeof(uint) * tmp_alter_info.key_list.elements)))
+ DBUG_RETURN(1);
+ }
/*
Some very basic checks. If number of fields changes, or the
handler, we need to run full ALTER TABLE. In the future
@@ -5033,8 +4988,8 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
prior to 5.0 branch.
See BUG#6236.
*/
- if (table->s->fields != create_list->elements ||
- table->s->db_type != create_info->db_type ||
+ if (table->s->fields != alter_info->create_list.elements ||
+ table->s->db_type() != create_info->db_type ||
table->s->tmp_table ||
create_info->used_fields & HA_CREATE_USED_ENGINE ||
create_info->used_fields & HA_CREATE_USED_CHARSET ||
@@ -5043,7 +4998,10 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
order_num ||
!table->s->mysql_version ||
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
- DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
+ {
+ *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_RETURN(0);
+ }
/*
Go through fields and check if the original ones are compatible
@@ -5059,7 +5017,10 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
/* Check that NULL behavior is same for old and new fields */
if ((new_field->flags & NOT_NULL_FLAG) !=
(uint) (field->flags & NOT_NULL_FLAG))
- DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
+ {
+ *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_RETURN(0);
+ }
/* Don't pack rows in old tables if the user has requested this. */
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
@@ -5077,7 +5038,10 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
if (!(tmp= field->is_equal(new_field)))
- DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
+ {
+ *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_RETURN(0);
+ }
// Clear indexed marker
field->flags&= ~FIELD_IN_ADD_INDEX;
changes|= tmp;
@@ -5090,7 +5054,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
KEY *table_key;
KEY *table_key_end= table->key_info + table->s->keys;
KEY *new_key;
- KEY *new_key_end= key_info_buffer + key_count;
+ KEY *new_key_end= *key_info_buffer + key_count;
DBUG_PRINT("info", ("index count old: %d new: %d",
table->s->keys, key_count));
@@ -5106,7 +5070,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
KEY_PART_INFO *new_part;
/* Search a new key with the same name. */
- for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
+ for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
{
if (! strcmp(table_key->name, new_key->name))
break;
@@ -5114,7 +5078,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
if (new_key >= new_key_end)
{
/* Key not found. Add the offset of the key to the drop buffer. */
- index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info;
+ (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
DBUG_PRINT("info", ("index dropped: '%s'", table_key->name));
continue;
}
@@ -5147,8 +5111,8 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
index_changed:
/* Key modified. Add the offset of the key to both buffers. */
- index_drop_buffer[(*index_drop_count)++]= table_key - table->key_info;
- index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer;
+ (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
+ (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
key_part= new_key->key_part;
end= key_part + new_key->key_parts;
for(; key_part != end; key_part++)
@@ -5164,7 +5128,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
/*
Step through all keys of the new table and find matching old keys.
*/
- for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
+ for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
{
/* Search an old key with the same name. */
for (table_key= table->key_info; table_key < table_key_end; table_key++)
@@ -5175,7 +5139,7 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
if (table_key >= table_key_end)
{
/* Key not found. Add the offset of the key to the add buffer. */
- index_add_buffer[(*index_add_count)++]= new_key - key_info_buffer;
+ (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
key_part= new_key->key_part;
end= key_part + new_key->key_parts;
for(; key_part != end; key_part++)
@@ -5190,12 +5154,19 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list,
/* Check if changes are compatible with current handler without a copy */
if (table->file->check_if_incompatible_data(create_info, changes))
- DBUG_RETURN(ALTER_TABLE_DATA_CHANGED);
+ {
+ *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_RETURN(0);
+ }
if (*index_drop_count || *index_add_count)
- DBUG_RETURN(ALTER_TABLE_INDEX_CHANGED);
+ {
+ *need_copy_table= ALTER_TABLE_INDEX_CHANGED;
+ DBUG_RETURN(0);
+ }
- DBUG_RETURN(0); // Tables are compatible
+ *need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible
+ DBUG_RETURN(0);
}
@@ -5247,6 +5218,409 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
}
+/**
+ Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
+
+ This function transforms parse output of ALTER TABLE - lists of
+ columns and keys to add, drop or modify into, essentially,
+ CREATE TABLE definition - a list of columns and keys of the new
+ table. While doing so, it also performs some (bug not all)
+ semantic checks.
+
+ This function is invoked when we know that we're going to
+ perform ALTER TABLE via a temporary table -- i.e. fast ALTER TABLE
+ is not possible, perhaps because the ALTER statement contains
+ instructions that require change in table data, not only in
+ table definition or indexes.
+
+ @param[in,out] thd thread handle. Used as a memory pool
+ and source of environment information.
+ @param[in] table the source table, open and locked
+ Used as an interface to the storage engine
+ to acquire additional information about
+ the original table.
+ @param[in,out] create_info A blob with CREATE/ALTER TABLE
+ parameters
+ @param[in,out] alter_info Another blob with ALTER/CREATE parameters.
+ Originally create_info was used only in
+ CREATE TABLE and alter_info only in ALTER TABLE.
+ But since ALTER might end-up doing CREATE,
+ this distinction is gone and we just carry
+ around two structures.
+
+ @return
+ Fills various create_info members based on information retrieved
+ from the storage engine.
+ Sets create_info->varchar if the table has a VARCHAR column.
+ Prepares alter_info->create_list and alter_info->key_list with
+ columns and keys of the new table.
+ @retval TRUE error, out of memory or a semantical error in ALTER
+ TABLE instructions
+ @retval FALSE success
+*/
+
+static bool
+mysql_prepare_alter_table(THD *thd, TABLE *table,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info)
+{
+ /* New column definitions are added here */
+ List<create_field> new_create_list;
+ /* New key definitions are added here */
+ List<Key> new_key_list;
+ List_iterator<Alter_drop> drop_it(alter_info->drop_list);
+ List_iterator<create_field> def_it(alter_info->create_list);
+ List_iterator<Alter_column> alter_it(alter_info->alter_list);
+ List_iterator<Key> key_it(alter_info->key_list);
+ List_iterator<create_field> find_it(new_create_list);
+ List_iterator<create_field> field_it(new_create_list);
+ List<key_part_spec> key_parts;
+ uint db_create_options= (table->s->db_create_options
+ & ~(HA_OPTION_PACK_RECORD));
+ uint used_fields= create_info->used_fields;
+ KEY *key_info=table->key_info;
+ bool rc= TRUE;
+
+ DBUG_ENTER("mysql_prepare_alter_table");
+
+ create_info->varchar= FALSE;
+ /* Let new create options override the old ones */
+ if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
+ create_info->min_rows= table->s->min_rows;
+ if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
+ create_info->max_rows= table->s->max_rows;
+ if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
+ create_info->avg_row_length= table->s->avg_row_length;
+ if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
+ create_info->default_table_charset= table->s->table_charset;
+ if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
+ {
+ /* Table has an autoincrement, copy value to new table */
+ table->file->info(HA_STATUS_AUTO);
+ create_info->auto_increment_value= table->file->stats.auto_increment_value;
+ }
+ if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
+ create_info->key_block_size= table->s->key_block_size;
+
+ if (!create_info->tablespace && create_info->storage_media != HA_SM_MEMORY)
+ {
+ char *tablespace= static_cast<char *>(thd->alloc(FN_LEN));
+ /*
+ Regular alter table of disk stored table (no tablespace/storage change)
+ Copy tablespace name
+ */
+ if (tablespace &&
+ (table->file->get_tablespace_name(thd, tablespace, FN_LEN)))
+ create_info->tablespace= tablespace;
+ }
+ restore_record(table, s->default_values); // Empty record for DEFAULT
+ create_field *def;
+
+ /*
+ First collect all fields from table which isn't in drop_list
+ */
+ Field **f_ptr,*field;
+ for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
+ {
+ if (field->type() == MYSQL_TYPE_STRING)
+ create_info->varchar= TRUE;
+ /* Check if field should be dropped */
+ Alter_drop *drop;
+ drop_it.rewind();
+ while ((drop=drop_it++))
+ {
+ if (drop->type == Alter_drop::COLUMN &&
+ !my_strcasecmp(system_charset_info,field->field_name, drop->name))
+ {
+ /* Reset auto_increment value if it was dropped */
+ if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
+ !(used_fields & HA_CREATE_USED_AUTO))
+ {
+ create_info->auto_increment_value=0;
+ create_info->used_fields|=HA_CREATE_USED_AUTO;
+ }
+ break;
+ }
+ }
+ if (drop)
+ {
+ drop_it.remove();
+ continue;
+ }
+ /* Check if field is changed */
+ def_it.rewind();
+ while ((def=def_it++))
+ {
+ if (def->change &&
+ !my_strcasecmp(system_charset_info,field->field_name, def->change))
+ break;
+ }
+ if (def)
+ { // Field is changed
+ def->field=field;
+ if (!def->after)
+ {
+ new_create_list.push_back(def);
+ def_it.remove();
+ }
+ }
+ else
+ {
+ /*
+ This field was not dropped and not changed, add it to the list
+ for the new table.
+ */
+ def= new create_field(field, field);
+ new_create_list.push_back(def);
+ alter_it.rewind(); // Change default if ALTER
+ Alter_column *alter;
+ while ((alter=alter_it++))
+ {
+ if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
+ break;
+ }
+ if (alter)
+ {
+ if (def->sql_type == MYSQL_TYPE_BLOB)
+ {
+ my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
+ goto err;
+ }
+ if ((def->def=alter->def)) // Use new default
+ def->flags&= ~NO_DEFAULT_VALUE_FLAG;
+ else
+ def->flags|= NO_DEFAULT_VALUE_FLAG;
+ alter_it.remove();
+ }
+ }
+ }
+ def_it.rewind();
+ while ((def=def_it++)) // Add new columns
+ {
+ if (def->change && ! def->field)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name);
+ goto err;
+ }
+ /*
+ Check that the DATE/DATETIME not null field we are going to add is
+ either has a default value or the '0000-00-00' is allowed by the
+ set sql mode.
+ If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
+ flag to allow ALTER TABLE only if the table to be altered is empty.
+ */
+ if ((def->sql_type == MYSQL_TYPE_DATE ||
+ def->sql_type == MYSQL_TYPE_NEWDATE ||
+ def->sql_type == MYSQL_TYPE_DATETIME) &&
+ !alter_info->datetime_field &&
+ !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
+ thd->variables.sql_mode & MODE_NO_ZERO_DATE)
+ {
+ alter_info->datetime_field= def;
+ alter_info->error_if_not_empty= TRUE;
+ }
+ if (!def->after)
+ new_create_list.push_back(def);
+ else if (def->after == first_keyword)
+ new_create_list.push_front(def);
+ else
+ {
+ create_field *find;
+ find_it.rewind();
+ while ((find=find_it++)) // Add new columns
+ {
+ if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
+ break;
+ }
+ if (!find)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name);
+ goto err;
+ }
+ find_it.after(def); // Put element after this
+ alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
+ }
+ }
+ if (alter_info->alter_list.elements)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ alter_info->alter_list.head()->name, table->s->table_name);
+ goto err;
+ }
+ if (!new_create_list.elements)
+ {
+ my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
+ MYF(0));
+ goto err;
+ }
+
+ /*
+ Collect all keys which isn't in drop list. Add only those
+ for which some fields exists.
+ */
+
+ for (uint i=0 ; i < table->s->keys ; i++,key_info++)
+ {
+ char *key_name= key_info->name;
+ Alter_drop *drop;
+ drop_it.rewind();
+ while ((drop=drop_it++))
+ {
+ if (drop->type == Alter_drop::KEY &&
+ !my_strcasecmp(system_charset_info,key_name, drop->name))
+ break;
+ }
+ if (drop)
+ {
+ drop_it.remove();
+ continue;
+ }
+
+ KEY_PART_INFO *key_part= key_info->key_part;
+ key_parts.empty();
+ for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
+ {
+ if (!key_part->field)
+ continue; // Wrong field (from UNIREG)
+ const char *key_part_name=key_part->field->field_name;
+ create_field *cfield;
+ field_it.rewind();
+ while ((cfield=field_it++))
+ {
+ if (cfield->change)
+ {
+ if (!my_strcasecmp(system_charset_info, key_part_name,
+ cfield->change))
+ break;
+ }
+ else if (!my_strcasecmp(system_charset_info,
+ key_part_name, cfield->field_name))
+ break;
+ }
+ if (!cfield)
+ continue; // Field is removed
+ uint key_part_length=key_part->length;
+ if (cfield->field) // Not new field
+ {
+ /*
+ If the field can't have only a part used in a key according to its
+ new type, or should not be used partially according to its
+ previous type, or the field length is less than the key part
+ length, unset the key part length.
+
+ We also unset the key part length if it is the same as the
+ old field's length, so the whole new field will be used.
+
+ BLOBs may have cfield->length == 0, which is why we test it before
+ checking whether cfield->length < key_part_length (in chars).
+ */
+ if (!Field::type_can_have_key_part(cfield->field->type()) ||
+ !Field::type_can_have_key_part(cfield->sql_type) ||
+ /* spatial keys can't have sub-key length */
+ (key_info->flags & HA_SPATIAL) ||
+ (cfield->field->field_length == key_part_length &&
+ !f_is_blob(key_part->key_type)) ||
+ (cfield->length && (cfield->length < key_part_length /
+ key_part->field->charset()->mbmaxlen)))
+ key_part_length= 0; // Use whole field
+ }
+ key_part_length /= key_part->field->charset()->mbmaxlen;
+ key_parts.push_back(new key_part_spec(cfield->field_name,
+ key_part_length));
+ }
+ if (key_parts.elements)
+ {
+ KEY_CREATE_INFO key_create_info;
+ Key *key;
+ enum Key::Keytype key_type;
+ bzero((char*) &key_create_info, sizeof(key_create_info));
+
+ key_create_info.algorithm= key_info->algorithm;
+ if (key_info->flags & HA_USES_BLOCK_SIZE)
+ key_create_info.block_size= key_info->block_size;
+ if (key_info->flags & HA_USES_PARSER)
+ key_create_info.parser_name= *key_info->parser_name;
+
+ if (key_info->flags & HA_SPATIAL)
+ key_type= Key::SPATIAL;
+ else if (key_info->flags & HA_NOSAME)
+ {
+ if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
+ key_type= Key::PRIMARY;
+ else
+ key_type= Key::UNIQUE;
+ }
+ else if (key_info->flags & HA_FULLTEXT)
+ key_type= Key::FULLTEXT;
+ else
+ key_type= Key::MULTIPLE;
+
+ key= new Key(key_type, key_name,
+ &key_create_info,
+ test(key_info->flags & HA_GENERATED_KEY),
+ key_parts);
+ new_key_list.push_back(key);
+ }
+ }
+ {
+ Key *key;
+ while ((key=key_it++)) // Add new keys
+ {
+ if (key->type != Key::FOREIGN_KEY)
+ new_key_list.push_back(key);
+ if (key->name &&
+ !my_strcasecmp(system_charset_info,key->name,primary_key_name))
+ {
+ my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
+ goto err;
+ }
+ }
+ }
+
+ if (alter_info->drop_list.elements)
+ {
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
+ alter_info->drop_list.head()->name);
+ goto err;
+ }
+ if (alter_info->alter_list.elements)
+ {
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
+ alter_info->alter_list.head()->name);
+ goto err;
+ }
+
+ if (!create_info->comment.str)
+ {
+ create_info->comment.str= table->s->comment.str;
+ create_info->comment.length= table->s->comment.length;
+ }
+
+ table->file->update_create_info(create_info);
+ if ((create_info->table_options &
+ (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
+ (used_fields & HA_CREATE_USED_PACK_KEYS))
+ db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
+ if (create_info->table_options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
+ db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
+ if (create_info->table_options &
+ (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
+ db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
+ HA_OPTION_NO_DELAY_KEY_WRITE);
+ create_info->table_options|= db_create_options;
+
+ if (table->s->tmp_table)
+ create_info->options|=HA_LEX_CREATE_TMP_TABLE;
+
+ rc= FALSE;
+ alter_info->create_list.swap(new_create_list);
+ alter_info->key_list.swap(new_key_list);
+err:
+ DBUG_RETURN(rc);
+}
+
+
/*
Alter table
@@ -5255,21 +5629,14 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
thd Thread handle
new_db If there is a RENAME clause
new_name If there is a RENAME clause
- lex_create_info Information from the parsing phase. Since some
- clauses are common to CREATE and ALTER TABLE, the
- data is stored in lex->create_info. The non-common
- is stored in lex->alter_info.
+ create_info Information from the parsing phase about new
+ table properties.
table_list The table to change.
- fields lex->create_list - List of fields to be changed,
- added or dropped.
- keys lex->key_list - List of keys to be changed, added or
- dropped.
+ alter_info Lists of fields, keys to be changed, added
+ or dropped.
order_num How many ORDER BY fields has been specified.
order List of fields to ORDER BY.
ignore Whether we have ALTER IGNORE TABLE
- alter_info Information from the parsing phase specific to ALTER
- TABLE and not shared with CREATE TABLE.
- do_send_ok Whether to call send_ok() on success.
DESCRIPTION
This is a veery long function and is everything but the kitchen sink :)
@@ -5281,15 +5648,15 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
the table and/or enabling/disabling the keys. In this case, the FRM is
not changed, directly by mysql_alter_table. However, if there is a
RENAME + change of a field, or an index, the short cut is not used.
- See how `fields` is used to generate the new FRM regarding the structure
- of the fields. The same is done for the indices of the table.
+ See how `create_list` is used to generate the new FRM regarding the
+ structure of the fields. The same is done for the indices of the table.
Important is the fact, that this function tries to do as little work as
possible, by finding out whether a intermediate table is needed to copy
data into and when finishing the altering to use it as the original table.
For this reason the function compare_tables() is called, which decides
based on all kind of data how similar are the new and the original
- tables.
+ tables.
RETURN VALUES
FALSE OK
@@ -5297,36 +5664,28 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
*/
bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
- HA_CREATE_INFO *lex_create_info,
+ HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
- List<create_field> &fields, List<Key> &keys,
- uint order_num, ORDER *order, bool ignore,
- ALTER_INFO *alter_info, bool do_send_ok)
+ Alter_info *alter_info,
+ uint order_num, ORDER *order, bool ignore)
{
- TABLE *table,*new_table=0;
- int error;
+ TABLE *table, *new_table= 0, *name_lock= 0;
+ int error= 0;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
char index_file[FN_REFLEN], data_file[FN_REFLEN];
char path[FN_REFLEN];
char reg_path[FN_REFLEN+1];
ha_rows copied,deleted;
- uint db_create_options, used_fields;
handlerton *old_db_type, *new_db_type, *save_old_db_type;
legacy_db_type table_type;
- HA_CREATE_INFO *create_info;
frm_type_enum frm_type;
- uint need_copy_table= 0;
- bool no_table_reopen= FALSE, varchar= FALSE;
+ enum_alter_table_change_level need_copy_table= ALTER_TABLE_METADATA_ONLY;
#ifdef WITH_PARTITION_STORAGE_ENGINE
uint fast_alter_partition= 0;
bool partition_changed= FALSE;
#endif
- List<create_field> prepared_create_list;
- List<Key> prepared_key_list;
bool need_lock_for_indexes= TRUE;
- uint db_options= 0;
- uint key_count;
KEY *key_info_buffer;
uint index_drop_count;
uint *index_drop_buffer;
@@ -5340,6 +5699,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
LINT_INIT(index_add_buffer);
LINT_INIT(index_drop_buffer);
+ /*
+ Check if we attempt to alter mysql.slow_log or
+ mysql.general_log table and return an error if
+ it is the case.
+ TODO: this design is obsolete and will be removed.
+ */
if (table_list && table_list->db && table_list->table_name)
{
int table_kind= 0;
@@ -5357,20 +5722,21 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Disable alter of log tables to unsupported engine */
if (table_kind &&
- (lex_create_info->used_fields & HA_CREATE_USED_ENGINE) &&
- (!lex_create_info->db_type || /* unknown engine */
- !(lex_create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
+ (create_info->used_fields & HA_CREATE_USED_ENGINE) &&
+ (!create_info->db_type || /* unknown engine */
+ !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
{
my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
DBUG_RETURN(TRUE);
}
}
+ /*
+ Assign variables table_name, new_name, db, new_db, path, reg_path
+ to simplify further comparisions: we want to see if it's a RENAME
+ later just by comparing the pointers, avoiding the need for strcmp.
+ */
thd->proc_info="init";
- if (!(create_info= copy_create_info(lex_create_info)))
- {
- DBUG_RETURN(TRUE);
- }
table_name=table_list->table_name;
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
db=table_list->db;
@@ -5379,7 +5745,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0);
build_table_filename(path, sizeof(path), db, table_name, "", 0);
- used_fields=create_info->used_fields;
mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE);
@@ -5393,8 +5758,22 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
(void) unpack_filename(new_name_buff, new_name_buff);
if (lower_case_table_names != 2)
my_casedn_str(files_charset_info, new_name_buff);
+ /*
+ If this is just a rename of a view, short cut to the
+ following scenario: 1) lock LOCK_open 2) do a RENAME
+ 2) unlock LOCK_open.
+ This is a copy-paste added to make sure
+ ALTER (sic:) TABLE .. RENAME works for views. ALTER VIEW is handled
+ as an independent branch in mysql_execute_command. The need
+ for a copy-paste arose because the main code flow of ALTER TABLE
+ ... RENAME tries to use open_ltable, which does not work for views
+ (open_ltable was never modified to merge table lists of child tables
+ into the main table list, like open_tables does).
+ This code is wrong and will be removed, please do not copy.
+ */
frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
/* Rename a view */
+ /* Sic: there is a race here */
if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
{
/*
@@ -5406,16 +5785,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
if (wait_if_global_read_lock(thd,0,1))
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
VOID(pthread_mutex_lock(&LOCK_open));
if (lock_table_names(thd, table_list))
+ {
+ error= 1;
goto view_err;
+ }
- error=0;
if (!do_rename(thd, table_list, new_db, new_name, new_name, 1))
{
if (mysql_bin_log.is_open())
@@ -5474,13 +5855,21 @@ view_err:
}
else
{
+ if (lock_table_name_if_not_cached(thd, new_db, new_name, &name_lock))
+ DBUG_RETURN(TRUE);
+ if (!name_lock)
+ {
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
+ DBUG_RETURN(TRUE);
+ }
+
build_table_filename(new_name_buff, sizeof(new_name_buff),
new_db, new_name_buff, reg_ext, 0);
if (!access(new_name_buff, F_OK))
{
/* Table will be closed in do_command() */
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
- DBUG_RETURN(TRUE);
+ goto err;
}
}
}
@@ -5491,7 +5880,7 @@ view_err:
new_name= table_name;
}
- old_db_type= table->s->db_type;
+ old_db_type= table->s->db_type();
if (!create_info->db_type)
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -5512,16 +5901,17 @@ view_err:
create_info->db_type= old_db_type;
}
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
- &partition_changed, &fast_alter_partition))
- {
- DBUG_RETURN(TRUE);
- }
-#endif
if (check_engine(thd, new_name, create_info))
- DBUG_RETURN(TRUE);
+ goto err;
new_db_type= create_info->db_type;
+
+ if (new_db_type != old_db_type &&
+ !table->file->can_switch_engines())
+ {
+ my_error(ER_ROW_IS_REFERENCED, MYF(0));
+ goto err;
+ }
+
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type= table->s->row_type;
@@ -5533,42 +5923,79 @@ view_err:
{
DBUG_PRINT("info", ("doesn't support alter"));
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
- DBUG_RETURN(TRUE);
+ goto err;
}
thd->proc_info="setup";
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
!table->s->tmp_table) // no need to touch frm
{
- VOID(pthread_mutex_lock(&LOCK_open));
-
switch (alter_info->keys_onoff) {
case LEAVE_AS_IS:
- error= 0;
break;
case ENABLE:
+ /*
+ wait_while_table_is_used() ensures that table being altered is
+ opened only by this thread and that TABLE::TABLE_SHARE::version
+ of TABLE object corresponding to this table is 0.
+ The latter guarantees that no DML statement will open this table
+ until ALTER TABLE finishes (i.e. until close_thread_tables())
+ while the fact that the table is still open gives us protection
+ from concurrent DDL statements.
+ */
+ VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
/* COND_refresh will be signaled in close_thread_tables() */
break;
case DISABLE:
+ VOID(pthread_mutex_lock(&LOCK_open));
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
+ VOID(pthread_mutex_unlock(&LOCK_open));
error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
/* COND_refresh will be signaled in close_thread_tables() */
break;
+ default:
+ DBUG_ASSERT(FALSE);
+ error= 0;
+ break;
}
if (error == HA_ERR_WRONG_COMMAND)
{
+ error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias);
- error= 0;
}
+ VOID(pthread_mutex_lock(&LOCK_open));
+ /*
+ Unlike to the above case close_cached_table() below will remove ALL
+ instances of TABLE from table cache (it will also remove table lock
+ held by this thread). So to make actual table renaming and writing
+ to binlog atomic we have to put them into the same critical section
+ protected by LOCK_open mutex. This also removes gap for races between
+ access() and mysql_rename_table() calls.
+ */
+
if (!error && (new_name != table_name || new_db != db))
{
thd->proc_info="rename";
- /* Then do a 'simple' rename of the table */
+ /*
+ Then do a 'simple' rename of the table. First we need to close all
+ instances of 'source' table.
+ */
+ close_cached_table(thd, table);
+ /*
+ Then, we want check once again that target table does not exist.
+ Actually the order of these two steps does not matter since
+ earlier we took name-lock on the target table, so we do them
+ in this particular order only to be consistent with 5.0, in which
+ we don't take this name-lock and where this order really matters.
+ TODO: Investigate if we need this access() check at all.
+ */
if (!access(new_name_buff,F_OK))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
@@ -5577,8 +6004,6 @@ view_err:
else
{
*fn_ext(new_name)=0;
- table->s->version= 0; // Force removal of table def
- close_cached_table(thd, table);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
error= -1;
else if (Table_triggers_list::change_table_name(thd, db, table_name,
@@ -5593,404 +6018,78 @@ view_err:
if (error == HA_ERR_WRONG_COMMAND)
{
+ error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias);
- error= 0;
}
if (!error)
{
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- if (do_send_ok)
- send_ok(thd);
+ send_ok(thd);
}
else if (error > 0)
{
table->file->print_error(error, MYF(0));
error= -1;
}
+ if (name_lock)
+ unlink_open_table(thd, name_lock, FALSE);
VOID(pthread_mutex_unlock(&LOCK_open));
table_list->table= NULL; // For query cache
query_cache_invalidate3(thd, table_list, 0);
DBUG_RETURN(error);
}
- /* We have to do full alter table */
-
- /* Let new create options override the old ones */
- if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
- create_info->min_rows= table->s->min_rows;
- if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
- create_info->max_rows= table->s->max_rows;
- if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
- create_info->avg_row_length= table->s->avg_row_length;
- if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
- create_info->default_table_charset= table->s->table_charset;
- if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
- create_info->key_block_size= table->s->key_block_size;
-
- restore_record(table, s->default_values); // Empty record for DEFAULT
- List_iterator<Alter_drop> drop_it(alter_info->drop_list);
- List_iterator<create_field> def_it(fields);
- List_iterator<Alter_column> alter_it(alter_info->alter_list);
- List<create_field> create_list; // Add new fields here
- List<Key> key_list; // Add new keys here
- create_field *def;
-
- /*
- First collect all fields from table which isn't in drop_list
- */
-
- Field **f_ptr,*field;
- for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
- {
- if (field->type() == MYSQL_TYPE_STRING)
- varchar= TRUE;
- /* Check if field should be dropped */
- Alter_drop *drop;
- drop_it.rewind();
- while ((drop=drop_it++))
- {
- if (drop->type == Alter_drop::COLUMN &&
- !my_strcasecmp(system_charset_info,field->field_name, drop->name))
- {
- /* Reset auto_increment value if it was dropped */
- if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
- !(used_fields & HA_CREATE_USED_AUTO))
- {
- create_info->auto_increment_value=0;
- create_info->used_fields|=HA_CREATE_USED_AUTO;
- }
- break;
- }
- }
- if (drop)
- {
- drop_it.remove();
- continue;
- }
- /* Check if field is changed */
- def_it.rewind();
- while ((def=def_it++))
- {
- if (def->change &&
- !my_strcasecmp(system_charset_info,field->field_name, def->change))
- break;
- }
- if (def)
- { // Field is changed
- def->field=field;
- if (!def->after)
- {
- create_list.push_back(def);
- def_it.remove();
- }
- }
- else
- {
- /*
- This field was not dropped and not changed, add it to the list
- for the new table.
- */
- create_list.push_back(def=new create_field(field,field));
- alter_it.rewind(); // Change default if ALTER
- Alter_column *alter;
- while ((alter=alter_it++))
- {
- if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
- break;
- }
- if (alter)
- {
- if (def->sql_type == FIELD_TYPE_BLOB)
- {
- my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
- DBUG_RETURN(TRUE);
- }
- if ((def->def=alter->def)) // Use new default
- def->flags&= ~NO_DEFAULT_VALUE_FLAG;
- else
- def->flags|= NO_DEFAULT_VALUE_FLAG;
- alter_it.remove();
- }
- }
- }
- def_it.rewind();
- List_iterator<create_field> find_it(create_list);
- while ((def=def_it++)) // Add new columns
- {
- if (def->change && ! def->field)
- {
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name);
- DBUG_RETURN(TRUE);
- }
- if (!def->after)
- create_list.push_back(def);
- else if (def->after == first_keyword)
- create_list.push_front(def);
- else
- {
- create_field *find;
- find_it.rewind();
- while ((find=find_it++)) // Add new columns
- {
- if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
- break;
- }
- if (!find)
- {
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table_name);
- DBUG_RETURN(TRUE);
- }
- find_it.after(def); // Put element after this
- }
- }
- if (alter_info->alter_list.elements)
- {
- my_error(ER_BAD_FIELD_ERROR, MYF(0),
- alter_info->alter_list.head()->name, table_name);
- DBUG_RETURN(TRUE);
- }
- if (!create_list.elements)
- {
- my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
- MYF(0));
- DBUG_RETURN(TRUE);
- }
+ /* We have to do full alter table. */
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
+ &partition_changed, &fast_alter_partition))
+ goto err;
+#endif
/*
- Collect all keys which isn't in drop list. Add only those
- for which some fields exists.
+ If the old table had partitions and we are doing ALTER TABLE ...
+ engine= <new_engine>, the new table must preserve the original
+ partitioning. That means that the new engine is still the
+ partitioning engine, not the engine specified in the parser.
+ This is discovered in prep_alter_part_table, which in such case
+ updates create_info->db_type.
+ Now we need to update the stack copy of create_info->db_type,
+ as otherwise we won't be able to correctly move the files of the
+ temporary table to the result table files.
*/
+ new_db_type= create_info->db_type;
- List_iterator<Key> key_it(keys);
- List_iterator<create_field> field_it(create_list);
- List<key_part_spec> key_parts;
-
- KEY *key_info=table->key_info;
- for (uint i=0 ; i < table->s->keys ; i++,key_info++)
- {
- char *key_name= key_info->name;
- Alter_drop *drop;
- drop_it.rewind();
- while ((drop=drop_it++))
- {
- if (drop->type == Alter_drop::KEY &&
- !my_strcasecmp(system_charset_info,key_name, drop->name))
- break;
- }
- if (drop)
- {
- drop_it.remove();
- continue;
- }
-
- KEY_PART_INFO *key_part= key_info->key_part;
- key_parts.empty();
- for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
- {
- if (!key_part->field)
- continue; // Wrong field (from UNIREG)
- const char *key_part_name=key_part->field->field_name;
- create_field *cfield;
- field_it.rewind();
- while ((cfield=field_it++))
- {
- if (cfield->change)
- {
- if (!my_strcasecmp(system_charset_info, key_part_name,
- cfield->change))
- break;
- }
- else if (!my_strcasecmp(system_charset_info,
- key_part_name, cfield->field_name))
- break;
- }
- if (!cfield)
- continue; // Field is removed
- uint key_part_length=key_part->length;
- if (cfield->field) // Not new field
- {
- /*
- If the field can't have only a part used in a key according to its
- new type, or should not be used partially according to its
- previous type, or the field length is less than the key part
- length, unset the key part length.
-
- We also unset the key part length if it is the same as the
- old field's length, so the whole new field will be used.
-
- BLOBs may have cfield->length == 0, which is why we test it before
- checking whether cfield->length < key_part_length (in chars).
- */
- if (!Field::type_can_have_key_part(cfield->field->type()) ||
- !Field::type_can_have_key_part(cfield->sql_type) ||
- (cfield->field->field_length == key_part_length &&
- !f_is_blob(key_part->key_type)) ||
- (cfield->length && (cfield->length < key_part_length /
- key_part->field->charset()->mbmaxlen)))
- key_part_length= 0; // Use whole field
- }
- key_part_length /= key_part->field->charset()->mbmaxlen;
- key_parts.push_back(new key_part_spec(cfield->field_name,
- key_part_length));
- }
- if (key_parts.elements)
- {
- KEY_CREATE_INFO key_create_info;
- bzero((char*) &key_create_info, sizeof(key_create_info));
-
- key_create_info.algorithm= key_info->algorithm;
- if (key_info->flags & HA_USES_BLOCK_SIZE)
- key_create_info.block_size= key_info->block_size;
- if (key_info->flags & HA_USES_PARSER)
- key_create_info.parser_name= *key_info->parser_name;
-
- key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
- (key_info->flags & HA_NOSAME ?
- (!my_strcasecmp(system_charset_info,
- key_name, primary_key_name) ?
- Key::PRIMARY : Key::UNIQUE) :
- (key_info->flags & HA_FULLTEXT ?
- Key::FULLTEXT : Key::MULTIPLE)),
- key_name,
- &key_create_info,
- test(key_info->flags & HA_GENERATED_KEY),
- key_parts));
- }
- }
- {
- Key *key;
- while ((key=key_it++)) // Add new keys
- {
- if (key->type != Key::FOREIGN_KEY)
- key_list.push_back(key);
- if (key->name &&
- !my_strcasecmp(system_charset_info,key->name,primary_key_name))
- {
- my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name);
- DBUG_RETURN(TRUE);
- }
- }
- }
-
- if (alter_info->drop_list.elements)
- {
- my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
- alter_info->drop_list.head()->name);
+ if (mysql_prepare_alter_table(thd, table, create_info, alter_info))
goto err;
- }
- if (alter_info->alter_list.elements)
- {
- my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
- alter_info->alter_list.head()->name);
- goto err;
- }
-
- db_create_options= table->s->db_create_options & ~(HA_OPTION_PACK_RECORD);
- my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
- current_pid, thd->thread_id);
- /* Safety fix for innodb */
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, tmp_name);
- if (new_db_type != old_db_type && !table->file->can_switch_engines()) {
- my_error(ER_ROW_IS_REFERENCED, MYF(0));
- goto err;
- }
- create_info->db_type=new_db_type;
- if (!create_info->comment.str)
- {
- create_info->comment.str= table->s->comment.str;
- create_info->comment.length= table->s->comment.length;
- }
-
- table->file->update_create_info(create_info);
- if ((create_info->table_options &
- (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
- (used_fields & HA_CREATE_USED_PACK_KEYS))
- db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
- if (create_info->table_options &
- (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
- db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
- if (create_info->table_options &
- (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
- db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
- HA_OPTION_NO_DELAY_KEY_WRITE);
- create_info->table_options|= db_create_options;
-
- if (table->s->tmp_table)
- create_info->options|=HA_LEX_CREATE_TMP_TABLE;
+
+ need_copy_table= alter_info->change_level;
set_table_default_charset(thd, create_info, db);
- {
- /*
- For some purposes we need prepared table structures and translated
- key descriptions with proper default key name assignment.
-
- Unfortunately, mysql_prepare_table() modifies the field and key
- lists. mysql_create_table() needs the unmodified lists. Hence, we
- need to copy the lists and all their elements. The lists contain
- pointers to the elements only.
-
- We cannot copy conditionally because the partition code always
- needs prepared lists and compare_tables() needs them and is almost
- always called.
- */
-
- /* Copy fields. */
- List_iterator<create_field> prep_field_it(create_list);
- create_field *prep_field;
- while ((prep_field= prep_field_it++))
- prepared_create_list.push_back(new create_field(*prep_field));
-
- /* Copy keys and key parts. */
- List_iterator<Key> prep_key_it(key_list);
- Key *prep_key;
- while ((prep_key= prep_key_it++))
- {
- List<key_part_spec> prep_columns;
- List_iterator<key_part_spec> prep_col_it(prep_key->columns);
- key_part_spec *prep_col;
-
- while ((prep_col= prep_col_it++))
- prep_columns.push_back(new key_part_spec(*prep_col));
- prepared_key_list.push_back(new Key(prep_key->type, prep_key->name,
- &prep_key->key_create_info,
- prep_key->generated, prep_columns));
- }
-
- /* Create the prepared information. */
- if (mysql_prepare_table(thd, create_info, &prepared_create_list,
- &prepared_key_list,
- (table->s->tmp_table != NO_TMP_TABLE), &db_options,
- table->file, &key_info_buffer, &key_count, 0))
- goto err;
- }
-
if (thd->variables.old_alter_table
- || (table->s->db_type != create_info->db_type)
+ || (table->s->db_type() != create_info->db_type)
#ifdef WITH_PARTITION_STORAGE_ENGINE
|| partition_changed
#endif
)
- need_copy_table= 1;
+ need_copy_table= ALTER_TABLE_DATA_CHANGED;
else
{
- /* Try to optimize ALTER TABLE. Allocate result buffers. */
- if (! (index_drop_buffer=
- (uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
- ! (index_add_buffer=
- (uint*) thd->alloc(sizeof(uint) * prepared_key_list.elements)))
- goto err;
+ enum_alter_table_change_level need_copy_table_res;
/* Check how much the tables differ. */
- need_copy_table= compare_tables(table, &prepared_create_list,
- key_info_buffer, key_count,
- create_info, alter_info, order_num,
- index_drop_buffer, &index_drop_count,
- index_add_buffer, &index_add_count,
- varchar);
+ if (compare_tables(table, alter_info,
+ create_info, order_num,
+ &need_copy_table_res,
+ &key_info_buffer,
+ &index_drop_buffer, &index_drop_count,
+ &index_add_buffer, &index_add_count))
+ goto err;
+
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
+ need_copy_table= need_copy_table_res;
}
/*
@@ -6008,8 +6107,8 @@ view_err:
uint *idx_p;
uint *idx_end_p;
- if (table->s->db_type->alter_table_flags)
- alter_flags= table->s->db_type->alter_table_flags(alter_info->flags);
+ if (table->s->db_type()->alter_table_flags)
+ alter_flags= table->s->db_type()->alter_table_flags(alter_info->flags);
DBUG_PRINT("info", ("alter_flags: %lu", alter_flags));
/* Check dropped indexes. */
for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count;
@@ -6088,13 +6187,13 @@ view_err:
if ((alter_flags & needed_online_flags) == needed_online_flags)
{
/* All required online flags are present. */
- need_copy_table= 0;
+ need_copy_table= ALTER_TABLE_METADATA_ONLY;
need_lock_for_indexes= FALSE;
}
else if ((alter_flags & needed_fast_flags) == needed_fast_flags)
{
/* All required fast flags are present. */
- need_copy_table= 0;
+ need_copy_table= ALTER_TABLE_METADATA_ONLY;
}
}
DBUG_PRINT("info", ("need_copy_table: %u need_lock: %d",
@@ -6106,20 +6205,26 @@ view_err:
alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
so that ALTER TABLE won't break when somebody will add new flag
*/
- if (!need_copy_table)
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
create_info->frm_only= 1;
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (fast_alter_partition)
{
+ DBUG_ASSERT(!name_lock);
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
create_info, table_list,
- &create_list, &key_list,
db, table_name,
fast_alter_partition));
}
#endif
+ my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
+ current_pid, thd->thread_id);
+ /* Safety fix for innodb */
+ if (lower_case_table_names)
+ my_casedn_str(files_charset_info, tmp_name);
+
/*
Handling of symlinked tables:
If no rename:
@@ -6172,14 +6277,16 @@ view_err:
We don't log the statement, it will be logged later.
*/
tmp_disable_binlog(thd);
- error= mysql_create_table(thd, new_db, tmp_name,
- create_info,create_list,key_list,1,0,0);
+ error= mysql_create_table_no_lock(thd, new_db, tmp_name,
+ create_info,
+ alter_info,
+ 1, 0);
reenable_binlog(thd);
if (error)
- DBUG_RETURN(error);
+ goto err;
/* Open the table if we need to copy the data. */
- if (need_copy_table)
+ if (need_copy_table != ALTER_TABLE_METADATA_ONLY)
{
if (table->s->tmp_table)
{
@@ -6214,9 +6321,11 @@ view_err:
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field;
- error=copy_data_between_tables(table, new_table, create_list, ignore,
- order_num, order, &copied, &deleted,
- alter_info->keys_onoff);
+ error= copy_data_between_tables(table, new_table,
+ alter_info->create_list, ignore,
+ order_num, order, &copied, &deleted,
+ alter_info->keys_onoff,
+ alter_info->error_if_not_empty);
}
else
{
@@ -6246,26 +6355,6 @@ view_err:
table->file->prepare_for_alter();
if (index_add_count)
{
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892
- if (! need_lock_for_indexes)
- {
- /* Downgrade the write lock. */
- mysql_lock_downgrade_write(thd, table, TL_WRITE_ALLOW_WRITE);
- }
-
- /* Create a new .frm file for crash recovery. */
- /* TODO: Must set INDEX_TO_BE_ADDED flags in the frm file. */
- VOID(pthread_mutex_lock(&LOCK_open));
- error= (mysql_create_frm(thd, reg_path, db, table_name,
- create_info, prepared_create_list, key_count,
- key_info_buffer, table->file) ||
- table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG,
- create_info));
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (error)
- goto err1;
-#endif
-
/* The add_index() method takes an array of KEY structs. */
key_info= (KEY*) thd->alloc(sizeof(KEY) * index_add_count);
key= key_info;
@@ -6298,36 +6387,6 @@ view_err:
if (index_drop_count)
{
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020_AND_WL1892
- /* Create a new .frm file for crash recovery. */
- /* TODO: Must set INDEX_IS_ADDED in the frm file. */
- /* TODO: Must set INDEX_TO_BE_DROPPED in the frm file. */
- VOID(pthread_mutex_lock(&LOCK_open));
- error= (mysql_create_frm(thd, reg_path, db, table_name,
- create_info, prepared_create_list, key_count,
- key_info_buffer, table->file) ||
- table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG,
- create_info));
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (error)
- goto err1;
-
- if (! need_lock_for_indexes)
- {
- LOCK_PARAM_TYPE lpt;
-
- lpt.thd= thd;
- lpt.table= table;
- lpt.db= db;
- lpt.table_name= table_name;
- lpt.create_info= create_info;
- lpt.create_list= &create_list;
- lpt.key_count= key_count;
- lpt.key_info_buffer= key_info_buffer;
- abort_and_upgrade_lock(lpt);
- }
-#endif
-
/* The prepare_drop_index() method takes an array of key numbers. */
key_numbers= (uint*) thd->alloc(sizeof(uint) * index_drop_count);
keyno_p= key_numbers;
@@ -6347,27 +6406,6 @@ view_err:
goto err1;
}
-#ifdef XXX_TO_BE_DONE_LATER_BY_WL3020
- if (! need_lock_for_indexes)
- {
- /* Downgrade the lock again. */
- if (table->reginfo.lock_type == TL_WRITE_ALLOW_READ)
- {
- LOCK_PARAM_TYPE lpt;
-
- lpt.thd= thd;
- lpt.table= table;
- lpt.db= db;
- lpt.table_name= table_name;
- lpt.create_info= create_info;
- lpt.create_list= &create_list;
- lpt.key_count= key_count;
- lpt.key_info_buffer= key_info_buffer;
- close_open_tables_and_downgrade(lpt);
- }
- }
-#endif
-
/* Tell the handler to finally drop the indexes. */
if ((error= table->file->final_drop_index(table)))
{
@@ -6416,7 +6454,7 @@ view_err:
{
/* Close the intermediate table that will be the new table */
intern_close_table(new_table);
- my_free((gptr) new_table,MYF(0));
+ my_free(new_table,MYF(0));
}
VOID(pthread_mutex_lock(&LOCK_open));
if (error)
@@ -6427,9 +6465,19 @@ view_err:
}
/*
- Data is copied. Now we rename the old table to a temp name,
- rename the new one to the old name, remove all entries about the old table
- from the cache, free all locks, close the old table and remove it.
+ Data is copied. Now we:
+ 1) Wait until all other threads close old version of table.
+ 2) Close instances of table open by this thread and replace them
+ with exclusive name-locks.
+ 3) Rename the old table to a temp name, rename the new one to the
+ old name.
+ 4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
+ we reopen new version of table.
+ 5) Write statement to the binary log.
+ 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
+ remove name-locks from list of open tables and table cache.
+ 7) If we are not not under LOCK TABLES we rely on close_thread_tables()
+ call to remove name-locks from table cache and list of open table.
*/
thd->proc_info="rename result table";
@@ -6437,36 +6485,9 @@ view_err:
current_pid, thd->thread_id);
if (lower_case_table_names)
my_casedn_str(files_charset_info, old_name);
- if (new_name != table_name || new_db != db)
- {
- if (!access(new_name_buff,F_OK))
- {
- error=1;
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
- VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- }
-
-#if !defined( __WIN__)
- if (table->file->has_transactions())
-#endif
- {
- /*
- Win32 and InnoDB can't drop a table that is in use, so we must
- close the original table before doing the rename
- */
- table->s->version= 0; // Force removal of table def
- close_cached_table(thd, table);
- table=0; // Marker that table is closed
- no_table_reopen= TRUE;
- }
-#if !defined( __WIN__)
- else
- table->file->extra(HA_EXTRA_FORCE_REOPEN); // Don't use this file anymore
-#endif
+ wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE);
+ close_data_files_and_morph_locks(thd, db, table_name);
error=0;
save_old_db_type= old_db_type;
@@ -6484,18 +6505,22 @@ view_err:
table is renamed and the SE is also changed, then an intermediate table
is created and the additional call will not take place.
*/
- if (!need_copy_table)
- new_db_type=old_db_type= NULL; // this type cannot happen in regular ALTER
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
+ {
+ DBUG_ASSERT(new_db_type == old_db_type);
+ /* This type cannot happen in regular ALTER. */
+ new_db_type= old_db_type= NULL;
+ }
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
FN_TO_IS_TMP))
{
error=1;
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
}
- else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db,
+ else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
new_alias, FN_FROM_IS_TMP) ||
(new_name != table_name || new_db != db) && // we also do rename
- (need_copy_table ||
+ (need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
Table_triggers_list::change_table_name(thd, db, table_name,
@@ -6511,88 +6536,64 @@ view_err:
if (error)
{
+ /* This shouldn't happen. But let us play it safe. */
+ goto err_with_placeholders;
+ }
+
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
+ {
/*
- This shouldn't happen. We solve this the safe way by
- closing the locked table.
+ Now we have to inform handler that new .FRM file is in place.
+ To do this we need to obtain a handler object for it.
*/
- if (table)
- {
- table->s->version= 0; // Force removal of table def
- close_cached_table(thd,table);
+ TABLE *t_table;
+ if (new_name != table_name || new_db != db)
+ {
+ table_list->alias= new_name;
+ table_list->table_name= new_name;
+ table_list->table_name_length= strlen(new_name);
+ table_list->db= new_db;
+ table_list->db_length= strlen(new_db);
+ table_list->table= name_lock;
+ if (reopen_name_locked_table(thd, table_list, FALSE))
+ goto err_with_placeholders;
+ t_table= table_list->table;
}
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
- if (! need_copy_table)
- {
- if (! table)
+ else
{
- if (new_name != table_name || new_db != db)
- {
- table_list->alias= new_name;
- table_list->table_name= new_name;
- table_list->table_name_length= strlen(new_name);
- table_list->db= new_db;
- table_list->db_length= strlen(new_db);
- }
-
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (! (table= open_ltable(thd, table_list, TL_WRITE_ALLOW_READ)))
- goto err;
- VOID(pthread_mutex_lock(&LOCK_open));
+ if (reopen_table(table))
+ goto err_with_placeholders;
+ t_table= table;
}
/* Tell the handler that a new frm file is in place. */
- if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG,
- create_info))
+ if (t_table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG,
+ create_info))
+ goto err_with_placeholders;
+ if (thd->locked_tables && new_name == table_name && new_db == db)
{
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
+ /*
+ We are going to reopen table down on the road, so we have to restore
+ state of the TABLE object which we used for obtaining of handler
+ object to make it suitable for reopening.
+ */
+ DBUG_ASSERT(t_table == table);
+ table->open_placeholder= 1;
+ close_handle_and_leave_table_as_lock(table);
}
}
- if (thd->lock || new_name != table_name || no_table_reopen) // True if WIN32
- {
- /*
- Not table locking or alter table with rename.
- Free locks and remove old table
- */
- if (table)
- {
- table->s->version= 0; // Force removal of table def
- close_cached_table(thd,table);
- }
- VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
- }
- else
+ VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
+
+ if (thd->locked_tables && new_name == table_name && new_db == db)
{
- /*
- Using LOCK TABLES without rename.
- This code is never executed on WIN32!
- Remove old renamed table, reopen table and get new locks
- */
- if (table)
- {
- VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
- /* Mark in-use copies old */
- remove_table_from_cache(thd,db,table_name,RTFC_NO_FLAG);
- /* end threads waiting on lock */
- mysql_lock_abort(thd,table, TRUE);
- }
- VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
- if (close_data_tables(thd,db,table_name) ||
- reopen_tables(thd,1,0))
- { // This shouldn't happen
- if (table)
- {
- table->s->version= 0; // Force removal of table def
- close_cached_table(thd,table); // Remove lock for table
- }
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
+ thd->in_lock_tables= 1;
+ error= reopen_tables(thd, 1, 0);
+ thd->in_lock_tables= 0;
+ if (error)
+ goto err_with_placeholders;
}
VOID(pthread_mutex_unlock(&LOCK_open));
- broadcast_refresh();
+
/*
The ALTER TABLE is always in its own transaction.
Commit must not be called while LOCK_open is locked. It could call
@@ -6609,15 +6610,18 @@ view_err:
}
thd->proc_info="end";
+ DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
+
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
thd->query, thd->query_length,
db, table_name);
- DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based &&
+ DBUG_ASSERT(!(mysql_bin_log.is_open() &&
+ thd->current_stmt_binlog_row_based &&
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- if (ha_check_storage_engine_flag(old_db_type,HTON_FLUSH_AFTER_RENAME))
+ if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
{
/*
For the alter table to be properly flushed to the logs, we
@@ -6625,12 +6629,13 @@ view_err:
shutdown.
*/
char path[FN_REFLEN];
+ TABLE *t_table;
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
- table=open_temporary_table(thd, path, new_db, tmp_name,0);
- if (table)
+ t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
+ if (t_table)
{
- intern_close_table(table);
- my_free((char*) table, MYF(0));
+ intern_close_table(t_table);
+ my_free(t_table, MYF(0));
}
else
sql_print_warning("Could not open table %s.%s after rename\n",
@@ -6640,12 +6645,25 @@ view_err:
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
+ if (thd->locked_tables && (new_name != table_name || new_db != db))
+ {
+ /*
+ If are we under LOCK TABLES and did ALTER TABLE with RENAME we need
+ to remove placeholders for the old table and for the target table
+ from the list of open tables and table cache. If we are not under
+ LOCK TABLES we can rely on close_thread_tables() doing this job.
+ */
+ pthread_mutex_lock(&LOCK_open);
+ unlink_open_table(thd, table, FALSE);
+ unlink_open_table(thd, name_lock, FALSE);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+
end_temporary:
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
(ulong) thd->cuted_fields);
- if (do_send_ok)
- send_ok(thd,copied+deleted,0L,tmp_name);
+ send_ok(thd, copied + deleted, 0L, tmp_name);
thd->some_tables_deleted=0;
DBUG_RETURN(FALSE);
@@ -6659,6 +6677,56 @@ err1:
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
err:
+ /*
+ No default value was provided for a DATE/DATETIME field, the
+ current sql_mode doesn't allow the '0000-00-00' value and
+ the table to be altered isn't empty.
+ Report error here.
+ */
+ if (alter_info->error_if_not_empty && thd->row_count)
+ {
+ const char *f_val= 0;
+ enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
+ switch (alter_info->datetime_field->sql_type)
+ {
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
+ f_val= "0000-00-00";
+ t_type= MYSQL_TIMESTAMP_DATE;
+ break;
+ case MYSQL_TYPE_DATETIME:
+ f_val= "0000-00-00 00:00:00";
+ t_type= MYSQL_TIMESTAMP_DATETIME;
+ break;
+ default:
+ /* Shouldn't get here. */
+ DBUG_ASSERT(0);
+ }
+ bool save_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= TRUE;
+ make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ f_val, strlength(f_val), t_type,
+ alter_info->datetime_field->field_name);
+ thd->abort_on_warning= save_abort_on_warning;
+ }
+ if (name_lock)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ unlink_open_table(thd, name_lock, FALSE);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+ DBUG_RETURN(TRUE);
+
+err_with_placeholders:
+ /*
+ An error happened while we were holding exclusive name-lock on table
+ being altered. To be safe under LOCK TABLES we should remove placeholders
+ from list of open tables list and table cache.
+ */
+ unlink_open_table(thd, table, FALSE);
+ if (name_lock)
+ unlink_open_table(thd, name_lock, FALSE);
+ VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(TRUE);
}
/* mysql_alter_table */
@@ -6670,13 +6738,14 @@ copy_data_between_tables(TABLE *from,TABLE *to,
uint order_num, ORDER *order,
ha_rows *copied,
ha_rows *deleted,
- enum enum_enable_or_disable keys_onoff)
+ enum enum_enable_or_disable keys_onoff,
+ bool error_if_not_empty)
{
int error;
Copy_field *copy,*copy_end;
ulong found_count,delete_count;
THD *thd= current_thd;
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
READ_RECORD info;
TABLE_LIST tables;
@@ -6708,7 +6777,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
/* We can abort alter table for any table type */
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES));
@@ -6782,6 +6851,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
break;
}
thd->row_count++;
+ /* Return error if source table isn't empty. */
+ if (error_if_not_empty)
+ {
+ error= 1;
+ break;
+ }
if (to->next_number_field)
{
if (auto_increment_field_copied)
@@ -6795,7 +6870,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
copy_ptr->do_copy(copy_ptr);
}
prev_insert_id= to->file->next_insert_id;
- if ((error=to->file->ha_write_row((byte*) to->record[0])))
+ error=to->file->write_row(to->record[0]);
+ to->auto_increment_field_not_null= FALSE;
+ if (error)
{
if (!ignore ||
to->file->is_fatal_error(error, HA_CHECK_DUP))
@@ -6805,7 +6882,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
uint key_nr= to->file->get_dup_key(error);
if ((int) key_nr >= 0)
{
- const char *err_msg= ER(ER_DUP_ENTRY);
+ const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
if (key_nr == 0 &&
(to->key_info[0].key_part[0].field->flags &
AUTO_INCREMENT_FLAG))
@@ -6866,31 +6943,26 @@ copy_data_between_tables(TABLE *from,TABLE *to,
mysql_recreate_table()
thd Thread handler
tables Tables to recreate
- do_send_ok If we should send_ok() or leave it to caller
RETURN
Like mysql_alter_table().
*/
-bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
- bool do_send_ok)
+bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
{
- DBUG_ENTER("mysql_recreate_table");
- LEX *lex= thd->lex;
HA_CREATE_INFO create_info;
- lex->create_list.empty();
- lex->key_list.empty();
- lex->col_list.empty();
- lex->alter_info.reset();
- bzero((char*) &create_info,sizeof(create_info));
+ Alter_info alter_info;
+
+ DBUG_ENTER("mysql_recreate_table");
+
+ bzero((char*) &create_info, sizeof(create_info));
create_info.db_type= 0;
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
/* Force alter table to recreate table */
- lex->alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
+ alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
- table_list, lex->create_list,
- lex->key_list, 0, (ORDER *) 0,
- 0, &lex->alter_info, do_send_ok));
+ table_list, &alter_info, 0,
+ (ORDER *) 0, 0));
}
@@ -6905,7 +6977,8 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
item->maybe_null= 1;
- field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
+ field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
item->maybe_null= 1;
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -6973,15 +7046,15 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
for (uint i= 0; i < t->s->fields; i++ )
{
Field *f= t->field[i];
- if ((f->type() == FIELD_TYPE_BLOB) ||
+ if ((f->type() == MYSQL_TYPE_BLOB) ||
(f->type() == MYSQL_TYPE_VARCHAR))
{
String tmp;
f->val_str(&tmp);
- row_crc= my_checksum(row_crc, (byte*) tmp.ptr(), tmp.length());
+ row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), tmp.length());
}
else
- row_crc= my_checksum(row_crc, (byte*) f->ptr,
+ row_crc= my_checksum(row_crc, f->ptr,
f->pack_length());
}
@@ -7022,7 +7095,7 @@ static bool check_engine(THD *thd, const char *table_name,
if (req_engine && req_engine != *new_engine)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
ha_resolve_storage_engine_name(*new_engine),
@@ -7034,7 +7107,7 @@ static bool check_engine(THD *thd, const char *table_name,
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
{
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
- hton2plugin[(*new_engine)->slot]->name.str, "TEMPORARY");
+ ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
*new_engine= 0;
return TRUE;
}
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index 470fa5bc862..b4a03a370ba 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,7 +34,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- hton2plugin[hton->slot]->name.str,
+ ha_resolve_storage_engine_name(hton),
ts_info->tablespace_name ? ts_info->tablespace_name
: ts_info->logfile_group_name);
}
@@ -64,7 +63,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
- hton2plugin[hton->slot]->name.str,
+ ha_resolve_storage_engine_name(hton),
"TABLESPACE or LOGFILE GROUP");
}
if (mysql_bin_log.is_open())
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 219ca8260ed..5bd01eea68c 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -74,17 +73,18 @@ void print_cached_tables(void)
uint idx,count,unused;
TABLE *start_link,*lnk;
+ /* purecov: begin tested */
VOID(pthread_mutex_lock(&LOCK_open));
- puts("DB Table Version Thread L.thread Open Lock");
+ puts("DB Table Version Thread Open Lock");
for (idx=unused=0 ; idx < open_cache.records ; idx++)
{
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n",
- entry->s->db.str, entry->s->table_name.str, entry->s->version,
+ printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
+ entry->s->db.str, entry->s->table_name.str, entry->s->version,
entry->in_use ? entry->in_use->thread_id : 0L,
- entry->in_use ? entry->in_use->dbug_thread_id : 0L,
- entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
+ entry->db_stat ? 1 : 0,
+ entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
if (!entry->in_use)
unused++;
}
@@ -111,6 +111,7 @@ void print_cached_tables(void)
printf("Error: File hash table is corrupted\n");
fflush(stdout);
VOID(pthread_mutex_unlock(&LOCK_open));
+ /* purecov: end */
return;
}
@@ -348,7 +349,7 @@ static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data,
table_lock_info.lock_text=text;
// lock_type is also obtainable from THR_LOCK_DATA
table_lock_info.type=table->reginfo.lock_type;
- VOID(push_dynamic(ar,(gptr) &table_lock_info));
+ VOID(push_dynamic(ar,(uchar*) &table_lock_info));
}
}
}
@@ -393,7 +394,7 @@ static void display_table_locks(void)
VOID(pthread_mutex_unlock(&THR_LOCK_lock));
if (!saved_table_locks.elements) goto end;
- qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
+ qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
freeze_size(&saved_table_locks);
puts("\nThread database.table_name Locked/Waiting Lock_type\n");
@@ -507,7 +508,9 @@ Next alarm time: %lu\n",
display_table_locks();
fflush(stdout);
my_checkmalloc();
+ fprintf(stdout,"\nBegin safemalloc memory dump:\n"); // tag needed for test suite
TERMINATE(stdout); // Write malloc information
+ fprintf(stdout,"\nEnd safemalloc memory dump.\n");
#ifdef HAVE_MALLINFO
struct mallinfo info= mallinfo();
@@ -536,6 +539,6 @@ Estimated memory (with thread stack): %ld\n",
(long) (thread_count * thread_stack + info.hblkhd + info.arena));
#endif
- Events::get_instance()->dump_internal_status();
+ Events::dump_internal_status();
puts("");
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 8ca72eab8bf..e15003ab243 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -107,10 +106,6 @@ const LEX_STRING trg_event_type_names[]=
};
-static int
-add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
- TABLE_LIST ** table);
-
class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
{
private:
@@ -119,7 +114,7 @@ public:
Handle_old_incorrect_sql_modes_hook(char *file_path)
:path(file_path)
{};
- virtual bool process_unknown_string(char *&unknown_key, gptr base,
+ virtual bool process_unknown_string(char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end);
};
@@ -130,7 +125,7 @@ public:
LEX_STRING *trigger_table_arg)
:path(file_path), trigger_table_value(trigger_table_arg)
{};
- virtual bool process_unknown_string(char *&unknown_key, gptr base,
+ virtual bool process_unknown_string(char *&unknown_key, uchar* base,
MEM_ROOT *mem_root, char *end);
private:
char *path;
@@ -284,7 +279,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
/* We also don't allow creation of triggers on views. */
tables->required_type= FRMTYPE_TABLE;
- if (reopen_name_locked_table(thd, tables))
+ if (reopen_name_locked_table(thd, tables, TRUE))
{
unlock_table_name(thd, tables);
goto end;
@@ -341,7 +336,7 @@ end:
tables - table list containing one open table for which the
trigger is created.
stmt_query - [OUT] after successful return, this string contains
- well-formed statement for creation this trigger.
+ well-formed statement for creating this trigger.
NOTE
- Assumes that trigger name is fully qualified.
@@ -381,7 +376,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
}
/* We don't allow creation of several triggers of the same type yet */
- if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
+ if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time] != 0)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"multiple triggers with the same action time"
@@ -489,7 +484,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
trigname.trigger_table.length= tables->table_name_length;
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
- (gptr)&trigname, trigname_file_parameters, 0))
+ (uchar*)&trigname, trigname_file_parameters, 0))
return 1;
/*
@@ -579,7 +574,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
/* Create trigger definition file. */
if (!sql_create_definition_file(NULL, &file, &triggers_file_type,
- (gptr)this, triggers_file_parameters, 0))
+ (uchar*)this, triggers_file_parameters, 0))
return 0;
err_with_cleanup:
@@ -659,7 +654,7 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
triggers_file_ext, 0);
file.str= file_buff;
return sql_create_definition_file(NULL, &file, &triggers_file_type,
- (gptr)triggers, triggers_file_parameters,
+ (uchar*)triggers, triggers_file_parameters,
0);
}
@@ -674,7 +669,7 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
tables - table list containing one open table for which trigger
is dropped.
stmt_query - [OUT] after successful return, this string contains
- well-formed statement for creation this trigger.
+ well-formed statement for deleting this trigger.
RETURN VALUE
False - success
@@ -782,7 +777,7 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
table == (*fld)->table)))
return 1;
(*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] -
- table->record[0]));
+ table->record[0]));
}
*old_fld= 0;
@@ -800,8 +795,8 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
void Table_triggers_list::set_table(TABLE *new_table)
{
- table= new_table;
- for (Field **field= table->triggers->record1_field ; *field ; field++)
+ trigger_table= new_table;
+ for (Field **field= new_table->triggers->record1_field ; *field ; field++)
{
(*field)->table= (*field)->orig_table= new_table;
(*field)->table_name= &new_table->alias;
@@ -870,7 +865,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
triggers->definition_modes_list.empty();
triggers->definers_list.empty();
- if (parser->parse((gptr)triggers, &table->mem_root,
+ if (parser->parse((uchar*)triggers, &table->mem_root,
triggers_file_parameters,
TRG_NUM_REQUIRED_PARAMETERS,
&sql_modes_hook))
@@ -950,7 +945,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
of routines used by statement.
*/
triggers->sroutines_key.length= 1+strlen(db)+1+strlen(table_name)+1;
- if (!(triggers->sroutines_key.str=
+ if (!(triggers->sroutines_key.str= (char*)
alloc_root(&table->mem_root, triggers->sroutines_key.length)))
DBUG_RETURN(1);
triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER;
@@ -981,16 +976,17 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
LEX_STRING *trg_definer= it_definer++;
thd->variables.sql_mode= (ulong)*trg_sql_mode;
- lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
- thd->spcont= 0;
- if (MYSQLparse((void *)thd) || thd->is_fatal_error)
+ Lex_input_stream lip(thd, trg_create_str->str, trg_create_str->length);
+ thd->m_lip= &lip;
+ lex_start(thd);
+ thd->spcont= 0;
+ int err= MYSQLparse((void *)thd);
+
+ if (err || thd->is_fatal_error)
{
- /*
- Free lex associated resources.
- QQ: Do we really need all this stuff here ?
- */
- delete lex.sphead;
+ /* Currently sphead is always deleted in case of a parse error */
+ DBUG_ASSERT(lex.sphead == 0);
goto err_with_lex_cleanup;
}
@@ -1181,7 +1177,7 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
1 Error
*/
-static int
+int
add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
TABLE_LIST **table)
{
@@ -1227,7 +1223,7 @@ add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
DBUG_RETURN(1);
}
- if (parser->parse((gptr)&trigname, thd->mem_root,
+ if (parser->parse((uchar*)&trigname, thd->mem_root,
trigname_file_parameters, 1,
&trigger_table_hook))
DBUG_RETURN(1);
@@ -1364,7 +1360,8 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
It is OK to allocate some memory on table's MEM_ROOT since this
table instance will be thrown out at the end of rename anyway.
*/
- new_def.str= memdup_root(&table->mem_root, buff.ptr(), buff.length());
+ new_def.str= (char*) memdup_root(&trigger_table->mem_root, buff.ptr(),
+ buff.length());
new_def.length= buff.length();
on_table_name->str= new_def.str + before_on_len;
on_table_name->length= on_q_table_name_len;
@@ -1425,7 +1422,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
trigname.trigger_table= *new_table_name;
if (sql_create_definition_file(NULL, &trigname_file, &trigname_file_type,
- (gptr)&trigname, trigname_file_parameters,
+ (uchar*)&trigname, trigname_file_parameters,
0))
return trigger;
}
@@ -1542,17 +1539,24 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
if (old_row_is_record1)
{
old_field= record1_field;
- new_field= table->field;
+ new_field= trigger_table->field;
}
else
{
new_field= record1_field;
- old_field= table->field;
+ old_field= trigger_table->field;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- Security_context *save_ctx;
+ Security_context *sctx= &sp_trigger->m_security_ctx;
+ Security_context *save_ctx= NULL;
+
- if (sp_change_security_context(thd, sp_trigger, &save_ctx))
+ if (sp_trigger->m_chistics->suid != SP_IS_NOT_SUID &&
+ sctx->change_security_context(thd,
+ &sp_trigger->m_definer_user,
+ &sp_trigger->m_definer_host,
+ &sp_trigger->m_db,
+ &save_ctx))
return TRUE;
/*
@@ -1563,7 +1567,8 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
fill_effective_table_privileges(thd,
&subject_table_grants[event][time_type],
- table->s->db.str, table->s->table_name.str);
+ trigger_table->s->db.str,
+ trigger_table->s->table_name.str);
/* Check that the definer has TRIGGER privilege on the subject table. */
@@ -1574,21 +1579,21 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
- table->s->table_name.str);
+ trigger_table->s->table_name.str);
- sp_restore_security_context(thd, save_ctx);
+ sctx->restore_security_context(thd, save_ctx);
return TRUE;
}
#endif // NO_EMBEDDED_ACCESS_CHECKS
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
err_status= sp_trigger->execute_trigger
- (thd, table->s->db.str, table->s->table_name.str,
+ (thd, trigger_table->s->db.str, trigger_table->s->table_name.str,
&subject_table_grants[event][time_type]);
thd->restore_sub_statement_state(&statement_state);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sp_restore_security_context(thd, save_ctx);
+ sctx->restore_security_context(thd, save_ctx);
#endif // NO_EMBEDDED_ACCESS_CHECKS
}
@@ -1624,13 +1629,13 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
/* We cannot mark fields which does not present in table. */
if (trg_field->field_idx != (uint)-1)
{
- bitmap_set_bit(table->read_set, trg_field->field_idx);
+ bitmap_set_bit(trigger_table->read_set, trg_field->field_idx);
if (trg_field->get_settable_routine_parameter())
- bitmap_set_bit(table->write_set, trg_field->field_idx);
+ bitmap_set_bit(trigger_table->write_set, trg_field->field_idx);
}
}
}
- table->file->column_bitmaps_signal();
+ trigger_table->file->column_bitmaps_signal();
}
@@ -1658,7 +1663,7 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
bool
Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
- gptr base,
+ uchar* base,
MEM_ROOT *mem_root,
char *end)
{
@@ -1701,7 +1706,7 @@ Handle_old_incorrect_sql_modes_hook::process_unknown_string(char *&unknown_key,
bool
Handle_old_incorrect_trigger_table_hook::
-process_unknown_string(char *&unknown_key, gptr base, MEM_ROOT *mem_root,
+process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root,
char *end)
{
DBUG_ENTER("Handle_old_incorrect_trigger_table_hook::process_unknown_string");
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 09576f5e523..7d99dd811cd 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -43,8 +42,9 @@ class Table_triggers_list: public Sql_alloc
*/
Field **new_field;
Field **old_field;
+
/* TABLE instance for which this triggers list object was created */
- TABLE *table;
+ TABLE *trigger_table;
/*
Names of triggers.
Should correspond to order of triggers on definitions_list,
@@ -84,7 +84,7 @@ public:
List<LEX_STRING> definers_list;
Table_triggers_list(TABLE *table_arg):
- record1_field(0), table(table_arg)
+ record1_field(0), trigger_table(table_arg)
{
bzero((char *)bodies, sizeof(bodies));
bzero((char *)trigger_fields, sizeof(trigger_fields));
@@ -110,6 +110,11 @@ public:
const char *old_table,
const char *new_db,
const char *new_table);
+ bool has_triggers(trg_event_type event_type,
+ trg_action_time_type action_time)
+ {
+ return (bodies[event_type][action_time] != NULL);
+ }
bool has_delete_triggers()
{
return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
@@ -137,3 +142,7 @@ private:
extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];
+
+int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST **table);
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index f0d31965573..20ce614f361 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -93,12 +92,12 @@ static char *init_syms(udf_func *tmp, char *nm)
}
-extern "C" byte* get_hash_key(const byte *buff,uint *length,
+extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
udf_func *udf=(udf_func*) buff;
*length=(uint) udf->name.length;
- return (byte*) udf->name.str;
+ return (uchar*) udf->name.str;
}
@@ -138,7 +137,7 @@ void udf_init()
new_thd->store_globals();
new_thd->set_db(db, sizeof(db)-1);
- bzero((gptr) &tables,sizeof(tables));
+ bzero((uchar*) &tables,sizeof(tables));
tables.alias= tables.table_name= (char*) "func";
tables.lock_type = TL_READ;
tables.db= db;
@@ -146,7 +145,8 @@ void udf_init()
if (simple_open_n_lock_tables(new_thd, &tables))
{
DBUG_PRINT("error",("Can't open udf table"));
- sql_print_error("Can't open the mysql.func table. Please run the mysql_upgrade script to create it.");
+ sql_print_error("Can't open the mysql.func table. Please "
+ "run mysql_upgrade to create it.");
goto end;
}
@@ -169,9 +169,15 @@ void udf_init()
Ensure that the .dll doesn't have a path
This is done to ensure that only approved dll from the system
directories are used (to make this even remotely secure).
+
+ On windows we must check both FN_LIBCHAR and '/'.
*/
- if (my_strchr(files_charset_info, dl_name, dl_name + strlen(dl_name), FN_LIBCHAR) ||
- strlen(name.str) > NAME_LEN)
+ if (my_strchr(files_charset_info, dl_name,
+ dl_name + strlen(dl_name), FN_LIBCHAR) ||
+ IF_WIN(my_strchr(files_charset_info, dl_name,
+ dl_name + strlen(dl_name), '/'), 0) ||
+ check_string_char_length(&name, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
{
sql_print_error("Invalid row in mysql.func table for function '%.64s'",
name.str);
@@ -188,10 +194,13 @@ void udf_init()
void *dl = find_udf_dl(tmp->dl);
if (dl == NULL)
{
- if (!(dl= dlopen(tmp->dl, RTLD_NOW)))
+ char dlpath[FN_REFLEN];
+ strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl,
+ NullS);
+ if (!(dl= dlopen(dlpath, RTLD_NOW)))
{
/* Print warning to log */
- sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl, errno, dlerror());
+ sql_print_error(ER(ER_CANT_OPEN_LIBRARY), tmp->dl, errno, dlerror());
/* Keep the udf in the hash so that we can remove it later */
continue;
}
@@ -258,7 +267,7 @@ static void del_udf(udf_func *udf)
DBUG_ENTER("del_udf");
if (!--udf->usage_count)
{
- hash_delete(&udf_hash,(byte*) udf);
+ hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
}
else
@@ -272,7 +281,7 @@ static void del_udf(udf_func *udf)
uint name_length=udf->name.length;
udf->name.str=(char*) "*";
udf->name.length=1;
- hash_update(&udf_hash,(byte*) udf,(byte*) name,name_length);
+ hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
}
DBUG_VOID_RETURN;
}
@@ -292,7 +301,7 @@ void free_udf(udf_func *udf)
We come here when someone has deleted the udf function
while another thread still was using the udf
*/
- hash_delete(&udf_hash,(byte*) udf);
+ hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
if (!find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
@@ -318,7 +327,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used)
else
rw_rdlock(&THR_LOCK_udf); /* Called during parsing */
- if ((udf=(udf_func*) hash_search(&udf_hash,(byte*) name,
+ if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name,
length ? length : (uint) strlen(name))))
{
if (!udf->dlhandle)
@@ -365,7 +374,7 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
tmp->returns = ret;
tmp->type = type;
tmp->usage_count=1;
- if (my_hash_insert(&udf_hash,(byte*) tmp))
+ if (my_hash_insert(&udf_hash,(uchar*) tmp))
return 0;
using_udf_functions=1;
return tmp;
@@ -392,30 +401,45 @@ int mysql_create_function(THD *thd,udf_func *udf)
Ensure that the .dll doesn't have a path
This is done to ensure that only approved dll from the system
directories are used (to make this even remotely secure).
+
+ On windows we must check both FN_LIBCHAR and '/'.
*/
- if (my_strchr(files_charset_info, udf->dl, udf->dl + strlen(udf->dl), FN_LIBCHAR))
+ if (my_strchr(files_charset_info, udf->dl,
+ udf->dl + strlen(udf->dl), FN_LIBCHAR) ||
+ IF_WIN(my_strchr(files_charset_info, udf->dl,
+ udf->dl + strlen(udf->dl), '/'), 0))
{
my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
DBUG_RETURN(1);
}
- if (udf->name.length > NAME_LEN)
+ if (check_string_char_length(&udf->name, "", NAME_CHAR_LEN,
+ system_charset_info, 1))
{
my_error(ER_TOO_LONG_IDENT, MYF(0), udf->name);
DBUG_RETURN(1);
}
+ /*
+ Turn off row binlogging of this statement and use statement-based
+ so that all supporting tables are updated for CREATE FUNCTION command.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
+
rw_wrlock(&THR_LOCK_udf);
- if ((hash_search(&udf_hash,(byte*) udf->name.str, udf->name.length)))
+ if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
{
my_error(ER_UDF_EXISTS, MYF(0), udf->name);
goto err;
}
if (!(dl = find_udf_dl(udf->dl)))
{
- if (!(dl = dlopen(udf->dl, RTLD_NOW)))
+ char dlpath[FN_REFLEN];
+ strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
+ if (!(dl = dlopen(dlpath, RTLD_NOW)))
{
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
- udf->dl, errno, dlerror()));
+ udf->dl, errno, dlerror()));
my_error(ER_CANT_OPEN_LIBRARY, MYF(0),
udf->dl, errno, dlerror());
goto err;
@@ -467,6 +491,15 @@ int mysql_create_function(THD *thd,udf_func *udf)
goto err;
}
rw_unlock(&THR_LOCK_udf);
+
+ /* Binlog the create function. */
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ thd->query, thd->query_length, FALSE, FALSE);
+ }
+
DBUG_RETURN(0);
err:
@@ -482,19 +515,32 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
TABLE *table;
TABLE_LIST tables;
udf_func *udf;
+ char *exact_name_str;
+ uint exact_name_len;
DBUG_ENTER("mysql_drop_function");
+
if (!initialized)
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
DBUG_RETURN(1);
}
+
+ /*
+ Turn off row binlogging of this statement and use statement-based
+ so that all supporting tables are updated for DROP FUNCTION command.
+ */
+ if (thd->current_stmt_binlog_row_based)
+ thd->clear_current_stmt_binlog_row_based();
+
rw_wrlock(&THR_LOCK_udf);
- if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str,
+ if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
(uint) udf_name->length)))
{
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
goto err;
}
+ exact_name_str= udf->name.str;
+ exact_name_len= udf->name.length;
del_udf(udf);
/*
Close the handle if this was function that was found during boot or
@@ -509,10 +555,9 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
table->use_all_columns();
- table->field[0]->store(udf_name->str, udf_name->length, system_charset_info);
+ table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
if (!table->file->index_read_idx(table->record[0], 0,
- (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
+ (uchar*) table->field[0]->ptr, HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
int error;
@@ -521,7 +566,16 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
}
close_thread_tables(thd);
- rw_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
+
+ /* Binlog the drop function. */
+ if (mysql_bin_log.is_open())
+ {
+ thd->clear_error();
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ thd->query, thd->query_length, FALSE, FALSE);
+ }
+
DBUG_RETURN(0);
err:
rw_unlock(&THR_LOCK_udf);
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 21cf735f5ab..3cd9343610c 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2003-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 0715a0c4296..c872d3cb241 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -112,7 +111,7 @@ bool select_union::flush()
*/
bool
-select_union::create_result_table(THD *thd, List<Item> *column_types,
+select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *alias)
{
@@ -120,7 +119,7 @@ select_union::create_result_table(THD *thd, List<Item> *column_types,
tmp_table_param.init();
tmp_table_param.field_count= column_types->elements;
- if (! (table= create_tmp_table(thd, &tmp_table_param, *column_types,
+ if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, (char*) alias)))
return TRUE;
@@ -142,18 +141,28 @@ select_union::create_result_table(THD *thd, List<Item> *column_types,
*/
void
-st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
+st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
{
- thd->lex->current_select= fake_select_lex;
- fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
- (byte **)
+ thd_arg->lex->current_select= fake_select_lex;
+ fake_select_lex->table_list.link_in_list((uchar *)&result_table_list,
+ (uchar **)
&result_table_list.next_local);
+ fake_select_lex->context.table_list=
+ fake_select_lex->context.first_name_resolution_table=
+ fake_select_lex->get_table_list();
+ if (!fake_select_lex->first_execution)
+ {
+ for (ORDER *order= (ORDER *) global_parameters->order_list.first;
+ order;
+ order= order->next)
+ order->item= &order->item_ptr;
+ }
for (ORDER *order= (ORDER *)global_parameters->order_list.first;
order;
order=order->next)
{
(*order->item)->walk(&Item::change_context_processor, 0,
- (byte*) &fake_select_lex->context);
+ (uchar*) &fake_select_lex->context);
}
}
@@ -164,7 +173,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_sl= first_select();
select_result *tmp_result;
- bool is_union;
+ bool is_union_select;
TABLE *empty_table= 0;
DBUG_ENTER("st_select_lex_unit::prepare");
@@ -198,15 +207,15 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
DBUG_RETURN(FALSE);
}
prepared= 1;
- res= FALSE;
+ saved_error= FALSE;
thd_arg->lex->current_select= sl= first_sl;
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
- is_union= first_sl->next_select() || fake_select_lex;
+ is_union_select= is_union() || fake_select_lex;
/* Global option */
- if (is_union)
+ if (is_union_select)
{
if (!(tmp_result= union_result= new select_union))
goto err;
@@ -237,31 +246,33 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= sl;
- can_skip_order_by= is_union && !(sl->braces && sl->explicit_limit);
-
- res= join->prepare(&sl->ref_pointer_array,
- (TABLE_LIST*) sl->table_list.first, sl->with_wild,
- sl->where,
- (can_skip_order_by ? 0 : sl->order_list.elements) +
- sl->group_list.elements,
- can_skip_order_by ?
- (ORDER*) 0 : (ORDER *)sl->order_list.first,
- (ORDER*) sl->group_list.first,
- sl->having,
- (is_union ? (ORDER*) 0 :
- (ORDER*) thd_arg->lex->proc_list.first),
- sl, this);
+ can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit);
+
+ saved_error= join->prepare(&sl->ref_pointer_array,
+ (TABLE_LIST*) sl->table_list.first,
+ sl->with_wild,
+ sl->where,
+ (can_skip_order_by ? 0 :
+ sl->order_list.elements) +
+ sl->group_list.elements,
+ can_skip_order_by ?
+ (ORDER*) 0 : (ORDER *)sl->order_list.first,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (is_union_select ? (ORDER*) 0 :
+ (ORDER*) thd_arg->lex->proc_list.first),
+ sl, this);
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
- if ((res= (res || thd_arg->is_fatal_error)))
+ if (saved_error || (saved_error= thd_arg->is_fatal_error))
goto err;
/*
Use items list of underlaid select for derived tables to preserve
information about fields lengths and exact types
*/
- if (!is_union)
+ if (!is_union_select)
types= first_sl->item_list;
else if (sl == first_sl)
{
@@ -304,7 +315,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
- if (is_union)
+ if (is_union_select)
{
/*
Check that it was possible to aggregate
@@ -350,12 +361,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
- res= table->fill_item_list(&item_list);
+ saved_error= table->fill_item_list(&item_list);
if (arena)
thd->restore_active_arena(arena, &backup_arena);
- if (res)
+ if (saved_error)
goto err;
if (thd->stmt_arena->is_stmt_prepare())
@@ -374,7 +385,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
fake_select_lex->item_list= item_list;
thd_arg->lex->current_select= fake_select_lex;
- res= fake_select_lex->join->
+ saved_error= fake_select_lex->join->
prepare(&fake_select_lex->ref_pointer_array,
(TABLE_LIST*) fake_select_lex->table_list.first,
0, 0,
@@ -399,7 +410,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
- DBUG_RETURN(res || thd_arg->is_fatal_error);
+ DBUG_RETURN(saved_error || thd_arg->is_fatal_error);
err:
thd_arg->lex->current_select= lex_select_save;
@@ -443,7 +454,7 @@ bool st_select_lex_unit::exec()
thd->lex->current_select= sl;
if (optimized)
- res= sl->join->reinit();
+ saved_error= sl->join->reinit();
else
{
set_limit(sl);
@@ -466,9 +477,9 @@ bool st_select_lex_unit::exec()
sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
- res= sl->join->optimize();
+ saved_error= sl->join->optimize();
}
- if (!res)
+ if (!saved_error)
{
records_at_start= table->file->stats.records;
sl->join->exec();
@@ -478,11 +489,11 @@ bool st_select_lex_unit::exec()
DBUG_RETURN(TRUE);
table->no_keyread=1;
}
- res= sl->join->error;
+ saved_error= sl->join->error;
offset_limit_cnt= (ha_rows)(sl->offset_limit ?
sl->offset_limit->val_uint() :
0);
- if (!res)
+ if (!saved_error)
{
examined_rows+= thd->examined_row_count;
if (union_result->flush())
@@ -492,10 +503,10 @@ bool st_select_lex_unit::exec()
}
}
}
- if (res)
+ if (saved_error)
{
thd->lex->current_select= lex_select_save;
- DBUG_RETURN(res);
+ DBUG_RETURN(saved_error);
}
/* Needed for the following test and for records_at_start in next loop */
int error= table->file->info(HA_STATUS_VARIABLE);
@@ -521,7 +532,7 @@ bool st_select_lex_unit::exec()
optimized= 1;
/* Send result to 'result' */
- res= TRUE;
+ saved_error= TRUE;
{
List<Item_func_match> empty_list;
empty_list.empty();
@@ -562,17 +573,17 @@ bool st_select_lex_unit::exec()
}
join->init(thd, item_list, fake_select_lex->options, result);
}
- res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
- &result_table_list,
- 0, item_list, NULL,
- global_parameters->order_list.elements,
- (ORDER*)global_parameters->order_list.first,
- (ORDER*) NULL, NULL, (ORDER*) NULL,
- fake_select_lex->options | SELECT_NO_UNLOCK,
- result, this, fake_select_lex);
+ saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
+ &result_table_list,
+ 0, item_list, NULL,
+ global_parameters->order_list.elements,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ fake_select_lex->options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex);
fake_select_lex->table_list.empty();
- if (!res)
+ if (!saved_error)
{
thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows;
thd->examined_row_count+= examined_rows;
@@ -584,7 +595,7 @@ bool st_select_lex_unit::exec()
}
}
thd->lex->current_select= lex_select_save;
- DBUG_RETURN(res);
+ DBUG_RETURN(saved_error);
}
@@ -620,6 +631,12 @@ bool st_select_lex_unit::cleanup()
join->tables= 0;
}
error|= fake_select_lex->cleanup();
+ if (fake_select_lex->order_list.elements)
+ {
+ ORDER *ord;
+ for (ord= (ORDER*)fake_select_lex->order_list.first; ord; ord= ord->next)
+ (*ord->item)->cleanup();
+ }
}
DBUG_RETURN(error);
@@ -630,7 +647,7 @@ void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
#ifndef DBUG_OFF
- if (first_select()->next_select())
+ if (is_union())
{
List_iterator_fast<Item> it(item_list);
Item *field;
@@ -661,18 +678,18 @@ void st_select_lex_unit::reinit_exec_mechanism()
TRUE - error
*/
-bool st_select_lex_unit::change_result(select_subselect *result,
+bool st_select_lex_unit::change_result(select_subselect *new_result,
select_subselect *old_result)
{
bool res= FALSE;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl->join && sl->join->result == old_result)
- if (sl->join->change_result(result))
+ if (sl->join->change_result(new_result))
return TRUE;
}
if (fake_select_lex && fake_select_lex->join)
- res= fake_select_lex->join->change_result(result);
+ res= fake_select_lex->join->change_result(new_result);
return (res);
}
@@ -697,7 +714,6 @@ bool st_select_lex_unit::change_result(select_subselect *result,
List<Item> *st_select_lex_unit::get_unit_column_types()
{
SELECT_LEX *sl= first_select();
- bool is_union= test(sl->next_select());
bool is_procedure= test(sl->join->procedure);
if (is_procedure)
@@ -708,7 +724,7 @@ List<Item> *st_select_lex_unit::get_unit_column_types()
}
- if (is_union)
+ if (is_union())
{
DBUG_ASSERT(prepared);
/* Types are generated during prepare */
@@ -735,6 +751,8 @@ bool st_select_lex::cleanup()
{
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
}
+ non_agg_fields.empty();
+ inner_refs_list.empty();
DBUG_RETURN(error);
}
@@ -751,4 +769,3 @@ void st_select_lex::cleanup_all_joins(bool full)
for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full);
}
-
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index a379ea66db6..693ba779e5d 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,11 +24,9 @@
#include "sp_head.h"
#include "sql_trigger.h"
-static bool safe_update_on_fly(JOIN_TAB *join_tab);
-
/* Return 0 if row hasn't changed */
-static bool compare_record(TABLE *table)
+bool compare_record(TABLE *table)
{
if (table->s->blob_fields + table->s->varchar_fields == 0)
return cmp_record(table,record[1]);
@@ -67,7 +64,6 @@ static bool check_fields(THD *thd, List<Item> &items)
List_iterator<Item> it(items);
Item *item;
Item_field *field;
- Name_resolution_context *context= &thd->lex->select_lex.context;
while ((item= it++))
{
@@ -130,13 +126,14 @@ int mysql_update(THD *thd,
#endif
uint table_count= 0;
ha_rows updated, found;
- key_map old_used_keys;
+ key_map old_covering_keys;
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen;
ulonglong id;
+ List<Item> all_fields;
DBUG_ENTER("mysql_update");
for ( ; ; )
@@ -168,18 +165,19 @@ int mysql_update(THD *thd,
thd->proc_info="init";
table= table_list->table;
- /* Calculate "table->used_keys" based on the WHERE */
- table->used_keys= table->s->keys_in_use;
+ /* Calculate "table->covering_keys" based on the WHERE */
+ table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /* TABLE_LIST contain right privilages request */
- want_privilege= table_list->grant.want_privilege;
+ /* Force privilege re-checking for views after they have been opened. */
+ want_privilege= (table_list->view ? UPDATE_ACL :
+ table_list->grant.want_privilege);
#endif
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(1);
- old_used_keys= table->used_keys; // Keys used in WHERE
+ old_covering_keys= table->covering_keys; // Keys used in WHERE
/* Check the fields we are going to modify */
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
@@ -204,8 +202,10 @@ int mysql_update(THD *thd,
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
else
{
- bitmap_set_bit(table->write_set,
- table->timestamp_field->field_index);
+ if (table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE ||
+ table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH)
+ bitmap_set_bit(table->write_set,
+ table->timestamp_field->field_index);
}
}
@@ -220,6 +220,10 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); /* purecov: inspected */
}
+ if (select_lex->inner_refs_list.elements &&
+ fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
+ DBUG_RETURN(-1);
+
if (conds)
{
Item::cond_result cond_value;
@@ -228,7 +232,7 @@ int mysql_update(THD *thd,
limit= 0; // Impossible WHERE
}
// Don't count on usage of 'only index' when calculating which key to use
- table->used_keys.clear_all();
+ table->covering_keys.clear_all();
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (prune_partitions(thd, table, conds))
@@ -303,7 +307,7 @@ int mysql_update(THD *thd,
We can't update table directly; We must first search after all
matching rows before updating the table!
*/
- if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
+ if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
{
table->key_read=1;
table->mark_columns_used_by_index(used_index);
@@ -321,7 +325,7 @@ int mysql_update(THD *thd,
to update
NOTE: filesort will call table->prepare_for_position()
*/
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
ha_rows examined_rows;
@@ -446,12 +450,25 @@ int mysql_update(THD *thd,
thd->proc_info="Updating";
transactional_table= table->file->has_transactions();
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= test(!ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- will_batch= !table->file->start_bulk_update();
+ if (table->triggers &&
+ table->triggers->has_triggers(TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER UPDATE triggers that might access to subject
+ table and therefore might need update to be done immediately.
+ So we turn-off the batching.
+ */
+ (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+ will_batch= FALSE;
+ }
+ else
+ will_batch= !table->file->start_bulk_update();
/*
We can use compare_record() to optimize away updates if
@@ -473,7 +490,7 @@ int mysql_update(THD *thd,
if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
table->triggers,
TRG_EVENT_UPDATE))
- break; /* purecov: inspected */
+ break; /* purecov: inspected */
found++;
@@ -528,13 +545,13 @@ int mysql_update(THD *thd,
else
{
/* Non-batched update */
- error= table->file->ha_update_row((byte*) table->record[1],
- (byte*) table->record[0]);
+ error= table->file->ha_update_row(table->record[1],
+ table->record[0]);
}
if (!error)
{
updated++;
- thd->no_trans_update= !transactional_table;
+ thd->no_trans_update.stmt= !transactional_table;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
@@ -604,6 +621,37 @@ int mysql_update(THD *thd,
thd->row_count++;
}
dup_key_found= 0;
+
+ /*
+ todo bug#27571: to avoid asynchronization of `error' and
+ `error_code' of binlog event constructor
+
+ The concept, which is a bit different for insert(!), is to
+ replace `error' assignment with the following lines
+
+ killed_status= thd->killed; // get the status of the volatile
+
+ Notice: thd->killed is type of "state" whereas the lhs has
+ "status" the suffix which translates according to WordNet: a state
+ at a particular time - at the time of the end of per-row loop in
+ our case. Binlogging ops are conducted with the status.
+
+ error= (killed_status == THD::NOT_KILLED)? error : 1;
+
+ which applies to most mysql_$query functions.
+ Event's constructor will accept `killed_status' as an argument:
+
+ Query_log_event qinfo(..., killed_status);
+
+ thd->killed might be changed after killed_status had got cached and this
+ won't affect binlogging event but other effects remain.
+
+ Open issue: In a case the error happened not because of KILLED -
+ and then KILLED was caught later still within the loop - we shall
+ do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN
+ error_code.
+ */
+
if (thd->killed && !error)
error= 1; // Aborted
else if (will_batch &&
@@ -660,11 +708,11 @@ int mysql_update(THD *thd,
transactional_table, FALSE) &&
transactional_table)
{
- error=1; // Rollback update
+ error=1; // Rollback update
}
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
free_underlaid_joins(thd, select_lex);
if (transactional_table)
@@ -760,7 +808,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
/* Check that we are not using table that we are updating in a sub select */
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
@@ -906,7 +954,7 @@ reopen_tables:
tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
tl->updating= 0;
/* Update TABLE::lock_type accordingly. */
- if (!tl->placeholder() && !tl->schema_table && !using_lock_tables)
+ if (!tl->placeholder() && !using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type;
}
}
@@ -919,7 +967,7 @@ reopen_tables:
if (check_access(thd, want_privilege,
tl->db, &tl->grant.privilege, 0, 0,
test(tl->schema_table)) ||
- (grant_option && check_grant(thd, want_privilege, tl, 0, 1, 0)))
+ check_grant(thd, want_privilege, tl, 0, 1, 0))
DBUG_RETURN(TRUE);
}
}
@@ -986,7 +1034,7 @@ reopen_tables:
tl->lock_type != TL_READ_NO_INSERT)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, tl, table_list)))
+ if ((duplicate= unique_table(thd, tl, table_list, 0)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
DBUG_RETURN(TRUE);
@@ -1021,6 +1069,7 @@ bool mysql_multi_update(THD *thd,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
multi_update *result;
+ bool res;
DBUG_ENTER("mysql_multi_update");
if (!(result= new multi_update(table_list,
@@ -1029,13 +1078,13 @@ bool mysql_multi_update(THD *thd,
handle_duplicates, ignore)))
DBUG_RETURN(TRUE);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= test(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES));
List<Item> total_list;
- (void) mysql_select(thd, &select_lex->ref_pointer_array,
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
table_list, select_lex->with_wild,
total_list,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
@@ -1043,6 +1092,15 @@ bool mysql_multi_update(THD *thd,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
+ DBUG_PRINT("info",("res: %d report_error: %d", res,
+ thd->net.report_error));
+ res|= thd->net.report_error;
+ if (unlikely(res))
+ {
+ /* If we had a another error reported earlier then this will be ignored */
+ result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
+ result->abort();
+ }
delete result;
thd->abort_on_warning= 0;
DBUG_RETURN(FALSE);
@@ -1076,6 +1134,7 @@ int multi_update::prepare(List<Item> &not_used_values,
List_iterator_fast<Item> field_it(*fields);
List_iterator_fast<Item> value_it(*values);
uint i, max_fields;
+ uint leaf_table_count= 0;
DBUG_ENTER("multi_update::prepare");
thd->count_cuted_fields= CHECK_FIELD_WARN;
@@ -1091,7 +1150,7 @@ int multi_update::prepare(List<Item> &not_used_values,
}
/*
- We have to check values after setup_tables to get used_keys right in
+ We have to check values after setup_tables to get covering_keys right in
reference tables
*/
@@ -1109,17 +1168,29 @@ int multi_update::prepare(List<Item> &not_used_values,
{
/* TODO: add support of view of join support */
TABLE *table=table_ref->table;
+ leaf_table_count++;
if (tables_to_update & table->map)
{
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
sizeof(*tl));
if (!tl)
DBUG_RETURN(1);
- update.link_in_list((byte*) tl, (byte**) &tl->next_local);
+ update.link_in_list((uchar*) tl, (uchar**) &tl->next_local);
tl->shared= table_count++;
table->no_keyread=1;
- table->used_keys.clear_all();
+ table->covering_keys.clear_all();
table->pos_in_table_list= tl;
+ if (table->triggers &&
+ table->triggers->has_triggers(TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER))
+ {
+ /*
+ The table has AFTER UPDATE triggers that might access to subject
+ table and therefore might need update to be done immediately.
+ So we turn-off the batching.
+ */
+ (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
+ }
}
}
@@ -1159,29 +1230,73 @@ int multi_update::prepare(List<Item> &not_used_values,
/* Allocate copy fields */
max_fields=0;
for (i=0 ; i < table_count ; i++)
- set_if_bigger(max_fields, fields_for_table[i]->elements);
+ set_if_bigger(max_fields, fields_for_table[i]->elements + leaf_table_count);
copy_field= new Copy_field[max_fields];
+ DBUG_RETURN(thd->is_fatal_error != 0);
+}
- /*
- Mark all copies of tables that are updates to ensure that
- init_read_record() will not try to enable a cache on them
- The problem is that for queries like
+/*
+ Check if table is safe to update on fly
- UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a;
+ SYNOPSIS
+ safe_update_on_fly()
+ thd Thread handler
+ join_tab How table is used in join
+ all_tables List of tables
- the row buffer may contain things that doesn't match what is on disk
- which will cause an error when reading a row.
- (This issue is mostly relevent for MyISAM tables)
- */
- for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
- {
- TABLE *table=table_ref->table;
- if ((tables_to_update & table->map) &&
- unique_table(thd, table_ref, update_tables))
- table->no_cache= 1; // Disable row cache
+ NOTES
+ We can update the first table in join on the fly if we know that
+ a row in this table will never be read twice. This is true under
+ the following conditions:
+
+ - We are doing a table scan and the data is in a separate file (MyISAM) or
+ if we don't update a clustered key.
+
+ - We are doing a range scan and we don't update the scan key or
+ the primary key for a clustered table handler.
+
+ - Table is not joined to itself.
+
+ This function gets information about fields to be updated from
+ the TABLE::write_set bitmap.
+
+ WARNING
+ This code is a bit dependent of how make_join_readinfo() works.
+
+ RETURN
+ 0 Not safe to update
+ 1 Safe to update
+*/
+
+static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab,
+ TABLE_LIST *table_ref, TABLE_LIST *all_tables)
+{
+ TABLE *table= join_tab->table;
+ if (unique_table(thd, table_ref, all_tables, 0))
+ return 0;
+ switch (join_tab->type) {
+ case JT_SYSTEM:
+ case JT_CONST:
+ case JT_EQ_REF:
+ return TRUE; // At most one matching row
+ case JT_REF:
+ case JT_REF_OR_NULL:
+ return !is_key_used(table, join_tab->ref.key, table->write_set);
+ case JT_ALL:
+ /* If range search on index */
+ if (join_tab->quick)
+ return !join_tab->quick->is_keys_used(table->write_set);
+ /* If scanning in clustered key */
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
+ table->s->primary_key < MAX_KEY)
+ return !is_key_used(table, table->s->primary_key, table->write_set);
+ return TRUE;
+ default:
+ break; // Avoid compler warning
}
- DBUG_RETURN(thd->is_fatal_error != 0);
+ return FALSE;
+
}
@@ -1206,13 +1321,22 @@ multi_update::initialize_tables(JOIN *join)
trans_safe= transactional_tables= main_table->file->has_transactions();
table_to_update= 0;
+ /* Any update has at least one pair (field, value) */
+ DBUG_ASSERT(fields->elements);
+ /*
+ Only one table may be modified by UPDATE of an updatable view.
+ For an updatable view first_table_for_update indicates this
+ table.
+ For a regular multi-update it refers to some updated table.
+ */
+ TABLE *first_table_for_update= ((Item_field *) fields->head())->field->table;
+
/* Create a temporary table for keys to all tables, except main table */
for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
{
TABLE *table=table_ref->table;
uint cnt= table_ref->shared;
- Item_field *ifield;
- List<Item> temp_fields= *fields_for_table[cnt];
+ List<Item> temp_fields;
ORDER group;
TMP_TABLE_PARAM *tmp_param;
@@ -1221,7 +1345,7 @@ multi_update::initialize_tables(JOIN *join)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (table == main_table) // First table in join
{
- if (safe_update_on_fly(join->join_tab))
+ if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables))
{
table_to_update= main_table; // Update table on the fly
continue;
@@ -1229,27 +1353,56 @@ multi_update::initialize_tables(JOIN *join)
}
table->prepare_for_position();
+ if (table == first_table_for_update && table_ref->check_option)
+ {
+ table_map unupdated_tables= table_ref->check_option->used_tables() &
+ ~first_table_for_update->map;
+ for (TABLE_LIST *tbl_ref =leaves;
+ unupdated_tables && tbl_ref;
+ tbl_ref= tbl_ref->next_leaf)
+ {
+ if (unupdated_tables & tbl_ref->table->map)
+ unupdated_tables&= ~tbl_ref->table->map;
+ else
+ continue;
+ if (unupdated_check_opt_tables.push_back(tbl_ref->table))
+ DBUG_RETURN(1);
+ }
+ }
+
tmp_param= tmp_table_param+cnt;
+
/*
Create a temporary table to store all fields that are changed for this
table. The first field in the temporary table is a pointer to the
- original row so that we can find and update it
+ original row so that we can find and update it. For the updatable
+ VIEW a few following fields are rowids of tables used in the CHECK
+ OPTION condition.
*/
- /* ok to be on stack as this is not referenced outside of this func */
- Field_string offset(table->file->ref_length, 0, "offset",
- &my_charset_bin);
- offset.init(table);
- /*
- The field will be converted to varstring when creating tmp table if
- table to be updated was created by mysql 4.1. Deny this.
- */
- offset.can_alter_field_type= 0;
- if (!(ifield= new Item_field(((Field *) &offset))))
- DBUG_RETURN(1);
- ifield->maybe_null= 0;
- if (temp_fields.push_front(ifield))
- DBUG_RETURN(1);
+ List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
+ TABLE *tbl= table;
+ do
+ {
+ Field_string *field= new Field_string(tbl->file->ref_length, 0,
+ tbl->alias, &my_charset_bin);
+ if (!field)
+ DBUG_RETURN(1);
+ field->init(tbl);
+ /*
+ The field will be converted to varstring when creating tmp table if
+ table to be updated was created by mysql 4.1. Deny this.
+ */
+ field->can_alter_field_type= 0;
+ Item_field *ifield= new Item_field((Field *) field);
+ if (!ifield)
+ DBUG_RETURN(1);
+ ifield->maybe_null= 0;
+ if (temp_fields.push_back(ifield))
+ DBUG_RETURN(1);
+ } while ((tbl= tbl_it++));
+
+ temp_fields.concat(fields_for_table[cnt]);
/* Make an unique key over the first field to avoid duplicated updates */
bzero((char*) &group, sizeof(group));
@@ -1273,61 +1426,6 @@ multi_update::initialize_tables(JOIN *join)
DBUG_RETURN(0);
}
-/*
- Check if table is safe to update on fly
-
- SYNOPSIS
- safe_update_on_fly
- join_tab How table is used in join
-
- NOTES
- We can update the first table in join on the fly if we know that
- a row in this table will never be read twice. This is true under
- the following conditions:
-
- - We are doing a table scan and the data is in a separate file (MyISAM) or
- if we don't update a clustered key.
-
- - We are doing a range scan and we don't update the scan key or
- the primary key for a clustered table handler.
-
- This function gets information about fields to be updated from
- the TABLE::write_set bitmap.
-
- WARNING
- This code is a bit dependent of how make_join_readinfo() works.
-
- RETURN
- 0 Not safe to update
- 1 Safe to update
-*/
-
-static bool safe_update_on_fly(JOIN_TAB *join_tab)
-{
- TABLE *table= join_tab->table;
- switch (join_tab->type) {
- case JT_SYSTEM:
- case JT_CONST:
- case JT_EQ_REF:
- return TRUE; // At most one matching row
- case JT_REF:
- case JT_REF_OR_NULL:
- return !is_key_used(table, join_tab->ref.key, table->write_set);
- case JT_ALL:
- /* If range search on index */
- if (join_tab->quick)
- return !join_tab->quick->is_keys_used(table->write_set);
- /* If scanning in clustered key */
- if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
- table->s->primary_key < MAX_KEY)
- return !is_key_used(table, table->s->primary_key, table->write_set);
- return TRUE;
- default:
- break; // Avoid compler warning
- }
- return FALSE;
-}
-
multi_update::~multi_update()
{
@@ -1353,8 +1451,9 @@ multi_update::~multi_update()
if (copy_field)
delete [] copy_field;
thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting
- if (!trans_safe)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ if (!trans_safe) // todo: remove since redundant
+ thd->no_trans_update.all= TRUE;
+ DBUG_ASSERT(trans_safe || thd->no_trans_update.all);
}
@@ -1415,40 +1514,47 @@ bool multi_update::send_data(List<Item> &not_used_values)
else if (error == VIEW_CHECK_ERROR)
DBUG_RETURN(1);
}
- if (!updated++)
- {
- /*
- Inform the main table that we are going to update the table even
- while we may be scanning it. This will flush the read cache
- if it's used.
- */
- main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
- }
- if ((error=table->file->ha_update_row(table->record[1],
- table->record[0])))
- {
- updated--;
+ if (!updated++)
+ {
+ /*
+ Inform the main table that we are going to update the table even
+ while we may be scanning it. This will flush the read cache
+ if it's used.
+ */
+ main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
+ }
+ if ((error=table->file->ha_update_row(table->record[1],
+ table->record[0])))
+ {
+ updated--;
if (!ignore ||
table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
- {
+ {
/*
If (ignore && error == is ignorable) we don't have to
do anything; otherwise...
*/
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
thd->fatal_error(); /* Other handler errors are fatal */
- table->file->print_error(error,MYF(0));
- DBUG_RETURN(1);
- }
- }
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
else
{
- if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ /* non-transactional or transactional table got modified */
+ /* either multi_update class' flag is raised in its branch */
+ if (table->file->has_transactions())
+ transactional_tables= 1;
+ else
+ {
+ trans_safe= 0;
+ thd->no_trans_update.stmt= TRUE;
+ }
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
- DBUG_RETURN(1);
+ DBUG_RETURN(1);
}
}
}
@@ -1456,24 +1562,39 @@ bool multi_update::send_data(List<Item> &not_used_values)
{
int error;
TABLE *tmp_table= tmp_tables[offset];
- table->file->position(table->record[0]);
- fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
- /* Store pointer to row */
- memcpy((char*) tmp_table->field[0]->ptr,
- (char*) table->file->ref, table->file->ref_length);
+ /*
+ For updatable VIEW store rowid of the updated table and
+ rowids of tables used in the CHECK OPTION condition.
+ */
+ uint field_num= 0;
+ List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
+ TABLE *tbl= table;
+ do
+ {
+ tbl->file->position(tbl->record[0]);
+ memcpy((char*) tmp_table->field[field_num]->ptr,
+ (char*) tbl->file->ref, tbl->file->ref_length);
+ field_num++;
+ } while ((tbl= tbl_it++));
+
+ /* Store regular updated fields in the row. */
+ fill_record(thd,
+ tmp_table->field + 1 + unupdated_check_opt_tables.elements,
+ *values_for_table[offset], 1);
+
/* Write row, ignoring duplicated updates to a row */
- if ((error= tmp_table->file->ha_write_row(tmp_table->record[0])))
+ error= tmp_table->file->ha_write_row(tmp_table->record[0]);
+ if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
{
- if (tmp_table->file->is_fatal_error(error, HA_CHECK_DUP) &&
+ if (error &&
create_myisam_from_heap(thd, tmp_table,
- tmp_table_param + offset, error, 1))
- {
- do_update=0;
- DBUG_RETURN(1); // Not a table_is_full error
- }
- }
- else
+ tmp_table_param + offset, error, 1))
+ {
+ do_update= 0;
+ DBUG_RETURN(1); // Not a table_is_full error
+ }
found++;
+ }
}
}
DBUG_RETURN(0);
@@ -1486,8 +1607,8 @@ void multi_update::send_error(uint errcode,const char *err)
my_error(errcode, MYF(0), err);
/* If nothing updated return */
- if (!updated)
- return;
+ if (updated == 0) /* the counter might be reset in send_eof */
+ return; /* and then the query has been binlogged */
/* Something already updated so we have to invalidate cache */
query_cache_invalidate3(thd, update_tables, 1);
@@ -1498,11 +1619,43 @@ void multi_update::send_error(uint errcode,const char *err)
*/
if (trans_safe)
- ha_rollback_stmt(thd);
- else if (do_update && table_count > 1)
{
- /* Add warning here */
- VOID(do_updates(0));
+ DBUG_ASSERT(transactional_tables);
+ (void) ha_autocommit_or_rollback(thd, 1);
+ }
+ else
+ {
+ DBUG_ASSERT(thd->no_trans_update.stmt);
+ if (do_update && table_count > 1)
+ {
+ /* Add warning here */
+ /*
+ todo/fixme: do_update() is never called with the arg 1.
+ should it change the signature to become argless?
+ */
+ VOID(do_updates(0));
+ }
+ }
+ if (thd->no_trans_update.stmt)
+ {
+ /*
+ The query has to binlog because there's a modified non-transactional table
+ either from the query's list or via a stored routine: bug#13270,23333
+ */
+ if (mysql_bin_log.is_open())
+ {
+ thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query, thd->query_length,
+ transactional_tables, FALSE);
+ }
+ if (!trans_safe)
+ thd->no_trans_update.all= TRUE;
+ }
+ DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt);
+
+ if (transactional_tables)
+ {
+ (void) ha_autocommit_or_rollback(thd, 1);
}
}
@@ -1510,9 +1663,10 @@ void multi_update::send_error(uint errcode,const char *err)
int multi_update::do_updates(bool from_send_error)
{
TABLE_LIST *cur_table;
- int local_error;
+ int local_error= 0;
ha_rows org_updated;
TABLE *table, *tmp_table;
+ List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables);
DBUG_ENTER("do_updates");
do_update= 0; // Don't retry this function
@@ -1520,8 +1674,8 @@ int multi_update::do_updates(bool from_send_error)
DBUG_RETURN(0);
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
- byte *ref_pos;
bool can_compare_record;
+ uint offset= cur_table->shared;
table = cur_table->table;
if (table == table_to_update)
@@ -1532,11 +1686,20 @@ int multi_update::do_updates(bool from_send_error)
(void) table->file->ha_rnd_init(0);
table->file->extra(HA_EXTRA_NO_CACHE);
+ check_opt_it.rewind();
+ while(TABLE *tbl= check_opt_it++)
+ {
+ if (tbl->file->ha_rnd_init(1))
+ goto err;
+ tbl->file->extra(HA_EXTRA_CACHE);
+ }
+
/*
Setup copy functions to copy fields from temporary table
*/
- List_iterator_fast<Item> field_it(*fields_for_table[cur_table->shared]);
- Field **field= tmp_table->field+1; // Skip row pointer
+ List_iterator_fast<Item> field_it(*fields_for_table[offset]);
+ Field **field= tmp_table->field +
+ 1 + unupdated_check_opt_tables.elements; // Skip row pointers
Copy_field *copy_field_ptr= copy_field, *copy_field_end;
for ( ; *field ; field++)
{
@@ -1553,7 +1716,6 @@ int multi_update::do_updates(bool from_send_error)
bitmap_is_subset(table->write_set,
table->read_set));
- ref_pos= (byte*) tmp_table->field[0]->ptr;
for (;;)
{
if (thd->killed && trans_safe)
@@ -1566,8 +1728,20 @@ int multi_update::do_updates(bool from_send_error)
continue; // May happen on dup key
goto err;
}
- if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
- goto err;
+
+ /* call rnd_pos() using rowids from temporary table */
+ check_opt_it.rewind();
+ TABLE *tbl= table;
+ uint field_num= 0;
+ do
+ {
+ if((local_error=
+ tbl->file->rnd_pos(tbl->record[0],
+ (uchar *) tmp_table->field[field_num]->ptr)))
+ goto err;
+ field_num++;
+ } while((tbl= check_opt_it++));
+
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
@@ -1584,6 +1758,15 @@ int multi_update::do_updates(bool from_send_error)
if (!can_compare_record || compare_record(table))
{
+ int error;
+ if ((error= cur_table->view_check_option(thd, ignore)) !=
+ VIEW_CHECK_OK)
+ {
+ if (error == VIEW_CHECK_SKIP)
+ continue;
+ else if (error == VIEW_CHECK_ERROR)
+ goto err;
+ }
if ((local_error=table->file->ha_update_row(table->record[1],
table->record[0])))
{
@@ -1603,12 +1786,19 @@ int multi_update::do_updates(bool from_send_error)
if (updated != org_updated)
{
if (table->file->has_transactions())
- transactional_tables= 1;
+ transactional_tables= 1;
else
- trans_safe= 0; // Can't do safe rollback
+ {
+ trans_safe= 0; // Can't do safe rollback
+ thd->no_trans_update.stmt= TRUE;
+ }
}
(void) table->file->ha_rnd_end();
(void) tmp_table->file->ha_rnd_end();
+ check_opt_it.rewind();
+ while (TABLE *tbl= check_opt_it++)
+ tbl->file->ha_rnd_end();
+
}
DBUG_RETURN(0);
@@ -1622,13 +1812,19 @@ err:
err2:
(void) table->file->ha_rnd_end();
(void) tmp_table->file->ha_rnd_end();
+ check_opt_it.rewind();
+ while (TABLE *tbl= check_opt_it++)
+ tbl->file->ha_rnd_end();
if (updated != org_updated)
{
if (table->file->has_transactions())
transactional_tables= 1;
else
+ {
trans_safe= 0;
+ thd->no_trans_update.stmt= TRUE;
+ }
}
DBUG_RETURN(1);
}
@@ -1658,14 +1854,20 @@ bool multi_update::send_eof()
Write the SQL statement to the binlog if we updated
rows and we succeeded or if we updated some non
transactional tables.
+
+ The query has to binlog because there's a modified non-transactional table
+ either from the query's list or via a stored routine: bug#13270,23333
*/
- if ((local_error == 0) || (updated && !trans_safe))
+ DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt);
+ if (local_error == 0 || thd->no_trans_update.stmt)
{
if (mysql_bin_log.is_open())
{
if (local_error == 0)
thd->clear_error();
+ else
+ updated= 0; /* if there's an error binlog it here not in ::send_error */
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_tables, FALSE) &&
@@ -1674,8 +1876,8 @@ bool multi_update::send_eof()
local_error= 1; // Rollback update
}
}
- if (!transactional_tables)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ if (!trans_safe)
+ thd->no_trans_update.all= TRUE;
}
if (transactional_tables)
@@ -1686,7 +1888,7 @@ bool multi_update::send_eof()
if (local_error > 0) // if the above log write did not fail ...
{
- /* Safety: If we haven't got an error before (should not happen) */
+ /* Safety: If we haven't got an error before (can happen in do_updates) */
my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
MYF(0));
return TRUE;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index cb4f6c088f6..0aab0472f4a 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -225,6 +224,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
{
LEX *lex= thd->lex;
bool link_to_local;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool definer_check_is_needed= mode != VIEW_ALTER || lex->definer;
+#endif
/* first table in list is target VIEW name => cut off it */
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
@@ -257,8 +259,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
/*
DEFINER-clause is missing; we have to create default definer in
persistent arena to be PS/SP friendly.
+ If this is an ALTER VIEW then the current user should be set as
+ the definer.
*/
-
Query_arena original_arena;
Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
@@ -278,11 +281,11 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
- same as current user
- current user has SUPER_ACL
*/
- if (strcmp(lex->definer->user.str,
- thd->security_ctx->priv_user) != 0 ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host) != 0)
+ if (definer_check_is_needed &&
+ (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
+ my_strcasecmp(system_charset_info,
+ lex->definer->host.str,
+ thd->security_ctx->priv_host) != 0))
{
if (!(thd->security_ctx->master_access & SUPER_ACL))
{
@@ -319,11 +322,11 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
*/
if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
0, 0, is_schema_db(view->db)) ||
- grant_option && check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
+ check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
(mode != VIEW_CREATE_NEW &&
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
0, 0, is_schema_db(view->db)) ||
- grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0))))
+ check_grant(thd, DROP_ACL, view, 0, 1, 0))))
{
res= TRUE;
goto err;
@@ -376,7 +379,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
{
if (check_access(thd, SELECT_ACL, tbl->db,
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
- grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
+ check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
{
res= TRUE;
goto err;
@@ -493,35 +496,46 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
/*
Compare/check grants on view with grants of underlying tables
*/
+
+ fill_effective_table_privileges(thd, &view->grant, view->db,
+ view->table_name);
+
+ {
+ Item *report_item= NULL;
+ uint final_priv= VIEW_ANY_ACL;
+
for (sl= select_lex; sl; sl= sl->next_select())
{
DBUG_ASSERT(view->db); /* Must be set in the parser */
List_iterator_fast<Item> it(sl->item_list);
Item *item;
- fill_effective_table_privileges(thd, &view->grant, view->db,
- view->table_name);
while ((item= it++))
{
- Item_field *fld;
+ Item_field *fld= item->filed_for_view_update();
uint priv= (get_column_grant(thd, &view->grant, view->db,
view->table_name, item->name) &
VIEW_ANY_ACL);
- if ((fld= item->filed_for_view_update()))
+
+ if (fld && !fld->field->table->s->tmp_table)
{
- /*
- Do we have more privileges on view field then underlying table field?
- */
- if (!fld->field->table->s->tmp_table && (~fld->have_privileges & priv))
+ final_priv&= fld->have_privileges;
+
+ if (~fld->have_privileges & priv)
+ report_item= item;
+ }
+ }
+ }
+
+ if (!final_priv)
{
- /* VIEW column has more privileges */
+ DBUG_ASSERT(report_item);
+
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"create view", thd->security_ctx->priv_user,
- thd->security_ctx->priv_host, item->name,
+ thd->security_ctx->priv_host, report_item->name,
view->table_name);
res= TRUE;
goto err;
- }
- }
}
}
#endif
@@ -676,8 +690,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
char dir_buff[FN_REFLEN], path_buff[FN_REFLEN];
- const uchar *endp;
+ const char *endp;
LEX_STRING dir, file, path;
+ int error= 0;
DBUG_ENTER("mysql_register_view");
/* print query */
@@ -688,9 +703,56 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
lex->unit.print(&str);
thd->variables.sql_mode|= sql_mode;
}
- str.append('\0');
DBUG_PRINT("info", ("View: %s", str.ptr()));
+ /* fill structure */
+ view->query.str= str.c_ptr_safe();
+ view->query.length= str.length();
+ view->source.str= thd->query + thd->lex->create_view_select_start;
+ endp= view->source.str;
+ endp= skip_rear_comments(thd->charset(), endp, thd->query + thd->query_length);
+ view->source.length= endp - view->source.str;
+ view->file_version= 1;
+ view->calc_md5(md5);
+ view->md5.str= md5;
+ view->md5.length= 32;
+ can_be_merged= lex->can_be_merged();
+ if (lex->create_view_algorithm == VIEW_ALGORITHM_MERGE &&
+ !lex->can_be_merged())
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_VIEW_MERGE,
+ ER(ER_WARN_VIEW_MERGE));
+ lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
+ }
+ view->algorithm= lex->create_view_algorithm;
+ view->definer.user= lex->definer->user;
+ view->definer.host= lex->definer->host;
+ view->view_suid= lex->create_view_suid;
+ view->with_check= lex->create_view_check;
+ if ((view->updatable_view= (can_be_merged &&
+ view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
+ {
+ /* TODO: change here when we will support UNIONs */
+ for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
+ tbl;
+ tbl= tbl->next_local)
+ {
+ if ((tbl->view && !tbl->updatable_view) || tbl->schema_table)
+ {
+ view->updatable_view= 0;
+ break;
+ }
+ for (TABLE_LIST *up= tbl; up; up= up->embedding)
+ {
+ if (up->outer_join)
+ {
+ view->updatable_view= 0;
+ goto loop_out;
+ }
+ }
+ }
+ }
+loop_out:
/* print file name */
dir.length= build_table_filename(dir_buff, sizeof(dir_buff),
view->db, "", "", 0);
@@ -714,7 +776,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
File_parser *parser;
path.str= path_buff;
- fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
+ fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME);
path.length= strlen(path_buff);
if (!access(path.str, F_OK))
@@ -722,16 +784,21 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
if (mode == VIEW_CREATE_NEW)
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), view->alias);
- DBUG_RETURN(-1);
+ error= -1;
+ goto err;
}
if (!(parser= sql_parse_prepare(&path, thd->mem_root, 0)))
- DBUG_RETURN(1);
+ {
+ error= 1;
+ goto err;
+ }
if (!parser->ok() || !is_equal(&view_type, parser->type()))
{
my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
- DBUG_RETURN(-1);
+ error= -1;
+ goto err;
}
/*
@@ -740,70 +807,25 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
TODO: read dependence list, too, to process cascade/restrict
TODO: special cascade/restrict procedure for alter?
*/
- if (parser->parse((gptr)view, thd->mem_root,
+ if (parser->parse((uchar*)view, thd->mem_root,
view_parameters + revision_number_position, 1,
&file_parser_dummy_hook))
{
- DBUG_RETURN(thd->net.report_error? -1 : 0);
+ error= thd->net.report_error? -1 : 0;
+ goto err;
}
}
else
- {
+ {
if (mode == VIEW_ALTER)
{
my_error(ER_NO_SUCH_TABLE, MYF(0), view->db, view->alias);
- DBUG_RETURN(-1);
- }
- }
- }
- /* fill structure */
- view->query.str= (char*)str.ptr();
- view->query.length= str.length()-1; // we do not need last \0
- view->source.str= thd->query + thd->lex->create_view_select_start;
- endp= (uchar*) view->source.str;
- endp= skip_rear_comments(endp, (uchar*) (thd->query + thd->query_length));
- view->source.length= endp - (uchar*) view->source.str;
- view->file_version= 1;
- view->calc_md5(md5);
- view->md5.str= md5;
- view->md5.length= 32;
- can_be_merged= lex->can_be_merged();
- if (lex->create_view_algorithm == VIEW_ALGORITHM_MERGE &&
- !lex->can_be_merged())
- {
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_VIEW_MERGE,
- ER(ER_WARN_VIEW_MERGE));
- lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
- }
- view->algorithm= lex->create_view_algorithm;
- view->definer.user= lex->definer->user;
- view->definer.host= lex->definer->host;
- view->view_suid= lex->create_view_suid;
- view->with_check= lex->create_view_check;
- if ((view->updatable_view= (can_be_merged &&
- view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
- {
- /* TODO: change here when we will support UNIONs */
- for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
- tbl;
- tbl= tbl->next_local)
- {
- if ((tbl->view && !tbl->updatable_view) || tbl->schema_table)
- {
- view->updatable_view= 0;
- break;
- }
- for (TABLE_LIST *up= tbl; up; up= up->embedding)
- {
- if (up->outer_join)
- {
- view->updatable_view= 0;
- goto loop_out;
- }
+ error= -1;
+ goto err;
}
}
}
-loop_out:
+
/*
Check that table of main select do not used in subqueries.
@@ -815,7 +837,7 @@ loop_out:
UNION
*/
if (view->updatable_view &&
- !lex->select_lex.next_select() &&
+ !lex->select_lex.master_unit()->is_union() &&
!((TABLE_LIST*)lex->select_lex.table_list.first)->next_local &&
find_table_in_global_list(lex->query_tables->next_global,
lex->query_tables->db,
@@ -828,15 +850,23 @@ loop_out:
!view->updatable_view)
{
my_error(ER_VIEW_NONUPD_CHECK, MYF(0), view->db, view->table_name);
- DBUG_RETURN(-1);
+ error= -1;
+ goto err;
}
if (sql_create_definition_file(&dir, &file, view_file_type,
- (gptr)view, view_parameters, num_view_backups))
+ (uchar*)view, view_parameters, num_view_backups))
{
- DBUG_RETURN(thd->net.report_error? -1 : 1);
+ error= thd->net.report_error? -1 : 1;
+ goto err;
}
DBUG_RETURN(0);
+err:
+ view->query.str= NULL;
+ view->query.length= 0;
+ view->md5.str= NULL;
+ view->md5.length= 0;
+ DBUG_RETURN(error);
}
@@ -863,7 +893,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
Query_arena *arena, backup;
TABLE_LIST *top_view= table->top_table();
int res;
- bool result;
+ bool result, view_is_mergeable;
+ TABLE_LIST *view_main_select_tables;
DBUG_ENTER("mysql_make_view");
DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
@@ -930,7 +961,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
TODO: when VIEWs will be stored in cache, table mem_root should
be used here
*/
- if (parser->parse((gptr)table, thd->mem_root, view_parameters,
+ if (parser->parse((uchar*)table, thd->mem_root, view_parameters,
required_view_parameters, &file_parser_dummy_hook))
goto err;
@@ -970,10 +1001,14 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
now Lex placed in statement memory
*/
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
- lex_start(thd, (uchar*)table->query.str, table->query.length);
- view_select= &lex->select_lex;
- view_select->select_number= ++thd->select_number;
+
{
+ Lex_input_stream lip(thd, table->query.str, table->query.length);
+ thd->m_lip= &lip;
+ lex_start(thd);
+ view_select= &lex->select_lex;
+ view_select->select_number= ++thd->select_number;
+
ulong save_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
- MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing
@@ -1004,6 +1039,11 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
CHARSET_INFO *save_cs= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info;
res= MYSQLparse((void *)thd);
+
+ if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||
+ (old_lex->sql_command == SQLCOM_SHOW_CREATE))
+ lex->sql_command= old_lex->sql_command;
+
thd->variables.character_set_client= save_cs;
thd->variables.sql_mode= save_mode;
}
@@ -1029,7 +1069,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
}
}
else if (!table->prelocking_placeholder &&
- old_lex->sql_command == SQLCOM_SHOW_CREATE &&
+ (old_lex->sql_command == SQLCOM_SHOW_CREATE) &&
!table->belong_to_view)
{
if (check_table_access(thd, SHOW_VIEW_ACL, table, 0))
@@ -1094,11 +1134,10 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
If the view's body needs row-based binlogging (e.g. the VIEW is created
from SELECT UUID()), the top statement also needs it.
*/
- if (lex->binlog_row_based_if_mixed)
- old_lex->binlog_row_based_if_mixed= TRUE;
- bool view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
- lex->can_be_merged());
- TABLE_LIST *view_main_select_tables;
+ if (lex->is_stmt_unsafe())
+ old_lex->set_stmt_unsafe();
+ view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
+ lex->can_be_merged());
LINT_INIT(view_main_select_tables);
if (view_is_mergeable)
@@ -1145,13 +1184,17 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
/*
Prepare a security context to check underlying objects of the view
*/
- Security_context *save_security_ctx= thd->security_ctx;
if (!(table->view_sctx= (Security_context *)
thd->stmt_arena->alloc(sizeof(Security_context))))
goto err;
/* Assign the context to the tables referenced in the view */
- for (tbl= view_tables; tbl; tbl= tbl->next_global)
- tbl->security_ctx= table->view_sctx;
+ if (view_tables)
+ {
+ DBUG_ASSERT(view_tables_tail);
+ for (tbl= view_tables; tbl != view_tables_tail->next_global;
+ tbl= tbl->next_global)
+ tbl->security_ctx= table->view_sctx;
+ }
/* assign security context to SELECT name resolution contexts of view */
for(SELECT_LEX *sl= lex->all_selects_list;
sl;
@@ -1263,12 +1306,18 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
unit->slave= save_slave; // fix include_down initialisation
}
+ /*
+ We can safely ignore the VIEW's ORDER BY if we merge into union
+ branch, as order is not important there.
+ */
+ if (!table->select_lex->master_unit()->is_union())
+ table->select_lex->order_list.push_back(&lex->select_lex.order_list);
/*
This SELECT_LEX will be linked in global SELECT_LEX list
to make it processed by mysql_handle_derived(),
but it will not be included to SELECT_LEX tree, because it
will not be executed
- */
+ */
goto ok;
}
@@ -1298,8 +1347,6 @@ ok:
(st_select_lex_node**)&old_lex->all_selects_list;
ok2:
- if (!old_lex->time_zone_tables_used && thd->lex->time_zone_tables_used)
- old_lex->time_zone_tables_used= thd->lex->time_zone_tables_used;
DBUG_ASSERT(lex == thd->lex);
thd->lex= old_lex; // Needed for prepare_security
result= !table->prelocking_placeholder && table->prepare_security(thd);
@@ -1457,7 +1504,7 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt)
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(FRMTYPE_ERROR);
- error= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME | MY_NABP));
+ error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_WME | MY_NABP));
my_close(file, MYF(MY_WME));
if (error)
@@ -1720,7 +1767,7 @@ mysql_rename_view(THD *thd,
view_def.view_suid= TRUE;
/* get view definition and source */
- if (parser->parse((gptr)&view_def, thd->mem_root, view_parameters,
+ if (parser->parse((uchar*)&view_def, thd->mem_root, view_parameters,
array_elements(view_parameters)-1,
&file_parser_dummy_hook))
goto err;
@@ -1742,7 +1789,7 @@ mysql_rename_view(THD *thd,
file.length= pathstr.length - dir.length;
if (sql_create_definition_file(&dir, &file, view_file_type,
- (gptr)&view_def, view_parameters,
+ (uchar*)&view_def, view_parameters,
num_view_backups))
{
/* restore renamed view in case of error */
diff --git a/sql/sql_view.h b/sql/sql_view.h
index fc480167216..d3c83c82f44 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -3,8 +3,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 704c505ded9..2b256070276 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -48,26 +47,42 @@ const LEX_STRING null_lex_str={0,0};
#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if (my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }}
-#define YYERROR_UNLESS(A) \
- if (!(A)) \
+#define MYSQL_YYABORT \
+ do \
{ \
- yyerror(ER(ER_SYNTAX_ERROR)); \
+ LEX::cleanup_lex_after_parse_error(YYTHD);\
YYABORT; \
+ } while (0)
+
+#define MYSQL_YYABORT_UNLESS(A) \
+ if (!(A)) \
+ { \
+ my_parse_error(ER(ER_SYNTAX_ERROR));\
+ MYSQL_YYABORT; \
}
-/* Helper for parsing "IS [NOT] truth_value" */
-inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2)
-{
- Item *v1_t= new (thd->mem_root) Item_int((char *) (v1 ? "TRUE" : "FALSE"),
- v1, 1);
- Item *v1_f= new (thd->mem_root) Item_int((char *) (v1 ? "FALSE" : "TRUE"),
- !v1, 1);
- Item *v2_t= new (thd->mem_root) Item_int((char *) (v2 ? "TRUE" : "FALSE"),
- v2, 1);
- Item *ifnull= new (thd->mem_root) Item_func_ifnull(A, v2_t);
-
- return new (thd->mem_root) Item_func_if(ifnull, v1_t, v1_f);
-}
+/*
+ Work around for broken code generated by bison 1.875.
+
+ The code generated by bison 1.875a and later, bison 2.1 and bison 2.2 is ok.
+ With bison 1.875 however, the generated code contains:
+<pre>
+ yyerrlab1:
+ #if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+ __attribute__ ((__unused__))
+ #endif
+</pre>
+ This usage of __attribute__ is illegal, so we remove it.
+ See the following references for details:
+ http://lists.gnu.org/archive/html/bug-bison/2004-02/msg00014.html
+ http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14273
+*/
+
+#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
+#undef __attribute__
+#define __attribute__(X)
+#endif
+
#ifndef DBUG_OFF
#define YYDEBUG 1
@@ -75,6 +90,67 @@ inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2)
#define YYDEBUG 0
#endif
+/**
+ @brief Push an error message into MySQL error stack with line
+ and position information.
+
+ This function provides semantic action implementers with a way
+ to push the famous "You have a syntax error near..." error
+ message into the error stack, which is normally produced only if
+ a parse error is discovered internally by the Bison generated
+ parser.
+*/
+
+void my_parse_error(const char *s)
+{
+ THD *thd= current_thd;
+ Lex_input_stream *lip= thd->m_lip;
+
+ const char *yytext= lip->tok_start;
+ /* Push an error into the error stack */
+ my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
+ (yytext ? yytext : ""),
+ lip->yylineno);
+}
+
+/**
+ @brief Bison callback to report a syntax/OOM error
+
+ This function is invoked by the bison-generated parser
+ when a syntax error, a parse error or an out-of-memory
+ condition occurs. This function is not invoked when the
+ parser is requested to abort by semantic action code
+ by means of YYABORT or YYACCEPT macros. This is why these
+ macros should not be used (use MYSQL_YYABORT/MYSQL_YYACCEPT
+ instead).
+
+ The parser will abort immediately after invoking this callback.
+
+ This function is not for use in semantic actions and is internal to
+ the parser, as it performs some pre-return cleanup.
+ In semantic actions, please use my_parse_error or my_error to
+ push an error into the error stack and MYSQL_YYABORT
+ to abort from the parser.
+*/
+
+void MYSQLerror(const char *s)
+{
+ THD *thd= current_thd;
+
+ /*
+ Restore the original LEX if it was replaced when parsing
+ a stored procedure. We must ensure that a parsing error
+ does not leave any side effects in the THD.
+ */
+ LEX::cleanup_lex_after_parse_error(thd);
+
+ /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
+ if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
+ s= ER(ER_SYNTAX_ERROR);
+ my_parse_error(s);
+}
+
+
#ifndef DBUG_OFF
void turn_parser_debug_on()
{
@@ -108,6 +184,262 @@ static bool is_native_function(THD *thd, const LEX_STRING *name)
return false;
}
+
+/**
+ Helper action for a case statement (entering the CASE).
+ This helper is used for both 'simple' and 'searched' cases.
+ This helper, with the other case_stmt_action_..., is executed when
+ the following SQL code is parsed:
+<pre>
+CREATE PROCEDURE proc_19194_simple(i int)
+BEGIN
+ DECLARE str CHAR(10);
+
+ CASE i
+ WHEN 1 THEN SET str="1";
+ WHEN 2 THEN SET str="2";
+ WHEN 3 THEN SET str="3";
+ ELSE SET str="unknown";
+ END CASE;
+
+ SELECT str;
+END
+</pre>
+ The actions are used to generate the following code:
+<pre>
+SHOW PROCEDURE CODE proc_19194_simple;
+Pos Instruction
+0 set str@1 NULL
+1 set_case_expr (12) 0 i@0
+2 jump_if_not 5(12) (case_expr@0 = 1)
+3 set str@1 _latin1'1'
+4 jump 12
+5 jump_if_not 8(12) (case_expr@0 = 2)
+6 set str@1 _latin1'2'
+7 jump 12
+8 jump_if_not 11(12) (case_expr@0 = 3)
+9 set str@1 _latin1'3'
+10 jump 12
+11 set str@1 _latin1'unknown'
+12 stmt 0 "SELECT str"
+</pre>
+
+ @param lex the parser lex context
+*/
+
+void case_stmt_action_case(LEX *lex)
+{
+ lex->sphead->new_cont_backpatch(NULL);
+
+ /*
+ BACKPATCH: Creating target label for the jump to
+ "case_stmt_action_end_case"
+ (Instruction 12 in the example)
+ */
+
+ lex->spcont->push_label((char *)"", lex->sphead->instructions());
+}
+
+/**
+ Helper action for a case expression statement (the expr in 'CASE expr').
+ This helper is used for 'searched' cases only.
+ @param lex the parser lex context
+ @param expr the parsed expression
+ @return 0 on success
+*/
+
+int case_stmt_action_expr(LEX *lex, Item* expr)
+{
+ sp_head *sp= lex->sphead;
+ sp_pcontext *parsing_ctx= lex->spcont;
+ int case_expr_id= parsing_ctx->register_case_expr();
+ sp_instr_set_case_expr *i;
+
+ if (parsing_ctx->push_case_expr_id(case_expr_id))
+ return 1;
+
+ i= new sp_instr_set_case_expr(sp->instructions(),
+ parsing_ctx, case_expr_id, expr, lex);
+
+ sp->add_cont_backpatch(i);
+ sp->add_instr(i);
+
+ return 0;
+}
+
+/**
+ Helper action for a case when condition.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+ @param when the parsed expression for the WHEN clause
+ @param simple true for simple cases, false for searched cases
+*/
+
+void case_stmt_action_when(LEX *lex, Item *when, bool simple)
+{
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i;
+ Item_case_expr *var;
+ Item *expr;
+
+ if (simple)
+ {
+ var= new Item_case_expr(ctx->get_current_case_expr_id());
+
+#ifndef DBUG_OFF
+ if (var)
+ {
+ var->m_sp= sp;
+ }
+#endif
+
+ expr= new Item_func_eq(var, when);
+ i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
+ }
+ else
+ i= new sp_instr_jump_if_not(ip, ctx, when, lex);
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_cont_backpatch(i);
+ sp->add_instr(i);
+}
+
+/**
+ Helper action for a case then statements.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+*/
+
+void case_stmt_action_then(LEX *lex)
+{
+ sp_head *sp= lex->sphead;
+ sp_pcontext *ctx= lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump *i = new sp_instr_jump(ip, ctx);
+ sp->add_instr(i);
+
+ /*
+ BACKPATCH: Resolving forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ sp->backpatch(ctx->pop_label());
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_then" to "case_stmt_action_end_case"
+ (jump from instruction 4 to 12, 7 to 12 ... in the example)
+ */
+
+ sp->push_backpatch(i, ctx->last_label());
+}
+
+/**
+ Helper action for an end case.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+ @param simple true for simple cases, false for searched cases
+*/
+
+void case_stmt_action_end_case(LEX *lex, bool simple)
+{
+ /*
+ BACKPATCH: Resolving forward jump from
+ "case_stmt_action_then" to "case_stmt_action_end_case"
+ (jump from instruction 4 to 12, 7 to 12 ... in the example)
+ */
+ lex->sphead->backpatch(lex->spcont->pop_label());
+
+ if (simple)
+ lex->spcont->pop_case_expr_id();
+
+ lex->sphead->do_cont_backpatch();
+}
+
+/**
+ Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
+ See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
+ This function returns the proper item for the SQL expression
+ <code>left [NOT] IN ( expr )</code>
+ @param thd the current thread
+ @param left the in predicand
+ @param equal true for IN predicates, false for NOT IN predicates
+ @param expr first and only expression of the in value list
+ @return an expression representing the IN predicate.
+*/
+Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
+ Item *expr)
+{
+ /*
+ Relevant references for this issue:
+ - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
+ - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
+ - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
+ - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
+ - SQL:2003 Feature F561, "Full value expressions".
+
+ The exception in SQL:2003 Note 184 means:
+ Item_singlerow_subselect, which corresponds to a <scalar subquery>,
+ should be re-interpreted as an Item_in_subselect, which corresponds
+ to a <table subquery> when used inside an <in predicate>.
+
+ Our reading of Note 184 is reccursive, so that all:
+ - IN (( <subquery> ))
+ - IN ((( <subquery> )))
+ - IN '('^N <subquery> ')'^N
+ - etc
+ should be interpreted as a <table subquery>, no matter how deep in the
+ expression the <subquery> is.
+ */
+
+ Item *result;
+
+ DBUG_ENTER("handle_sql2003_note184_exception");
+
+ if (expr->type() == Item::SUBSELECT_ITEM)
+ {
+ Item_subselect *expr2 = (Item_subselect*) expr;
+
+ if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
+ {
+ Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
+ st_select_lex *subselect;
+
+ /*
+ Implement the mandated change, by altering the semantic tree:
+ left IN Item_singlerow_subselect(subselect)
+ is modified to
+ left IN (subselect)
+ which is represented as
+ Item_in_subselect(left, subselect)
+ */
+ subselect= expr3->invalidate_and_restore_select_lex();
+ result= new (thd->mem_root) Item_in_subselect(left, subselect);
+
+ if (! equal)
+ result = negate_expression(thd, result);
+
+ DBUG_RETURN(result);
+ }
+ }
+
+ if (equal)
+ result= new (thd->mem_root) Item_func_eq(left, expr);
+ else
+ result= new (thd->mem_root) Item_func_ne(left, expr);
+
+ DBUG_RETURN(result);
+}
+
%}
%union {
int num;
@@ -150,6 +482,7 @@ static bool is_native_function(THD *thd, const LEX_STRING *name)
struct st_lex *lex;
sp_head *sphead;
struct p_elem_val *p_elem_value;
+ enum index_hint_type index_hint;
}
%{
@@ -157,6 +490,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%}
%pure_parser /* We have threads */
+/*
+ Currently there is 286 shift/reduce conflict. We should not introduce
+ new conflicts any more.
+*/
+%expect 286
/*
Comments for TOKENS.
@@ -354,9 +692,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token GLOBAL_SYM /* SQL-2003-R */
%token GRANT /* SQL-2003-R */
%token GRANTS
-%token GROUP /* SQL-2003-R */
+%token GROUP_SYM /* SQL-2003-R */
%token GROUP_CONCAT_SYM
-%token GROUP_UNIQUE_USERS
%token GT_SYM /* OPERATOR */
%token HANDLER_SYM
%token HASH_SYM
@@ -364,6 +701,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token HELP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
+%token HOST_SYM
%token HOSTS_SYM
%token HOUR_MICROSECOND_SYM
%token HOUR_MINUTE_SYM
@@ -443,6 +781,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MASTER_SSL_CIPHER_SYM
%token MASTER_SSL_KEY_SYM
%token MASTER_SSL_SYM
+%token MASTER_SSL_VERIFY_SERVER_CERT_SYM
%token MASTER_SYM
%token MASTER_USER_SYM
%token MATCH /* SQL-2003-R */
@@ -506,6 +845,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ONE_SYM
%token OPEN_SYM /* SQL-2003-R */
%token OPTIMIZE
+%token OPTIONS_SYM
%token OPTION /* SQL-2003-N */
%token OPTIONALLY
%token OR2_SYM
@@ -515,6 +855,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token OUTER
%token OUTFILE
%token OUT_SYM /* SQL-2003-R */
+%token OWNER_SYM
%token PACK_KEYS_SYM
%token PARAM_MARKER
%token PARSER_SYM
@@ -528,6 +869,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PLUGIN_SYM
%token POINT_SYM
%token POLYGON
+%token PORT_SYM
%token POSITION_SYM /* SQL-2003-N */
%token PRECISION /* SQL-2003-R */
%token PREPARE_SYM /* SQL-2003-R */
@@ -596,6 +938,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SERIALIZABLE_SYM /* SQL-2003-N */
%token SERIAL_SYM
%token SESSION_SYM /* SQL-2003-N */
+%token SERVER_SYM
+%token SERVER_OPTIONS
%token SET /* SQL-2003-R */
%token SET_VAR
%token SHARE_SYM
@@ -608,6 +952,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SLAVE
%token SMALLINT /* SQL-2003-R */
%token SNAPSHOT_SYM
+%token SOCKET_SYM
%token SONAME_SYM
%token SOUNDS_SYM
%token SPATIAL_SYM
@@ -683,7 +1028,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token UNINSTALL_SYM
%token UNION_SYM /* SQL-2003-R */
%token UNIQUE_SYM
-%token UNIQUE_USERS
%token UNKNOWN_SYM /* SQL-2003-R */
%token UNLOCK_SYM
%token UNSIGNED
@@ -715,6 +1059,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WHILE_SYM
%token WITH /* SQL-2003-R */
%token WORK_SYM /* SQL-2003-N */
+%token WRAPPER_SYM
%token WRITE_SYM /* SQL-2003-N */
%token X509_SYM
%token XA_SYM
@@ -820,7 +1165,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
btree_or_rtree
%type <string_list>
- key_usage_list using_list
+ using_list
%type <key_part>
key_part
@@ -835,7 +1180,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <interval_time_st> interval_time_st
-%type <db_type> storage_engines
+%type <db_type> storage_engines known_storage_engines
%type <row_type> row_types
@@ -859,6 +1204,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
old_or_new_charset_name_or_default
collation_name
collation_name_or_default
+ opt_load_data_charset
%type <variable> internal_variable_name
@@ -879,7 +1225,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
- when_list2 expr_list2 udf_expr_list3 handler
+ expr_list2 udf_expr_list3 handler
opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary table_lock_list table_lock
@@ -890,7 +1236,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option
- equal optional_braces opt_key_definition key_usage_list2
+ equal optional_braces
opt_mi_check_type opt_to mi_check_types normal_join
db_to_db table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
@@ -903,27 +1249,31 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
- definer view_replace_or_algorithm view_replace view_algorithm_opt
+ definer view_replace_or_algorithm view_replace
view_algorithm view_or_trigger_or_sp_or_event
view_or_trigger_or_sp_or_event_tail
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail
install uninstall partition_entry binlog_base64_event
init_key_options key_options key_opts key_opt key_using_alg
+ server_def server_options_list server_option
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
-%type <NONE> sp_proc_stmt_if sp_proc_stmt_case_simple sp_proc_stmt_case
+%type <NONE> sp_proc_stmt_if
%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled sp_proc_stmt_leave
%type <NONE> sp_proc_stmt_iterate
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
+%type <NONE> case_stmt_specification simple_case_stmt searched_case_stmt
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
%type <spcondtype> sp_cond sp_hcond
%type <spblock> sp_decls sp_decl
%type <lex> sp_cursor_stmt
%type <spname> sp_name
+%type <index_hint> index_hint_type
+%type <num> index_hint_clause
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
@@ -940,7 +1290,7 @@ query:
(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
{
my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -1012,13 +1362,8 @@ statement:
deallocate:
deallocate_or_drop PREPARE_SYM ident
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
- if (lex->stmt_prepare_mode)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
lex->prepared_stmt_name= $3;
};
@@ -1032,13 +1377,8 @@ deallocate_or_drop:
prepare:
PREPARE_SYM ident FROM prepare_src
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
- if (lex->stmt_prepare_mode)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
lex->sql_command= SQLCOM_PREPARE;
lex->prepared_stmt_name= $2;
};
@@ -1046,14 +1386,14 @@ prepare:
prepare_src:
TEXT_STRING_sys
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->prepared_stmt_code= $1;
lex->prepared_stmt_code_is_varref= FALSE;
}
| '@' ident_or_text
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
lex->prepared_stmt_code= $2;
lex->prepared_stmt_code_is_varref= TRUE;
@@ -1062,13 +1402,8 @@ prepare_src:
execute:
EXECUTE_SYM ident
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
- if (lex->stmt_prepare_mode)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
lex->sql_command= SQLCOM_EXECUTE;
lex->prepared_stmt_name= $2;
}
@@ -1091,7 +1426,7 @@ execute_var_ident: '@' ident_or_text
LEX *lex=Lex;
LEX_STRING *lexstr= (LEX_STRING*)sql_memdup(&$2, sizeof(LEX_STRING));
if (!lexstr || lex->prepared_stmt_params.push_back(lexstr))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -1103,7 +1438,7 @@ help:
if (Lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HELP");
- YYABORT;
+ MYSQL_YYABORT;
}
}
ident_or_text
@@ -1180,6 +1515,11 @@ master_def:
{
Lex->mi.ssl_key= $3.str;
}
+ | MASTER_SSL_VERIFY_SERVER_CERT_SYM EQ ulong_num
+ {
+ Lex->mi.ssl_verify_server_cert= $3 ?
+ LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
+ }
|
master_file_def
;
@@ -1223,28 +1563,36 @@ create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
{
THD *thd= YYTHD;
- LEX *lex=Lex;
+ LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_TABLE;
if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
TL_OPTION_UPDATING,
- (using_update_log ?
- TL_READ_NO_INSERT:
- TL_READ)))
- YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ TL_WRITE))
+ MYSQL_YYABORT;
+ lex->alter_info.reset();
lex->col_list.empty();
lex->change=NullS;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.options=$2 | $4;
- lex->create_info.db_type= lex->thd->variables.table_type;
+ lex->create_info.db_type= ha_default_handlerton(thd);
lex->create_info.default_table_charset= NULL;
lex->name.str= 0;
lex->name.length= 0;
- lex->like_name= 0;
}
create2
- { Lex->current_select= &Lex->select_lex; }
+ {
+ LEX *lex= YYTHD->lex;
+ lex->current_select= &lex->select_lex;
+ if (!lex->create_info.db_type)
+ {
+ lex->create_info.db_type= ha_default_handlerton(YYTHD);
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_USING_OTHER_HANDLER,
+ ER(ER_WARN_USING_OTHER_HANDLER),
+ ha_resolve_storage_engine_name(lex->create_info.db_type),
+ $5->table.str);
+ }
+ }
| CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON
table_ident
{
@@ -1253,22 +1601,24 @@ create:
if (!lex->current_select->add_table_to_list(lex->thd, $7,
NULL,
TL_OPTION_UPDATING))
- YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ MYSQL_YYABORT;
+ lex->alter_info.reset();
+ lex->alter_info.flags= ALTER_ADD_INDEX;
lex->col_list.empty();
lex->change=NullS;
}
'(' key_list ')' key_options
{
LEX *lex=Lex;
+ Key *key;
if ($2 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
- lex->key_list.push_back(new Key($2, $4.str, &lex->key_create_info, 0,
- lex->col_list));
+ key= new Key($2, $4.str, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
@@ -1295,7 +1645,7 @@ create:
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
- | CREATE LOGFILE_SYM GROUP logfile_group_info
+ | CREATE LOGFILE_SYM GROUP_SYM logfile_group_info
{
Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
}
@@ -1303,8 +1653,61 @@ create:
{
Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
}
+ | CREATE server_def
+ {
+ Lex->sql_command= SQLCOM_CREATE_SERVER;
+ }
;
+server_def:
+ SERVER_SYM ident_or_text FOREIGN DATA_SYM WRAPPER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')'
+ {
+ Lex->server_options.server_name= $2.str;
+ Lex->server_options.server_name_length= $2.length;
+ Lex->server_options.scheme= $6.str;
+ }
+ ;
+server_options_list:
+ server_option
+ | server_options_list ',' server_option
+ ;
+
+server_option:
+ USER TEXT_STRING_sys
+ {
+ Lex->server_options.username= $2.str;
+ }
+ |
+ HOST_SYM TEXT_STRING_sys
+ {
+ Lex->server_options.host= $2.str;
+ }
+ |
+ DATABASE TEXT_STRING_sys
+ {
+ Lex->server_options.db= $2.str;
+ }
+ |
+ OWNER_SYM TEXT_STRING_sys
+ {
+ Lex->server_options.owner= $2.str;
+ }
+ |
+ PASSWORD TEXT_STRING_sys
+ {
+ Lex->server_options.password= $2.str;
+ }
+ |
+ SOCKET_SYM TEXT_STRING_sys
+ {
+ Lex->server_options.socket= $2.str;
+ }
+ |
+ PORT_SYM ulong_num
+ {
+ Lex->server_options.port= $2;
+ }
+ ;
event_tail:
EVENT_SYM opt_if_not_exists sp_name
@@ -1316,7 +1719,7 @@ event_tail:
Lex->create_info.options= $2;
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
- YYABORT;
+ MYSQL_YYABORT;
Lex->event_parse_data->identifier= $3;
/*
@@ -1369,12 +1772,17 @@ ev_schedule_time: EVERY_SYM expr interval
opt_ev_status: /* empty */ { $$= 0; }
| ENABLE_SYM
{
- Lex->event_parse_data->status= Event_parse_data::ENABLED;
+ Lex->event_parse_data->status= Event_basic::ENABLED;
+ $$= 1;
+ }
+ | DISABLE_SYM ON SLAVE
+ {
+ Lex->event_parse_data->status= Event_basic::SLAVESIDE_DISABLED;
$$= 1;
}
| DISABLE_SYM
{
- Lex->event_parse_data->status= Event_parse_data::DISABLED;
+ Lex->event_parse_data->status= Event_basic::DISABLED;
$$= 1;
}
;
@@ -1404,13 +1812,13 @@ ev_on_completion:
ON COMPLETION_SYM PRESERVE_SYM
{
Lex->event_parse_data->on_completion=
- Event_parse_data::ON_COMPLETION_PRESERVE;
+ Event_basic::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
Lex->event_parse_data->on_completion=
- Event_parse_data::ON_COMPLETION_DROP;
+ Event_basic::ON_COMPLETION_DROP;
$$= 1;
}
;
@@ -1425,7 +1833,9 @@ opt_ev_comment: /* empty */ { $$= 0; }
ev_sql_stmt:
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
/*
This stops the following :
@@ -1446,12 +1856,12 @@ ev_sql_stmt:
*/
if (lex->sphead)
{
- my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
- YYABORT;
+ my_error(ER_EVENT_RECURSION_FORBIDDEN, MYF(0));
+ MYSQL_YYABORT;
}
if (!(lex->sphead= new sp_head()))
- YYABORT;
+ MYSQL_YYABORT;
lex->sphead->reset_thd_mem_root(YYTHD);
lex->sphead->init(lex);
@@ -1462,22 +1872,23 @@ ev_sql_stmt:
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->ptr;
+ lex->sphead->m_body_begin= lip->ptr;
- Lex->event_parse_data->body_begin= lex->ptr;
+ lex->event_parse_data->body_begin= lip->ptr;
}
ev_sql_stmt_inner
{
- LEX *lex=Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
/* return back to the original memory root ASAP */
- lex->sphead->init_strings(YYTHD, lex);
- lex->sphead->restore_thd_mem_root(YYTHD);
+ lex->sphead->init_strings(thd, lex);
+ lex->sphead->restore_thd_mem_root(thd);
lex->sp_chistics.suid= SP_IS_SUID; //always the definer!
- Lex->event_parse_data->init_body(YYTHD);
+ lex->event_parse_data->init_body(thd);
}
;
@@ -1485,8 +1896,7 @@ ev_sql_stmt_inner:
sp_proc_stmt_statement
| sp_proc_stmt_return
| sp_proc_stmt_if
- | sp_proc_stmt_case_simple
- | sp_proc_stmt_case
+ | case_stmt_specification
| sp_labeled_control
| sp_proc_stmt_unlabeled
| sp_proc_stmt_leave
@@ -1518,28 +1928,26 @@ sp_name:
if (!$1.str || check_db_name(&$1))
{
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
- if (check_routine_name($3))
+ if (check_routine_name(&$3))
{
- my_error(ER_SP_WRONG_NAME, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
- $$= new sp_name($1, $3);
+ $$= new sp_name($1, $3, true);
$$->init_qname(YYTHD);
}
| ident
{
THD *thd= YYTHD;
LEX_STRING db;
- if (check_routine_name($1))
+ if (check_routine_name(&$1))
{
- my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (thd->copy_db_to(&db.str, &db.length))
- YYABORT;
- $$= new sp_name(db, $1);
+ MYSQL_YYABORT;
+ $$= new sp_name(db, $1, false);
if ($$)
$$->init_qname(YYTHD);
}
@@ -1549,7 +1957,7 @@ create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
THD *thd= YYTHD;
- LEX *lex=Lex;
+ LEX *lex= thd->lex;
if (lex->definer != NULL)
{
/*
@@ -1559,13 +1967,13 @@ create_function_tail:
and is considered a parsing error.
*/
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
- YYABORT;
+ MYSQL_YYABORT;
}
if (is_native_function(thd, & lex->spname->m_name))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
lex->spname->m_name.str);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
@@ -1574,7 +1982,9 @@ create_function_tail:
}
| '('
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
sp_head *sp;
/*
@@ -1584,19 +1994,19 @@ create_function_tail:
if (lex->udf.type == UDFTYPE_AGGREGATE)
{
my_error(ER_SP_NO_AGGREGATE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
/* Order is important here: new - reset - init */
sp= new sp_head();
- sp->reset_thd_mem_root(YYTHD);
+ sp->reset_thd_mem_root(thd);
sp->init(lex);
- sp->init_sp_name(YYTHD, lex->spname);
+ sp->init_sp_name(thd, lex->spname);
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
@@ -1605,15 +2015,17 @@ create_function_tail:
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
- $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
- YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
- lex->sphead->m_param_begin= lex->tok_start+1;
+ $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
+ thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+ lex->sphead->m_param_begin= lip->tok_start+1;
}
sp_fdparam_list ')'
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
- lex->sphead->m_param_end= lex->tok_start;
+ lex->sphead->m_param_end= lip->tok_start;
}
RETURNS_SYM
{
@@ -1632,42 +2044,44 @@ create_function_tail:
When collation support in SP is implemented, then this test
should be removed.
*/
- if (($8 == FIELD_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR)
+ if (($8 == MYSQL_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR)
&& (lex->type & BINCMP_FLAG))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
- YYABORT;
+ MYSQL_YYABORT;
}
if (sp->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $8,
&sp->m_return_field_def))
- YYABORT;
+ MYSQL_YYABORT;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
sp_c_chistics
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->tok_start;
+ lex->sphead->m_body_begin= lip->tok_start;
}
sp_proc_stmt
{
THD *thd= YYTHD;
- LEX *lex= Lex;
+ LEX *lex= thd->lex;
sp_head *sp= lex->sphead;
if (sp->is_not_allowed_in_function("function"))
- YYABORT;
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
sp->init_strings(thd, lex);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (is_native_function(thd, & sp->m_name))
{
@@ -1831,7 +2245,7 @@ sp_fdparam:
if (spc->find_variable(&$1, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
sp_variable_t *spvar= spc->push_variable(&$1,
(enum enum_field_types)$3,
@@ -1841,7 +2255,7 @@ sp_fdparam:
(enum enum_field_types) $3,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
@@ -1868,7 +2282,7 @@ sp_pdparam:
if (spc->find_variable(&$3, TRUE))
{
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
sp_variable_t *spvar= spc->push_variable(&$3,
(enum enum_field_types)$4,
@@ -1878,7 +2292,7 @@ sp_pdparam:
(enum enum_field_types) $4,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
@@ -1917,13 +2331,13 @@ sp_decls:
{ /* Variable or condition following cursor or handler */
my_message(ER_SP_VARCOND_AFTER_CURSHNDLR,
ER(ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if ($2.curs && $1.hndlrs)
{ /* Cursor following handler */
my_message(ER_SP_CURSOR_AFTER_HANDLER,
ER(ER_SP_CURSOR_AFTER_HANDLER), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
$$.vars= $1.vars + $2.vars;
$$.conds= $1.conds + $2.conds;
@@ -1961,7 +2375,7 @@ sp_decl:
sp_variable_t *spvar= pctx->find_variable(var_idx);
if (!spvar)
- YYABORT;
+ MYSQL_YYABORT;
spvar->type= var_type;
spvar->dflt= dflt_value_item;
@@ -1969,7 +2383,7 @@ sp_decl:
if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
&spvar->field_def))
{
- YYABORT;
+ MYSQL_YYABORT;
}
spvar->field_def.field_name= spvar->name.str;
@@ -1997,7 +2411,7 @@ sp_decl:
if (spc->find_cond(&$2, TRUE))
{
my_error(ER_SP_DUP_COND, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
YYTHD->lex->spcont->push_cond(&$2, $5);
$$.vars= $$.hndlrs= $$.curs= 0;
@@ -2007,6 +2421,9 @@ sp_decl:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
+
+ lex->spcont= lex->spcont->push_context(LABEL_HANDLER_SCOPE);
+
sp_pcontext *ctx= lex->spcont;
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
@@ -2014,7 +2431,6 @@ sp_decl:
sp->add_instr(i);
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- sp->m_flags|= sp_head::IN_HANDLER;
}
sp_hcond_list sp_proc_stmt
{
@@ -2038,10 +2454,12 @@ sp_decl:
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
}
lex->sphead->backpatch(hlab);
- sp->m_flags&= ~sp_head::IN_HANDLER;
+
+ lex->spcont= ctx->pop_context();
+
$$.vars= $$.conds= $$.curs= 0;
$$.hndlrs= $6;
- ctx->add_handlers($6);
+ lex->spcont->add_handlers($6);
}
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
{
@@ -2055,7 +2473,7 @@ sp_decl:
{
my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
delete $5;
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
ctx->current_cursor_count());
@@ -2086,13 +2504,13 @@ sp_cursor_stmt:
{
my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY),
MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->result)
{
my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT),
MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sp_lex_in_use= TRUE;
$$= lex;
@@ -2107,16 +2525,23 @@ sp_handler_type:
;
sp_hcond_list:
+ sp_hcond_element
+ { $$= 1; }
+ | sp_hcond_list ',' sp_hcond_element
+ { $$+= 1; }
+ ;
+
+sp_hcond_element:
sp_hcond
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
+ sp_pcontext *ctx= lex->spcont->parent_context();
if (ctx->find_handler($1))
{
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2125,28 +2550,6 @@ sp_hcond_list:
i->add_condition($1);
ctx->push_handler($1);
- $$= 1;
- }
- }
- | sp_hcond_list ',' sp_hcond
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
-
- if (ctx->find_handler($3))
- {
- my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
- YYABORT;
- }
- else
- {
- sp_instr_hpush_jump *i=
- (sp_instr_hpush_jump *)sp->last_instruction();
-
- i->add_condition($3);
- ctx->push_handler($3);
- $$= $1 + 1;
}
}
;
@@ -2163,7 +2566,7 @@ sp_cond:
if (!sp_cond_check(&$3))
{
my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
$$->type= sp_cond_type_t::state;
@@ -2188,7 +2591,7 @@ sp_hcond:
if ($$ == NULL)
{
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| SQLWARNING_SYM /* SQLSTATEs 01??? */
@@ -2219,7 +2622,7 @@ sp_decl_idents:
if (spc->find_variable(&$1, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
spc->push_variable(&$1, (enum_field_types)0, sp_param_in);
$$= 1;
@@ -2234,7 +2637,7 @@ sp_decl_idents:
if (spc->find_variable(&$3, TRUE))
{
my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
spc->push_variable(&$3, (enum_field_types)0, sp_param_in);
$$= $1 + 1;
@@ -2250,8 +2653,7 @@ sp_proc_stmt:
sp_proc_stmt_statement
| sp_proc_stmt_return
| sp_proc_stmt_if
- | sp_proc_stmt_case_simple
- | sp_proc_stmt_case
+ | case_stmt_specification
| sp_labeled_control
| sp_proc_stmt_unlabeled
| sp_proc_stmt_leave
@@ -2269,21 +2671,25 @@ sp_proc_stmt_if:
sp_proc_stmt_statement:
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
- lex->sphead->reset_lex(YYTHD);
- lex->sphead->m_tmp_query= lex->tok_start;
+ lex->sphead->reset_lex(thd);
+ lex->sphead->m_tmp_query= lip->tok_start;
}
statement
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
sp_head *sp= lex->sphead;
sp->m_flags|= sp_get_flags_for_command(lex);
if (lex->sql_command == SQLCOM_CHANGE_DB)
{ /* "USE db" doesn't work in a procedure */
my_error(ER_SP_BADSTATEMENT, MYF(0), "USE");
- YYABORT;
+ MYSQL_YYABORT;
}
/*
Don't add an instruction for SET statements, since all
@@ -2303,15 +2709,15 @@ sp_proc_stmt_statement:
lex->tok_end otherwise.
*/
if (yychar == YYEMPTY)
- i->m_query.length= lex->ptr - sp->m_tmp_query;
+ i->m_query.length= lip->ptr - sp->m_tmp_query;
else
- i->m_query.length= lex->tok_end - sp->m_tmp_query;
- i->m_query.str= strmake_root(YYTHD->mem_root,
- (char *)sp->m_tmp_query,
+ i->m_query.length= lip->tok_end - sp->m_tmp_query;
+ i->m_query.str= strmake_root(thd->mem_root,
+ sp->m_tmp_query,
i->m_query.length);
sp->add_instr(i);
}
- sp->restore_lex(YYTHD);
+ sp->restore_lex(thd);
}
;
@@ -2326,7 +2732,7 @@ sp_proc_stmt_return:
if (sp->m_type != TYPE_ENUM_FUNCTION)
{
my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2341,49 +2747,6 @@ sp_proc_stmt_return:
}
;
-sp_proc_stmt_case_simple:
- CASE_SYM WHEN_SYM
- {
- Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE;
- Lex->sphead->new_cont_backpatch(NULL);
- }
- sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); }
- ;
-
-sp_proc_stmt_case:
- CASE_SYM
- {
- Lex->sphead->reset_lex(YYTHD);
- Lex->sphead->new_cont_backpatch(NULL);
- }
- expr WHEN_SYM
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *parsing_ctx= lex->spcont;
- int case_expr_id= parsing_ctx->register_case_expr();
- sp_instr_set_case_expr *i;
-
- if (parsing_ctx->push_case_expr_id(case_expr_id))
- YYABORT;
-
- i= new sp_instr_set_case_expr(sp->instructions(),
- parsing_ctx,
- case_expr_id,
- $3,
- lex);
- sp->add_cont_backpatch(i);
- sp->add_instr(i);
- sp->m_flags|= sp_head::IN_SIMPLE_CASE;
- sp->restore_lex(YYTHD);
- }
- sp_case END CASE_SYM
- {
- Lex->spcont->pop_case_expr_id();
- Lex->sphead->do_cont_backpatch();
- }
- ;
-
sp_proc_stmt_unlabeled:
{ /* Unlabeled controls get a secret label. */
LEX *lex= Lex;
@@ -2409,7 +2772,7 @@ sp_proc_stmt_leave:
if (! lab)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2441,7 +2804,7 @@ sp_proc_stmt_iterate:
if (! lab || lab->type != SP_LAB_ITER)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2472,7 +2835,7 @@ sp_proc_stmt_open:
if (! lex->spcont->find_cursor(&$2, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2490,7 +2853,7 @@ sp_proc_stmt_fetch:
if (! lex->spcont->find_cursor(&$3, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2510,7 +2873,7 @@ sp_proc_stmt_close:
if (! lex->spcont->find_cursor(&$2, &offset))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
- YYABORT;
+ MYSQL_YYABORT;
}
i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
@@ -2534,7 +2897,7 @@ sp_fetch_list:
if (!spc || !(spv = spc->find_variable(&$1)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2555,7 +2918,7 @@ sp_fetch_list:
if (!spc || !(spv = spc->find_variable(&$3)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2608,72 +2971,114 @@ sp_elseifs:
| ELSE sp_proc_stmts1
;
-sp_case:
- { Lex->sphead->reset_lex(YYTHD); }
- expr THEN_SYM
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= Lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump_if_not *i;
-
- if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE))
- i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
- else
- { /* Simple case: <caseval> = <whenval> */
+case_stmt_specification:
+ simple_case_stmt
+ | searched_case_stmt
+ ;
- Item_case_expr *var;
- Item *expr;
+simple_case_stmt:
+ CASE_SYM
+ {
+ LEX *lex= Lex;
+ case_stmt_action_case(lex);
+ lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ }
+ expr
+ {
+ LEX *lex= Lex;
+ if (case_stmt_action_expr(lex, $3))
+ MYSQL_YYABORT;
- var= new Item_case_expr(ctx->get_current_case_expr_id());
+ lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ }
+ simple_when_clause_list
+ else_clause_opt
+ END
+ CASE_SYM
+ {
+ LEX *lex= Lex;
+ case_stmt_action_end_case(lex, true);
+ }
+ ;
-#ifndef DBUG_OFF
- if (var)
- var->m_sp= sp;
-#endif
+searched_case_stmt:
+ CASE_SYM
+ {
+ LEX *lex= Lex;
+ case_stmt_action_case(lex);
+ }
+ searched_when_clause_list
+ else_clause_opt
+ END
+ CASE_SYM
+ {
+ LEX *lex= Lex;
+ case_stmt_action_end_case(lex, false);
+ }
+ ;
- expr= new Item_func_eq(var, $2);
+simple_when_clause_list:
+ simple_when_clause
+ | simple_when_clause_list simple_when_clause
+ ;
- i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
- }
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- sp->add_cont_backpatch(i);
- sp->add_instr(i);
- sp->restore_lex(YYTHD);
- }
- sp_proc_stmts1
- {
- sp_head *sp= Lex->sphead;
- sp_pcontext *ctx= Lex->spcont;
- uint ip= sp->instructions();
- sp_instr_jump *i = new sp_instr_jump(ip, ctx);
+searched_when_clause_list:
+ searched_when_clause
+ | searched_when_clause_list searched_when_clause
+ ;
- sp->add_instr(i);
- sp->backpatch(ctx->pop_label());
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- }
- sp_whens
- {
- LEX *lex= Lex;
+simple_when_clause:
+ WHEN_SYM
+ {
+ Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ }
+ expr
+ {
+ /* Simple case: <caseval> = <whenval> */
- lex->sphead->backpatch(lex->spcont->pop_label());
- }
- ;
+ LEX *lex= Lex;
+ case_stmt_action_when(lex, $3, true);
+ lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ }
+ THEN_SYM
+ sp_proc_stmts1
+ {
+ LEX *lex= Lex;
+ case_stmt_action_then(lex);
+ }
+ ;
-sp_whens:
- /* Empty */
- {
- sp_head *sp= Lex->sphead;
- uint ip= sp->instructions();
- sp_instr_error *i= new sp_instr_error(ip, Lex->spcont,
- ER_SP_CASE_NOT_FOUND);
+searched_when_clause:
+ WHEN_SYM
+ {
+ Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ }
+ expr
+ {
+ LEX *lex= Lex;
+ case_stmt_action_when(lex, $3, false);
+ lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ }
+ THEN_SYM
+ sp_proc_stmts1
+ {
+ LEX *lex= Lex;
+ case_stmt_action_then(lex);
+ }
+ ;
- sp->add_instr(i);
- }
- | ELSE sp_proc_stmts1 {}
- | WHEN_SYM sp_case {}
- ;
+else_clause_opt:
+ /* empty */
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint ip= sp->instructions();
+ sp_instr_error *i= new sp_instr_error(ip, lex->spcont,
+ ER_SP_CASE_NOT_FOUND);
+ sp->add_instr(i);
+ }
+ | ELSE sp_proc_stmts1
+ ;
sp_labeled_control:
label_ident ':'
@@ -2685,7 +3090,7 @@ sp_labeled_control:
if (lab)
{
my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -2706,7 +3111,7 @@ sp_labeled_control:
my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
{
my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
lex->sphead->backpatch(lex->spcont->pop_label());
@@ -2727,7 +3132,7 @@ sp_unlabeled_control:
sp_label_t *lab= lex->spcont->last_label();
lab->type= SP_LAB_BEGIN;
- lex->spcont= lex->spcont->push_context();
+ lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE);
}
sp_decls
sp_proc_stmts
@@ -2821,11 +3226,11 @@ trg_event:
ALTER TABLESPACE name CHANGE DATAFILE ...
ALTER TABLESPACE name ADD DATAFILE ...
ALTER TABLESPACE name access_mode
- CREATE LOGFILE GROUP name ...
- ALTER LOGFILE GROUP name ADD UNDOFILE ..
- ALTER LOGFILE GROUP name ADD REDOFILE ..
+ CREATE LOGFILE GROUP_SYM name ...
+ ALTER LOGFILE GROUP_SYM name ADD UNDOFILE ..
+ ALTER LOGFILE GROUP_SYM name ADD REDOFILE ..
DROP TABLESPACE name
- DROP LOGFILE GROUP name
+ DROP LOGFILE GROUP_SYM name
*/
change_tablespace_access:
tablespace_name
@@ -2847,7 +3252,7 @@ tablespace_info:
opt_logfile_group_name:
/* empty */ {}
- | USE_SYM LOGFILE_SYM GROUP ident
+ | USE_SYM LOGFILE_SYM GROUP_SYM ident
{
LEX *lex= Lex;
lex->alter_tablespace_info->logfile_group_name= $4.str;
@@ -3087,7 +3492,7 @@ opt_ts_nodegroup:
if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP)
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->nodegroup_id= $3;
};
@@ -3099,7 +3504,7 @@ opt_ts_comment:
if (lex->alter_tablespace_info->ts_comment != NULL)
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->ts_comment= $3.str;
};
@@ -3112,7 +3517,7 @@ opt_ts_engine:
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),
"STORAGE ENGINE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->storage_engine= $4;
};
@@ -3134,7 +3539,7 @@ ts_wait:
if (!(lex->alter_tablespace_info->wait_until_completed))
{
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_tablespace_info->wait_until_completed= FALSE;
};
@@ -3168,20 +3573,20 @@ size_number:
default:
{
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
if (prefix_number >> 31)
{
my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
number= prefix_number << text_shift_number;
}
else
{
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
$$= number;
}
@@ -3198,27 +3603,15 @@ create2:
create3 {}
| LIKE table_ident
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
- if (!(lex->like_name= $2))
- YYABORT;
- if ($2->db.str == NULL &&
- thd->copy_db_to(&($2->db.str), &($2->db.length)))
- {
- YYABORT;
- }
+ Lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
+ if (!Lex->select_lex.add_table_to_list(YYTHD, $2, NULL, 0, TL_READ))
+ MYSQL_YYABORT;
}
| '(' LIKE table_ident ')'
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
- if (!(lex->like_name= $3))
- YYABORT;
- if ($3->db.str == NULL &&
- thd->copy_db_to(&($3->db.str), &($3->db.length)))
- {
- YYABORT;
- }
+ Lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
+ if (!Lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0, TL_READ))
+ MYSQL_YYABORT;
}
;
@@ -3273,11 +3666,18 @@ partitioning:
{
#ifdef WITH_PARTITION_STORAGE_ENGINE
LEX *lex= Lex;
+ LEX_STRING partition_name={C_STRING_WITH_LEN("partition")};
+ if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN))
+ {
+ my_error(ER_FEATURE_DISABLED, MYF(0),
+ "partitioning", "--with-partition");
+ MYSQL_YYABORT;
+ }
lex->part_info= new partition_info();
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sql_command == SQLCOM_ALTER_TABLE)
{
@@ -3286,7 +3686,7 @@ partitioning:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
"partitioning", "--with-partition");
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
@@ -3299,8 +3699,8 @@ partition_entry:
LEX *lex= Lex;
if (!lex->part_info)
{
- yyerror(ER(ER_PARTITION_ENTRY_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_ENTRY_ERROR));
+ MYSQL_YYABORT;
}
/*
We enter here when opening the frm file to translate
@@ -3354,7 +3754,7 @@ part_field_item:
if (Lex->part_info->part_field_list.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3393,7 +3793,7 @@ opt_no_parts:
if (no_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->part_info->no_parts= no_parts;
@@ -3427,7 +3827,7 @@ sub_part_field_item:
if (Lex->part_info->subpart_field_list.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3441,8 +3841,8 @@ part_func_expr:
lex->safe_to_cache_query= 1;
if (not_corr_func)
{
- yyerror(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
+ MYSQL_YYABORT;
}
$$=$1;
}
@@ -3457,7 +3857,7 @@ opt_no_subparts:
if (no_parts == 0)
{
my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->part_info->no_subparts= no_parts;
lex->part_info->use_default_no_subpartitions= FALSE;
@@ -3477,8 +3877,8 @@ part_defs:
if (part_info->no_parts !=
count_curr_parts)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
+ MYSQL_YYABORT;
}
}
else if (count_curr_parts > 0)
@@ -3500,12 +3900,11 @@ part_definition:
LEX *lex= Lex;
partition_info *part_info= lex->part_info;
partition_element *p_elem= new partition_element();
- uint part_id= part_info->partitions.elements;
if (!p_elem || part_info->partitions.push_back(p_elem))
{
mem_alloc_error(sizeof(partition_element));
- YYABORT;
+ MYSQL_YYABORT;
}
p_elem->part_state= PART_NORMAL;
part_info->curr_part_elem= p_elem;
@@ -3533,19 +3932,19 @@ opt_part_values:
/* empty */
{
LEX *lex= Lex;
- if (!is_partition_management(lex))
+ if (! lex->is_partition_management())
{
if (lex->part_info->part_type == RANGE_PARTITION)
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->part_info->part_type == LIST_PARTITION)
{
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
"LIST", "IN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3554,13 +3953,13 @@ opt_part_values:
| VALUES LESS_SYM THAN_SYM part_func_max
{
LEX *lex= Lex;
- if (!is_partition_management(lex))
+ if (! lex->is_partition_management())
{
if (Lex->part_info->part_type != RANGE_PARTITION)
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"RANGE", "LESS THAN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3569,13 +3968,13 @@ opt_part_values:
| VALUES IN_SYM '(' part_list_func ')'
{
LEX *lex= Lex;
- if (!is_partition_management(lex))
+ if (! lex->is_partition_management())
{
if (Lex->part_info->part_type != LIST_PARTITION)
{
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
"LIST", "IN");
- YYABORT;
+ MYSQL_YYABORT;
}
}
else
@@ -3589,8 +3988,8 @@ part_func_max:
LEX *lex= Lex;
if (lex->part_info->defined_max_value)
{
- yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
+ MYSQL_YYABORT;
}
lex->part_info->defined_max_value= TRUE;
lex->part_info->curr_part_elem->max_value= TRUE;
@@ -3600,13 +3999,13 @@ part_func_max:
{
if (Lex->part_info->defined_max_value)
{
- yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR));
+ MYSQL_YYABORT;
}
if (Lex->part_info->curr_part_elem->has_null_value)
{
- yyerror(ER(ER_NULL_IN_VALUES_LESS_THAN));
- YYABORT;
+ my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN));
+ MYSQL_YYABORT;
}
}
;
@@ -3643,7 +4042,7 @@ part_list_item:
list_val_list.push_back(value_ptr))
{
mem_alloc_error(sizeof(part_elem_value));
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -3652,9 +4051,8 @@ part_bit_expr:
bit_expr
{
Item *part_expr= $1;
- int part_expression_ok= 1;
- LEX *lex= Lex;
THD *thd= YYTHD;
+ LEX *lex= thd->lex;
Name_resolution_context *context= &lex->current_select->context;
TABLE_LIST *save_list= context->table_list;
const char *save_where= thd->where;
@@ -3667,13 +4065,13 @@ part_bit_expr:
if (!value_ptr)
{
mem_alloc_error(sizeof(part_elem_value));
- YYABORT;
+ MYSQL_YYABORT;
}
if (part_expr->walk(&Item::check_partition_func_processor, 0,
NULL))
{
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
if (part_expr->fix_fields(YYTHD, (Item**)0) ||
((context->table_list= save_list), FALSE) ||
@@ -3681,7 +4079,7 @@ part_bit_expr:
(!lex->safe_to_cache_query))
{
my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
thd->where= save_where;
value_ptr->value= part_expr->val_int();
@@ -3694,15 +4092,15 @@ part_bit_expr:
if (Lex->part_info->curr_part_elem->has_null_value)
{
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->part_info->curr_part_elem->has_null_value= TRUE;
}
else if (part_expr->result_type() != INT_RESULT &&
!part_expr->null_value)
{
- yyerror(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
+ MYSQL_YYABORT;
}
$$= value_ptr;
}
@@ -3714,8 +4112,8 @@ opt_sub_partition:
if (Lex->part_info->no_subparts != 0 &&
!Lex->part_info->use_default_subpartitions)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
}
| '(' sub_part_list ')'
@@ -3727,16 +4125,16 @@ opt_sub_partition:
if (part_info->no_subparts !=
part_info->count_curr_subparts)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
}
else if (part_info->count_curr_subparts > 0)
{
if (part_info->partitions.elements > 1)
{
- yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
+ MYSQL_YYABORT;
}
part_info->no_subparts= part_info->count_curr_subparts;
}
@@ -3760,7 +4158,7 @@ sub_part_definition:
curr_part->subpartitions.push_back(sub_p_elem))
{
mem_alloc_error(sizeof(partition_element));
- YYABORT;
+ MYSQL_YYABORT;
}
part_info->curr_part_elem= sub_p_elem;
part_info->use_default_subpartitions= FALSE;
@@ -3912,8 +4310,8 @@ create_table_option:
Lex->create_info.table_options|= HA_OPTION_PACK_KEYS;
break;
default:
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;
}
@@ -3934,10 +4332,10 @@ create_table_option:
lex->create_info.merge_list= lex->select_lex.table_list;
lex->create_info.merge_list.elements--;
lex->create_info.merge_list.first=
- (byte*) (table_list->next_local);
+ (uchar*) (table_list->next_local);
lex->select_lex.table_list.elements=1;
lex->select_lex.table_list.next=
- (byte**) &(table_list->next_local);
+ (uchar**) &(table_list->next_local);
table_list->next_local= 0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
@@ -3947,8 +4345,8 @@ create_table_option:
| DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.data_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; }
| INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; }
| TABLESPACE ident {Lex->create_info.tablespace= $2.str;}
- | STORAGE_SYM DISK_SYM {Lex->create_info.store_on_disk= TRUE;}
- | STORAGE_SYM MEMORY_SYM {Lex->create_info.store_on_disk= FALSE;}
+ | STORAGE_SYM DISK_SYM {Lex->create_info.storage_media= HA_SM_DISK;}
+ | STORAGE_SYM MEMORY_SYM {Lex->create_info.storage_media= HA_SM_MEMORY;}
| CONNECTION_SYM opt_equal TEXT_STRING_sys { Lex->create_info.connect_string.str= $3.str; Lex->create_info.connect_string.length= $3.length; Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION; }
| KEY_BLOCK_SIZE opt_equal ulong_num
{
@@ -3968,7 +4366,7 @@ default_charset:
my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
"CHARACTER SET ", cinfo->default_table_charset->csname,
"CHARACTER SET ", $4->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->create_info.default_table_charset= $4;
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
@@ -3984,7 +4382,7 @@ default_collation:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$4->name, cinfo->default_table_charset->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
Lex->create_info.default_table_charset= $4;
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
@@ -3993,20 +4391,39 @@ default_collation:
storage_engines:
ident_or_text
{
- $$ = ha_resolve_by_name(YYTHD, &$1);
- if ($$ == NULL)
- if (YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
- {
- my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
- YYABORT;
- }
+ plugin_ref plugin= ha_resolve_by_name(YYTHD, &$1);
+
+ if (plugin)
+ $$= plugin_data(plugin, handlerton*);
else
{
- push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ if (YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
+ {
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ $$= 0;
+ push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_STORAGE_ENGINE,
- ER(ER_UNKNOWN_STORAGE_ENGINE), $1.str);
+ ER(ER_UNKNOWN_STORAGE_ENGINE),
+ $1.str);
}
- };
+ }
+ ;
+
+known_storage_engines:
+ ident_or_text
+ {
+ plugin_ref plugin;
+ if ((plugin= ha_resolve_by_name(YYTHD, &$1)))
+ $$= plugin_data(plugin, handlerton*);
+ else
+ {
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ }
+ ;
row_types:
DEFAULT { $$= ROW_TYPE_DEFAULT; }
@@ -4059,11 +4476,12 @@ key_def:
LEX *lex=Lex;
if ($1 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
- lex->key_list.push_back(new Key($1,$2, &lex->key_create_info, 0,
- lex->col_list));
+ Key *key= new Key($1, $2, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint constraint_key_type opt_ident key_alg
@@ -4071,24 +4489,27 @@ key_def:
{
LEX *lex=Lex;
const char *key_name= $3 ? $3 : $1;
- lex->key_list.push_back(new Key($2, key_name, &lex->key_create_info, 0,
- lex->col_list));
+ Key *key= new Key($2, key_name, &lex->key_create_info, 0,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
LEX *lex=Lex;
- lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list,
- $8,
- lex->ref_list,
- lex->fk_delete_opt,
- lex->fk_update_opt,
- lex->fk_match_option));
- lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
- &default_key_create_info, 1,
- lex->col_list));
+ const char *key_name= $4 ? $4 : $1;
+ Key *key= new foreign_key(key_name, lex->col_list,
+ $8,
+ lex->ref_list,
+ lex->fk_delete_opt,
+ lex->fk_update_opt,
+ lex->fk_match_option);
+ lex->alter_info.key_list.push_back(key);
+ key= new Key(Key::MULTIPLE, key_name,
+ &default_key_create_info, 1,
+ lex->col_list);
+ lex->alter_info.key_list.push_back(key);
lex->col_list.empty(); /* Alloced by sql_alloc */
-
/* Only used for ALTER TABLE. Ignored otherwise. */
lex->alter_info.flags|= ALTER_FOREIGN_KEY;
}
@@ -4132,44 +4553,43 @@ field_spec:
type opt_attribute
{
LEX *lex=Lex;
- if (add_field_to_list(lex->thd, $1.str,
- (enum enum_field_types) $3,
+ if (add_field_to_list(lex->thd, &$1, (enum enum_field_types) $3,
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
&lex->comment,
lex->change,&lex->interval_list,lex->charset,
lex->uint_geom_type))
- YYABORT;
+ MYSQL_YYABORT;
};
type:
int_type opt_len field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; }
- | FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
+ | FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; }
| BIT_SYM { Lex->length= (char*) "1";
- $$=FIELD_TYPE_BIT; }
+ $$=MYSQL_TYPE_BIT; }
| BIT_SYM '(' NUM ')' { Lex->length= $3.str;
- $$=FIELD_TYPE_BIT; }
+ $$=MYSQL_TYPE_BIT; }
| BOOL_SYM { Lex->length=(char*) "1";
- $$=FIELD_TYPE_TINY; }
+ $$=MYSQL_TYPE_TINY; }
| BOOLEAN_SYM { Lex->length=(char*) "1";
- $$=FIELD_TYPE_TINY; }
+ $$=MYSQL_TYPE_TINY; }
| char '(' NUM ')' opt_binary { Lex->length=$3.str;
- $$=FIELD_TYPE_STRING; }
+ $$=MYSQL_TYPE_STRING; }
| char opt_binary { Lex->length=(char*) "1";
- $$=FIELD_TYPE_STRING; }
+ $$=MYSQL_TYPE_STRING; }
| nchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str;
- $$=FIELD_TYPE_STRING;
+ $$=MYSQL_TYPE_STRING;
Lex->charset=national_charset_info; }
| nchar opt_bin_mod { Lex->length=(char*) "1";
- $$=FIELD_TYPE_STRING;
+ $$=MYSQL_TYPE_STRING;
Lex->charset=national_charset_info; }
| BINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_STRING; }
+ $$=MYSQL_TYPE_STRING; }
| BINARY { Lex->length= (char*) "1";
Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_STRING; }
+ $$=MYSQL_TYPE_STRING; }
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
$$= MYSQL_TYPE_VARCHAR; }
| nvarchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str;
@@ -4178,64 +4598,64 @@ type:
| VARBINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=&my_charset_bin;
$$= MYSQL_TYPE_VARCHAR; }
- | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; }
- | DATE_SYM { $$=FIELD_TYPE_DATE; }
- | TIME_SYM { $$=FIELD_TYPE_TIME; }
+ | YEAR_SYM opt_len field_options { $$=MYSQL_TYPE_YEAR; }
+ | DATE_SYM { $$=MYSQL_TYPE_DATE; }
+ | TIME_SYM { $$=MYSQL_TYPE_TIME; }
| TIMESTAMP opt_len
{
if (YYTHD->variables.sql_mode & MODE_MAXDB)
- $$=FIELD_TYPE_DATETIME;
+ $$=MYSQL_TYPE_DATETIME;
else
{
/*
Unlike other types TIMESTAMP fields are NOT NULL by default.
*/
Lex->type|= NOT_NULL_FLAG;
- $$=FIELD_TYPE_TIMESTAMP;
+ $$=MYSQL_TYPE_TIMESTAMP;
}
}
- | DATETIME { $$=FIELD_TYPE_DATETIME; }
+ | DATETIME { $$=MYSQL_TYPE_DATETIME; }
| TINYBLOB { Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_TINY_BLOB; }
+ $$=MYSQL_TYPE_TINY_BLOB; }
| BLOB_SYM opt_len { Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_BLOB; }
+ $$=MYSQL_TYPE_BLOB; }
| spatial_type
{
#ifdef HAVE_SPATIAL
Lex->charset=&my_charset_bin;
Lex->uint_geom_type= (uint)$1;
- $$=FIELD_TYPE_GEOMETRY;
+ $$=MYSQL_TYPE_GEOMETRY;
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
| MEDIUMBLOB { Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_MEDIUM_BLOB; }
+ $$=MYSQL_TYPE_MEDIUM_BLOB; }
| LONGBLOB { Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_LONG_BLOB; }
+ $$=MYSQL_TYPE_LONG_BLOB; }
| LONG_SYM VARBINARY { Lex->charset=&my_charset_bin;
- $$=FIELD_TYPE_MEDIUM_BLOB; }
- | LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
- | TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; }
- | TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; }
- | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
- | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; }
+ $$=MYSQL_TYPE_MEDIUM_BLOB; }
+ | LONG_SYM varchar opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; }
+ | TINYTEXT opt_binary { $$=MYSQL_TYPE_TINY_BLOB; }
+ | TEXT_SYM opt_len opt_binary { $$=MYSQL_TYPE_BLOB; }
+ | MEDIUMTEXT opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; }
+ | LONGTEXT opt_binary { $$=MYSQL_TYPE_LONG_BLOB; }
| DECIMAL_SYM float_options field_options
- { $$=FIELD_TYPE_NEWDECIMAL;}
+ { $$=MYSQL_TYPE_NEWDECIMAL;}
| NUMERIC_SYM float_options field_options
- { $$=FIELD_TYPE_NEWDECIMAL;}
+ { $$=MYSQL_TYPE_NEWDECIMAL;}
| FIXED_SYM float_options field_options
- { $$=FIELD_TYPE_NEWDECIMAL;}
+ { $$=MYSQL_TYPE_NEWDECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
- { $$=FIELD_TYPE_ENUM; }
+ { $$=MYSQL_TYPE_ENUM; }
| SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
- { $$=FIELD_TYPE_SET; }
- | LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ { $$=MYSQL_TYPE_SET; }
+ | LONG_SYM opt_binary { $$=MYSQL_TYPE_MEDIUM_BLOB; }
| SERIAL_SYM
{
- $$=FIELD_TYPE_LONGLONG;
+ $$=MYSQL_TYPE_LONGLONG;
Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
UNIQUE_FLAG);
}
@@ -4277,17 +4697,17 @@ nvarchar:
;
int_type:
- INT_SYM { $$=FIELD_TYPE_LONG; }
- | TINYINT { $$=FIELD_TYPE_TINY; }
- | SMALLINT { $$=FIELD_TYPE_SHORT; }
- | MEDIUMINT { $$=FIELD_TYPE_INT24; }
- | BIGINT { $$=FIELD_TYPE_LONGLONG; };
+ INT_SYM { $$=MYSQL_TYPE_LONG; }
+ | TINYINT { $$=MYSQL_TYPE_TINY; }
+ | SMALLINT { $$=MYSQL_TYPE_SHORT; }
+ | MEDIUMINT { $$=MYSQL_TYPE_INT24; }
+ | BIGINT { $$=MYSQL_TYPE_LONGLONG; };
real_type:
REAL { $$= YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ?
- FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
- | DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; }
- | DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; };
+ MYSQL_TYPE_FLOAT : MYSQL_TYPE_DOUBLE; }
+ | DOUBLE_SYM { $$=MYSQL_TYPE_DOUBLE; }
+ | DOUBLE_SYM PRECISION { $$=MYSQL_TYPE_DOUBLE; };
float_options:
@@ -4369,7 +4789,7 @@ attribute:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$2->name,Lex->charset->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
else
{
@@ -4394,7 +4814,7 @@ charset_name:
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| BINARY { $$= &my_charset_bin; }
@@ -4404,6 +4824,10 @@ charset_name_or_default:
charset_name { $$=$1; }
| DEFAULT { $$=NULL; } ;
+opt_load_data_charset:
+ /* Empty */ { $$= NULL; }
+ | charset charset_name_or_default { $$= $2; }
+ ;
old_or_new_charset_name:
ident_or_text
@@ -4412,7 +4836,7 @@ old_or_new_charset_name:
!($$=get_old_charset_by_name($1.str)))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
| BINARY { $$= &my_charset_bin; }
@@ -4428,7 +4852,7 @@ collation_name:
if (!($$=get_charset_by_name($1.str,MYF(0))))
{
my_error(ER_UNKNOWN_COLLATION, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
};
@@ -4455,7 +4879,7 @@ opt_binary:
MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
- YYABORT;
+ MYSQL_YYABORT;
}
}
| charset charset_name opt_bin_mod { Lex->charset=$2; }
@@ -4474,7 +4898,7 @@ opt_bin_charset:
MY_CS_PRIMARY,MYF(0))))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
- YYABORT;
+ MYSQL_YYABORT;
}
}
| charset charset_name { Lex->charset=$2; } ;
@@ -4537,7 +4961,7 @@ key_type:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
};
@@ -4570,7 +4994,7 @@ opt_unique_or_fulltext:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
;
@@ -4618,7 +5042,7 @@ key_opt:
else
{
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -4675,21 +5099,19 @@ alter:
lex->duplicates= DUP_ERROR;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING))
- YYABORT;
- lex->create_list.empty();
- lex->key_list.empty();
+ MYSQL_YYABORT;
+ lex->alter_info.reset();
lex->col_list.empty();
lex->select_lex.init_order();
- lex->like_name= 0;
lex->select_lex.db=
((TABLE_LIST*) lex->select_lex.table_list.first)->db;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.db_type= 0;
lex->create_info.default_table_charset= NULL;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
- lex->alter_info.reset();
- lex->alter_info.flags= 0;
+ lex->alter_info.reset();
lex->no_write_to_binlog= 0;
+ lex->create_info.storage_media= HA_SM_DEFAULT;
}
alter_commands
{}
@@ -4700,13 +5122,13 @@ alter:
}
opt_create_database_options
{
- LEX *lex=Lex;
- THD *thd= Lex->thd;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
lex->sql_command=SQLCOM_ALTER_DB;
lex->name= $3;
if (lex->name.str == NULL &&
thd->copy_db_to(&lex->name.str, &lex->name.length))
- YYABORT;
+ MYSQL_YYABORT;
}
| ALTER PROCEDURE sp_name
{
@@ -4715,7 +5137,7 @@ alter:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -4733,7 +5155,7 @@ alter:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
@@ -4744,19 +5166,26 @@ alter:
lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->spname= $3;
}
- | ALTER view_algorithm_opt definer view_suid
- VIEW_SYM table_ident
+ | ALTER view_algorithm definer
{
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- lex->sql_command= SQLCOM_CREATE_VIEW;
+ Lex->create_view_mode= VIEW_ALTER;
+ }
+ view_tail
+ {}
+ | ALTER definer
+ /*
+ We have two separate rules for ALTER VIEW rather that
+ optional view_algorithm above, to resolve the ambiguity
+ with the ALTER EVENT below.
+ */
+ {
+ LEX *lex= Lex;
+ lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
lex->create_view_mode= VIEW_ALTER;
- /* first table in list is target VIEW name */
- lex->select_lex.add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING);
}
- view_list_opt AS view_select view_check_option
+ view_tail
{}
- | ALTER EVENT_SYM sp_name
+ | ALTER definer EVENT_SYM sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
@@ -4771,8 +5200,8 @@ alter:
*/
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
- YYABORT;
- Lex->event_parse_data->identifier= $3;
+ MYSQL_YYABORT;
+ Lex->event_parse_data->identifier= $4;
/*
We have to turn off CLIENT_MULTI_QUERIES while parsing a
@@ -4792,16 +5221,17 @@ alter:
{
/*
$1 - ALTER
- $2 - EVENT_SYM
- $3 - sp_name
- $4 - the block above
+ $2 - definer
+ $3 - EVENT_SYM
+ $4 - sp_name
+ $5 - the block above
*/
- YYTHD->client_capabilities |= $<ulong_num>4;
+ YYTHD->client_capabilities |= $<ulong_num>5;
- if (!($5 || $6 || $7 || $8 || $9))
+ if (!($6 || $7 || $8 || $9 || $10))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/*
sql_command is set here because some rules in ev_sql_stmt
@@ -4814,7 +5244,7 @@ alter:
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
}
- | ALTER LOGFILE_SYM GROUP alter_logfile_group_info
+ | ALTER LOGFILE_SYM GROUP_SYM alter_logfile_group_info
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
@@ -4829,6 +5259,13 @@ alter:
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE;
}
+ | ALTER SERVER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')'
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_ALTER_SERVER;
+ lex->server_options.server_name= $3.str;
+ lex->server_options.server_name_length= $3.length;
+ }
;
ev_alter_on_schedule_completion: /* empty */ { $$= 0;}
@@ -4853,7 +5290,6 @@ opt_ev_sql_stmt: /* empty*/ { $$= 0;}
| DO_SYM ev_sql_stmt { $$= 1; }
;
-
ident_or_empty:
/* empty */ { $$.str= 0; $$.length= 0; }
| ident { $$= $1; };
@@ -4954,7 +5390,7 @@ add_partition_rule:
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->alter_info.flags|= ALTER_ADD_PARTITION;
lex->no_write_to_binlog= $3;
@@ -4984,7 +5420,7 @@ reorg_partition_rule:
if (!lex->part_info)
{
mem_alloc_error(sizeof(partition_info));
- YYABORT;
+ MYSQL_YYABORT;
}
lex->no_write_to_binlog= $3;
}
@@ -5019,7 +5455,7 @@ alt_part_name_item:
if (Lex->alter_info.partition_names.push_back($1.str))
{
mem_alloc_error(1);
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -5070,14 +5506,14 @@ alter_list_item:
type opt_attribute
{
LEX *lex=Lex;
- if (add_field_to_list(lex->thd,$3.str,
+ if (add_field_to_list(lex->thd,&$3,
(enum enum_field_types) $5,
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
&lex->comment,
$3.str, &lex->interval_list, lex->charset,
lex->uint_geom_type))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_place
| DROP opt_column field_ident opt_restrict
@@ -5132,20 +5568,20 @@ alter_list_item:
}
| RENAME opt_to table_ident
{
- LEX *lex=Lex;
- THD *thd= lex->thd;
- uint dummy;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ size_t dummy;
lex->select_lex.db=$3->db.str;
if (lex->select_lex.db == NULL &&
- thd->copy_db_to(&lex->select_lex.db, &dummy))
+ thd->copy_db_to(&lex->select_lex.db, &dummy))
{
- YYABORT;
+ MYSQL_YYABORT;
}
if (check_table_name($3->table.str,$3->table.length) ||
$3->db.str && check_db_name(&$3->db))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->name= $3->table;
lex->alter_info.flags|= ALTER_RENAME;
@@ -5162,7 +5598,7 @@ alter_list_item:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$5->name, $4->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
LEX *lex= Lex;
lex->create_info.table_charset=
@@ -5180,7 +5616,7 @@ alter_list_item:
{
Lex->alter_info.flags|= ALTER_FORCE;
}
- | order_clause
+ | alter_order_clause
{
LEX *lex=Lex;
lex->alter_info.flags|= ALTER_ORDER;
@@ -5300,7 +5736,7 @@ slave_until:
{
my_message(ER_BAD_SLAVE_UNTIL_COND,
ER(ER_BAD_SLAVE_UNTIL_COND), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
@@ -5404,7 +5840,7 @@ check:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
@@ -5471,12 +5907,12 @@ rename_list:
user TO_SYM user
{
if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
| rename_list ',' user TO_SYM user
{
if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -5493,18 +5929,18 @@ table_to_table:
TL_IGNORE) ||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
TL_IGNORE))
- YYABORT;
+ MYSQL_YYABORT;
};
db_to_db:
ident TO_SYM ident
{
LEX *lex=Lex;
- if (Lex->db_list.push_back((LEX_STRING*)
+ if (lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$1, sizeof(LEX_STRING))) ||
- Lex->db_list.push_back((LEX_STRING*)
+ lex->db_list.push_back((LEX_STRING*)
sql_memdup(&$3, sizeof(LEX_STRING))))
- YYABORT;
+ MYSQL_YYABORT;
};
keycache:
@@ -5523,13 +5959,9 @@ keycache_list:
assign_to_keycache:
table_ident cache_keys_spec
{
- LEX *lex=Lex;
- SELECT_LEX *sel= &lex->select_lex;
- if (!sel->add_table_to_list(lex->thd, $1, NULL, 0,
- TL_READ,
- sel->get_use_index(),
- (List<String> *)0))
- YYABORT;
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ Select->pop_index_hints()))
+ MYSQL_YYABORT;
}
;
@@ -5555,33 +5987,26 @@ preload_list:
preload_keys:
table_ident cache_keys_spec opt_ignore_leaves
{
- LEX *lex=Lex;
- SELECT_LEX *sel= &lex->select_lex;
- if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
- TL_READ,
- sel->get_use_index(),
- (List<String> *)0))
- YYABORT;
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
+ Select->pop_index_hints()))
+ MYSQL_YYABORT;
}
;
cache_keys_spec:
- { Select->interval_list.empty(); }
- cache_key_list_or_empty
{
- LEX *lex=Lex;
- SELECT_LEX *sel= &lex->select_lex;
- sel->use_index= sel->interval_list;
+ Lex->select_lex.alloc_index_hints(YYTHD);
+ Select->set_index_hint_type(INDEX_HINT_USE,
+ global_system_variables.old_mode ?
+ INDEX_HINT_MASK_JOIN :
+ INDEX_HINT_MASK_ALL);
}
+ cache_key_list_or_empty
;
cache_key_list_or_empty:
- /* empty */ { Lex->select_lex.use_index_ptr= 0; }
- | opt_key_or_index '(' key_usage_list2 ')'
- {
- SELECT_LEX *sel= &Lex->select_lex;
- sel->use_index_ptr= &sel->use_index;
- }
+ /* empty */ { }
+ | key_or_index '(' opt_key_usage_list ')'
;
opt_ignore_leaves:
@@ -5616,16 +6041,16 @@ select_paren:
SELECT_LEX * sel= lex->current_select;
if (sel->set_braces(1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (sel->linkage == UNION_TYPE &&
!sel->master_unit()->first_select()->braces &&
sel->master_unit()->first_select()->linkage ==
UNION_TYPE)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* select in braces, can't contain global parameters */
if (sel->master_unit()->fake_select_lex)
@@ -5641,14 +6066,14 @@ select_init2:
SELECT_LEX * sel= lex->current_select;
if (lex->current_select->set_braces(0))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (sel->linkage == UNION_TYPE &&
sel->master_unit()->first_select()->braces)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
union_clause
@@ -5678,6 +6103,11 @@ select_into:
select_from:
FROM join_table_list where_clause group_clause having_clause
opt_order_clause opt_limit_clause procedure_clause
+ {
+ Select->context.table_list=
+ Select->context.first_name_resolution_table=
+ (TABLE_LIST *) Select->table_list.first;
+ }
| FROM DUAL_SYM where_clause opt_limit_clause
/* oracle compatibility: oracle always requires FROM clause,
and DUAL is system table without fields.
@@ -5692,7 +6122,7 @@ select_options:
if (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL)
{
my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT");
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -5706,7 +6136,7 @@ select_option:
| HIGH_PRIORITY
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Lex->lock_option= TL_READ_HIGH_PRIORITY;
}
| DISTINCT { Select->options|= SELECT_DISTINCT; }
@@ -5715,13 +6145,13 @@ select_option:
| SQL_BUFFER_RESULT
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Select->options|= OPTION_BUFFER_RESULT;
}
| SQL_CALC_FOUND_ROWS
{
if (check_simple_select())
- YYABORT;
+ MYSQL_YYABORT;
Select->options|= OPTION_FOUND_ROWS;
}
| SQL_NO_CACHE_SYM
@@ -5770,7 +6200,7 @@ select_item_list:
new Item_field(&thd->lex->current_select->
context,
NULL, NULL, "*")))
- YYABORT;
+ MYSQL_YYABORT;
(thd->lex->current_select->with_wild)++;
};
@@ -5778,26 +6208,36 @@ select_item_list:
select_item:
remember_name select_item2 remember_end select_alias
{
- if (add_item_to_list(YYTHD, $2))
- YYABORT;
+ THD *thd= YYTHD;
+ DBUG_ASSERT($1 < $3);
+
+ if (add_item_to_list(thd, $2))
+ MYSQL_YYABORT;
if ($4.str)
{
$2->is_autogenerated_name= FALSE;
$2->set_name($4.str, $4.length, system_charset_info);
}
- else if (!$2->name) {
- char *str = $1;
- if (str[-1] == '`')
- str--;
- $2->set_name(str,(uint) ($3 - str), YYTHD->charset());
+ else if (!$2->name)
+ {
+ $2->set_name($1, (uint) ($3 - $1), thd->charset());
}
};
+
remember_name:
- { $$=(char*) Lex->tok_start; };
+ {
+ THD *thd= YYTHD;
+ Lex_input_stream *lip= thd->m_lip;
+ $$= (char*) lip->tok_start;
+ };
remember_end:
- { $$=(char*) Lex->tok_end; };
+ {
+ THD *thd= YYTHD;
+ Lex_input_stream *lip= thd->m_lip;
+ $$=(char*) lip->tok_end;
+ };
select_item2:
table_wild { $$=$1; } /* table.* */
@@ -5870,13 +6310,18 @@ bool_factor:
| bool_test ;
bool_test:
- bool_pri IS TRUE_SYM { $$= is_truth_value(YYTHD, $1,1,0); }
- | bool_pri IS not TRUE_SYM { $$= is_truth_value(YYTHD, $1,0,0); }
- | bool_pri IS FALSE_SYM { $$= is_truth_value(YYTHD, $1,0,1); }
- | bool_pri IS not FALSE_SYM { $$= is_truth_value(YYTHD, $1,1,1); }
+ bool_pri IS TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_istrue($1); }
+ | bool_pri IS not TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnottrue($1); }
+ | bool_pri IS FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isfalse($1); }
+ | bool_pri IS not FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); }
| bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
| bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
- | bool_pri ;
+ | bool_pri
+ ;
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
@@ -5890,28 +6335,34 @@ bool_pri:
predicate:
bit_expr IN_SYM '(' subselect ')'
- { $$= new Item_in_subselect($1, $4); }
+ {
+ $$= new (YYTHD->mem_root) Item_in_subselect($1, $4);
+ }
| bit_expr not IN_SYM '(' subselect ')'
- { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
+ {
+ THD *thd= YYTHD;
+ Item *item= new (thd->mem_root) Item_in_subselect($1, $5);
+ $$= negate_expression(thd, item);
+ }
| bit_expr IN_SYM '(' expr ')'
{
- $$= new Item_func_eq($1, $4);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4);
}
| bit_expr IN_SYM '(' expr ',' expr_list ')'
{
$6->push_front($4);
$6->push_front($1);
- $$= new Item_func_in(*$6);
+ $$= new (YYTHD->mem_root) Item_func_in(*$6);
}
| bit_expr not IN_SYM '(' expr ')'
{
- $$= new Item_func_ne($1, $5);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5);
}
| bit_expr not IN_SYM '(' expr ',' expr_list ')'
{
$7->push_front($5);
$7->push_front($1);
- Item_func_in *item = new Item_func_in(*$7);
+ Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7);
item->negate();
$$= item;
}
@@ -6048,29 +6499,25 @@ simple_expr:
}
| BINARY simple_expr %prec NEG
{
- $$= create_func_cast(YYTHD, $2, ITEM_CAST_CHAR, -1, 0,
+ $$= create_func_cast(YYTHD, $2, ITEM_CAST_CHAR, NULL, NULL,
&my_charset_bin);
}
| CAST_SYM '(' expr AS cast_type ')'
{
LEX *lex= Lex;
- $$= create_func_cast(YYTHD, $3, $5,
- lex->length ? atoi(lex->length) : -1,
- lex->dec ? atoi(lex->dec) : 0,
+ $$= create_func_cast(YYTHD, $3, $5, lex->length, lex->dec,
lex->charset);
if (!$$)
- YYABORT;
+ MYSQL_YYABORT;
}
- | CASE_SYM opt_expr WHEN_SYM when_list opt_else END
- { $$= new (YYTHD->mem_root) Item_func_case(* $4, $2, $5 ); }
+ | CASE_SYM opt_expr when_list opt_else END
+ { $$= new (YYTHD->mem_root) Item_func_case(* $3, $2, $4 ); }
| CONVERT_SYM '(' expr ',' cast_type ')'
{
- $$= create_func_cast(YYTHD, $3, $5,
- Lex->length ? atoi(Lex->length) : -1,
- Lex->dec ? atoi(Lex->dec) : 0,
- Lex->charset);
+ $$= create_func_cast(YYTHD, $3, $5, Lex->length, Lex->dec,
+ Lex->charset);
if (!$$)
- YYABORT;
+ MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
{ $$= new (YYTHD->mem_root) Item_func_conv_charset($3,$5); }
@@ -6081,7 +6528,7 @@ simple_expr:
Item_splocal *il= static_cast<Item_splocal *>($3);
my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= new (YYTHD->mem_root) Item_default_value(Lex->current_context(),
$3);
@@ -6096,15 +6543,11 @@ simple_expr:
{
if ($1->type() != Item::ROW_ITEM)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
$$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1);
}
- | UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
- {
- $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
- }
;
/*
@@ -6280,7 +6723,7 @@ function_call_nonkeyword:
;
/*
- Functions calls using a non reserved keywork, and using a regular syntax.
+ Functions calls using a non reserved keyword, and using a regular syntax.
Because the non reserved keyword is used in another part of the grammar,
a dedicated rule is needed here.
*/
@@ -6342,7 +6785,7 @@ function_call_conflict:
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
- YYABORT;
+ MYSQL_YYABORT;
#endif
}
;
@@ -6421,8 +6864,8 @@ function_call_generic:
{
if (lex->current_select->inc_in_sum_expr())
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
/* Temporary placing the result of find_udf in $3 */
@@ -6432,7 +6875,6 @@ function_call_generic:
udf_expr_list ')'
{
THD *thd= YYTHD;
- LEX *lex= Lex;
Create_func *builder;
Item *item= NULL;
@@ -6455,7 +6897,6 @@ function_call_generic:
#ifdef HAVE_DLOPEN
/* Retrieving the result of find_udf */
udf_func *udf= $<udf>3;
- LEX *lex= Lex;
if (udf)
{
@@ -6477,7 +6918,7 @@ function_call_generic:
if (! ($$= item))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
| ident '.' ident '(' opt_expr_list ')'
@@ -6495,18 +6936,18 @@ function_call_generic:
parser and the implementation in item_create.cc clean,
since this will change with WL#2128 (SQL PATH):
- INFORMATION_SCHEMA.version() is the SQL 99 syntax for the native
- funtion version(),
+ function version(),
- MySQL.version() is the SQL 2003 syntax for the native function
version() (a vendor can specify any schema).
*/
builder= find_qualified_function_builder(thd);
DBUG_ASSERT(builder);
- item= builder->create(thd, $1, $3, $5);
+ item= builder->create(thd, $1, $3, true, $5);
if (! ($$= item))
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -6591,13 +7032,11 @@ sum_expr:
{ Select->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 ')'
{ $$=new Item_sum_min($3); }
/*
According to ANSI SQL, DISTINCT is allowed and has
- no sence inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
+ no sense inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
is processed like an ordinary MIN | MAX()
*/
| MIN_SYM '(' DISTINCT in_sum_expr ')'
@@ -6637,7 +7076,7 @@ variable:
if (! Lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
variable_aux
@@ -6663,11 +7102,11 @@ variable_aux:
{
if ($3.str && $4.str && check_reserved_words(&$3))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (!($$= get_system_var(YYTHD, $2, $3, $4)))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -6701,8 +7140,8 @@ in_sum_expr:
LEX *lex= Lex;
if (lex->current_select->inc_in_sum_expr())
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
expr
@@ -6761,23 +7200,19 @@ opt_else:
| ELSE expr { $$= $2; };
when_list:
- { Select->when_list.push_front(new List<Item>); }
- when_list2
- { $$= Select->when_list.pop(); };
-
-when_list2:
- expr THEN_SYM expr
- {
- SELECT_LEX *sel=Select;
- sel->when_list.head()->push_back($1);
- sel->when_list.head()->push_back($3);
- }
- | when_list2 WHEN_SYM expr THEN_SYM expr
- {
- SELECT_LEX *sel=Select;
- sel->when_list.head()->push_back($3);
- sel->when_list.head()->push_back($5);
- };
+ WHEN_SYM expr THEN_SYM expr
+ {
+ $$= new List<Item>;
+ $$->push_back($2);
+ $$->push_back($4);
+ }
+ | when_list WHEN_SYM expr THEN_SYM expr
+ {
+ $1->push_back($3);
+ $1->push_back($5);
+ $$= $1;
+ }
+ ;
/* Warning - may return NULL in case of incomplete SELECT */
table_ref:
@@ -6786,12 +7221,12 @@ table_ref:
{
LEX *lex= Lex;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
- YYABORT;
+ MYSQL_YYABORT;
}
;
join_table_list:
- derived_table_list { YYERROR_UNLESS($$=$1); }
+ derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); }
;
/* Warning - may return NULL in case of incomplete SELECT */
@@ -6799,7 +7234,7 @@ derived_table_list:
table_ref { $$=$1; }
| derived_table_list ',' table_ref
{
- YYERROR_UNLESS($1 && ($$=$3));
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
}
;
@@ -6818,16 +7253,16 @@ join_table:
left-associative joins.
*/
table_ref %prec TABLE_REF_PRIORITY normal_join table_ref
- { YYERROR_UNLESS($1 && ($$=$3)); }
+ { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); }
| table_ref STRAIGHT_JOIN table_factor
- { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
+ { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; }
| table_ref normal_join table_ref
ON
{
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -6839,10 +7274,10 @@ join_table:
| table_ref STRAIGHT_JOIN table_factor
ON
{
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $3))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -6855,25 +7290,24 @@ join_table:
| table_ref normal_join table_ref
USING
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $3);
+ MYSQL_YYABORT_UNLESS($1 && $3);
}
'(' using_list ')'
- { add_join_natural($1,$3,$7); $$=$3; }
+ { add_join_natural($1,$3,$7,Select); $$=$3; }
| table_ref NATURAL JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && ($$=$4));
- add_join_natural($1,$4,NULL);
+ MYSQL_YYABORT_UNLESS($1 && ($$=$4));
+ add_join_natural($1,$4,NULL,Select);
}
/* LEFT JOIN variants */
| table_ref LEFT opt_outer JOIN_SYM table_ref
ON
{
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
@@ -6886,15 +7320,18 @@ join_table:
}
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
}
USING '(' using_list ')'
- { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
+ {
+ add_join_natural($1,$5,$9,Select);
+ $5->outer_join|=JOIN_TYPE_LEFT;
+ $$=$5;
+ }
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && $6);
- add_join_natural($1,$6,NULL);
+ MYSQL_YYABORT_UNLESS($1 && $6);
+ add_join_natural($1,$6,NULL,Select);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
@@ -6903,40 +7340,39 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_ref
ON
{
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $1, $5))
- YYABORT;
+ MYSQL_YYABORT;
Select->parsing_place= IN_ON;
}
expr
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
+ MYSQL_YYABORT;
add_join_on($$, $8);
Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
- SELECT_LEX *sel= Select;
- YYERROR_UNLESS($1 && $5);
+ MYSQL_YYABORT_UNLESS($1 && $5);
}
USING '(' using_list ')'
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
- add_join_natural($$,$5,$9);
+ MYSQL_YYABORT;
+ add_join_natural($$,$5,$9,Select);
}
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
- YYERROR_UNLESS($1 && $6);
- add_join_natural($6,$1,NULL);
+ MYSQL_YYABORT_UNLESS($1 && $6);
+ add_join_natural($6,$1,NULL,Select);
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
- YYABORT;
+ MYSQL_YYABORT;
};
normal_join:
@@ -6949,39 +7385,35 @@ normal_join:
table_factor:
{
SELECT_LEX *sel= Select;
- sel->use_index_ptr=sel->ignore_index_ptr=0;
sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
- LEX *lex= Lex;
- SELECT_LEX *sel= lex->current_select;
- if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
- sel->get_table_join_options(),
- lex->lock_option,
- sel->get_use_index(),
- sel->get_ignore_index())))
- YYABORT;
- sel->add_joined_table($$);
+ if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
+ Select->get_table_join_options(),
+ Lex->lock_option,
+ Select->pop_index_hints())))
+ MYSQL_YYABORT;
+ Select->add_joined_table($$);
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
ON
{
/* Change the current name resolution context to a local context. */
if (push_new_name_resolution_context(YYTHD, $3, $7))
- YYABORT;
+ MYSQL_YYABORT;
}
expr '}'
{
LEX *lex= Lex;
- YYERROR_UNLESS($3 && $7);
+ MYSQL_YYABORT_UNLESS($3 && $7);
add_join_on($7,$10);
Lex->pop_context();
$7->outer_join|=JOIN_TYPE_LEFT;
$$=$7;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
- YYABORT;
+ MYSQL_YYABORT;
}
| select_derived_init get_select_lex select_derived2
{
@@ -6991,8 +7423,8 @@ table_factor:
{
if (sel->set_braces(1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* select in braces, can't contain global parameters */
if (sel->master_unit()->fake_select_lex)
@@ -7000,7 +7432,7 @@ table_factor:
sel->master_unit()->fake_select_lex;
}
if ($2->init_nested_join(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
$$= 0;
/* incomplete derived tables return NULL, we must be
nested in select_derived rule to be here. */
@@ -7031,10 +7463,9 @@ table_factor:
lex->current_select= sel= unit->outer_select();
if (!($$= sel->
add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
- TL_READ,(List<String> *)0,
- (List<String> *)0)))
+ TL_READ)))
- YYABORT;
+ MYSQL_YYABORT;
sel->add_joined_table($$);
lex->pop_context();
}
@@ -7042,8 +7473,8 @@ table_factor:
if ($4 || $6)
{
/* simple nested joins cannot have aliases or unions */
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
else
$$= $3;
@@ -7056,7 +7487,7 @@ select_derived:
{
LEX *lex= Lex;
if ($1->init_nested_join(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
}
derived_table_list
{
@@ -7065,11 +7496,11 @@ select_derived:
for derived tables, both must equal NULL */
if (!($$= $1->end_nested_join(lex->thd)) && $3)
- YYABORT;
+ MYSQL_YYABORT;
if (!$3 && $$)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
}
;
@@ -7080,12 +7511,12 @@ select_derived2:
lex->derived_tables|= DERIVED_SUBQUERY;
if (!lex->expr_allows_subselect)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
mysql_new_select(lex, 1))
- YYABORT;
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->linkage= DERIVED_TABLE_TYPE;
lex->current_select->parsing_place= SELECT_LIST;
@@ -7109,7 +7540,7 @@ select_derived_init:
if (! lex->parsing_options.allows_derived)
{
my_error(ER_VIEW_SELECT_DERIVED, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
SELECT_LEX *sel= lex->current_select;
@@ -7117,8 +7548,8 @@ select_derived_init:
if (!sel->embedding || sel->end_nested_join(lex->thd))
{
/* we are not in parentheses */
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
embedding= Select->embedding;
$$= embedding &&
@@ -7131,58 +7562,73 @@ opt_outer:
/* empty */ {}
| OUTER {};
-opt_key_definition:
- /* empty */ {}
- | USE_SYM key_usage_list
+index_hint_clause:
+ /* empty */
{
- SELECT_LEX *sel= Select;
- sel->use_index= *$2;
- sel->use_index_ptr= &sel->use_index;
+ $$= global_system_variables.old_mode ?
+ INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
}
- | FORCE_SYM key_usage_list
+ | FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
+ | FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
+ | FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; }
+ ;
+
+index_hint_type:
+ FORCE_SYM { $$= INDEX_HINT_FORCE; }
+ | IGNORE_SYM { $$= INDEX_HINT_IGNORE; }
+ ;
+
+index_hint_definition:
+ index_hint_type key_or_index index_hint_clause
{
- SELECT_LEX *sel= Select;
- sel->use_index= *$2;
- sel->use_index_ptr= &sel->use_index;
- sel->table_join_options|= TL_OPTION_FORCE_INDEX;
+ Select->set_index_hint_type($1, $3);
}
- | IGNORE_SYM key_usage_list
+ '(' key_usage_list ')'
+ | USE_SYM key_or_index index_hint_clause
{
- SELECT_LEX *sel= Select;
- sel->ignore_index= *$2;
- sel->ignore_index_ptr= &sel->ignore_index;
- };
+ Select->set_index_hint_type(INDEX_HINT_USE, $3);
+ }
+ '(' opt_key_usage_list ')'
+ ;
-key_usage_list:
- key_or_index { Select->interval_list.empty(); }
- '(' key_list_or_empty ')'
- { $$= &Select->interval_list; }
+index_hints_list:
+ index_hint_definition
+ | index_hints_list index_hint_definition
;
-key_list_or_empty:
- /* empty */ {}
- | key_usage_list2 {}
+opt_index_hints_list:
+ /* empty */
+ | { Select->alloc_index_hints(YYTHD); } index_hints_list
;
-key_usage_list2:
- key_usage_list2 ',' ident
- { Select->
- interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
- system_charset_info)); }
- | ident
- { Select->
- interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
- system_charset_info)); }
+opt_key_definition:
+ { Select->clear_index_hints(); }
+ opt_index_hints_list
+ ;
+
+opt_key_usage_list:
+ /* empty */ { Select->add_index_hint(YYTHD, NULL, 0); }
+ | key_usage_list {}
+ ;
+
+key_usage_element:
+ ident { Select->add_index_hint(YYTHD, $1.str, $1.length); }
| PRIMARY_SYM
- { Select->
- interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
- system_charset_info)); };
+ {
+ Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7);
+ }
+ ;
+
+key_usage_list:
+ key_usage_element
+ | key_usage_list ',' key_usage_element
+ ;
using_list:
ident
{
if (!($$= new List<String>))
- YYABORT;
+ MYSQL_YYABORT;
$$->push_back(new (YYTHD->mem_root)
String((const char *) $1.str, $1.length,
system_charset_info));
@@ -7298,13 +7744,13 @@ opt_escape:
group_clause:
/* empty */
- | GROUP BY group_list olap_opt;
+ | GROUP_SYM BY group_list olap_opt;
group_list:
group_list ',' order_ident order_dir
- { if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
+ { if (add_group_to_list(YYTHD, $3,(bool) $4)) MYSQL_YYABORT; }
| order_ident order_dir
- { if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
+ { if (add_group_to_list(YYTHD, $1,(bool) $2)) MYSQL_YYABORT; };
olap_opt:
/* empty */ {}
@@ -7315,11 +7761,11 @@ olap_opt:
{
my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE",
"global union parameters");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->current_select->olap= CUBE_TYPE;
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE");
- YYABORT; /* To be deleted in 5.1 */
+ MYSQL_YYABORT; /* To be deleted in 5.1 */
}
| WITH ROLLUP_SYM
{
@@ -7328,13 +7774,36 @@ olap_opt:
{
my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
"global union parameters");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->current_select->olap= ROLLUP_TYPE;
}
;
/*
+ Order by statement in ALTER TABLE
+*/
+
+alter_order_clause:
+ ORDER_SYM BY alter_order_list
+ ;
+
+alter_order_list:
+ alter_order_list ',' alter_order_item
+ | alter_order_item
+ ;
+
+alter_order_item:
+ simple_ident_nospvar order_dir
+ {
+ THD *thd= YYTHD;
+ bool ascending= ($2 == 1) ? true : false;
+ if (add_order_to_list(thd, $1, ascending))
+ MYSQL_YYABORT;
+ }
+ ;
+
+/*
Order by statement in select
*/
@@ -7353,7 +7822,7 @@ order_clause:
{
my_error(ER_WRONG_USAGE, MYF(0),
"CUBE/ROLLUP", "ORDER BY");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex)
{
@@ -7366,19 +7835,19 @@ order_clause:
yet.
*/
SELECT_LEX *first_sl= unit->first_select();
- if (!first_sl->next_select() &&
+ if (!unit->is_union() &&
(first_sl->order_list.elements ||
first_sl->select_limit) &&
unit->add_fake_select_lex(lex->thd))
- YYABORT;
+ MYSQL_YYABORT;
}
} order_list;
order_list:
order_list ',' order_ident order_dir
- { if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
+ { if (add_order_to_list(YYTHD, $3,(bool) $4)) MYSQL_YYABORT; }
| order_ident order_dir
- { if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
+ { if (add_order_to_list(YYTHD, $1,(bool) $2)) MYSQL_YYABORT; };
order_dir:
/* empty */ { $$ = 1; }
@@ -7463,7 +7932,7 @@ real_ulong_num:
| HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
| LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { YYABORT; }
+ | dec_num_error { MYSQL_YYABORT; }
;
ulonglong_num:
@@ -7478,12 +7947,12 @@ real_ulonglong_num:
NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | dec_num_error { YYABORT; }
+ | dec_num_error { MYSQL_YYABORT; }
;
dec_num_error:
dec_num
- { yyerror(ER(ER_ONLY_INTEGERS_ALLOWED)); }
+ { my_parse_error(ER(ER_ONLY_INTEGERS_ALLOWED)); }
;
dec_num:
@@ -7500,22 +7969,22 @@ procedure_clause:
if (! lex->parsing_options.allows_select_procedure)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
if (&lex->select_lex != lex->current_select)
{
my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->proc_list.elements=0;
lex->proc_list.first=0;
- lex->proc_list.next= (byte**) &lex->proc_list.first;
+ lex->proc_list.next= (uchar**) &lex->proc_list.first;
if (add_proc_to_list(lex->thd, new Item_field(&lex->
current_select->
context,
NULL,NULL,$2.str)))
- YYABORT;
+ MYSQL_YYABORT;
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
}
'(' procedure_list ')';
@@ -7532,12 +8001,14 @@ procedure_list2:
procedure_item:
remember_name expr
{
- LEX *lex= Lex;
- if (add_proc_to_list(lex->thd, $2))
- YYABORT;
+ THD *thd= YYTHD;
+ Lex_input_stream *lip= thd->m_lip;
+
+ if (add_proc_to_list(thd, $2))
+ MYSQL_YYABORT;
if (!$2->name)
- $2->set_name($1,(uint) ((char*) lex->tok_end - $1),
- YYTHD->charset());
+ $2->set_name($1,(uint) ((char*) lip->tok_end - $1),
+ thd->charset());
}
;
@@ -7546,7 +8017,7 @@ select_var_list_init:
{
LEX *lex=Lex;
if (!lex->describe && (!(lex->result= new select_dumpvar())))
- YYABORT;
+ MYSQL_YYABORT;
}
select_var_list
{}
@@ -7578,7 +8049,7 @@ select_var_ident:
if (!lex->spcont || !(t=lex->spcont->find_variable(&$1)))
{
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->result)
{
@@ -7607,7 +8078,7 @@ into:
if (! Lex->parsing_options.allows_select_into)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO");
- YYABORT;
+ MYSQL_YYABORT;
}
}
into_destination
@@ -7620,7 +8091,7 @@ into_destination:
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
!(lex->result= new select_export(lex->exchange)))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_field_term opt_line_term
| DUMPFILE TEXT_STRING_filesystem
@@ -7630,9 +8101,9 @@ into_destination:
{
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($2.str,1)))
- YYABORT;
+ MYSQL_YYABORT;
if (!(lex->result= new select_dump(lex->exchange)))
- YYABORT;
+ MYSQL_YYABORT;
}
}
| select_var_list_init
@@ -7673,12 +8144,13 @@ drop:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_INDEX;
- lex->alter_info.drop_list.empty();
+ lex->alter_info.reset();
+ lex->alter_info.flags= ALTER_DROP_INDEX;
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
| DROP DATABASE if_exists ident
{
@@ -7693,7 +8165,7 @@ drop:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3;
@@ -7705,7 +8177,7 @@ drop:
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_DROP_PROCEDURE;
lex->drop_if_exists= $3;
@@ -7739,11 +8211,18 @@ drop:
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
}
- | DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait
+ | DROP LOGFILE_SYM GROUP_SYM logfile_group_name opt_ts_engine opt_ts_wait
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
}
+ | DROP SERVER_SYM if_exists ident_or_text
+ {
+ Lex->sql_command = SQLCOM_DROP_SERVER;
+ Lex->drop_if_exists= $3;
+ Lex->server_options.server_name= $4.str;
+ Lex->server_options.server_name_length= $4.length;
+ }
;
table_list:
@@ -7754,7 +8233,7 @@ table_name:
table_ident
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -7816,7 +8295,7 @@ insert_lock_option:
insert visible only after the table unlocking but everyone can
read table.
*/
- $$= (Lex->sphead ? TL_WRITE :TL_WRITE_CONCURRENT_INSERT);
+ $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
#else
$$= TL_WRITE_CONCURRENT_INSERT;
#endif
@@ -7852,7 +8331,7 @@ insert_field_spec:
LEX *lex=Lex;
if (!(lex->insert_list = new List_item) ||
lex->many_values.push_back(lex->insert_list))
- YYABORT;
+ MYSQL_YYABORT;
}
ident_eq_list;
@@ -7882,7 +8361,7 @@ ident_eq_value:
LEX *lex=Lex;
if (lex->field_list.push_back($1) ||
lex->insert_list->push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
};
equal: EQ {}
@@ -7898,13 +8377,13 @@ no_braces:
'('
{
if (!(Lex->insert_list = new List_item))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_values ')'
{
LEX *lex=Lex;
if (lex->many_values.push_back(lex->insert_list))
- YYABORT;
+ MYSQL_YYABORT;
};
opt_values:
@@ -7915,12 +8394,12 @@ values:
values ',' expr_or_default
{
if (Lex->insert_list->push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
| expr_or_default
{
if (Lex->insert_list->push_back($1))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -7957,7 +8436,7 @@ update:
/* it is single table update and it is update of derived table */
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
lex->select_lex.get_table_list()->alias, "UPDATE");
- YYABORT;
+ MYSQL_YYABORT;
}
/*
In case of multi-update setting write lock for all tables may
@@ -7977,7 +8456,7 @@ update_elem:
simple_ident_nospvar equal expr_or_default
{
if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
- YYABORT;
+ MYSQL_YYABORT;
};
insert_update_list:
@@ -7990,11 +8469,11 @@ insert_update_elem:
LEX *lex= Lex;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
};
opt_low_priority:
- /* empty */ { $$= YYTHD->update_lock_default; }
+ /* empty */ { $$= TL_WRITE_DEFAULT; }
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
/* Delete rows from a table */
@@ -8005,7 +8484,7 @@ delete:
LEX *lex= Lex;
lex->sql_command= SQLCOM_DELETE;
mysql_init_select(lex);
- lex->lock_option= lex->thd->update_lock_default;
+ lex->lock_option= TL_WRITE_DEFAULT;
lex->ignore= 0;
lex->select_lex.init_order();
}
@@ -8017,7 +8496,7 @@ single_multi:
{
if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
where_clause opt_order_clause
delete_limit_clause {}
@@ -8026,14 +8505,14 @@ single_multi:
FROM join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
- YYABORT;
+ MYSQL_YYABORT;
}
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
USING join_table_list where_clause
{
if (multi_delete_set_locks_and_link_aux_tables(Lex))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8047,7 +8526,7 @@ table_wild_one:
if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
TL_OPTION_UPDATING |
TL_OPTION_ALIAS, Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
| ident '.' ident opt_wild opt_table_alias
{
@@ -8057,7 +8536,7 @@ table_wild_one:
TL_OPTION_UPDATING |
TL_OPTION_ALIAS,
Lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -8111,7 +8590,7 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_DATABASES;
if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full TABLES opt_db wild_and_where
{
@@ -8119,7 +8598,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TABLES;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full TRIGGERS_SYM opt_db wild_and_where
{
@@ -8127,7 +8606,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TRIGGERS;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
- YYABORT;
+ MYSQL_YYABORT;
}
| EVENTS_SYM opt_db wild_and_where
{
@@ -8135,7 +8614,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_EVENTS;
lex->select_lex.db= $2;
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
- YYABORT;
+ MYSQL_YYABORT;
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
@@ -8143,7 +8622,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| OPEN_SYM TABLES opt_db wild_and_where
{
@@ -8151,7 +8630,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| opt_full PLUGIN_SYM
{
@@ -8159,29 +8638,27 @@ show_param:
WARN_DEPRECATED(yythd, "5.2", "SHOW PLUGIN", "'SHOW PLUGINS'");
lex->sql_command= SQLCOM_SHOW_PLUGINS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
- YYABORT;
+ MYSQL_YYABORT;
}
| PLUGINS_SYM
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_PLUGINS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
- YYABORT;
+ MYSQL_YYABORT;
}
- | ENGINE_SYM storage_engines
+ | ENGINE_SYM known_storage_engines show_engine_param
{ Lex->create_info.db_type= $2; }
- show_engine_param
- | ENGINE_SYM ALL
+ | ENGINE_SYM ALL show_engine_param
{ Lex->create_info.db_type= NULL; }
- show_engine_param
| opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
{
- LEX *lex= Lex;
+ LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_FIELDS;
if ($5)
$4->change_db($5);
if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
- YYABORT;
+ MYSQL_YYABORT;
}
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
TEXT_STRING_sys AND_SYM MASTER_LOG_POS_SYM EQ ulonglong_num
@@ -8213,7 +8690,7 @@ show_param:
if ($4)
$3->change_db($4);
if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
- YYABORT;
+ MYSQL_YYABORT;
}
| COLUMN_SYM TYPES_SYM
{
@@ -8231,7 +8708,7 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
if (prepare_schema_table(YYTHD, lex, 0, SCH_ENGINES))
- YYABORT;
+ MYSQL_YYABORT;
}
| AUTHORS_SYM
{
@@ -8262,7 +8739,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_STATUS;
lex->option_type= $1;
if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
- YYABORT;
+ MYSQL_YYABORT;
}
| INNOBASE_SYM STATUS_SYM
{
@@ -8272,7 +8749,7 @@ show_param:
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- YYABORT;
+ MYSQL_YYABORT;
}
WARN_DEPRECATED(yythd, "5.2", "SHOW INNODB STATUS", "'SHOW ENGINE INNODB STATUS'");
}
@@ -8284,7 +8761,7 @@ show_param:
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
{
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
- YYABORT;
+ MYSQL_YYABORT;
}
WARN_DEPRECATED(yythd, "5.2", "SHOW MUTEX STATUS", "'SHOW ENGINE INNODB MUTEX'");
}
@@ -8296,21 +8773,21 @@ show_param:
lex->sql_command= SQLCOM_SHOW_VARIABLES;
lex->option_type= $1;
if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
- YYABORT;
+ MYSQL_YYABORT;
}
| charset wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_CHARSETS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
- YYABORT;
+ MYSQL_YYABORT;
}
| COLLATION_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_COLLATIONS;
if (prepare_schema_table(YYTHD, lex, 0, SCH_COLLATIONS))
- YYABORT;
+ MYSQL_YYABORT;
}
| GRANTS
{
@@ -8318,7 +8795,7 @@ show_param:
lex->sql_command= SQLCOM_SHOW_GRANTS;
LEX_USER *curr_user;
if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
bzero(curr_user, sizeof(st_lex_user));
lex->grant_user= curr_user;
}
@@ -8340,15 +8817,16 @@ show_param:
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL,0))
- YYABORT;
+ MYSQL_YYABORT;
lex->only_view= 0;
+ lex->create_info.storage_media= HA_SM_DEFAULT;
}
| CREATE VIEW_SYM table_ident
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0))
- YYABORT;
+ MYSQL_YYABORT;
lex->only_view= 1;
}
| MASTER_SYM STATUS_SYM
@@ -8378,24 +8856,24 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
- YYABORT;
+ MYSQL_YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
- YYABORT;
+ MYSQL_YYABORT;
}
| FUNCTION_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_STATUS_FUNC;
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
- YYABORT;
+ MYSQL_YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
- YYABORT;
+ MYSQL_YYABORT;
}
| PROCEDURE CODE_SYM sp_name
{
#ifdef DBUG_OFF
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
#else
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
Lex->spname= $3;
@@ -8404,8 +8882,8 @@ show_param:
| FUNCTION_SYM CODE_SYM sp_name
{
#ifdef DBUG_OFF
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
#else
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
Lex->spname= $3;
@@ -8480,7 +8958,7 @@ describe:
lex->select_lex.db= 0;
lex->verbose= 0;
if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_describe_column {}
| describe_command opt_extended_describe
@@ -8621,13 +9099,16 @@ use: USE_SYM ident
load: LOAD DATA_SYM
{
- LEX *lex=Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
- YYABORT;
+ MYSQL_YYABORT;
}
- lex->fname_start= lex->ptr;
+ lex->fname_start= lip->ptr;
}
load_data
{}
@@ -8640,11 +9121,11 @@ load: LOAD DATA_SYM
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD TABLE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
};
load_data:
@@ -8657,23 +9138,27 @@ load_data:
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
if (!(lex->exchange= new sql_exchange($4.str, 0)))
- YYABORT;
+ MYSQL_YYABORT;
}
opt_duplicate INTO
{
- LEX *lex=Lex;
- lex->fname_end= lex->ptr;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+ lex->fname_end= lip->ptr;
}
TABLE_SYM table_ident
{
LEX *lex=Lex;
if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING,
lex->lock_option))
- YYABORT;
+ MYSQL_YYABORT;
lex->field_list.empty();
lex->update_list.empty();
lex->value_list.empty();
}
+ opt_load_data_charset
+ { Lex->exchange->cs= $12; }
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
{}
@@ -8691,7 +9176,7 @@ opt_local:
| LOCAL_SYM { $$=1;};
load_data_lock:
- /* empty */ { $$= YYTHD->update_lock_default; }
+ /* empty */ { $$= TL_WRITE_DEFAULT; }
| CONCURRENT
{
#ifdef HAVE_QUERY_CACHE
@@ -8699,7 +9184,7 @@ load_data_lock:
Ignore this option in SP to avoid problem with query cache
*/
if (Lex->sphead != 0)
- $$= YYTHD->update_lock_default;
+ $$= TL_WRITE_DEFAULT;
else
#endif
$$= TL_WRITE_CONCURRENT_INSERT;
@@ -8840,19 +9325,20 @@ text_string:
param_marker:
PARAM_MARKER
{
- THD *thd=YYTHD;
- LEX *lex= thd->lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
Item_param *item;
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
- item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query));
+ item= new Item_param((uint) (lip->tok_start - thd->query));
if (!($$= item) || lex->param_list.push_back(item))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -8871,8 +9357,11 @@ signed_literal:
literal:
text_literal { $$ = $1; }
| NUM_literal { $$ = $1; }
- | NULL_SYM { $$ = new Item_null();
- Lex->next_state=MY_LEX_OPERATOR_OR_IDENT;}
+ | NULL_SYM
+ {
+ $$ = new Item_null();
+ YYTHD->m_lip->next_state=MY_LEX_OPERATOR_OR_IDENT;
+ }
| FALSE_SYM { $$= new Item_int((char*) "FALSE",0,1); }
| TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); }
| HEX_NUM { $$ = new Item_hex_string($1.str, $1.length);}
@@ -8918,7 +9407,7 @@ NUM_literal:
$$= new Item_decimal($1.str, $1.length, YYTHD->charset());
if (YYTHD->net.report_error)
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
| FLOAT_NUM
@@ -8926,7 +9415,7 @@ NUM_literal:
$$ = new Item_float($1.str, $1.length);
if (YYTHD->net.report_error)
{
- YYABORT;
+ MYSQL_YYABORT;
}
}
;
@@ -8962,8 +9451,10 @@ order_ident:
simple_ident:
ident
{
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
sp_variable_t *spv;
- LEX *lex = Lex;
sp_pcontext *spc = lex->spcont;
if (spc && (spv = spc->find_variable(&$1)))
{
@@ -8971,12 +9462,12 @@ simple_ident:
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
Item_splocal *splocal;
splocal= new Item_splocal($1, spv->offset, spv->type,
- lex->tok_start_prev -
+ lip->tok_start_prev -
lex->sphead->m_tmp_query);
#ifndef DBUG_OFF
if (splocal)
@@ -9031,14 +9522,14 @@ simple_ident_q:
!new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
new_row)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
- YYABORT;
+ MYSQL_YYABORT;
}
DBUG_ASSERT(!new_row ||
@@ -9053,14 +9544,15 @@ simple_ident_q:
$3.str,
SELECT_ACL,
read_only)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
*/
- lex->trg_table_fields.link_in_list((byte *)trg_fld,
- (byte**)&trg_fld->next_trg_field);
+ lex->trg_table_fields.link_in_list((uchar*) trg_fld,
+ (uchar**) &trg_fld->
+ next_trg_field);
$$= (Item *)trg_fld;
}
@@ -9124,13 +9616,13 @@ field_ident:
if (my_strcasecmp(table_alias_charset, $1.str, table->db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (my_strcasecmp(table_alias_charset, $3.str,
table->table_name))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$=$5;
}
@@ -9140,7 +9632,7 @@ field_ident:
if (my_strcasecmp(table_alias_charset, $1.str, table->alias))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str);
- YYABORT;
+ MYSQL_YYABORT;
}
$$=$3;
}
@@ -9172,7 +9664,7 @@ IDENT_sys:
{
my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
cs->csname, $1.str + wlen);
- YYABORT;
+ MYSQL_YYABORT;
}
$$= $1;
}
@@ -9255,32 +9747,34 @@ user:
{
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
$$->user = $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
- if (check_string_length(&$$->user,
- ER(ER_USERNAME), USERNAME_LENGTH))
- YYABORT;
+ if (check_string_char_length(&$$->user, ER(ER_USERNAME),
+ USERNAME_CHAR_LENGTH,
+ system_charset_info, 0))
+ MYSQL_YYABORT;
}
| ident_or_text '@' ident_or_text
{
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
- if (check_string_length(&$$->user,
- ER(ER_USERNAME), USERNAME_LENGTH) ||
- check_string_length(&$$->host,
- ER(ER_HOSTNAME), HOSTNAME_LENGTH))
- YYABORT;
+ if (check_string_char_length(&$$->user, ER(ER_USERNAME),
+ USERNAME_CHAR_LENGTH,
+ system_charset_info, 0) ||
+ check_string_byte_length(&$$->host, ER(ER_HOSTNAME),
+ HOSTNAME_LENGTH))
+ MYSQL_YYABORT;
}
| CURRENT_USER optional_braces
{
if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
- YYABORT;
+ MYSQL_YYABORT;
/*
empty LEX_USER means current_user and
will be handled in the get_current_user() function
@@ -9310,12 +9804,16 @@ keyword:
| FLUSH_SYM {}
| HANDLER_SYM {}
| HELP_SYM {}
+ | HOST_SYM {}
| INSTALL_SYM {}
| LANGUAGE_SYM {}
| NO_SYM {}
| OPEN_SYM {}
+ | OPTIONS_SYM {}
+ | OWNER_SYM {}
| PARSER_SYM {}
| PARTITION_SYM {}
+ | PORT_SYM {}
| PREPARE_SYM {}
| REMOVE_SYM {}
| REPAIR {}
@@ -9324,7 +9822,9 @@ keyword:
| ROLLBACK_SYM {}
| SAVEPOINT_SYM {}
| SECURITY_SYM {}
+ | SERVER_SYM {}
| SIGNED_SYM {}
+ | SOCKET_SYM {}
| SLAVE {}
| SONAME_SYM {}
| START_SYM {}
@@ -9332,6 +9832,7 @@ keyword:
| TRUNCATE_SYM {}
| UNICODE_SYM {}
| UNINSTALL_SYM {}
+ | WRAPPER_SYM {}
| XA_SYM {}
| UPGRADE_SYM {}
;
@@ -9375,6 +9876,7 @@ keyword_sp:
| COMPLETION_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
+ | CONNECTION_SYM {}
| CONSISTENT_SYM {}
| CONTRIBUTORS_SYM {}
| CUBE_SYM {}
@@ -9616,7 +10118,11 @@ option_value_list:
option_type_value:
{
- if (Lex->sphead)
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+
+ if (lex->sphead)
{
/*
If we are in SP we want have own LEX for each assignment.
@@ -9628,9 +10134,8 @@ option_type_value:
QQ: May be we should simply prohibit group assignments in SP?
*/
- LEX *lex;
- Lex->sphead->reset_lex(YYTHD);
- lex= Lex;
+ lex->sphead->reset_lex(thd);
+ lex= thd->lex;
/* Set new LEX as if we at start of set rule. */
lex->sql_command= SQLCOM_SET_OPTION;
@@ -9638,12 +10143,14 @@ option_type_value:
lex->option_type=OPT_SESSION;
lex->var_list.empty();
lex->one_shot_set= 0;
- lex->sphead->m_tmp_query= lex->tok_start;
+ lex->sphead->m_tmp_query= lip->tok_start;
}
}
ext_option_value
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
if (lex->sphead)
{
@@ -9661,28 +10168,29 @@ option_type_value:
if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
lex)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Extract the query statement from the tokenizer. The
- end is either lex->ptr, if there was no lookahead,
- lex->tok_end otherwise.
+ end is either lip->ptr, if there was no lookahead,
+ lip->tok_end otherwise.
*/
if (yychar == YYEMPTY)
- qbuff.length= lex->ptr - sp->m_tmp_query;
+ qbuff.length= lip->ptr - sp->m_tmp_query;
else
- qbuff.length= lex->tok_end - sp->m_tmp_query;
+ qbuff.length= lip->tok_end - sp->m_tmp_query;
- if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
- YYABORT;
+ if (!(qbuff.str= (char*) alloc_root(thd->mem_root,
+ qbuff.length + 5)))
+ MYSQL_YYABORT;
- strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
+ strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query,
qbuff.length);
qbuff.length+= 4;
i->m_query= qbuff;
sp->add_instr(i);
}
- lex->sphead->restore_lex(YYTHD);
+ lex->sphead->restore_lex(thd);
}
};
@@ -9730,8 +10238,8 @@ sys_option_value:
LINT_INIT(sp_fld);
if ($1)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if ($4)
it= $4;
@@ -9753,14 +10261,15 @@ sys_option_value:
lex->spcont,
trg_fld,
it, lex)))
- YYABORT;
+ MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field
objects in trigger.
*/
- lex->trg_table_fields.link_in_list((byte *)trg_fld,
- (byte **)&trg_fld->next_trg_field);
+ lex->trg_table_fields.link_in_list((uchar *)trg_fld,
+ (uchar **) &trg_fld->
+ next_trg_field);
lex->sphead->add_instr(sp_fld);
}
@@ -9780,8 +10289,8 @@ sys_option_value:
Item *it;
if ($1)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
spv= ctx->find_variable(&$2.base_name);
@@ -9802,7 +10311,7 @@ sys_option_value:
LEX *lex=Lex;
lex->option_type= $1;
lex->var_list.push_back(new set_var(lex->option_type,
- find_sys_var("tx_isolation"),
+ find_sys_var(YYTHD, "tx_isolation"),
&null_lex_str,
new Item_int((int32) $5)));
}
@@ -9821,7 +10330,7 @@ option_value:
| charset old_or_new_charset_name_or_default
{
THD *thd= YYTHD;
- LEX *lex= Lex;
+ LEX *lex= thd->lex;
$2= $2 ? $2: global_system_variables.character_set_client;
lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2));
}
@@ -9836,9 +10345,9 @@ option_value:
if (spc && spc->find_variable(&names))
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
else
- yyerror(ER(ER_SYNTAX_ERROR));
+ my_parse_error(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ MYSQL_YYABORT;
}
| NAMES_SYM charset_name_or_default opt_collate
{
@@ -9849,15 +10358,15 @@ option_value:
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
$3->name, $2->csname);
- YYABORT;
+ MYSQL_YYABORT;
}
lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
}
| PASSWORD equal text_or_password
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
LEX_USER *user;
- LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
LEX_STRING pw;
@@ -9866,10 +10375,10 @@ option_value:
if (spc && spc->find_variable(&pw))
{
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
- YYABORT;
+ MYSQL_YYABORT;
}
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
- YYABORT;
+ MYSQL_YYABORT;
user->host=null_lex_str;
user->user.str=thd->security_ctx->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3));
@@ -9891,19 +10400,12 @@ internal_variable_name:
if (!spc || !(spv = spc->find_variable(&$1)))
{
/* Not an SP local variable */
- sys_var *tmp=find_sys_var($1.str, $1.length);
+ sys_var *tmp=find_sys_var(YYTHD, $1.str, $1.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
$$.var= tmp;
$$.base_name= null_lex_str;
- /*
- If this is time_zone variable we should open time zone
- describing tables
- */
- if (tmp == &sys_time_zone &&
- lex->add_time_zone_tables_to_query_tables(YYTHD))
- YYABORT;
- else if (spc && tmp == &sys_autocommit)
+ if (spc && tmp == &sys_autocommit)
{
/*
We don't allow setting AUTOCOMMIT from a stored function
@@ -9924,8 +10426,8 @@ internal_variable_name:
LEX *lex= Lex;
if (check_reserved_words(&$1))
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
@@ -9934,18 +10436,18 @@ internal_variable_name:
if ($1.str[0]=='O' || $1.str[0]=='o')
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.event == TRG_EVENT_DELETE)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
"NEW", "on DELETE");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
- YYABORT;
+ MYSQL_YYABORT;
}
/* This special combination will denote field of NEW row */
$$.var= trg_new_row_fake_var;
@@ -9953,9 +10455,9 @@ internal_variable_name:
}
else
{
- sys_var *tmp=find_sys_var($3.str, $3.length);
+ sys_var *tmp=find_sys_var(YYTHD, $3.str, $3.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
@@ -9964,9 +10466,9 @@ internal_variable_name:
}
| DEFAULT '.' ident
{
- sys_var *tmp=find_sys_var($3.str, $3.length);
+ sys_var *tmp=find_sys_var(YYTHD, $3.str, $3.length);
if (!tmp)
- YYABORT;
+ MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
@@ -10018,7 +10520,7 @@ lock:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_LOCK_TABLES;
}
@@ -10038,13 +10540,13 @@ table_lock:
table_ident opt_table_alias lock_option
{
if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
lock_option:
READ_SYM { $$=TL_READ_NO_INSERT; }
- | WRITE_SYM { $$=YYTHD->update_lock_default; }
+ | WRITE_SYM { $$=TL_WRITE_DEFAULT; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
@@ -10057,7 +10559,7 @@ unlock:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_UNLOCK_TABLES;
}
@@ -10077,11 +10579,11 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_OPEN;
if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb CLOSE_SYM
{
@@ -10089,11 +10591,11 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_HA_CLOSE;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
| HANDLER_SYM table_ident_nodb READ_SYM
{
@@ -10101,7 +10603,7 @@ handler:
if (lex->sphead)
{
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->expr_allows_subselect= FALSE;
lex->sql_command = SQLCOM_HA_READ;
@@ -10109,7 +10611,7 @@ handler:
lex->current_select->select_limit= new Item_int((int32) 1);
lex->current_select->offset_limit= 0;
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
- YYABORT;
+ MYSQL_YYABORT;
}
handler_read_or_scan where_clause opt_limit_clause
{
@@ -10138,7 +10640,7 @@ handler_rkey_function:
lex->ha_read_mode = RKEY;
lex->ha_rkey_mode=$1;
if (!(lex->insert_list = new List_item))
- YYABORT;
+ MYSQL_YYABORT;
} '(' values ')' { }
;
@@ -10170,8 +10672,8 @@ revoke_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
@@ -10183,8 +10685,8 @@ revoke_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE;
@@ -10216,8 +10718,8 @@ grant_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
@@ -10229,8 +10731,8 @@ grant_command:
LEX *lex= Lex;
if (lex->columns.elements)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
@@ -10309,7 +10811,7 @@ require_list_element:
if (lex->x509_subject)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->x509_subject=$2.str;
}
@@ -10319,7 +10821,7 @@ require_list_element:
if (lex->x509_issuer)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->x509_issuer=$2.str;
}
@@ -10329,7 +10831,7 @@ require_list_element:
if (lex->ssl_cipher)
{
my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->ssl_cipher=$2.str;
}
@@ -10338,18 +10840,18 @@ require_list_element:
grant_ident:
'*'
{
- LEX *lex= Lex;
- THD *thd= lex->thd;
- uint dummy;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ size_t dummy;
if (thd->copy_db_to(&lex->current_select->db, &dummy))
- YYABORT;
+ MYSQL_YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| ident '.' '*'
@@ -10362,7 +10864,7 @@ grant_ident:
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| '*' '.' '*'
@@ -10375,14 +10877,15 @@ grant_ident:
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
- YYABORT;
+ MYSQL_YYABORT;
}
}
| table_ident
{
LEX *lex=Lex;
- if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,0))
- YYABORT;
+ if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,
+ TL_OPTION_UPDATING))
+ MYSQL_YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
}
@@ -10390,21 +10893,21 @@ grant_ident:
user_list:
- user { if (Lex->users_list.push_back($1)) YYABORT;}
+ user { if (Lex->users_list.push_back($1)) MYSQL_YYABORT;}
| user_list ',' user
{
if (Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
grant_list:
- grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
+ grant_user { if (Lex->users_list.push_back($1)) MYSQL_YYABORT;}
| grant_list ',' grant_user
{
if (Lex->users_list.push_back($3))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -10623,21 +11126,21 @@ union_list:
UNION_SYM union_option
{
LEX *lex=Lex;
- if (lex->exchange)
+ if (lex->result)
{
/* Only the last SELECT can have INTO...... */
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
- YYABORT;
+ MYSQL_YYABORT;
}
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/* This counter shouldn't be incremented for UNION parts */
Lex->nest_level--;
if (mysql_new_select(lex, 0))
- YYABORT;
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->linkage=UNION_TYPE;
if ($2) /* UNION DISTINCT - remember position */
@@ -10702,7 +11205,6 @@ subselect:
}
| '(' subselect_start subselect ')'
{
- LEX *lex= Lex;
THD *thd= YYTHD;
/*
note that a local variable can't be used for
@@ -10731,8 +11233,8 @@ subselect_start:
LEX *lex=Lex;
if (!lex->expr_allows_subselect)
{
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
+ my_parse_error(ER(ER_SYNTAX_ERROR));
+ MYSQL_YYABORT;
}
/*
we are making a "derived table" for the parenthesis
@@ -10742,7 +11244,7 @@ subselect_start:
SELECT * FROM ((SELECT ...) UNION ...)
*/
if (mysql_new_select(Lex, 1))
- YYABORT;
+ MYSQL_YYABORT;
};
subselect_end:
@@ -10753,6 +11255,12 @@ subselect_end:
lex->current_select = lex->current_select->return_after_parsing();
lex->nest_level--;
lex->current_select->n_child_sum_items += child->n_sum_items;
+ /*
+ A subselect can add fields to an outer select. Reserve space for
+ them.
+ */
+ lex->current_select->select_n_where_fields+=
+ child->select_n_where_fields;
};
/**************************************************************************
@@ -10832,13 +11340,6 @@ view_algorithm:
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
;
-view_algorithm_opt:
- /* empty */
- { Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
- | view_algorithm
- {}
- ;
-
view_suid:
/* empty */
{ Lex->create_view_suid= VIEW_SUID_DEFAULT; }
@@ -10856,7 +11357,7 @@ view_tail:
lex->sql_command= SQLCOM_CREATE_VIEW;
/* first table in list is target VIEW name */
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
- YYABORT;
+ MYSQL_YYABORT;
}
view_list_opt AS view_select view_check_option
{}
@@ -10902,20 +11403,18 @@ view_select:
view_select_aux:
SELECT_SYM remember_name select_init2
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
- char *stmt_beg= (lex->sphead ?
- (char *)lex->sphead->m_tmp_query :
- thd->query);
+ const char *stmt_beg= (lex->sphead ?
+ lex->sphead->m_tmp_query : thd->query);
lex->create_view_select_start= $2 - stmt_beg;
}
| '(' remember_name select_paren ')' union_opt
{
- THD *thd=YYTHD;
+ THD *thd= YYTHD;
LEX *lex= thd->lex;
- char *stmt_beg= (lex->sphead ?
- (char *)lex->sphead->m_tmp_query :
- thd->query);
+ const char *stmt_beg= (lex->sphead ?
+ lex->sphead->m_tmp_query : thd->query);
lex->create_view_select_start= $2 - stmt_beg;
}
;
@@ -10941,20 +11440,22 @@ trigger_tail:
TRIGGER_SYM remember_name sp_name trg_action_time trg_event
ON remember_name table_ident FOR_SYM remember_name EACH_SYM ROW_SYM
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
sp_head *sp;
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
- YYABORT;
+ MYSQL_YYABORT;
}
if (!(sp= new sp_head()))
- YYABORT;
- sp->reset_thd_mem_root(YYTHD);
+ MYSQL_YYABORT;
+ sp->reset_thd_mem_root(thd);
sp->init(lex);
- sp->init_sp_name(YYTHD, $3);
+ sp->init_sp_name(thd, $3);
lex->stmt_definition_begin= $2;
lex->ident.str= $7;
lex->ident.length= $10 - $7;
@@ -10967,12 +11468,12 @@ trigger_tail:
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
- $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
- YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+ $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
+ thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->ptr;
+ lex->sphead->m_body_begin= lip->ptr;
while (my_isspace(system_charset_info, lex->sphead->m_body_begin[0]))
++lex->sphead->m_body_begin;
}
@@ -10989,7 +11490,7 @@ trigger_tail:
sp->restore_thd_mem_root(YYTHD);
if (sp->is_not_allowed_in_function("trigger"))
- YYABORT;
+ MYSQL_YYABORT;
/*
We have to do it after parsing trigger body, because some of
@@ -11000,7 +11501,7 @@ trigger_tail:
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
TL_IGNORE))
- YYABORT;
+ MYSQL_YYABORT;
}
;
@@ -11028,7 +11529,7 @@ sp_tail:
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
- YYABORT;
+ MYSQL_YYABORT;
}
lex->stmt_definition_begin= $2;
@@ -11051,24 +11552,30 @@ sp_tail:
}
'('
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
- lex->sphead->m_param_begin= lex->tok_start+1;
+ lex->sphead->m_param_begin= lip->tok_start+1;
}
sp_pdparam_list
')'
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
- lex->sphead->m_param_end= lex->tok_start;
+ lex->sphead->m_param_end= lip->tok_start;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
sp_c_chistics
{
- LEX *lex= Lex;
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->tok_start;
+ lex->sphead->m_body_begin= lip->tok_start;
}
sp_proc_stmt
{
@@ -11117,23 +11624,23 @@ xa: XA_SYM begin_or_start xid opt_join_or_resume
xid: text_string
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
}
| text_string ',' text_string
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
}
| text_string ',' text_string ',' ulong_num
{
- YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
+ MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
- YYABORT;
+ MYSQL_YYABORT;
Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
}
;
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index 77e7707592d..40507907120 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -54,21 +53,6 @@ void safe_print_str(const char* name, const char* val, int max_len)
#define SIGRETURN_FRAME_OFFSET 23
#endif
-static my_bool is_nptl;
-
-/* Check if we are using NPTL or LinuxThreads on Linux */
-void check_thread_lib(void)
-{
- char buf[5];
-
-#ifdef _CS_GNU_LIBPTHREAD_VERSION
- confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf));
- is_nptl = !strncasecmp(buf, "NPTL", sizeof(buf));
-#else
- is_nptl = 0;
-#endif
-}
-
#if defined(__alpha__) && defined(__GNUC__)
/*
The only way to backtrace without a symbol table on alpha
@@ -110,7 +94,7 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp)
#endif /* defined(__alpha__) && defined(__GNUC__) */
-void print_stacktrace(gptr stack_bottom, ulong thread_stack)
+void print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
uchar** fp;
uint frame_count = 0, sigreturn_frame_count;
@@ -145,11 +129,11 @@ terribly wrong...\n");
return;
}
- if (!stack_bottom || (gptr) stack_bottom > (gptr) &fp)
+ if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
{
ulong tmp= min(0x10000,thread_stack);
/* Assume that the stack starts at the previous even 65K */
- stack_bottom= (gptr) (((ulong) &fp + tmp) &
+ stack_bottom= (uchar*) (((ulong) &fp + tmp) &
~(ulong) 0xFFFF);
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
}
@@ -174,8 +158,8 @@ terribly wrong...\n");
#endif /* __alpha__ */
/* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
- sigreturn_frame_count = is_nptl ? 1 : 2;
-
+ sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
+
while (fp < (uchar**) stack_bottom)
{
#if defined(__i386__) || defined(__x86_64__)
@@ -222,9 +206,11 @@ terribly wrong...\n");
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
end:
- fprintf(stderr, "Please read http://dev.mysql.com/doc/mysql/en/using-stack-trace.html and follow instructions on how to resolve the stack trace. Resolved\n\
-stack trace is much more helpful in diagnosing the problem, so please do \n\
-resolve it\n");
+ fprintf(stderr,
+ "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
+ "and follow instructions on how to resolve the stack trace.\n"
+ "Resolved stack trace is much more helpful in diagnosing the\n"
+ "problem, so please do resolve it\n");
}
#endif /* TARGET_OS_LINUX */
#endif /* HAVE_STACKTRACE */
diff --git a/sql/stacktrace.h b/sql/stacktrace.h
index 527d10d70a2..1a0b80c88d3 100644
--- a/sql/stacktrace.h
+++ b/sql/stacktrace.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,11 +27,9 @@ extern char* heap_start;
#define init_stacktrace() do { \
heap_start = (char*) &__bss_start; \
- check_thread_lib(); \
} while(0);
-void print_stacktrace(gptr stack_bottom, ulong thread_stack);
+void print_stacktrace(uchar* stack_bottom, ulong thread_stack);
void safe_print_str(const char* name, const char* val, int max_len);
-void check_thread_lib(void);
#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
#endif /* TARGET_OS_LINUX */
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 2d2530eb876..9ffc5fd127f 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -105,7 +104,8 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
> 0 position in TYPELIB->type_names +1
*/
-uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match)
+uint find_type(const TYPELIB *lib, const char *find, uint length,
+ bool part_match)
{
uint found_count=0, found_pos=0;
const char *end= find+length;
@@ -145,7 +145,8 @@ uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match)
>0 Offset+1 in typelib for matched string
*/
-uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs)
+uint find_type2(const TYPELIB *typelib, const char *x, uint length,
+ CHARSET_INFO *cs)
{
int pos;
const char *j;
diff --git a/sql/structs.h b/sql/structs.h
index 83ae6cac032..da2339d27f8 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -29,8 +28,8 @@ typedef struct st_date_time_format {
typedef struct st_keyfile_info { /* used with ha_info() */
- byte ref[MAX_REFLENGTH]; /* Pointer to current row */
- byte dupp_ref[MAX_REFLENGTH]; /* Pointer to dupp row */
+ uchar ref[MAX_REFLENGTH]; /* Pointer to current row */
+ uchar dupp_ref[MAX_REFLENGTH]; /* Pointer to dupp row */
uint ref_length; /* Length of ref (1-8) */
uint block_size; /* index block size */
File filenr; /* (uniq) filenr for table */
@@ -84,7 +83,7 @@ typedef struct st_key {
*/
union
{
- struct st_plugin_int *parser; /* Fulltext [pre]parser */
+ plugin_ref parser; /* Fulltext [pre]parser */
LEX_STRING *parser_name; /* Fulltext [pre]parser name */
};
KEY_PART_INFO *key_part;
@@ -127,22 +126,21 @@ typedef struct st_read_record { /* Parameter to read_record */
uint cache_records;
uint ref_length,struct_length,reclength,rec_cache_size,error_offset;
uint index;
- byte *ref_pos; /* pointer to form->refpos */
- byte *record;
- byte *rec_buf; /* to read field values after filesort */
- byte *cache,*cache_pos,*cache_end,*read_positions;
+ uchar *ref_pos; /* pointer to form->refpos */
+ uchar *record;
+ uchar *rec_buf; /* to read field values after filesort */
+ uchar *cache,*cache_pos,*cache_end,*read_positions;
IO_CACHE *io_cache;
bool print_error, ignore_not_found_rows;
} READ_RECORD;
/*
- Originally MySQL used TIME structure inside server only, but since
+ Originally MySQL used MYSQL_TIME structure inside server only, but since
4.1 it's exported to user in the new client API. Define aliases for
new names to keep existing code simple.
*/
-typedef struct st_mysql_time TIME;
typedef enum enum_mysql_timestamp_type timestamp_type;
diff --git a/sql/table.cc b/sql/table.cc
index 0b6ce08cbda..745f3a2a34e 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -30,16 +29,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share,
uchar *head, File file);
static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
uint types, char **names);
-static uint find_field(Field **fields, byte *record, uint start, uint length);
+static uint find_field(Field **fields, uchar *record, uint start, uint length);
/* Get column name from column hash */
-static byte *get_field_name(Field **buff, uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar *get_field_name(Field **buff, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= (uint) strlen((*buff)->field_name);
- return (byte*) (*buff)->field_name;
+ return (uchar*) (*buff)->field_name;
}
@@ -121,7 +120,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
share->normalized_path.length= path_length;
share->version= refresh_version;
- share->flush_version= flush_version;
/*
This constant is used to mark that no table map version has been
@@ -239,6 +237,9 @@ void free_table_share(TABLE_SHARE *share)
pthread_cond_destroy(&share->cond);
}
hash_free(&share->name_hash);
+
+ plugin_unlock(NULL, share->db_plugin);
+ share->db_plugin= NULL;
/* We must copy mem_root from share because share is allocated through it */
memcpy((char*) &mem_root, (char*) &share->mem_root, sizeof(mem_root));
@@ -247,6 +248,57 @@ void free_table_share(TABLE_SHARE *share)
}
+/**
+ Return TRUE if a table name matches one of the system table names.
+ Currently these are:
+
+ help_category, help_keyword, help_relation, help_topic,
+ proc, event
+ time_zone, time_zone_leap_second, time_zone_name, time_zone_transition,
+ time_zone_transition_type
+
+ This function trades accuracy for speed, so may return false
+ positives. Presumably mysql.* database is for internal purposes only
+ and should not contain user tables.
+*/
+
+inline bool is_system_table_name(const char *name, uint length)
+{
+ CHARSET_INFO *ci= system_charset_info;
+
+ return (
+ /* mysql.proc table */
+ length == 4 &&
+ my_tolower(ci, name[0]) == 'p' &&
+ my_tolower(ci, name[1]) == 'r' &&
+ my_tolower(ci, name[2]) == 'o' &&
+ my_tolower(ci, name[3]) == 'c' ||
+
+ length > 4 &&
+ (
+ /* one of mysql.help* tables */
+ my_tolower(ci, name[0]) == 'h' &&
+ my_tolower(ci, name[1]) == 'e' &&
+ my_tolower(ci, name[2]) == 'l' &&
+ my_tolower(ci, name[3]) == 'p' ||
+
+ /* one of mysql.time_zone* tables */
+ my_tolower(ci, name[0]) == 't' &&
+ my_tolower(ci, name[1]) == 'i' &&
+ my_tolower(ci, name[2]) == 'm' &&
+ my_tolower(ci, name[3]) == 'e' ||
+
+ /* mysql.event table */
+ my_tolower(ci, name[0]) == 'e' &&
+ my_tolower(ci, name[1]) == 'v' &&
+ my_tolower(ci, name[2]) == 'e' &&
+ my_tolower(ci, name[3]) == 'n' &&
+ my_tolower(ci, name[4]) == 't'
+ )
+ );
+}
+
+
/*
Read table definition from a binary / text based .frm file
@@ -321,7 +373,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
}
error= 4;
- if (my_read(file,(byte*) head, 64, MYF(MY_NABP)))
+ if (my_read(file, head, 64, MYF(MY_NABP)))
goto err;
if (head[0] == (uchar) 254 && head[1] == 1)
@@ -367,11 +419,9 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
allow to lock such tables for writing with any other tables (even with
other system tables) and some privilege tables need this.
*/
- if (!(lower_case_table_names ?
- my_strcasecmp(system_charset_info, share->table_name.str, "proc") :
- strcmp(share->table_name.str, "proc")))
- share->system_table= 1;
- else
+ share->system_table= is_system_table_name(share->table_name.str,
+ share->table_name.length);
+ if (!share->system_table)
{
share->log_table= check_if_log_table(share->db.length, share->db.str,
share->table_name.length,
@@ -413,7 +463,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
uint extra_rec_buf_length;
uint i,j;
bool use_hash;
- char *keynames, *record, *names, *comment_pos;
+ char *keynames, *names, *comment_pos;
+ uchar *record;
uchar *disk_buff, *strpos, *null_flags, *null_pos;
ulong pos, record_offset, *rec_per_key, rec_buff_length;
handler *handler_file= 0;
@@ -453,7 +504,15 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
DBUG_PRINT("info", ("default_part_db_type = %u", head[61]));
#endif
legacy_db_type= (enum legacy_db_type) (uint) *(head+3);
- share->db_type= ha_checktype(thd, legacy_db_type, 0, 0);
+ DBUG_ASSERT(share->db_plugin == NULL);
+ /*
+ if the storage engine is dynamic, no point in resolving it by its
+ dynamically allocated legacy_db_type. We will resolve it later by name.
+ */
+ if (legacy_db_type > DB_TYPE_UNKNOWN &&
+ legacy_db_type < DB_TYPE_FIRST_DYNAMIC)
+ share->db_plugin= ha_lock_engine(NULL,
+ ha_checktype(thd, legacy_db_type, 0, 0));
share->db_create_options= db_create_options= uint2korr(head+30);
share->db_options_in_use= share->db_create_options;
share->mysql_version= uint4korr(head+51);
@@ -490,7 +549,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
/* Read keyinformation */
key_info_length= (uint) uint2korr(head+28);
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
- if (read_string(file,(gptr*) &disk_buff,key_info_length))
+ if (read_string(file,(uchar**) &disk_buff,key_info_length))
goto err; /* purecov: inspected */
if (disk_buff[0] & 0x80)
{
@@ -589,19 +648,21 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if ((n_length= uint4korr(head+55)))
{
/* Read extra data segment */
- char *buff, *next_chunk, *buff_end;
+ uchar *buff, *next_chunk, *buff_end;
DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));
- if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME))))
+ if (!(next_chunk= buff= (uchar*) my_malloc(n_length, MYF(MY_WME))))
goto err;
- if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
+ if (my_pread(file, buff, n_length, record_offset + share->reclength,
MYF(MY_NABP)))
{
my_free(buff, MYF(0));
goto err;
}
share->connect_string.length= uint2korr(buff);
- if (! (share->connect_string.str= strmake_root(&share->mem_root,
- next_chunk + 2, share->connect_string.length)))
+ if (!(share->connect_string.str= strmake_root(&share->mem_root,
+ (char*) next_chunk + 2,
+ share->connect_string.
+ length)))
{
my_free(buff, MYF(0));
goto err;
@@ -611,25 +672,51 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (next_chunk + 2 < buff_end)
{
uint str_db_type_length= uint2korr(next_chunk);
- LEX_STRING name= { next_chunk + 2, str_db_type_length };
- handlerton *tmp_db_type= ha_resolve_by_name(thd, &name);
- if (tmp_db_type != NULL)
+ LEX_STRING name;
+ name.str= (char*) next_chunk + 2;
+ name.length= str_db_type_length;
+
+ plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name);
+ if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, share->db_plugin))
{
- share->db_type= tmp_db_type;
+ if (legacy_db_type > DB_TYPE_UNKNOWN &&
+ legacy_db_type < DB_TYPE_FIRST_DYNAMIC &&
+ legacy_db_type != ha_legacy_type(
+ plugin_data(tmp_plugin, handlerton *)))
+ {
+ /* bad file, legacy_db_type did not match the name */
+ my_free(buff, MYF(0));
+ goto err;
+ }
+ /*
+ tmp_plugin is locked with a local lock.
+ we unlock the old value of share->db_plugin before
+ replacing it with a globally locked version of tmp_plugin
+ */
+ plugin_unlock(NULL, share->db_plugin);
+ share->db_plugin= my_plugin_lock(NULL, &tmp_plugin);
DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",
str_db_type_length, next_chunk + 2,
- ha_legacy_type(share->db_type)));
+ ha_legacy_type(share->db_type())));
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
else
{
- if (!strncmp(next_chunk + 2, "partition", str_db_type_length))
+ LEX_STRING pname= { C_STRING_WITH_LEN( "partition" ) };
+ if (str_db_type_length == pname.length &&
+ !strncmp((char *) next_chunk + 2, pname.str, pname.length))
{
- /* Use partition handler */
- share->db_type= partition_hton;
+ /*
+ Use partition handler
+ tmp_plugin is locked with a local lock.
+ we unlock the old value of share->db_plugin before
+ replacing it with a globally locked version of tmp_plugin
+ */
+ plugin_unlock(NULL, share->db_plugin);
+ share->db_plugin= ha_lock_engine(NULL, partition_hton);
DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",
str_db_type_length, next_chunk + 2,
- ha_legacy_type(share->db_type)));
+ ha_legacy_type(share->db_type())));
}
}
#endif
@@ -641,9 +728,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
#ifdef WITH_PARTITION_STORAGE_ENGINE
if ((share->partition_info_len= partition_info_len))
{
- if (!(share->partition_info=
- (uchar*) memdup_root(&share->mem_root, next_chunk + 4,
- partition_info_len + 1)))
+ if (!(share->partition_info= (char*)
+ memdup_root(&share->mem_root, next_chunk + 4,
+ partition_info_len + 1)))
{
my_free(buff, MYF(0));
goto err;
@@ -693,9 +780,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
my_free(buff, MYF(0));
goto err;
}
- parser_name.str= next_chunk;
- parser_name.length= strlen(next_chunk);
- keyinfo->parser= plugin_lock(&parser_name, MYSQL_FTPARSER_PLUGIN);
+ parser_name.str= (char*) next_chunk;
+ parser_name.length= strlen((char*) next_chunk);
+ keyinfo->parser= my_plugin_lock_by_name(NULL, &parser_name,
+ MYSQL_FTPARSER_PLUGIN);
if (! keyinfo->parser)
{
my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str);
@@ -712,16 +800,16 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
extra_rec_buf_length= uint2korr(head+59);
rec_buff_length= ALIGN_SIZE(share->reclength + 1 + extra_rec_buf_length);
share->rec_buff_length= rec_buff_length;
- if (!(record= (char *) alloc_root(&share->mem_root,
- rec_buff_length)))
+ if (!(record= (uchar *) alloc_root(&share->mem_root,
+ rec_buff_length)))
goto err; /* purecov: inspected */
- share->default_values= (byte *) record;
- if (my_pread(file,(byte*) record, (uint) share->reclength,
+ share->default_values= record;
+ if (my_pread(file, record, (size_t) share->reclength,
record_offset, MYF(MY_NABP)))
goto err; /* purecov: inspected */
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
- if (my_read(file,(byte*) head,288,MYF(MY_NABP)))
+ if (my_read(file, head,288,MYF(MY_NABP)))
goto err;
#ifdef HAVE_CRYPTED_FRM
if (crypted)
@@ -751,14 +839,14 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
(uint) ((share->fields+1)*sizeof(Field*)+
interval_count*sizeof(TYPELIB)+
(share->fields+interval_parts+
- keys+3)*sizeof(my_string)+
+ keys+3)*sizeof(char *)+
(n_length+int_length+com_length)))))
goto err; /* purecov: inspected */
share->field= field_ptr;
read_length=(uint) (share->fields * field_pack_length +
pos+ (uint) (n_length+int_length+com_length));
- if (read_string(file,(gptr*) &disk_buff,read_length))
+ if (read_string(file,(uchar**) &disk_buff,read_length))
goto err; /* purecov: inspected */
#ifdef HAVE_CRYPTED_FRM
if (crypted)
@@ -781,6 +869,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
fix_type_pointers(&interval_array, &share->fieldnames, 1, &names);
+ if (share->fieldnames.count != share->fields)
+ goto err;
fix_type_pointers(&interval_array, share->intervals, interval_count,
&names);
@@ -799,17 +889,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
char *val= (char*) interval->type_names[count];
interval->type_lengths[count]= strlen(val);
- /*
- Replace all ',' symbols with NAMES_SEP_CHAR.
- See the comment in unireg.cc, pack_fields() function
- for details.
- */
- for (uint cnt= 0 ; cnt < interval->type_lengths[count] ; cnt++)
- {
- char c= val[cnt];
- if (c == ',')
- val[cnt]= NAMES_SEP_CHAR;
- }
}
interval->type_lengths[count]= 0;
}
@@ -820,10 +899,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
/* Allocate handler */
if (!(handler_file= get_new_handler(share, thd->mem_root,
- share->db_type)))
+ share->db_type())))
goto err;
- record= (char*) share->default_values-1; /* Fieldstart = 1 */
+ record= share->default_values-1; /* Fieldstart = 1 */
if (share->null_field_first)
{
null_flags= null_pos= (uchar*) record+1;
@@ -872,7 +951,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
field_type=(enum_field_types) (uint) strpos[13];
/* charset and geometry_type share the same byte in frm */
- if (field_type == FIELD_TYPE_GEOMETRY)
+ if (field_type == MYSQL_TYPE_GEOMETRY)
{
#ifdef HAVE_SPATIAL
geom_type= (Field::geometry_type) strpos[14];
@@ -947,7 +1026,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
}
#ifndef TO_BE_DELETED_ON_PRODUCTION
- if (field_type == FIELD_TYPE_NEWDECIMAL && !share->mysql_version)
+ if (field_type == MYSQL_TYPE_NEWDECIMAL && !share->mysql_version)
{
/*
Fix pack length of old decimal values from 5.0.3 -> 5.0.4
@@ -994,7 +1073,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
reg_field->field_index= i;
reg_field->comment=comment;
- if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag))
+ if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
{
if ((null_bit_pos+= field_length & 7) > 7)
{
@@ -1017,7 +1096,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (use_hash)
(void) my_hash_insert(&share->name_hash,
- (byte*) field_ptr); // never fail
+ (uchar*) field_ptr); // never fail
}
*field_ptr=0; // End marker
@@ -1076,7 +1155,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
key_part->type= field->key_type();
if (field->null_ptr)
{
- key_part->null_offset=(uint) ((byte*) field->null_ptr -
+ key_part->null_offset=(uint) ((uchar*) field->null_ptr -
share->default_values);
key_part->null_bit= field->null_bit;
key_part->store_length+=HA_KEY_NULL_LENGTH;
@@ -1084,10 +1163,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keyinfo->extra_length+= HA_KEY_NULL_LENGTH;
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
- if (field->type() == FIELD_TYPE_BLOB ||
+ if (field->type() == MYSQL_TYPE_BLOB ||
field->real_type() == MYSQL_TYPE_VARCHAR)
{
- if (field->type() == FIELD_TYPE_BLOB)
+ if (field->type() == MYSQL_TYPE_BLOB)
key_part->key_part_flag|= HA_BLOB_PART;
else
key_part->key_part_flag|= HA_VAR_LENGTH_PART;
@@ -1139,7 +1218,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (field->key_length() != key_part->length)
{
#ifndef TO_BE_DELETED_ON_PRODUCTION
- if (field->type() == FIELD_TYPE_NEWDECIMAL)
+ if (field->type() == MYSQL_TYPE_NEWDECIMAL)
{
/*
Fix a fatal error in decimal key handling that causes crashes
@@ -1217,7 +1296,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
}
else
share->primary_key= MAX_KEY;
- x_free((gptr) disk_buff);
+ x_free((uchar*) disk_buff);
disk_buff=0;
if (new_field_pack_flag <= 1)
{
@@ -1233,12 +1312,12 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if ((int) (share->next_number_index= (uint)
find_ref_key(share->key_info, share->keys,
share->default_values, reg_field,
- &share->next_number_key_offset)) < 0)
+ &share->next_number_key_offset,
+ &share->next_number_keypart)) < 0)
{
/* Wrong field definition */
- DBUG_ASSERT(0);
- reg_field->unireg_check= Field::NONE; /* purecov: inspected */
- share->found_next_number_field= 0;
+ error= 4;
+ goto err;
}
else
reg_field->flags |= AUTO_INCREMENT_FLAG;
@@ -1247,17 +1326,17 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (share->blob_fields)
{
Field **ptr;
- uint i, *save;
+ uint k, *save;
/* Store offsets to blob fields to find them fast */
if (!(share->blob_field= save=
(uint*) alloc_root(&share->mem_root,
(uint) (share->blob_fields* sizeof(uint)))))
goto err;
- for (i=0, ptr= share->field ; *ptr ; ptr++, i++)
+ for (k=0, ptr= share->field ; *ptr ; ptr++, k++)
{
if ((*ptr)->flags & BLOB_FLAG)
- (*save++)= i;
+ (*save++)= k;
}
}
@@ -1273,7 +1352,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->column_bitmap_size= bitmap_buffer_size(share->fields);
if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root,
- share->column_bitmap_size)))
+ share->column_bitmap_size)))
goto err;
bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);
bitmap_set_all(&share->all_set);
@@ -1289,7 +1368,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->error= error;
share->open_errno= my_errno;
share->errarg= errarg;
- x_free((gptr) disk_buff);
+ x_free((uchar*) disk_buff);
delete crypted;
delete handler_file;
hash_free(&share->name_hash);
@@ -1331,7 +1410,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
int error;
uint records, i, bitmap_size;
bool error_reported= FALSE;
- byte *record, *bitmaps;
+ uchar *record, *bitmaps;
Field **field_ptr;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
@@ -1349,12 +1428,12 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
goto err;
outparam->quick_keys.init();
- outparam->used_keys.init();
+ outparam->covering_keys.init();
outparam->keys_in_use_for_query.init();
/* Allocate handler */
if (!(outparam->file= get_new_handler(share, &outparam->mem_root,
- share->db_type)))
+ share->db_type())))
goto err;
error= 4;
@@ -1366,7 +1445,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (prgflag & (READ_ALL+EXTRA_RECORD))
records++;
- if (!(record= (byte*) alloc_root(&outparam->mem_root,
+ if (!(record= (uchar*) alloc_root(&outparam->mem_root,
share->rec_buff_length * records)))
goto err; /* purecov: inspected */
@@ -1406,7 +1485,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
outparam->field= field_ptr;
- record= (byte*) outparam->record[0]-1; /* Fieldstart = 1 */
+ record= (uchar*) outparam->record[0]-1; /* Fieldstart = 1 */
if (share->null_field_first)
outparam->null_flags= (uchar*) record+1;
else
@@ -1497,7 +1576,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
tmp= mysql_unpack_partition(thd, share->partition_info,
share->partition_info_len,
- (uchar*)share->part_state,
+ share->part_state,
share->part_state_len,
outparam, is_create_table,
share->default_part_db_type);
@@ -1528,7 +1607,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
/* Allocate bitmaps */
bitmap_size= share->column_bitmap_size;
- if (!(bitmaps= (byte*) alloc_root(&outparam->mem_root, bitmap_size*3)))
+ if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*3)))
goto err;
bitmap_init(&outparam->def_read_set,
(my_bitmap_map*) bitmaps, share->fields, FALSE);
@@ -1638,7 +1717,7 @@ int closefrm(register TABLE *table, bool free_share)
{
if (key_info->flags & HA_USES_PARSER)
{
- plugin_unlock(key_info->parser);
+ plugin_unlock(NULL, key_info->parser);
key_info->flags= 0;
}
}
@@ -1695,7 +1774,7 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
DBUG_ENTER("get_form_pos");
names=uint2korr(head+8);
- a_length=(names+2)*sizeof(my_string); /* Room for two extra */
+ a_length=(names+2)*sizeof(char *); /* Room for two extra */
if (!save_names)
a_length=0;
@@ -1706,12 +1785,12 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
{
length=uint2korr(head+4);
VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
- if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
+ if (!(buf= (uchar*) my_malloc((size_t) length+a_length+names*4,
MYF(MY_WME))) ||
- my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
+ my_read(file, buf+a_length, (size_t) (length+names*4),
MYF(MY_NABP)))
{ /* purecov: inspected */
- x_free((gptr) buf); /* purecov: inspected */
+ x_free((uchar*) buf); /* purecov: inspected */
DBUG_RETURN(0L); /* purecov: inspected */
}
pos= buf+a_length+length;
@@ -1720,7 +1799,7 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
if (! save_names)
{
if (names)
- my_free((gptr) buf,MYF(0));
+ my_free((uchar*) buf,MYF(0));
}
else if (!names)
bzero((char*) save_names,sizeof(save_names));
@@ -1734,19 +1813,24 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
}
- /* Read string from a file with malloc */
+/*
+ Read string from a file with malloc
-int read_string(File file, gptr *to, uint length)
+ NOTES:
+ We add an \0 at end of the read string to make reading of C strings easier
+*/
+
+int read_string(File file, uchar**to, size_t length)
{
DBUG_ENTER("read_string");
- x_free((gptr) *to);
- if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
- my_read(file,(byte*) *to,length,MYF(MY_NABP)))
+ x_free(*to);
+ if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) ||
+ my_read(file, *to, length,MYF(MY_NABP)))
{
- x_free((gptr) *to); /* purecov: inspected */
- *to= 0; /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ x_free(*to); /* purecov: inspected */
+ *to= 0; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
*((char*) *to+length)= '\0';
DBUG_RETURN (0);
@@ -1760,7 +1844,7 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
{
uint i,bufflength,maxlength,n_length,length,names;
ulong endpos,newpos;
- char buff[IO_SIZE];
+ uchar buff[IO_SIZE];
uchar *pos;
DBUG_ENTER("make_new_entry");
@@ -1780,17 +1864,17 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
while (endpos > maxlength)
{
VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
- if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
+ if (my_read(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
MYF(0)));
- if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
+ if ((my_write(file, buff,bufflength,MYF(MY_NABP+MY_WME))))
DBUG_RETURN(0);
endpos-=bufflength; bufflength=IO_SIZE;
}
bzero(buff,IO_SIZE); /* Null new block */
VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
- if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
+ if (my_write(file,buff,bufflength,MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
maxlength+=IO_SIZE; /* Fix old ref */
int2store(fileinfo+6,maxlength);
@@ -1805,15 +1889,15 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
if (n_length == 1 )
{ /* First name */
length++;
- VOID(strxmov(buff,"/",newname,"/",NullS));
+ VOID(strxmov((char*) buff,"/",newname,"/",NullS));
}
else
- VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
+ VOID(strxmov((char*) buff,newname,"/",NullS)); /* purecov: inspected */
VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
- if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
- (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
+ if (my_write(file, buff, (size_t) length+1,MYF(MY_NABP+MY_WME)) ||
+ (names && my_write(file,(uchar*) (*formnames->type_names+n_length-1),
names*4, MYF(MY_NABP+MY_WME))) ||
- my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
+ my_write(file, fileinfo+10, 4,MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L); /* purecov: inspected */
int2store(fileinfo+8,names+1);
@@ -1849,10 +1933,10 @@ void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg)
handler *file= 0;
const char *datext= "";
- if (share->db_type != NULL)
+ if (share->db_type() != NULL)
{
if ((file= get_new_handler(share, current_thd->mem_root,
- share->db_type)))
+ share->db_type())))
{
if (!(datext= *file->bas_ext()))
datext= "";
@@ -1973,7 +2057,7 @@ TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings)
# field number +1
*/
-static uint find_field(Field **fields, byte *record, uint start, uint length)
+static uint find_field(Field **fields, uchar *record, uint start, uint length)
{
Field **field;
uint i, pos;
@@ -2086,7 +2170,7 @@ File create_frm(THD *thd, const char *name, const char *db,
{
register File file;
ulong length;
- char fill[IO_SIZE];
+ uchar fill[IO_SIZE];
int create_flags= O_RDWR | O_TRUNC;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
@@ -2149,7 +2233,7 @@ File create_frm(THD *thd, const char *name, const char *db,
bzero(fill,IO_SIZE);
for (; length > IO_SIZE ; length-= IO_SIZE)
{
- if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
+ if (my_write(file,fill, IO_SIZE, MYF(MY_WME | MY_NABP)))
{
VOID(my_close(file,MYF(0)));
VOID(my_delete(name,MYF(0)));
@@ -2255,6 +2339,30 @@ char *get_field(MEM_ROOT *mem, Field *field)
return to;
}
+/*
+ DESCRIPTION
+ given a buffer with a key value, and a map of keyparts
+ that are present in this value, returns the length of the value
+*/
+uint calculate_key_len(TABLE *table, uint key, const uchar *buf,
+ key_part_map keypart_map)
+{
+ /* works only with key prefixes */
+ DBUG_ASSERT(((keypart_map + 1) & keypart_map) == 0);
+
+ KEY *key_info= table->s->key_info+key;
+ KEY_PART_INFO *key_part= key_info->key_part;
+ KEY_PART_INFO *end_key_part= key_part + key_info->key_parts;
+ uint length= 0;
+
+ while (key_part < end_key_part && keypart_map)
+ {
+ length+= key_part->store_length;
+ keypart_map >>= 1;
+ key_part++;
+ }
+ return length;
+}
/*
Check if database name is valid
@@ -2274,8 +2382,9 @@ char *get_field(MEM_ROOT *mem, Field *field)
bool check_db_name(LEX_STRING *org_name)
{
char *name= org_name->str;
+ uint name_length= org_name->length;
- if (!org_name->length || org_name->length > NAME_LEN)
+ if (!name_length || name_length > NAME_LEN)
return 1;
if (lower_case_table_names && name != any_db)
@@ -2284,6 +2393,7 @@ bool check_db_name(LEX_STRING *org_name)
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(system_charset_info))
{
+ name_length= 0;
bool last_char_is_space= TRUE;
char *end= name + org_name->length;
while (name < end)
@@ -2294,12 +2404,14 @@ bool check_db_name(LEX_STRING *org_name)
if (!len)
len= 1;
name+= len;
+ name_length++;
}
- return last_char_is_space;
+ return (last_char_is_space || name_length > NAME_CHAR_LEN);
}
else
#endif
- return org_name->str[org_name->length - 1] != ' '; /* purecov: inspected */
+ return ((org_name->str[org_name->length - 1] != ' ') ||
+ (name_length > NAME_CHAR_LEN)); /* purecov: inspected */
}
@@ -2312,6 +2424,7 @@ bool check_db_name(LEX_STRING *org_name)
bool check_table_name(const char *name, uint length)
{
+ uint name_length= 0; // name length in symbols
const char *end= name+length;
if (!length || length > NAME_LEN)
return 1;
@@ -2332,14 +2445,16 @@ bool check_table_name(const char *name, uint length)
if (len)
{
name += len;
+ name_length++;
continue;
}
}
#endif
name++;
+ name_length++;
}
#if defined(USE_MB) && defined(USE_MB_IDENT)
- return last_char_is_space;
+ return (last_char_is_space || name_length > NAME_CHAR_LEN) ;
#else
return 0;
#endif
@@ -2348,7 +2463,7 @@ bool check_table_name(const char *name, uint length)
bool check_column_name(const char *name)
{
- const char *start= name;
+ uint name_length= 0; // name length in symbols
bool last_char_is_space= TRUE;
while (*name)
@@ -2362,6 +2477,7 @@ bool check_column_name(const char *name)
if (len)
{
name += len;
+ name_length++;
continue;
}
}
@@ -2371,159 +2487,150 @@ bool check_column_name(const char *name)
if (*name == NAMES_SEP_CHAR)
return 1;
name++;
+ name_length++;
}
/* Error if empty or too long column name */
- return last_char_is_space || (uint) (name - start) > NAME_LEN;
+ return last_char_is_space || (uint) name_length > NAME_CHAR_LEN;
}
-/*
+/**
Checks whether a table is intact. Should be done *just* after the table has
been opened.
-
- SYNOPSIS
- table_check_intact()
- table The table to check
- table_f_count Expected number of columns in the table
- table_def Expected structure of the table (column name and type)
- last_create_time The table->file->create_time of the table in memory
- we have checked last time
- error_num ER_XXXX from the error messages file. When 0 no error
- is sent to the client in case types does not match.
- If different col number either
- ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE or
- ER_COL_COUNT_DOESNT_MATCH_CORRUPTED is used
-
- RETURNS
- FALSE OK
- TRUE There was an error
+
+ @param[in] table The table to check
+ @param[in] table_f_count Expected number of columns in the table
+ @param[in] table_def Expected structure of the table (column name
+ and type)
+
+ @retval FALSE OK
+ @retval TRUE There was an error. An error message is output
+ to the error log. We do not push an error
+ message into the error stack because this
+ function is currently only called at start up,
+ and such errors never reach the user.
*/
my_bool
table_check_intact(TABLE *table, const uint table_f_count,
- const TABLE_FIELD_W_TYPE *table_def,
- time_t *last_create_time, int error_num)
+ const TABLE_FIELD_W_TYPE *table_def)
{
uint i;
my_bool error= FALSE;
my_bool fields_diff_count;
DBUG_ENTER("table_check_intact");
- DBUG_PRINT("info",("table: %s expected_count: %d last_create_time: %ld",
- table->alias, table_f_count, *last_create_time));
-
- if ((fields_diff_count= (table->s->fields != table_f_count)) ||
- (*last_create_time != table->file->stats.create_time))
+ DBUG_PRINT("info",("table: %s expected_count: %d",
+ table->alias, table_f_count));
+
+ fields_diff_count= (table->s->fields != table_f_count);
+ if (fields_diff_count)
{
- DBUG_PRINT("info", ("I am suspecting, checking table"));
- if (fields_diff_count)
+ DBUG_PRINT("info", ("Column count has changed, checking the definition"));
+
+ /* previous MySQL version */
+ if (MYSQL_VERSION_ID > table->s->mysql_version)
{
- /* previous MySQL version */
- error= TRUE;
- if (MYSQL_VERSION_ID > table->s->mysql_version)
- {
- my_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, MYF(0), table->alias,
- table_f_count, table->s->fields, table->s->mysql_version,
- MYSQL_VERSION_ID);
- sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
- table->alias, table_f_count, table->s->fields,
- table->s->mysql_version, MYSQL_VERSION_ID);
- DBUG_RETURN(error);
+ sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
+ table->alias, table_f_count, table->s->fields,
+ table->s->mysql_version, MYSQL_VERSION_ID);
+ DBUG_RETURN(TRUE);
+ }
+ else if (MYSQL_VERSION_ID == table->s->mysql_version)
+ {
+ sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias,
+ table_f_count, table->s->fields);
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Something has definitely changed, but we're running an older
+ version of MySQL with new system tables.
+ Let's check column definitions. If a column was added at
+ the end of the table, then we don't care much since such change
+ is backward compatible.
+ */
+ }
+ char buffer[STRING_BUFFER_USUAL_SIZE];
+ for (i=0 ; i < table_f_count; i++, table_def++)
+ {
+ String sql_type(buffer, sizeof(buffer), system_charset_info);
+ sql_type.length(0);
+ if (i < table->s->fields)
+ {
+ Field *field= table->field[i];
- }
- else if (MYSQL_VERSION_ID == table->s->mysql_version)
- {
- my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED,MYF(0), table->alias,
- table_f_count, table->s->fields);
- sql_print_error(ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), table->alias,
- table_f_count, table->s->fields);
- }
- else
+ if (strncmp(field->field_name, table_def->name.str,
+ table_def->name.length))
{
/*
- Moving from newer mysql to older one -> let's say not an error but
- will check the definition afterwards. If a column was added at the
- end then we don't care much since it's not in the middle.
+ Name changes are not fatal, we use ordinal numbers to access columns.
+ Still this can be a sign of a tampered table, output an error
+ to the error log.
*/
- error= FALSE;
+ sql_print_error("Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d, found '%s'.",
+ table->s->db.str, table->alias, table_def->name.str, i,
+ field->field_name);
}
- }
- /* definitely something has changed */
- char buffer[255];
- for (i=0 ; i < table_f_count; i++, table_def++)
- {
- String sql_type(buffer, sizeof(buffer), system_charset_info);
- sql_type.length(0);
+ field->sql_type(sql_type);
/*
- Name changes are not fatal, we use sequence numbers => no problem
- for us but this can show tampered table or broken table.
- */
- if (i < table->s->fields)
+ Generally, if column types don't match, then something is
+ wrong.
+
+ However, we only compare column definitions up to the
+ length of the original definition, since we consider the
+ following definitions compatible:
+
+ 1. DATETIME and DATETIM
+ 2. INT(11) and INT(11
+ 3. SET('one', 'two') and SET('one', 'two', 'more')
+
+ For SETs or ENUMs, if the same prefix is there it's OK to
+ add more elements - they will get higher ordinal numbers and
+ the new table definition is backward compatible with the
+ original one.
+ */
+ if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
+ table_def->type.length - 1))
{
- Field *field= table->field[i];
- if (strncmp(field->field_name, table_def->name.str,
- table_def->name.length))
- {
- sql_print_error("(%s) Expected field %s at position %d, found %s",
- table->alias, table_def->name.str, i,
- field->field_name);
- }
-
- /*
- If the type does not match than something is really wrong
- Check up to length - 1. Why?
- 1. datetime -> datetim -> the same
- 2. int(11) -> int(11 -> the same
- 3. set('one','two') -> set('one','two'
- so for sets if the same prefix is there it's ok if more are
- added as part of the set. The same is valid for enum. So a new
- table running on a old server will be valid.
- */
- field->sql_type(sql_type);
- if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
- table_def->type.length - 1))
- {
- sql_print_error("(%s) Expected field %s at position %d to have type "
- "%s, found %s", table->alias, table_def->name.str,
- i, table_def->type.str, sql_type.c_ptr_safe());
- error= TRUE;
- }
- else if (table_def->cset.str && !field->has_charset())
- {
- sql_print_error("(%s) Expected field %s at position %d to have "
- "character set '%s' but found no such", table->alias,
- table_def->name.str, i, table_def->cset.str);
- error= TRUE;
- }
- else if (table_def->cset.str &&
- strcmp(field->charset()->csname, table_def->cset.str))
- {
- sql_print_error("(%s) Expected field %s at position %d to have "
- "character set '%s' but found '%s'", table->alias,
- table_def->name.str, i, table_def->cset.str,
- field->charset()->csname);
- error= TRUE;
- }
+ sql_print_error("Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d to have type "
+ "%s, found type %s.", table->s->db.str, table->alias,
+ table_def->name.str, i, table_def->type.str,
+ sql_type.c_ptr_safe());
+ error= TRUE;
}
- else
+ else if (table_def->cset.str && !field->has_charset())
{
- sql_print_error("(%s) Expected field %s at position %d to have type %s "
- " but no field found.", table->alias,
- table_def->name.str, i, table_def->type.str);
- error= TRUE;
+ sql_print_error("Incorrect definition of table %s.%s: "
+ "expected the type of column '%s' at position %d "
+ "to have character set '%s' but the type has no "
+ "character set.", table->s->db.str, table->alias,
+ table_def->name.str, i, table_def->cset.str);
+ error= TRUE;
+ }
+ else if (table_def->cset.str &&
+ strcmp(field->charset()->csname, table_def->cset.str))
+ {
+ sql_print_error("Incorrect definition of table %s.%s: "
+ "expected the type of column '%s' at position %d "
+ "to have character set '%s' but found "
+ "character set '%s'.", table->s->db.str, table->alias,
+ table_def->name.str, i, table_def->cset.str,
+ field->charset()->csname);
+ error= TRUE;
}
}
- if (!error)
- *last_create_time= table->file->stats.create_time;
- else if (!fields_diff_count && error_num)
- my_error(error_num,MYF(0), table->alias, table_f_count, table->s->fields);
- }
- else
- {
- DBUG_PRINT("info", ("Table seems ok without thorough checking."));
- *last_create_time= table->file->stats.create_time;
+ else
+ {
+ sql_print_error("Incorrect definition of table %s.%s: "
+ "expected column '%s' at position %d to have type %s "
+ " but the column is not found.",
+ table->s->db.str, table->alias,
+ table_def->name.str, i, table_def->type.str);
+ error= TRUE;
+ }
}
-
- DBUG_RETURN(error);
+ DBUG_RETURN(error);
}
@@ -2682,7 +2789,7 @@ bool st_table_list::setup_underlying(THD *thd)
List_iterator_fast<Item> it(select->item_list);
uint field_count= 0;
- if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&field_count))
+ if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar*) &field_count))
{
DBUG_RETURN(TRUE);
}
@@ -2807,6 +2914,47 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
/*
+ Merge ON expressions for a view
+
+ SYNOPSIS
+ merge_on_conds()
+ thd thread handle
+ table table for the VIEW
+ is_cascaded TRUE <=> merge ON expressions from underlying views
+
+ DESCRIPTION
+ This function returns the result of ANDing the ON expressions
+ of the given view and all underlying views. The ON expressions
+ of the underlying views are added only if is_cascaded is TRUE.
+
+ RETURN
+ Pointer to the built expression if there is any.
+ Otherwise and in the case of a failure NULL is returned.
+*/
+
+static Item *
+merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
+{
+ DBUG_ENTER("merge_on_conds");
+
+ Item *cond= NULL;
+ DBUG_PRINT("info", ("alias: %s", table->alias));
+ if (table->on_expr)
+ cond= table->on_expr->copy_andor_structure(thd);
+ if (!table->nested_join)
+ DBUG_RETURN(cond);
+ List_iterator<TABLE_LIST> li(table->nested_join->join_list);
+ while (TABLE_LIST *tbl= li++)
+ {
+ if (tbl->view && !is_cascaded)
+ continue;
+ cond= and_conds(cond, merge_on_conds(thd, tbl, is_cascaded));
+ }
+ DBUG_RETURN(cond);
+}
+
+
+/*
Prepare check option expression of table
SYNOPSIS
@@ -2822,8 +2970,8 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
VIEW_CHECK_LOCAL option.
NOTE
- This method build check options for every call
- (usual execution or every SP/PS call)
+ This method builds check option condition to use it later on
+ every call (usual execution or every SP/PS call).
This method have to be called after WHERE preparation
(st_table_list::prep_where)
@@ -2835,38 +2983,42 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
{
DBUG_ENTER("st_table_list::prep_check_option");
+ bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED;
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
/* see comment of check_opt_type parameter */
- if (tbl->view &&
- tbl->prep_check_option(thd,
- ((check_opt_type == VIEW_CHECK_CASCADED) ?
- VIEW_CHECK_CASCADED :
- VIEW_CHECK_NONE)))
- {
+ if (tbl->view && tbl->prep_check_option(thd, (is_cascaded ?
+ VIEW_CHECK_CASCADED :
+ VIEW_CHECK_NONE)))
DBUG_RETURN(TRUE);
- }
}
- if (check_opt_type)
+ if (check_opt_type && !check_option_processed)
{
- Item *item= 0;
+ Query_arena *arena= thd->stmt_arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test
+
if (where)
{
DBUG_ASSERT(where->fixed);
- item= where->copy_andor_structure(thd);
+ check_option= where->copy_andor_structure(thd);
}
- if (check_opt_type == VIEW_CHECK_CASCADED)
+ if (is_cascaded)
{
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
if (tbl->check_option)
- item= and_conds(item, tbl->check_option);
+ check_option= and_conds(check_option, tbl->check_option);
}
}
- if (item)
- thd->change_item_tree(&check_option, item);
+ check_option= and_conds(check_option,
+ merge_on_conds(thd, this, is_cascaded));
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ check_option_processed= TRUE;
+
}
if (check_option)
@@ -2901,10 +3053,12 @@ void st_table_list::hide_view_error(THD *thd)
thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
- thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR)
+ thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR ||
+ thd->net.last_errno == ER_TABLE_NOT_LOCKED ||
+ thd->net.last_errno == ER_NO_SUCH_TABLE)
{
TABLE_LIST *top= top_table();
- thd->clear_error();
+ thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
}
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
@@ -2969,7 +3123,7 @@ void st_table_list::cleanup_items()
check CHECK OPTION condition
SYNOPSIS
- check_option()
+ st_table_list::view_check_option()
ignore_failure ignore check option fail
RETURN
@@ -2982,19 +3136,17 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
{
if (check_option && check_option->val_int() == 0)
{
- TABLE_LIST *view= top_table();
+ TABLE_LIST *main_view= top_table();
if (ignore_failure)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED),
- view->view_db.str, view->view_name.str);
+ main_view->view_db.str, main_view->view_name.str);
return(VIEW_CHECK_SKIP);
}
- else
- {
- my_error(ER_VIEW_CHECK_FAILED, MYF(0), view->view_db.str, view->view_name.str);
- return(VIEW_CHECK_ERROR);
- }
+ my_error(ER_VIEW_CHECK_FAILED, MYF(0), main_view->view_db.str,
+ main_view->view_name.str);
+ return(VIEW_CHECK_ERROR);
}
return(VIEW_CHECK_OK);
}
@@ -3006,19 +3158,20 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
SYNOPSIS
st_table_list::check_single_table()
- table reference on variable where to store found table
+ table_arg reference on variable where to store found table
(should be 0 on call, to find table, or point to table for
unique test)
map bit mask of tables
- view view for which we are looking table
+ view_arg view for which we are looking table
RETURN
FALSE table not found or found only one
TRUE found several tables
*/
-bool st_table_list::check_single_table(st_table_list **table, table_map map,
- st_table_list *view)
+bool st_table_list::check_single_table(st_table_list **table_arg,
+ table_map map,
+ st_table_list *view_arg)
{
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
@@ -3026,13 +3179,13 @@ bool st_table_list::check_single_table(st_table_list **table, table_map map,
{
if (tbl->table->map & map)
{
- if (*table)
+ if (*table_arg)
return TRUE;
- *table= tbl;
- tbl->check_option= view->check_option;
+ *table_arg= tbl;
+ tbl->check_option= view_arg->check_option;
}
}
- else if (tbl->check_single_table(table, map, view))
+ else if (tbl->check_single_table(table_arg, map, view_arg))
return TRUE;
}
return FALSE;
@@ -3056,7 +3209,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
if (table)
{
if (!table->insert_values &&
- !(table->insert_values= (byte *)alloc_root(mem_root,
+ !(table->insert_values= (uchar *)alloc_root(mem_root,
table->s->rec_buff_length)))
return TRUE;
}
@@ -3261,7 +3414,8 @@ bool st_table_list::prepare_view_securety_context(THD *thd)
definer.host.str,
thd->db))
{
- if (thd->lex->sql_command == SQLCOM_SHOW_CREATE)
+ if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,
@@ -3357,18 +3511,19 @@ bool st_table_list::prepare_security(THD *thd)
while ((tbl= tb++))
{
DBUG_ASSERT(tbl->referencing_view);
- char *db, *table_name;
+ char *local_db, *local_table_name;
if (tbl->view)
{
- db= tbl->view_db.str;
- table_name= tbl->view_name.str;
+ local_db= tbl->view_db.str;
+ local_table_name= tbl->view_name.str;
}
else
{
- db= tbl->db;
- table_name= tbl->table_name;
+ local_db= tbl->db;
+ local_table_name= tbl->table_name;
}
- fill_effective_table_privileges(thd, &tbl->grant, db, table_name);
+ fill_effective_table_privileges(thd, &tbl->grant, local_db,
+ local_table_name);
if (tbl->table)
tbl->table->grant= grant;
}
@@ -3440,6 +3595,7 @@ Field *Natural_join_column::field()
const char *Natural_join_column::table_name()
{
+ DBUG_ASSERT(table_ref);
return table_ref->alias;
}
@@ -3487,7 +3643,16 @@ const char *Field_iterator_table::name()
Item *Field_iterator_table::create_item(THD *thd)
{
- return new Item_field(thd, &thd->lex->current_select->context, *ptr);
+ SELECT_LEX *select= thd->lex->current_select;
+
+ Item_field *item= new Item_field(thd, &select->context, *ptr);
+ if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ select->non_agg_fields.push_back(item);
+ item->marker= select->cur_pos_in_select_list;
+ }
+ return item;
}
@@ -3727,13 +3892,13 @@ Field_iterator_table_ref::get_or_create_column_ref(TABLE_LIST *parent_table_ref)
uint field_count;
TABLE_LIST *add_table_ref= parent_table_ref ?
parent_table_ref : table_ref;
-
LINT_INIT(field_count);
+
if (field_it == &table_field_it)
{
/* The field belongs to a stored table. */
- Field *field= table_field_it.field();
- nj_col= new Natural_join_column(field, table_ref);
+ Field *tmp_field= table_field_it.field();
+ nj_col= new Natural_join_column(tmp_field, table_ref);
field_count= table_ref->table->s->fields;
}
else if (field_it == &view_field_it)
@@ -3946,7 +4111,7 @@ void st_table::mark_auto_increment_column()
*/
bitmap_set_bit(read_set, found_next_number_field->field_index);
bitmap_set_bit(write_set, found_next_number_field->field_index);
- if (s->next_number_key_offset)
+ if (s->next_number_keypart)
mark_columns_used_by_index_no_reset(s->next_number_index, read_set);
file->column_bitmaps_signal();
}
@@ -4095,19 +4260,19 @@ void st_table_list::reinit_before_use(THD *thd)
*/
table= 0;
/* Reset is_schema_table_processed value(needed for I_S tables */
- is_schema_table_processed= FALSE;
+ schema_table_state= NOT_PROCESSED;
TABLE_LIST *embedded; /* The table at the current level of nesting. */
- TABLE_LIST *embedding= this; /* The parent nested table reference. */
+ TABLE_LIST *parent_embedding= this; /* The parent nested table reference. */
do
{
- embedded= embedding;
+ embedded= parent_embedding;
if (embedded->prep_on_expr)
embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(thd);
- embedding= embedded->embedding;
+ parent_embedding= embedded->embedding;
}
- while (embedding &&
- embedding->nested_join->join_list.head() == embedded);
+ while (parent_embedding &&
+ parent_embedding->nested_join->join_list.head() == embedded);
}
/*
@@ -4128,6 +4293,193 @@ Item_subselect *st_table_list::containing_subselect()
return (select_lex ? select_lex->master_unit()->item : 0);
}
+/*
+ Compiles the tagged hints list and fills up the bitmasks.
+
+ SYNOPSIS
+ process_index_hints()
+ table the TABLE to operate on.
+
+ DESCRIPTION
+ The parser collects the index hints for each table in a "tagged list"
+ (st_table_list::index_hints). Using the information in this tagged list
+ this function sets the members st_table::keys_in_use_for_query,
+ st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
+ st_table::force_index and st_table::covering_keys.
+
+ Current implementation of the runtime does not allow mixing FORCE INDEX
+ and USE INDEX, so this is checked here. Then the FORCE INDEX list
+ (if non-empty) is appended to the USE INDEX list and a flag is set.
+
+ Multiple hints of the same kind are processed so that each clause
+ is applied to what is computed in the previous clause.
+ For example:
+ USE INDEX (i1) USE INDEX (i2)
+ is equivalent to
+ USE INDEX (i1,i2)
+ and means "consider only i1 and i2".
+
+ Similarly
+ USE INDEX () USE INDEX (i1)
+ is equivalent to
+ USE INDEX (i1)
+ and means "consider only the index i1"
+
+ It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is
+ not an error.
+
+ Different kind of hints (USE/FORCE/IGNORE) are processed in the following
+ order:
+ 1. All indexes in USE (or FORCE) INDEX are added to the mask.
+ 2. All IGNORE INDEX
+
+ e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all
+ as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1".
+
+ As an optimization if there is a covering index, and we have
+ IGNORE INDEX FOR GROUP/ORDER, and this index is used for the JOIN part,
+ then we have to ignore the IGNORE INDEX FROM GROUP/ORDER.
+
+ RETURN VALUE
+ FALSE no errors found
+ TRUE found and reported an error.
+*/
+bool st_table_list::process_index_hints(TABLE *table)
+{
+ /* initialize the result variables */
+ table->keys_in_use_for_query= table->keys_in_use_for_group_by=
+ table->keys_in_use_for_order_by= table->s->keys_in_use;
+
+ /* index hint list processing */
+ if (index_hints)
+ {
+ key_map index_join[INDEX_HINT_FORCE + 1];
+ key_map index_order[INDEX_HINT_FORCE + 1];
+ key_map index_group[INDEX_HINT_FORCE + 1];
+ index_hint *hint;
+ int type;
+ bool have_empty_use_join= FALSE, have_empty_use_order= FALSE,
+ have_empty_use_group= FALSE;
+ List_iterator <index_hint> iter(*index_hints);
+
+ /* initialize temporary variables used to collect hints of each kind */
+ for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
+ {
+ index_join[type].clear_all();
+ index_order[type].clear_all();
+ index_group[type].clear_all();
+ }
+
+ /* iterate over the hints list */
+ while ((hint= iter++))
+ {
+ uint pos;
+
+ /* process empty USE INDEX () */
+ if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
+ {
+ if (hint->clause & INDEX_HINT_MASK_JOIN)
+ {
+ index_join[hint->type].clear_all();
+ have_empty_use_join= TRUE;
+ }
+ if (hint->clause & INDEX_HINT_MASK_ORDER)
+ {
+ index_order[hint->type].clear_all();
+ have_empty_use_order= TRUE;
+ }
+ if (hint->clause & INDEX_HINT_MASK_GROUP)
+ {
+ index_group[hint->type].clear_all();
+ have_empty_use_group= TRUE;
+ }
+ continue;
+ }
+
+ /*
+ Check if an index with the given name exists and get his offset in
+ the keys bitmask for the table
+ */
+ if (table->s->keynames.type_names == 0 ||
+ (pos= find_type(&table->s->keynames, hint->key_name.str,
+ hint->key_name.length, 1)) <= 0)
+ {
+ my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
+ return 1;
+ }
+
+ pos--;
+
+ /* add to the appropriate clause mask */
+ if (hint->clause & INDEX_HINT_MASK_JOIN)
+ index_join[hint->type].set_bit (pos);
+ if (hint->clause & INDEX_HINT_MASK_ORDER)
+ index_order[hint->type].set_bit (pos);
+ if (hint->clause & INDEX_HINT_MASK_GROUP)
+ index_group[hint->type].set_bit (pos);
+ }
+
+ /* cannot mix USE INDEX and FORCE INDEX */
+ if ((!index_join[INDEX_HINT_FORCE].is_clear_all() ||
+ !index_order[INDEX_HINT_FORCE].is_clear_all() ||
+ !index_group[INDEX_HINT_FORCE].is_clear_all()) &&
+ (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join ||
+ !index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order ||
+ !index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group))
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
+ index_hint_type_name[INDEX_HINT_FORCE]);
+ return 1;
+ }
+
+ /* process FORCE INDEX as USE INDEX with a flag */
+ if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
+ !index_order[INDEX_HINT_FORCE].is_clear_all() ||
+ !index_group[INDEX_HINT_FORCE].is_clear_all())
+ {
+ table->force_index= TRUE;
+ index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]);
+ index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]);
+ index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]);
+ }
+
+ /* apply USE INDEX */
+ if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join)
+ table->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]);
+ if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order)
+ table->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]);
+ if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)
+ table->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]);
+
+ /* apply IGNORE INDEX */
+ table->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]);
+ table->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]);
+ table->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]);
+ }
+
+ /* make sure covering_keys don't include indexes disabled with a hint */
+ table->covering_keys.intersect(table->keys_in_use_for_query);
+ return 0;
+}
+
+
+size_t max_row_length(TABLE *table, const uchar *data)
+{
+ TABLE_SHARE *table_s= table->s;
+ size_t length= table_s->reclength + 2 * table_s->fields;
+ uint *const beg= table_s->blob_field;
+ uint *const end= beg + table_s->blob_fields;
+
+ for (uint *ptr= beg ; ptr != end ; ++ptr)
+ {
+ Field_blob* const blob= (Field_blob*) table->field[*ptr];
+ length+= blob->get_length((const uchar*)
+ (data + blob->offset(table->record[0]))) +
+ HA_KEY_BLOB_LENGTH;
+ }
+ return length;
+}
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/table.cc.rej b/sql/table.cc.rej
deleted file mode 100644
index fd728ba9965..00000000000
--- a/sql/table.cc.rej
+++ /dev/null
@@ -1,17 +0,0 @@
-***************
-*** 2246,2252 ****
-
- bool check_db_name(char *name)
- {
-! char *start=name;
- /* Used to catch empty names and names with end space */
- bool last_char_is_space= TRUE;
-
---- 2257,2263 ----
-
- bool check_db_name(char *name)
- {
-! char *start= name;
- /* Used to catch empty names and names with end space */
- bool last_char_is_space= TRUE;
-
diff --git a/sql/table.h b/sql/table.h
index 13666c82f4b..77807530ef1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -59,7 +58,7 @@ typedef struct st_grant_info
enum tmp_table_type
{
- NO_TMP_TABLE, TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
+ NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE
};
@@ -74,16 +73,16 @@ enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
typedef struct st_filesort_info
{
- IO_CACHE *io_cache; /* If sorted through filebyte */
- uchar **sort_keys; /* Buffer for sorting keys */
- byte *buffpek; /* Buffer for buffpek structures */
- uint buffpek_len; /* Max number of buffpeks in the buffer */
- byte *addon_buf; /* Pointer to a buffer if sorted with fields */
- uint addon_length; /* Length of the buffer */
+ IO_CACHE *io_cache; /* If sorted through filesort */
+ uchar **sort_keys; /* Buffer for sorting keys */
+ uchar *buffpek; /* Buffer for buffpek structures */
+ uint buffpek_len; /* Max number of buffpeks in the buffer */
+ uchar *addon_buf; /* Pointer to a buffer if sorted with fields */
+ size_t addon_length; /* Length of the buffer */
struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
- void (*unpack)(struct st_sort_addon_field *, byte *); /* To unpack back */
- byte *record_pointers; /* If sorted in memory */
- ha_rows found_records; /* How many records in sort */
+ void (*unpack)(struct st_sort_addon_field *, uchar *); /* To unpack back */
+ uchar *record_pointers; /* If sorted in memory */
+ ha_rows found_records; /* How many records in sort */
} FILESORT_INFO;
@@ -138,7 +137,7 @@ typedef struct st_table_share
KEY *key_info; /* data of keys in database */
uint *blob_field; /* Index to blobs in Field arrray*/
- byte *default_values; /* row with default values */
+ uchar *default_values; /* row with default values */
LEX_STRING comment; /* Comment about table */
CHARSET_INFO *table_charset; /* Default charset of string fields */
@@ -159,16 +158,26 @@ typedef struct st_table_share
LEX_STRING path; /* Path to .frm file (from datadir) */
LEX_STRING normalized_path; /* unpack_filename(path) */
LEX_STRING connect_string;
- key_map keys_in_use; /* Keys in use for table */
+
+ /*
+ Set of keys in use, implemented as a Bitmap.
+ Excludes keys disabled by ALTER TABLE ... DISABLE KEYS.
+ */
+ key_map keys_in_use;
key_map keys_for_keyread;
ha_rows min_rows, max_rows; /* create information */
ulong avg_row_length; /* create information */
ulong raid_chunksize;
- ulong version, flush_version, mysql_version;
+ ulong version, mysql_version;
ulong timestamp_offset; /* Set to offset+1 of record */
ulong reclength; /* Recordlength */
- handlerton *db_type; /* table_type for handler */
+ plugin_ref db_plugin; /* storage engine plugin */
+ inline handlerton *db_type() const /* table_type for handler */
+ {
+ // DBUG_ASSERT(db_plugin);
+ return db_plugin ? plugin_data(db_plugin, handlerton*) : NULL;
+ }
enum row_type row_type; /* How rows are stored */
enum tmp_table_type tmp_table;
@@ -193,8 +202,9 @@ typedef struct st_table_share
uint rowid_field_offset; /* Field_nr +1 to rowid field */
/* Index of auto-updated TIMESTAMP field in field array */
uint primary_key;
- uint next_number_index;
- uint next_number_key_offset;
+ uint next_number_index; /* autoincrement key number */
+ uint next_number_key_offset; /* autoinc keypart offset in a key */
+ uint next_number_keypart; /* autoinc keypart number in a key */
uint error, open_errno, errarg; /* error from open_table_def() */
uint column_bitmap_size;
uchar frm_version;
@@ -231,9 +241,9 @@ typedef struct st_table_share
bool log_table;
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool auto_partitioned;
- const uchar *partition_info;
+ const char *partition_info;
uint partition_info_len;
- const uchar *part_state;
+ const char *part_state;
uint part_state_len;
handlerton *default_part_db_type;
#endif
@@ -294,7 +304,15 @@ typedef struct st_table_share
} TABLE_SHARE;
+extern ulong refresh_version;
+
/* Information for one open table */
+enum index_hint_type
+{
+ INDEX_HINT_IGNORE,
+ INDEX_HINT_USE,
+ INDEX_HINT_FORCE
+};
struct st_table {
st_table() {} /* Remove gcc warning */
@@ -303,18 +321,39 @@ struct st_table {
handler *file;
#ifdef NOT_YET
struct st_table *used_next, **used_prev; /* Link to used tables */
-#endif
struct st_table *open_next, **open_prev; /* Link to open tables */
+#endif
struct st_table *next, *prev;
THD *in_use; /* Which thread uses this */
Field **field; /* Pointer to fields */
- byte *record[2]; /* Pointer to records */
- byte *write_row_record; /* Used as optimisation in
+ uchar *record[2]; /* Pointer to records */
+ uchar *write_row_record; /* Used as optimisation in
THD::write_row */
- byte *insert_values; /* used by INSERT ... UPDATE */
- key_map quick_keys, used_keys, keys_in_use_for_query, merge_keys;
+ uchar *insert_values; /* used by INSERT ... UPDATE */
+ /*
+ Map of keys that can be used to retrieve all data from this table
+ needed by the query without reading the row.
+ */
+ key_map covering_keys;
+ key_map quick_keys, merge_keys;
+ /*
+ A set of keys that can be used in the query that references this
+ table.
+
+ All indexes disabled on the table's TABLE_SHARE (see TABLE::s) will be
+ subtracted from this set upon instantiation. Thus for any TABLE t it holds
+ that t.keys_in_use_for_query is a subset of t.s.keys_in_use. Generally we
+ must not introduce any new keys here (see setup_tables).
+
+ The set is implemented as a bitmap.
+ */
+ key_map keys_in_use_for_query;
+ /* Map of keys that can be used to calculate GROUP BY without sorting */
+ key_map keys_in_use_for_group_by;
+ /* Map of keys that can be used to calculate ORDER BY without sorting */
+ key_map keys_in_use_for_order_by;
KEY *key_info; /* data of keys in database */
Field *next_number_field; /* Set if next_number is activated */
@@ -392,16 +431,45 @@ struct st_table {
NULL, including columns declared as "not null" (see maybe_null).
*/
my_bool null_row;
+
+ /*
+ TODO: Each of the following flags take up 8 bits. They can just as easily
+ be put into one single unsigned long and instead of taking up 18
+ bytes, it would take up 4.
+ */
my_bool force_index;
my_bool distinct,const_table,no_rows;
my_bool key_read, no_keyread;
- my_bool locked_by_flush;
+ /*
+ Placeholder for an open table which prevents other connections
+ from taking name-locks on this table. Typically used with
+ TABLE_SHARE::version member to take an exclusive name-lock on
+ this table name -- a name lock that not only prevents other
+ threads from opening the table, but also blocks other name
+ locks. This is achieved by:
+ - setting open_placeholder to 1 - this will block other name
+ locks, as wait_for_locked_table_name will be forced to wait,
+ see table_is_used for details.
+ - setting version to 0 - this will force other threads to close
+ the instance of this table and wait (this is the same approach
+ as used for usual name locks).
+ An exclusively name-locked table currently can have no handler
+ object associated with it (db_stat is always 0), but please do
+ not rely on that.
+ */
+ my_bool open_placeholder;
my_bool locked_by_logger;
+ my_bool no_replicate;
my_bool locked_by_name;
my_bool fulltext_searched;
my_bool no_cache;
/* To signal that we should reset query_id for tables and cols */
my_bool clear_query_id;
+ /*
+ To indicate that a non-null value of the auto_increment field
+ was provided by the user or retrieved from the current record.
+ Used only in the MODE_NO_AUTO_VALUE_ON_ZERO mode.
+ */
my_bool auto_increment_field_not_null;
my_bool insert_or_update; /* Can be used by the handler */
my_bool alias_name_used; /* true if table_name is alias */
@@ -450,9 +518,21 @@ struct st_table {
read_set= &def_read_set;
write_set= &def_write_set;
}
-
+ /* Is table open or should be treated as such by name-locking? */
+ inline bool is_name_opened() { return db_stat || open_placeholder; }
+ /*
+ Is this instance of the table should be reopen or represents a name-lock?
+ */
+ inline bool needs_reopen_or_name_lock()
+ { return s->version != refresh_version; }
};
+enum enum_schema_table_state
+{
+ NOT_PROCESSED= 0,
+ PROCESSED_BY_CREATE_SORT_INDEX,
+ PROCESSED_BY_JOIN_EXEC
+};
typedef struct st_foreign_key_info
{
@@ -461,6 +541,7 @@ typedef struct st_foreign_key_info
LEX_STRING *referenced_table;
LEX_STRING *update_method;
LEX_STRING *delete_method;
+ LEX_STRING *referenced_key_name;
List<LEX_STRING> foreign_fields;
List<LEX_STRING> referenced_fields;
} FOREIGN_KEY_INFO;
@@ -505,13 +586,17 @@ enum enum_schema_tables
};
+#define MY_I_S_MAYBE_NULL 1
+#define MY_I_S_UNSIGNED 2
+
+
typedef struct st_field_info
{
const char* field_name;
uint field_length;
enum enum_field_types field_type;
int value;
- bool maybe_null;
+ uint field_flags; // Field atributes(maybe_null, signed, unsigned etc.)
const char* old_name;
} ST_FIELD_INFO;
@@ -636,9 +721,25 @@ public:
(TABLE_LIST::join_using_fields != NULL)
*/
+class index_hint;
typedef struct st_table_list
{
st_table_list() {} /* Remove gcc warning */
+
+ /**
+ Prepare TABLE_LIST that consists of one table instance to use in
+ simple_open_and_lock_tables
+ */
+ inline void init_one_table(const char *db_name_arg,
+ const char *table_name_arg,
+ enum thr_lock_type lock_type_arg)
+ {
+ bzero((char*) this, sizeof(*this));
+ db= (char*) db_name_arg;
+ table_name= alias= (char*) table_name_arg;
+ lock_type= lock_type_arg;
+ }
+
/*
List of tables local to a subquery (used by SQL_LIST). Considers
views as leaves (unlike 'next_leaf' below). Created at parse time
@@ -692,7 +793,7 @@ typedef struct st_table_list
*/
struct st_table_list *next_name_resolution_table;
/* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */
- List<String> *use_index, *ignore_index;
+ List<index_hint> *index_hints;
TABLE *table; /* opened table */
uint table_id; /* table id (from binlog) for opened table */
/*
@@ -711,7 +812,6 @@ typedef struct st_table_list
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;
- bool is_schema_table_processed;
/*
True when the view field translation table is used to convert
schema table fields for backwards compatibility with SHOW command.
@@ -789,8 +889,8 @@ typedef struct st_table_list
thr_lock_type lock_type;
uint outer_join; /* Which join type */
uint shared; /* Used in multi-upd */
- uint db_length;
- uint32 table_name_length;
+ size_t db_length;
+ size_t table_name_length;
bool updatable; /* VIEW/TABLE can be updated now */
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
@@ -811,6 +911,8 @@ typedef struct st_table_list
bool compact_view_format; /* Use compact format for SHOW CREATE VIEW */
/* view where processed */
bool where_processed;
+ /* TRUE <=> VIEW CHECK OPTION expression has been processed */
+ bool check_option_processed;
/* FRMTYPE_ERROR if any type is acceptable */
enum frm_type_enum required_type;
handlerton *db_type; /* table_type for handler */
@@ -820,13 +922,24 @@ typedef struct st_table_list
used for implicit LOCK TABLES only and won't be used in real statement.
*/
bool prelocking_placeholder;
+ /*
+ This TABLE_LIST object corresponds to the table to be created
+ so it is possible that it does not exist (used in CREATE TABLE
+ ... SELECT implementation).
+ */
+ bool create;
+ enum enum_schema_table_state schema_table_state;
void calc_md5(char *buffer);
void set_underlying_merge();
int view_check_option(THD *thd, bool ignore_failure);
bool setup_underlying(THD *thd);
void cleanup_items();
- bool placeholder() {return derived || view; }
+ bool placeholder()
+ {
+ return derived || view || schema_table || create && !table->db_stat ||
+ !table;
+ }
void print(THD *thd, String *str);
bool check_single_table(st_table_list **table, table_map map,
st_table_list *view);
@@ -866,6 +979,13 @@ typedef struct st_table_list
void reinit_before_use(THD *thd);
Item_subselect *containing_subselect();
+ /*
+ Compiles the tagged hints list and fills up st_table::keys_in_use_for_query,
+ st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by,
+ st_table::force_index and st_table::covering_keys.
+ */
+ bool process_index_hints(TABLE *table);
+
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
@@ -1040,8 +1160,7 @@ typedef struct st_table_field_w_type
my_bool
table_check_intact(TABLE *table, const uint table_f_count,
- const TABLE_FIELD_W_TYPE *table_def,
- time_t *last_create_time, int error_num);
+ const TABLE_FIELD_W_TYPE *table_def);
static inline my_bitmap_map *tmp_use_all_columns(TABLE *table,
MY_BITMAP *bitmap)
@@ -1077,3 +1196,6 @@ static inline void dbug_tmp_restore_column_map(MY_BITMAP *bitmap,
tmp_restore_column_map(bitmap, old);
#endif
}
+
+size_t max_row_length(TABLE *table, const uchar *data);
+
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index 3a9ca397bba..ddf35002880 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001, 2003-2004 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -36,26 +35,25 @@ void init_sql_alloc(MEM_ROOT *mem_root, uint block_size, uint pre_alloc)
}
-gptr sql_alloc(uint Size)
+void *sql_alloc(size_t Size)
{
MEM_ROOT *root= *my_pthread_getspecific_ptr(MEM_ROOT**,THR_MALLOC);
- char *ptr= (char*) alloc_root(root,Size);
- return ptr;
+ return alloc_root(root,Size);
}
-gptr sql_calloc(uint size)
+void *sql_calloc(size_t size)
{
- gptr ptr;
+ void *ptr;
if ((ptr=sql_alloc(size)))
- bzero((char*) ptr,size);
+ bzero(ptr,size);
return ptr;
}
char *sql_strdup(const char *str)
{
- uint len=(uint) strlen(str)+1;
+ size_t len= strlen(str)+1;
char *pos;
if ((pos= (char*) sql_alloc(len)))
memcpy(pos,str,len);
@@ -63,7 +61,7 @@ char *sql_strdup(const char *str)
}
-char *sql_strmake(const char *str,uint len)
+char *sql_strmake(const char *str, size_t len)
{
char *pos;
if ((pos= (char*) sql_alloc(len+1)))
@@ -75,10 +73,10 @@ char *sql_strmake(const char *str,uint len)
}
-gptr sql_memdup(const void *ptr,uint len)
+void* sql_memdup(const void *ptr, size_t len)
{
- char *pos;
- if ((pos= (char*) sql_alloc(len)))
+ void *pos;
+ if ((pos= sql_alloc(len)))
memcpy(pos,ptr,len);
return pos;
}
@@ -88,17 +86,17 @@ void sql_element_free(void *ptr __attribute__((unused)))
-char *sql_strmake_with_convert(const char *str, uint32 arg_length,
+char *sql_strmake_with_convert(const char *str, size_t arg_length,
CHARSET_INFO *from_cs,
- uint32 max_res_length,
- CHARSET_INFO *to_cs, uint32 *result_length)
+ size_t max_res_length,
+ CHARSET_INFO *to_cs, size_t *result_length)
{
char *pos;
- uint32 new_length= to_cs->mbmaxlen*arg_length;
+ size_t 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)))
+ if (!(pos= (char*) sql_alloc(new_length+1)))
return pos; // Error
if ((from_cs == &my_charset_bin) || (to_cs == &my_charset_bin))
diff --git a/sql/time.cc b/sql/time.cc
index 85096cd27ac..c552d085f5e 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -97,7 +96,7 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week)
next week is week 1.
*/
-uint calc_week(TIME *l_time, uint week_behaviour, uint *year)
+uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
{
uint days;
ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
@@ -215,7 +214,7 @@ ulong convert_month_to_period(ulong month)
/*
- Convert a timestamp string to a TIME value and produce a warning
+ Convert a timestamp string to a MYSQL_TIME value and produce a warning
if string was truncated during conversion.
NOTE
@@ -223,7 +222,7 @@ ulong convert_month_to_period(ulong month)
*/
timestamp_type
-str_to_datetime_with_warn(const char *str, uint length, TIME *l_time,
+str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
uint flags)
{
int was_cut;
@@ -236,13 +235,14 @@ str_to_datetime_with_warn(const char *str, uint length, TIME *l_time,
MODE_NO_ZERO_DATE))),
&was_cut);
if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
- make_truncated_value_warning(current_thd, str, length, ts_type, NullS);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ str, length, ts_type, NullS);
return ts_type;
}
/*
- Convert a datetime from broken-down TIME representation to corresponding
+ Convert a datetime from broken-down MYSQL_TIME representation to corresponding
TIMESTAMP value.
SYNOPSIS
@@ -258,7 +258,7 @@ str_to_datetime_with_warn(const char *str, uint length, TIME *l_time,
0 - t contains datetime value which is out of TIMESTAMP range.
*/
-my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap)
+my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap)
{
my_time_t timestamp;
@@ -277,20 +277,20 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap)
/*
- Convert a time string to a TIME struct and produce a warning
+ Convert a time string to a MYSQL_TIME struct and produce a warning
if string was cut during conversion.
NOTE
See str_to_time() for more info.
*/
bool
-str_to_time_with_warn(const char *str, uint length, TIME *l_time)
+str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
{
int warning;
bool ret_val= str_to_time(str, length, l_time, &warning);
if (ret_val || warning)
- make_truncated_value_warning(current_thd, str, length,
- MYSQL_TIMESTAMP_TIME, NullS);
+ make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ str, length, MYSQL_TIMESTAMP_TIME, NullS);
return ret_val;
}
@@ -299,7 +299,7 @@ str_to_time_with_warn(const char *str, uint length, TIME *l_time)
Convert a system time structure to TIME
*/
-void localtime_to_TIME(TIME *to, struct tm *from)
+void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
{
to->neg=0;
to->second_part=0;
@@ -311,9 +311,14 @@ void localtime_to_TIME(TIME *to, struct tm *from)
to->second= (int) from->tm_sec;
}
-void calc_time_from_sec(TIME *to, long seconds, long microseconds)
+void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds)
{
long t_seconds;
+ // to->neg is not cleared, it may already be set to a useful value
+ to->time_type= MYSQL_TIMESTAMP_TIME;
+ to->year= 0;
+ to->month= 0;
+ to->day= 0;
to->hour= seconds/3600L;
t_seconds= seconds%3600L;
to->minute= t_seconds/60L;
@@ -680,7 +685,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
MySQL doesn't support comparing of date/time/datetime strings that
are not in arbutary order as dates are compared as strings in some
context)
- This functions don't check that given TIME structure members are
+ This functions don't check that given MYSQL_TIME structure members are
in valid range. If they are not, return value won't reflect any
valid date either. Additionally, make_time doesn't take into
account time->day member: it's assumed that days have been converted
@@ -688,7 +693,7 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
****************************************************************************/
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
- const TIME *l_time, String *str)
+ const MYSQL_TIME *l_time, String *str)
{
uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
str->length(length);
@@ -697,7 +702,7 @@ void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
- const TIME *l_time, String *str)
+ const MYSQL_TIME *l_time, String *str)
{
uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
str->length(length);
@@ -706,7 +711,7 @@ void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
- const TIME *l_time, String *str)
+ const MYSQL_TIME *l_time, String *str)
{
uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
str->length(length);
@@ -714,7 +719,8 @@ void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
}
-void make_truncated_value_warning(THD *thd, const char *str_val,
+void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ const char *str_val,
uint str_length, timestamp_type time_type,
const char *field_name)
{
@@ -753,14 +759,14 @@ void make_truncated_value_warning(THD *thd, const char *str_val,
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
ER(ER_WRONG_VALUE), type_str, str.c_ptr());
}
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, level,
ER_TRUNCATED_WRONG_VALUE, warn_buff);
}
/* Daynumber from year 0 to 9999-12-31 */
#define MAX_DAY_NUMBER 3652424L
-bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval)
+bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
{
long period, sign;
@@ -854,8 +860,9 @@ bool date_add_interval(TIME *ltime, interval_type int_type, INTERVAL interval)
}
break;
default:
- return 1;
+ goto null_date;
}
+
return 0; // Ok
invalid_date:
@@ -863,6 +870,7 @@ invalid_date:
ER_DATETIME_FUNCTION_OVERFLOW,
ER(ER_DATETIME_FUNCTION_OVERFLOW),
"datetime");
+null_date:
return 1;
}
@@ -884,7 +892,7 @@ invalid_date:
NOTE
This function calculates difference between l_time1 and l_time2 absolute
values. So one should set l_sign and correct result if he want to take
- signs into account (i.e. for TIME values).
+ signs into account (i.e. for MYSQL_TIME values).
RETURN VALUES
Returns sign of difference.
@@ -894,7 +902,7 @@ invalid_date:
*/
bool
-calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign, longlong *seconds_out,
+calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *seconds_out,
long *microseconds_out)
{
long days;
@@ -944,7 +952,7 @@ calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign, longlong *seconds_out,
/*
- Compares 2 TIME structures
+ Compares 2 MYSQL_TIME structures
SYNOPSIS
my_time_compare()
@@ -962,7 +970,7 @@ calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign, longlong *seconds_out,
*/
int
-my_time_compare(TIME *a, TIME *b)
+my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
{
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
diff --git a/sql/tzfile.h b/sql/tzfile.h
index 623cddc1f12..1ff82d62329 100644
--- a/sql/tzfile.h
+++ b/sql/tzfile.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,14 +34,14 @@
#define TZ_MAGIC "TZif"
struct tzhead {
- char tzh_magic[4]; /* TZ_MAGIC */
- char tzh_reserved[16]; /* reserved for future use */
- char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
- char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
- char tzh_leapcnt[4]; /* coded number of leap seconds */
- char tzh_timecnt[4]; /* coded number of transition times */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
+ uchar tzh_magic[4]; /* TZ_MAGIC */
+ uchar tzh_reserved[16]; /* reserved for future use */
+ uchar tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ uchar tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ uchar tzh_leapcnt[4]; /* coded number of leap seconds */
+ uchar tzh_timecnt[4]; /* coded number of transition times */
+ uchar tzh_typecnt[4]; /* coded number of local time types */
+ uchar tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
diff --git a/sql/tztime.cc b/sql/tztime.cc
index c44a907c07b..0c717dd2ece 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -78,7 +77,7 @@ typedef struct lsinfo
/*
Structure with information describing ranges of my_time_t shifted to local
- time (my_time_t + offset). Used for local TIME -> my_time_t conversion.
+ time (my_time_t + offset). Used for local MYSQL_TIME -> my_time_t conversion.
See comments for TIME_to_gmt_sec() for more info.
*/
typedef struct revtinfo
@@ -154,7 +153,7 @@ static my_bool prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage);
static my_bool
tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
{
- char *p;
+ uchar *p;
int read_from_file;
uint i;
FILE *file;
@@ -165,8 +164,8 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
union
{
struct tzhead tzhead;
- char buf[sizeof(struct tzhead) + sizeof(my_time_t) * TZ_MAX_TIMES +
- TZ_MAX_TIMES + sizeof(TRAN_TYPE_INFO) * TZ_MAX_TYPES +
+ uchar buf[sizeof(struct tzhead) + sizeof(my_time_t) * TZ_MAX_TIMES +
+ TZ_MAX_TIMES + sizeof(TRAN_TYPE_INFO) * TZ_MAX_TYPES +
#ifdef ABBR_ARE_USED
max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1))) +
#endif
@@ -190,7 +189,7 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
sp->timecnt= int4net(u.tzhead.tzh_timecnt);
sp->typecnt= int4net(u.tzhead.tzh_typecnt);
sp->charcnt= int4net(u.tzhead.tzh_charcnt);
- p= u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
+ p= u.tzhead.tzh_charcnt + sizeof(u.tzhead.tzh_charcnt);
if (sp->leapcnt > TZ_MAX_LEAPS ||
sp->typecnt == 0 || sp->typecnt > TZ_MAX_TYPES ||
sp->timecnt > TZ_MAX_TIMES ||
@@ -293,9 +292,9 @@ tz_load(const char *name, TIME_ZONE_INFO *sp, MEM_ROOT *storage)
be used if there are no transitions or we have moment in time before
any transitions.
Second task is to build "shifted my_time_t" -> my_time_t map used in
- TIME -> my_time_t conversion.
+ MYSQL_TIME -> my_time_t conversion.
Note: See description of TIME_to_gmt_sec() function first.
- In order to perform TIME -> my_time_t conversion we need to build table
+ In order to perform MYSQL_TIME -> my_time_t conversion we need to build table
which defines "shifted by tz offset and leap seconds my_time_t" ->
my_time_t function wich is almost the same (except ranges of ambiguity)
as reverse function to piecewise linear function used for my_time_t ->
@@ -532,14 +531,14 @@ static const uint year_lengths[2]=
offset - local time zone offset
DESCRIPTION
- Convert my_time_t with offset to TIME struct. Differs from timesub
+ Convert my_time_t with offset to MYSQL_TIME struct. Differs from timesub
(from elsie code) because doesn't contain any leap correction and
TM_GMTOFF and is_dst setting and contains some MySQL specific
initialization. Funny but with removing of these we almost have
glibc's offtime function.
*/
static void
-sec_to_TIME(TIME * tmp, my_time_t t, long offset)
+sec_to_TIME(MYSQL_TIME * tmp, my_time_t t, long offset)
{
long days;
long rem;
@@ -547,8 +546,8 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset)
int yleap;
const uint *ip;
- days= t / SECS_PER_DAY;
- rem= t % SECS_PER_DAY;
+ days= (long) (t / SECS_PER_DAY);
+ rem= (long) (t % SECS_PER_DAY);
/*
We do this as separate step after dividing t, because this
@@ -595,7 +594,7 @@ sec_to_TIME(TIME * tmp, my_time_t t, long offset)
tmp->month++;
tmp->day= (uint)(days + 1);
- /* filling MySQL specific TIME members */
+ /* filling MySQL specific MYSQL_TIME members */
tmp->neg= 0; tmp->second_part= 0;
tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
}
@@ -687,7 +686,7 @@ find_transition_type(my_time_t t, const TIME_ZONE_INFO *sp)
/*
Converts time in my_time_t representation (seconds in UTC since Epoch) to
- broken down TIME representation in local time zone.
+ broken down MYSQL_TIME representation in local time zone.
SYNOPSIS
gmt_sec_to_TIME()
@@ -702,12 +701,12 @@ find_transition_type(my_time_t t, const TIME_ZONE_INFO *sp)
(60th and 61st second, look how we calculate them as "hit" in this
function).
Under realistic assumptions about frequency of transitions the same array
- can be used fot TIME -> my_time_t conversion. For this we need to
+ can be used fot MYSQL_TIME -> my_time_t conversion. For this we need to
implement tweaked binary search which will take into account that some
- TIME has two matching my_time_t ranges and some of them have none.
+ MYSQL_TIME has two matching my_time_t ranges and some of them have none.
*/
static void
-gmt_sec_to_TIME(TIME *tmp, my_time_t sec_in_utc, const TIME_ZONE_INFO *sp)
+gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t sec_in_utc, const TIME_ZONE_INFO *sp)
{
const TRAN_TYPE_INFO *ttisp;
const LS_INFO *lp;
@@ -781,6 +780,8 @@ gmt_sec_to_TIME(TIME *tmp, my_time_t sec_in_utc, const TIME_ZONE_INFO *sp)
static my_time_t
sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
{
+ /* Guard against my_time_t overflow(on system with 32 bit my_time_t) */
+ DBUG_ASSERT(!(year == TIMESTAMP_MAX_YEAR && mon == 1 && mday > 17));
#ifndef WE_WANT_TO_HANDLE_UNORMALIZED_DATES
/*
It turns out that only whenever month is normalized or unnormalized
@@ -808,11 +809,11 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
/*
- Works like sec_since_epoch but expects TIME structure as parameter.
+ Works like sec_since_epoch but expects MYSQL_TIME structure as parameter.
*/
my_time_t
-sec_since_epoch_TIME(TIME *t)
+sec_since_epoch_TIME(MYSQL_TIME *t)
{
return sec_since_epoch(t->year, t->month, t->day,
t->hour, t->minute, t->second);
@@ -820,7 +821,7 @@ sec_since_epoch_TIME(TIME *t)
/*
- Converts local time in broken down TIME representation to my_time_t
+ Converts local time in broken down MYSQL_TIME representation to my_time_t
representation.
SYNOPSIS
@@ -862,7 +863,7 @@ sec_since_epoch_TIME(TIME *t)
We use completely different approach. It is better since it is both
faster than iterative implementations and fully determenistic. If you
- look at my_time_t to TIME conversion then you'll find that it consist
+ look at my_time_t to MYSQL_TIME conversion then you'll find that it consist
of two steps:
The first is calculating shifted my_time_t value and the second - TIME
calculation from shifted my_time_t value (well it is a bit simplified
@@ -892,7 +893,7 @@ sec_since_epoch_TIME(TIME *t)
0 in case of error.
*/
static my_time_t
-TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
+TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
my_bool *in_dst_time_gap)
{
my_time_t local_t;
@@ -961,12 +962,12 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp,
*/
if (shift)
{
- if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift*86400L +
+ if (local_t > (my_time_t) (TIMESTAMP_MAX_VALUE - shift * SECS_PER_DAY +
sp->revtis[i].rt_offset - saved_seconds))
{
DBUG_RETURN(0); /* my_time_t overflow */
}
- local_t+= shift*86400L;
+ local_t+= shift * SECS_PER_DAY;
}
if (sp->revtis[i].rt_type)
@@ -1019,20 +1020,20 @@ class Time_zone_system : public Time_zone
{
public:
Time_zone_system() {} /* Remove gcc warning */
- virtual my_time_t TIME_to_gmt_sec(const TIME *t,
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
my_bool *in_dst_time_gap) const;
- virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
+ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
/*
- Converts local time in system time zone in TIME representation
+ Converts local time in system time zone in MYSQL_TIME representation
to its my_time_t representation.
SYNOPSIS
TIME_to_gmt_sec()
- t - pointer to TIME structure with local time in
+ t - pointer to MYSQL_TIME structure with local time in
broken-down representation.
in_dst_time_gap - pointer to bool which is set to true if datetime
value passed doesn't really exist (i.e. falls into
@@ -1040,7 +1041,7 @@ public:
DESCRIPTION
This method uses system function (localtime_r()) for conversion
- local time in system time zone in TIME structure to its my_time_t
+ local time in system time zone in MYSQL_TIME structure to its my_time_t
representation. Unlike the same function for Time_zone_db class
it it won't handle unnormalized input properly. Still it will
return lowest possible my_time_t in case of ambiguity or if we
@@ -1052,7 +1053,7 @@ public:
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_system::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_system::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
{
long not_used;
return my_system_gmt_sec(t, &not_used, in_dst_time_gap);
@@ -1065,7 +1066,7 @@ Time_zone_system::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
SYNOPSIS
gmt_sec_to_TIME()
- tmp - pointer to TIME structure to fill-in
+ tmp - pointer to MYSQL_TIME structure to fill-in
t - my_time_t value to be converted
NOTE
@@ -1076,7 +1077,7 @@ Time_zone_system::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
the 1902 easily.
*/
void
-Time_zone_system::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
+Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{
struct tm tmp_tm;
time_t tmp_t= (time_t)t;
@@ -1106,26 +1107,26 @@ Time_zone_system::get_name() const
/*
Instance of this class represents UTC time zone. It uses system gmtime_r
function for conversions and is always available. It is used only for
- my_time_t -> TIME conversions in various UTC_... functions, it is not
- intended for TIME -> my_time_t conversions and shouldn't be exposed to user.
+ my_time_t -> MYSQL_TIME conversions in various UTC_... functions, it is not
+ intended for MYSQL_TIME -> my_time_t conversions and shouldn't be exposed to user.
*/
class Time_zone_utc : public Time_zone
{
public:
Time_zone_utc() {} /* Remove gcc warning */
- virtual my_time_t TIME_to_gmt_sec(const TIME *t,
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
my_bool *in_dst_time_gap) const;
- virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
+ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
};
/*
- Convert UTC time from TIME representation to its my_time_t representation.
+ Convert UTC time from MYSQL_TIME representation to its my_time_t representation.
SYNOPSIS
TIME_to_gmt_sec()
- t - pointer to TIME structure with local time
+ t - pointer to MYSQL_TIME structure with local time
in broken-down representation.
in_dst_time_gap - pointer to bool which is set to true if datetime
value passed doesn't really exist (i.e. falls into
@@ -1140,7 +1141,7 @@ public:
0
*/
my_time_t
-Time_zone_utc::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_utc::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
{
/* Should be never called */
DBUG_ASSERT(0);
@@ -1154,14 +1155,14 @@ Time_zone_utc::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
SYNOPSIS
gmt_sec_to_TIME()
- tmp - pointer to TIME structure to fill-in
+ tmp - pointer to MYSQL_TIME structure to fill-in
t - my_time_t value to be converted
NOTE
See note for apropriate Time_zone_system method.
*/
void
-Time_zone_utc::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
+Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{
struct tm tmp_tm;
time_t tmp_t= (time_t)t;
@@ -1202,9 +1203,9 @@ class Time_zone_db : public Time_zone
{
public:
Time_zone_db(TIME_ZONE_INFO *tz_info_arg, const String * tz_name_arg);
- virtual my_time_t TIME_to_gmt_sec(const TIME *t,
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
my_bool *in_dst_time_gap) const;
- virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
+ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
private:
TIME_ZONE_INFO *tz_info;
@@ -1238,7 +1239,7 @@ Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
SYNOPSIS
TIME_to_gmt_sec()
- t - pointer to TIME structure with local time
+ t - pointer to MYSQL_TIME structure with local time
in broken-down representation.
in_dst_time_gap - pointer to bool which is set to true if datetime
value passed doesn't really exist (i.e. falls into
@@ -1252,7 +1253,7 @@ Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_db::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_db::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
{
return ::TIME_to_gmt_sec(t, tz_info, in_dst_time_gap);
}
@@ -1264,11 +1265,11 @@ Time_zone_db::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
SYNOPSIS
gmt_sec_to_TIME()
- tmp - pointer to TIME structure to fill-in
+ tmp - pointer to MYSQL_TIME structure to fill-in
t - my_time_t value to be converted
*/
void
-Time_zone_db::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
+Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{
::gmt_sec_to_TIME(tmp, t, tz_info);
}
@@ -1298,9 +1299,9 @@ class Time_zone_offset : public Time_zone
{
public:
Time_zone_offset(long tz_offset_arg);
- virtual my_time_t TIME_to_gmt_sec(const TIME *t,
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
my_bool *in_dst_time_gap) const;
- virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const;
+ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
virtual const String * get_name() const;
/*
This have to be public because we want to be able to access it from
@@ -1335,11 +1336,11 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
/*
Converts local time in time zone described as offset from UTC
- from TIME representation to its my_time_t representation.
+ from MYSQL_TIME representation to its my_time_t representation.
SYNOPSIS
TIME_to_gmt_sec()
- t - pointer to TIME structure with local time
+ t - pointer to MYSQL_TIME structure with local time
in broken-down representation.
in_dst_time_gap - pointer to bool which should be set to true if
datetime value passed doesn't really exist
@@ -1351,9 +1352,10 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
Corresponding my_time_t value or 0 in case of error
*/
my_time_t
-Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
+Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t, my_bool *in_dst_time_gap) const
{
my_time_t local_t;
+ int shift= 0;
/*
Check timestamp range.we have to do this as calling function relies on
@@ -1362,10 +1364,24 @@ Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
if (!validate_timestamp_range(t))
return 0;
- local_t= sec_since_epoch(t->year, t->month, t->day,
+ /*
+ Do a temporary shift of the boundary dates to avoid
+ overflow of my_time_t if the time value is near it's
+ maximum range
+ */
+ if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && t->day > 4)
+ shift= 2;
+
+ local_t= sec_since_epoch(t->year, t->month, (t->day - shift),
t->hour, t->minute, t->second) -
offset;
+ if (shift)
+ {
+ /* Add back the shifted time */
+ local_t+= shift * SECS_PER_DAY;
+ }
+
if (local_t >= TIMESTAMP_MIN_VALUE && local_t <= TIMESTAMP_MAX_VALUE)
return local_t;
@@ -1381,11 +1397,11 @@ Time_zone_offset::TIME_to_gmt_sec(const TIME *t, my_bool *in_dst_time_gap) const
SYNOPSIS
gmt_sec_to_TIME()
- tmp - pointer to TIME structure to fill-in
+ tmp - pointer to MYSQL_TIME structure to fill-in
t - my_time_t value to be converted
*/
void
-Time_zone_offset::gmt_sec_to_TIME(TIME *tmp, my_time_t t) const
+Time_zone_offset::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
{
sec_to_TIME(tmp, t, offset);
}
@@ -1473,42 +1489,39 @@ public:
they should obey C calling conventions.
*/
-extern "C" byte* my_tz_names_get_key(Tz_names_entry *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" uchar *
+my_tz_names_get_key(Tz_names_entry *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= entry->name.length();
- return (byte*) entry->name.ptr();
+ return (uchar*) entry->name.ptr();
}
-extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" uchar *
+my_offset_tzs_get_key(Time_zone_offset *entry,
+ size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length= sizeof(long);
- return (byte*) &entry->offset;
+ return (uchar*) &entry->offset;
}
/*
- Prepare table list with time zone related tables from preallocated array
- and add to global table list.
+ Prepare table list with time zone related tables from preallocated array.
SYNOPSIS
tz_init_table_list()
tz_tabs - pointer to preallocated array of MY_TZ_TABLES_COUNT
TABLE_LIST objects
- global_next_ptr - pointer to variable which points to global_next member
- of last element of global table list (or list root
- then list is empty) (in/out).
DESCRIPTION
This function prepares list of TABLE_LIST objects which can be used
- for opening of time zone tables from preallocated array. It also links
- this list to the end of global table list (it will read and update
- accordingly variable pointed by global_next_ptr for this).
+ for opening of time zone tables from preallocated array.
*/
static void
-tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
+tz_init_table_list(TABLE_LIST *tz_tabs)
{
bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
@@ -1525,64 +1538,6 @@ tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
if (i != 0)
tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
}
-
- /* Link into global list */
- tz_tabs[0].prev_global= *global_next_ptr;
- **global_next_ptr= tz_tabs;
- /* Update last-global-pointer to point to pointer in last table */
- *global_next_ptr= &tz_tabs[MY_TZ_TABLES_COUNT-1].next_global;
-}
-
-
-/*
- Fake table list object, pointer to which is returned by
- my_tz_get_tables_list() as indication of error.
-*/
-TABLE_LIST fake_time_zone_tables_list;
-
-/*
- Create table list with time zone related tables and add it to the end
- of global table list.
-
- SYNOPSIS
- my_tz_get_table_list()
- thd - current thread object
- global_next_ptr - pointer to variable which points to global_next member
- of last element of global table list (or list root
- then list is empty) (in/out).
-
- DESCRIPTION
- This function creates list of TABLE_LIST objects allocated in thd's
- memroot, which can be used for opening of time zone tables. It will also
- link this list to the end of global table list (it will read and update
- accordingly variable pointed by global_next_ptr for this).
-
- NOTE
- my_tz_check_n_skip_implicit_tables() function depends on fact that
- elements of list created are allocated as TABLE_LIST[MY_TZ_TABLES_COUNT]
- array.
-
- RETURN VALUES
- Returns pointer to first TABLE_LIST object, (could be 0 if time zone
- tables don't exist) and &fake_time_zone_tables_list in case of error.
-*/
-
-TABLE_LIST *
-my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr)
-{
- TABLE_LIST *tz_tabs;
- DBUG_ENTER("my_tz_get_table_list");
-
- if (!time_zone_tables_exist)
- DBUG_RETURN(0);
-
- if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) *
- MY_TZ_TABLES_COUNT)))
- DBUG_RETURN(&fake_time_zone_tables_list);
-
- tz_init_table_list(tz_tabs, global_next_ptr);
-
- DBUG_RETURN(tz_tabs);
}
@@ -1615,8 +1570,8 @@ my_bool
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
- TABLE_LIST *tables= 0;
- TABLE_LIST tables_buff[1+MY_TZ_TABLES_COUNT], **last_global_next_ptr;
+ TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
+ Open_tables_state open_tables_state_backup;
TABLE *table;
Tz_names_entry *tmp_tzname;
my_bool return_val= 1;
@@ -1634,7 +1589,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
/* Init all memory structures that require explicit destruction */
if (hash_init(&tz_names, &my_charset_latin1, 20,
- 0, 0, (hash_get_key)my_tz_names_get_key, 0, 0))
+ 0, 0, (hash_get_key) my_tz_names_get_key, 0, 0))
{
sql_print_error("Fatal error: OOM while initializing time zones");
goto end;
@@ -1658,7 +1613,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
}
tmp_tzname->name.set(STRING_WITH_LEN("SYSTEM"), &my_charset_latin1);
tmp_tzname->tz= my_tz_SYSTEM;
- if (my_hash_insert(&tz_names, (const byte *)tmp_tzname))
+ if (my_hash_insert(&tz_names, (const uchar *)tmp_tzname))
{
sql_print_error("Fatal error: OOM while initializing time zones");
goto end_with_cleanup;
@@ -1678,19 +1633,23 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
*/
thd->set_db(db, sizeof(db)-1);
- bzero((char*) &tables_buff, sizeof(TABLE_LIST));
- tables_buff[0].alias= tables_buff[0].table_name=
+ bzero((char*) &tz_tables[0], sizeof(TABLE_LIST));
+ tz_tables[0].alias= tz_tables[0].table_name=
(char*)"time_zone_leap_second";
- tables_buff[0].lock_type= TL_READ;
- tables_buff[0].db= db;
+ tz_tables[0].table_name_length= 21;
+ tz_tables[0].db= db;
+ tz_tables[0].db_length= sizeof(db)-1;
+ tz_tables[0].lock_type= TL_READ;
+
+ tz_init_table_list(tz_tables+1);
+ tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
+ tz_tables[1].prev_global= &tz_tables[0].next_global;
+
/*
- Fill TABLE_LIST for the rest of the time zone describing tables
- and link it to first one.
+ We need to open only mysql.time_zone_leap_second, but we try to
+ open all time zone tables to see if they exist.
*/
- last_global_next_ptr= &(tables_buff[0].next_global);
- tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
-
- if (simple_open_n_lock_tables(thd, tables_buff))
+ if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
{
sql_print_warning("Can't open and lock time zone table: %s "
"trying to live without them", thd->net.last_error);
@@ -1698,7 +1657,6 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
- tables= tables_buff + 1;
/*
Now we are going to load leap seconds descriptions that are shared
@@ -1714,7 +1672,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
goto end_with_close;
}
- table= tables_buff[0].table;
+ table= tz_tables[0].table;
/*
It is OK to ignore ha_index_init()/ha_index_end() return values since
mysql.time_zone* tables are MyISAM and these operations always succeed
@@ -1770,8 +1728,13 @@ end_with_setting_default_tz:
/* If we have default time zone try to load it */
if (default_tzname)
{
- String tmp_tzname(default_tzname, &my_charset_latin1);
- if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname, tables)))
+ String tmp_tzname2(default_tzname, &my_charset_latin1);
+ /*
+ Time zone tables may be open here, and my_tz_find() may open
+ most of them once more, but this is OK for system tables open
+ for READ.
+ */
+ if (!(global_system_variables.time_zone= my_tz_find(thd, &tmp_tzname2)))
{
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
default_tzname);
@@ -1780,8 +1743,11 @@ end_with_setting_default_tz:
}
end_with_close:
- thd->version--; /* Force close to free memory */
- close_thread_tables(thd);
+ if (time_zone_tables_exist)
+ {
+ thd->version--; /* Force close to free memory */
+ close_system_tables(thd, &open_tables_state_backup);
+ }
end_with_cleanup:
@@ -1869,8 +1835,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
DBUG_ENTER("tz_load_from_open_tables");
/* Prepare tz_info for loading also let us make copy of time zone name */
- if (!(alloc_buff= alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) +
- tz_name->length() + 1)))
+ if (!(alloc_buff= (char*) alloc_root(&tz_storage, sizeof(TIME_ZONE_INFO) +
+ tz_name->length() + 1)))
{
sql_print_error("Out of memory while loading time zone description");
return 0;
@@ -1890,7 +1856,6 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
*/
table= tz_tables->table;
tz_tables= tz_tables->next_local;
- table->use_all_columns();
table->field[0]->store(tz_name->ptr(), tz_name->length(),
&my_charset_latin1);
/*
@@ -1900,10 +1865,10 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
*/
(void)table->file->ha_index_init(0, 1);
- if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
- 0, HA_READ_KEY_EXACT))
+ if (table->file->index_read(table->record[0], table->field[0]->ptr,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
-#ifdef EXTRA_DEBUG
+#ifdef EXTRA_DEBUG
/*
Most probably user has mistyped time zone name, so no need to bark here
unless we need it for debugging.
@@ -1923,13 +1888,12 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
using the only index in this table).
*/
table= tz_tables->table;
- table->use_all_columns();
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
- if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
- 0, HA_READ_KEY_EXACT))
+ if (table->file->index_read(table->record[0], table->field[0]->ptr,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
sql_print_error("Can't find description of time zone '%u'", tzid);
goto end;
@@ -1951,14 +1915,12 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
Right - using special index.
*/
table= tz_tables->table;
- table->use_all_columns();
tz_tables= tz_tables->next_local;
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
- // FIXME Is there any better approach than explicitly specifying 4 ???
- res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
- 4, HA_READ_KEY_EXACT);
+ res= table->file->index_read(table->record[0], table->field[0]->ptr,
+ (key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
ttid= (uint)table->field[1]->val_int();
@@ -2006,7 +1968,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
tz_info->typecnt= ttid + 1;
res= table->file->index_next_same(table->record[0],
- (byte*)table->field[0]->ptr, 4);
+ table->field[0]->ptr, 4);
}
if (res != HA_ERR_END_OF_FILE)
@@ -2025,13 +1987,11 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
in ascending order by index scan also satisfies us.
*/
table= tz_tables->table;
- table->use_all_columns();
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
- // FIXME Is there any better approach than explicitly specifying 4 ???
- res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
- 4, HA_READ_KEY_EXACT);
+ res= table->file->index_read(table->record[0], table->field[0]->ptr,
+ (key_part_map)1, HA_READ_KEY_EXACT);
while (!res)
{
ttime= (my_time_t)table->field[1]->val_int();
@@ -2061,7 +2021,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
tzid, (ulong) ttime, ttid));
res= table->file->index_next_same(table->record[0],
- (byte*)table->field[0]->ptr, 4);
+ table->field[0]->ptr, 4);
}
/*
@@ -2081,21 +2041,21 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
/*
Now we will allocate memory and init TIME_ZONE_INFO structure.
*/
- if (!(alloc_buff= alloc_root(&tz_storage,
- ALIGN_SIZE(sizeof(my_time_t) *
- tz_info->timecnt) +
- ALIGN_SIZE(tz_info->timecnt) +
+ if (!(alloc_buff= (char*) alloc_root(&tz_storage,
+ ALIGN_SIZE(sizeof(my_time_t) *
+ tz_info->timecnt) +
+ ALIGN_SIZE(tz_info->timecnt) +
#ifdef ABBR_ARE_USED
- ALIGN_SIZE(tz_info->charcnt) +
+ ALIGN_SIZE(tz_info->charcnt) +
#endif
- sizeof(TRAN_TYPE_INFO) * tz_info->typecnt)))
+ sizeof(TRAN_TYPE_INFO) *
+ tz_info->typecnt)))
{
sql_print_error("Out of memory while loading time zone description");
goto end;
}
-
- tz_info->ats= (my_time_t *)alloc_buff;
+ tz_info->ats= (my_time_t *) alloc_buff;
memcpy(tz_info->ats, ats, tz_info->timecnt * sizeof(my_time_t));
alloc_buff+= ALIGN_SIZE(sizeof(my_time_t) * tz_info->timecnt);
tz_info->types= (uchar *)alloc_buff;
@@ -2130,7 +2090,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
&(tmp_tzname->name))) ||
(tmp_tzname->name.set(tz_name_buff, tz_name->length(),
&my_charset_latin1),
- my_hash_insert(&tz_names, (const byte *)tmp_tzname)))
+ my_hash_insert(&tz_names, (const uchar *)tmp_tzname)))
{
sql_print_error("Out of memory while loading time zone");
goto end;
@@ -2235,8 +2195,8 @@ str_to_offset(const char *str, uint length, long *offset)
SYNOPSIS
my_tz_find()
+ thd - pointer to thread THD structure
name - time zone specification
- tz_tables - list of opened'n'locked time zone describing tables
DESCRIPTION
This function checks if name is one of time zones described in db,
@@ -2258,11 +2218,10 @@ str_to_offset(const char *str, uint length, long *offset)
values as parameter without additional external check and this property
is used by @@time_zone variable handling code).
- It will perform lookup in system tables (mysql.time_zone*) if needed
- using tz_tables as list of already opened tables (for info about this
- list look at tz_load_from_open_tables() description). It won't perform
- such lookup if no time zone describing tables were found during server
- start up.
+ It will perform lookup in system tables (mysql.time_zone*),
+ opening and locking them, and closing afterwards. It won't perform
+ such lookup if no time zone describing tables were found during
+ server start up.
RETURN VALUE
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
@@ -2270,7 +2229,7 @@ str_to_offset(const char *str, uint length, long *offset)
*/
Time_zone *
-my_tz_find(const String * name, TABLE_LIST *tz_tables)
+my_tz_find(THD *thd, const String *name)
{
Tz_names_entry *tmp_tzname;
Time_zone *result_tz= 0;
@@ -2278,8 +2237,6 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_ENTER("my_tz_find");
DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr_safe() : "NULL"));
- DBUG_ASSERT(!time_zone_tables_exist || tz_tables ||
- current_thd->slave_thread);
if (!name)
DBUG_RETURN(0);
@@ -2290,13 +2247,13 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
{
if (!(result_tz= (Time_zone_offset *)hash_search(&offset_tzs,
- (const byte *)&offset,
+ (const uchar *)&offset,
sizeof(long))))
{
DBUG_PRINT("info", ("Creating new Time_zone_offset object"));
if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
- my_hash_insert(&offset_tzs, (const byte *) result_tz))
+ my_hash_insert(&offset_tzs, (const uchar *) result_tz))
{
result_tz= 0;
sql_print_error("Fatal error: Out of memory "
@@ -2308,11 +2265,22 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
{
result_tz= 0;
if ((tmp_tzname= (Tz_names_entry *)hash_search(&tz_names,
- (const byte *)name->ptr(),
+ (const uchar *)name->ptr(),
name->length())))
result_tz= tmp_tzname->tz;
- else if (time_zone_tables_exist && tz_tables)
- result_tz= tz_load_from_open_tables(name, tz_tables);
+ else if (time_zone_tables_exist)
+ {
+ TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
+ Open_tables_state open_tables_state_backup;
+
+ tz_init_table_list(tz_tables);
+ if (!open_system_tables_for_read(thd, tz_tables,
+ &open_tables_state_backup))
+ {
+ result_tz= tz_load_from_open_tables(name, tz_tables);
+ close_system_tables(thd, &open_tables_state_backup);
+ }
+ }
}
VOID(pthread_mutex_unlock(&tz_LOCK));
@@ -2321,58 +2289,6 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
}
-/*
- A more standalone version of my_tz_find(): will open tz tables if needed.
- This is so far only used by replication, where time zone setting does not
- happen in the usual query context.
-
- SYNOPSIS
- my_tz_find_with_opening_tz_tables()
- thd - pointer to thread's THD structure
- name - time zone specification
-
- DESCRIPTION
- This function tries to find a time zone which matches the named passed in
- argument. If it fails, it will open time zone tables and re-try the
- search.
- This function is needed for the slave SQL thread, which does not do the
- addition of time zone tables which is usually done during query parsing
- (as time zone setting by slave does not happen in mysql_parse() but
- before). So it needs to open tz tables by itself if needed.
- See notes of my_tz_find() as they also apply here.
-
- RETURN VALUE
- Pointer to corresponding Time_zone object. 0 - in case of bad time zone
- specification or other error.
-*/
-
-Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
-{
- Time_zone *tz;
- DBUG_ENTER("my_tz_find_with_opening_tables");
- DBUG_ASSERT(thd);
- DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
-
- if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
- {
- /*
- Probably we have not loaded this time zone yet so let us look it up in
- our time zone tables. Note that if we don't have tz tables on this
- slave, we don't even try.
- */
- TABLE_LIST tables[MY_TZ_TABLES_COUNT];
- TABLE_LIST *dummy;
- TABLE_LIST **dummyp= &dummy;
- tz_init_table_list(tables, &dummyp);
- if (simple_open_n_lock_tables(thd, tables))
- DBUG_RETURN(0);
- tz= my_tz_find(name, tables);
- /* We need to close tables _now_ to not pollute coming query */
- close_thread_tables(thd);
- }
- DBUG_RETURN(tz);
-}
-
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
@@ -2651,7 +2567,7 @@ main(int argc, char **argv)
my_bool localtime_negative;
TIME_ZONE_INFO tz_info;
struct tm tmp;
- TIME time_tmp;
+ MYSQL_TIME time_tmp;
time_t t, t1, t2;
char fullname[FN_REFLEN+1];
char *str_end;
diff --git a/sql/tztime.h b/sql/tztime.h
index 95184c9b3d1..f7cc7042d79 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,7 +22,7 @@
/*
This class represents abstract time zone and provides
- basic interface for TIME <-> my_time_t conversion.
+ basic interface for MYSQL_TIME <-> my_time_t conversion.
Actual time zones which are specified by DB, or via offset
or use system functions are its descendants.
*/
@@ -32,18 +31,18 @@ class Time_zone: public Sql_alloc
public:
Time_zone() {} /* Remove gcc warning */
/*
- Converts local time in broken down TIME representation to
+ Converts local time in broken down MYSQL_TIME representation to
my_time_t (UTC seconds since Epoch) represenation.
Returns 0 in case of error. Sets in_dst_time_gap to true if date provided
falls into spring time-gap (or lefts it untouched otherwise).
*/
- virtual my_time_t TIME_to_gmt_sec(const TIME *t,
+ virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
my_bool *in_dst_time_gap) const = 0;
/*
Converts time in my_time_t representation to local time in
- broken down TIME representation.
+ broken down MYSQL_TIME representation.
*/
- virtual void gmt_sec_to_TIME(TIME *tmp, my_time_t t) const = 0;
+ virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const = 0;
/*
Because of constness of String returned by get_name() time zone name
have to be already zeroended to be able to use String::ptr() instead
@@ -60,14 +59,10 @@ public:
extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM;
-extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr);
-extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
-extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
+extern Time_zone * my_tz_find(THD *thd, const String *name);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();
-extern my_time_t sec_since_epoch_TIME(TIME *t);
-
-extern TABLE_LIST fake_time_zone_tables_list;
+extern my_time_t sec_since_epoch_TIME(MYSQL_TIME *t);
/*
Number of elements in table list produced by my_tz_get_table_list()
@@ -78,34 +73,5 @@ extern TABLE_LIST fake_time_zone_tables_list;
static const int MY_TZ_TABLES_COUNT= 4;
-/*
- Check if we have pointer to the begining of list of implicitly used time
- zone tables, set SELECT_ACL for them and fast-forward to its end.
-
- SYNOPSIS
- my_tz_check_n_skip_implicit_tables()
- table - (in/out) pointer to element of table list to check
- tz_tables - list of implicitly used time zone tables received
- from my_tz_get_table_list() function.
-
- NOTE
- This function relies on my_tz_get_table_list() implementation.
-
- RETURN VALUE
- TRUE - if table points to the beggining of tz_tables list
- FALSE - otherwise.
-*/
-inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
- TABLE_LIST *tz_tables)
-{
- if (*table == tz_tables)
- {
- for (int i= 0; i < MY_TZ_TABLES_COUNT; i++)
- (*table)[i].grant.privilege= SELECT_ACL;
- (*table)+= MY_TZ_TABLES_COUNT - 1;
- return TRUE;
- }
- return FALSE;
-}
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
diff --git a/sql/udf_example.c b/sql/udf_example.c
index bbab47e253d..b603464568e 100644
--- a/sql/udf_example.c
+++ b/sql/udf_example.c
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -131,7 +130,8 @@ typedef long long longlong;
#include <m_string.h> /* To get strmov() */
#else
/* when compiled as standalone */
-#define strmov(a,b) strcpy(a,b)
+#include <string.h>
+#define strmov(a,b) stpcpy(a,b)
#define bzero(a,b) memset(a,0,b)
#define memcpy_fixed(a,b,c) memcpy(a,b,c)
#endif
@@ -685,7 +685,7 @@ longlong sequence(UDF_INIT *initid __attribute__((unused)), UDF_ARGS *args,
****************************************************************************/
#ifdef __WIN__
-#include <winsock.h>
+#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
@@ -1087,7 +1087,7 @@ my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
strmov(message, "IS_CONST accepts only one argument");
return 1;
}
- initid->ptr= (char*)((args->args[0] != NULL) ? 1 : 0);
+ initid->ptr= (char*)((args->args[0] != NULL) ? 1UL : 0);
return 0;
}
diff --git a/sql/udf_example.def b/sql/udf_example.def
index ee107d58e51..7a87147d7b6 100644
--- a/sql/udf_example.def
+++ b/sql/udf_example.def
@@ -1,5 +1,4 @@
LIBRARY udf_example
-DESCRIPTION 'MySQL Sample for UDF'
VERSION 1.0
EXPORTS
lookup
diff --git a/sql/uniques.cc b/sql/uniques.cc
index c7bdbdeb207..7a05ceaddfc 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -2,8 +2,7 @@
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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -35,7 +34,7 @@
#include "sql_sort.h"
-int unique_write_to_file(gptr key, element_count count, Unique *unique)
+int unique_write_to_file(uchar* key, element_count count, Unique *unique)
{
/*
Use unique->size (size of element stored in the tree) and not
@@ -43,11 +42,10 @@ int unique_write_to_file(gptr key, element_count count, Unique *unique)
when tree implementation chooses to store pointer to key in TREE_ELEMENT
(instead of storing the element itself there)
*/
- return my_b_write(&unique->file, (byte*) key,
- unique->size) ? 1 : 0;
+ return my_b_write(&unique->file, key, unique->size) ? 1 : 0;
}
-int unique_write_to_ptrs(gptr key, element_count count, Unique *unique)
+int unique_write_to_ptrs(uchar* key, element_count count, Unique *unique)
{
memcpy(unique->record_pointers, key, unique->size);
unique->record_pointers+=unique->size;
@@ -331,7 +329,7 @@ bool Unique::flush()
if (tree_walk(&tree, (tree_walk_action) unique_write_to_file,
(void*) this, left_root_right) ||
- insert_dynamic(&file_ptrs, (gptr) &file_ptr))
+ insert_dynamic(&file_ptrs, (uchar*) &file_ptr))
return 1;
delete_tree(&tree);
return 0;
@@ -375,11 +373,11 @@ struct BUFFPEK_COMPARE_CONTEXT
C_MODE_START
-static int buffpek_compare(void *arg, byte *key_ptr1, byte *key_ptr2)
+static int buffpek_compare(void *arg, uchar *key_ptr1, uchar *key_ptr2)
{
BUFFPEK_COMPARE_CONTEXT *ctx= (BUFFPEK_COMPARE_CONTEXT *) arg;
return ctx->key_compare(ctx->key_compare_arg,
- *((byte **) key_ptr1), *((byte **)key_ptr2));
+ *((uchar **) key_ptr1), *((uchar **)key_ptr2));
}
C_MODE_END
@@ -456,7 +454,7 @@ static bool merge_walk(uchar *merge_buffer, ulong merge_buffer_size,
if (bytes_read == (uint) (-1))
goto end;
DBUG_ASSERT(bytes_read);
- queue_insert(&queue, (byte *) top);
+ queue_insert(&queue, (uchar *) top);
}
top= (BUFFPEK *) queue_top(&queue);
while (queue.elements > 1)
@@ -587,7 +585,7 @@ bool Unique::get(TABLE *table)
if (my_b_tell(&file) == 0)
{
/* Whole tree is in memory; Don't use disk if you don't need to */
- if ((record_pointers=table->sort.record_pointers= (byte*)
+ if ((record_pointers=table->sort.record_pointers= (uchar*)
my_malloc(size * tree.elements_in_tree, MYF(0))))
{
(void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs,
@@ -642,7 +640,7 @@ bool Unique::get(TABLE *table)
goto err;
error=0;
err:
- x_free((gptr) sort_buffer);
+ x_free(sort_buffer);
if (flush_io_cache(outfile))
error=1;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 4514f969913..a02d24d8ae5 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -83,7 +82,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
- char buff[32];
+ char buff[128];
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info= thd->work_part_info;
#endif
@@ -105,7 +104,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
screens, create_info->table_options,
data_offset, db_file))
{
- my_free((gptr) screen_buff,MYF(0));
+ my_free(screen_buff, MYF(0));
if (thd->net.last_errno != ER_TOO_MANY_FIELDS)
DBUG_RETURN(1);
@@ -117,7 +116,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_fields,info_length,
screens, create_info->table_options, data_offset, db_file))
{
- my_free((gptr) screen_buff,MYF(0));
+ my_free(screen_buff, MYF(0));
DBUG_RETURN(1);
}
}
@@ -153,7 +152,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
create_info, keys)) < 0)
{
- my_free((gptr) screen_buff,MYF(0));
+ my_free(screen_buff, MYF(0));
DBUG_RETURN(1);
}
@@ -176,7 +175,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_info->comment.length, 60);
if (tmp_len < create_info->comment.length)
{
- char buff[128];
(void) my_snprintf(buff, sizeof(buff), "Too long comment for table '%s'",
table);
if ((thd->variables.sql_mode &
@@ -202,8 +200,8 @@ bool mysql_create_frm(THD *thd, const char *file_name,
#endif
int2store(fileinfo+59,db_file->extra_rec_buf_length());
- if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) ||
- my_pwrite(file,(byte*) keybuff,key_info_length,
+ if (my_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
+ my_pwrite(file, keybuff, key_info_length,
(ulong) uint2korr(fileinfo+6),MYF_RW))
goto err;
VOID(my_seek(file,
@@ -215,14 +213,14 @@ bool mysql_create_frm(THD *thd, const char *file_name,
goto err;
int2store(buff, create_info->connect_string.length);
- if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
- my_write(file, (const byte*)create_info->connect_string.str,
+ if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
+ my_write(file, (const uchar*)create_info->connect_string.str,
create_info->connect_string.length, MYF(MY_NABP)))
goto err;
int2store(buff, str_db_type.length);
- if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
- my_write(file, (const byte*)str_db_type.str,
+ if (my_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
+ my_write(file, (const uchar*)str_db_type.str,
str_db_type.length, MYF(MY_NABP)))
goto err;
@@ -231,32 +229,32 @@ bool mysql_create_frm(THD *thd, const char *file_name,
{
char auto_partitioned= part_info->is_auto_partitioned ? 1 : 0;
int4store(buff, part_info->part_info_len);
- if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
- my_write(file, (const byte*)part_info->part_info_string,
+ if (my_write(file, (const uchar*)buff, 4, MYF_RW) ||
+ my_write(file, (const uchar*)part_info->part_info_string,
part_info->part_info_len + 1, MYF_RW) ||
- my_write(file, (const byte*)&auto_partitioned, 1, MYF_RW))
+ my_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
goto err;
}
else
#endif
{
- bzero(buff, 6);
- if (my_write(file, (byte*) buff, 6, MYF_RW))
+ bzero((uchar*) buff, 6);
+ if (my_write(file, (uchar*) buff, 6, MYF_RW))
goto err;
}
for (i= 0; i < keys; i++)
{
if (key_info[i].parser_name)
{
- if (my_write(file, (const byte*)key_info[i].parser_name->str,
+ if (my_write(file, (const uchar*)key_info[i].parser_name->str,
key_info[i].parser_name->length + 1, MYF(MY_NABP)))
goto err;
}
}
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
- if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
- my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
+ if (my_write(file, forminfo, 288, MYF_RW) ||
+ my_write(file, screen_buff, info_length, MYF_RW) ||
pack_fields(file, create_fields, data_offset))
goto err;
@@ -269,7 +267,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
goto err;
uint read_length=uint2korr(forminfo)-256;
VOID(my_seek(file,filepos+256,MY_SEEK_SET,MYF(0)));
- if (read_string(file,(gptr*) &disk_buff,read_length))
+ if (read_string(file,(uchar**) &disk_buff,read_length))
goto err;
crypted->encode(disk_buff,read_length);
delete crypted;
@@ -282,8 +280,8 @@ bool mysql_create_frm(THD *thd, const char *file_name,
}
#endif
- my_free((gptr) screen_buff,MYF(0));
- my_free((gptr) keybuff, MYF(0));
+ my_free(screen_buff,MYF(0));
+ my_free(keybuff, MYF(0));
if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
my_sync(file, MYF(MY_WME)))
@@ -310,8 +308,8 @@ bool mysql_create_frm(THD *thd, const char *file_name,
DBUG_RETURN(0);
err:
- my_free((gptr) screen_buff,MYF(0));
- my_free((gptr) keybuff, MYF(0));
+ my_free(screen_buff, MYF(0));
+ my_free(keybuff, MYF(0));
err2:
VOID(my_close(file,MYF(MY_WME)));
err3:
@@ -419,7 +417,7 @@ static uchar *pack_screens(List<create_field> &create_fields,
pos[0]= (uchar) start_row-2; /* Header string */
pos[1]= (uchar) (cols >> 2);
pos[2]= (uchar) (cols >> 1) +1;
- strfill((my_string) pos+3,(uint) (cols >> 1),' ');
+ strfill((char *) pos+3,(uint) (cols >> 1),' ');
pos+=(cols >> 1)+4;
}
length=(uint) strlen(cfield->field_name);
@@ -550,11 +548,11 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
create_field *field;
while ((field=it++))
{
-
uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
field->comment.str,
field->comment.str +
- field->comment.length, 255);
+ field->comment.length,
+ 255);
if (tmp_len < field->comment.length)
{
char buff[128];
@@ -584,7 +582,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE
as auto-update field.
*/
- if (field->sql_type == FIELD_TYPE_TIMESTAMP &&
+ if (field->sql_type == MYSQL_TYPE_TIMESTAMP &&
MTYP_TYPENR(field->unireg_check) != Field::NONE &&
!time_stamp_pos)
time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
@@ -623,11 +621,13 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
- uint length= field->save_interval->type_lengths[pos], hex_length;
const char *src= field->save_interval->type_names[pos];
+ uint hex_length;
+ length= field->save_interval->type_lengths[pos];
hex_length= length * 2;
field->interval->type_lengths[pos]= hex_length;
- field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
+ field->interval->type_names[pos]= dst= (char*) sql_alloc(hex_length +
+ 1);
octet2hex(dst, src, length);
}
}
@@ -743,7 +743,7 @@ static bool pack_fields(File file, List<create_field> &create_fields,
int2store(buff+10,field->unireg_check);
buff[12]= (uchar) field->interval_id;
buff[13]= (uchar) field->sql_type;
- if (field->sql_type == FIELD_TYPE_GEOMETRY)
+ if (field->sql_type == MYSQL_TYPE_GEOMETRY)
{
buff[14]= (uchar) field->geom_type;
#ifndef HAVE_SPATIAL
@@ -757,13 +757,13 @@ static bool pack_fields(File file, List<create_field> &create_fields,
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
- if (my_write(file,(byte*) buff,FCOMP,MYF_RW))
+ if (my_write(file, buff, FCOMP, MYF_RW))
DBUG_RETURN(1);
}
/* Write fieldnames */
buff[0]=(uchar) NAMES_SEP_CHAR;
- if (my_write(file,(byte*) buff,1,MYF_RW))
+ if (my_write(file, buff, 1, MYF_RW))
DBUG_RETURN(1);
i=0;
it.rewind();
@@ -773,7 +773,7 @@ static bool pack_fields(File file, List<create_field> &create_fields,
*pos++=NAMES_SEP_CHAR;
if (i == create_fields.elements-1)
*pos++=0;
- if (my_write(file,(byte*) buff,(uint) (pos-(char*) buff),MYF_RW))
+ if (my_write(file, buff, (size_t) (pos-(char*) buff),MYF_RW))
DBUG_RETURN(1);
i++;
}
@@ -789,32 +789,51 @@ static bool pack_fields(File file, List<create_field> &create_fields,
{
if (field->interval_id > int_count)
{
- int_count=field->interval_id;
- tmp.append(NAMES_SEP_CHAR);
- for (const char **pos=field->interval->type_names ; *pos ; pos++)
- {
- char *val= (char*) *pos;
- uint str_len= strlen(val);
- /*
- Note, hack: in old frm NAMES_SEP_CHAR is used to separate
- names in the interval (ENUM/SET). To allow names to contain
- NAMES_SEP_CHAR, we replace it with a comma before writing frm.
- Backward conversion is done during frm file opening,
- See table.cc, openfrm() function
- */
- for (uint cnt= 0 ; cnt < str_len ; cnt++)
+ unsigned char sep= 0;
+ unsigned char occ[256];
+ uint i;
+ unsigned char *val= NULL;
+
+ bzero(occ, sizeof(occ));
+
+ for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++)
+ for (uint j = 0; j < field->interval->type_lengths[i]; j++)
+ occ[(unsigned int) (val[j])]= 1;
+
+ if (!occ[(unsigned char)NAMES_SEP_CHAR])
+ sep= (unsigned char) NAMES_SEP_CHAR;
+ else if (!occ[(unsigned int)','])
+ sep= ',';
+ else
+ {
+ for (uint i=1; i<256; i++)
+ {
+ if(!occ[i])
+ {
+ sep= i;
+ break;
+ }
+ }
+
+ if(!sep) /* disaster, enum uses all characters, none left as separator */
{
- char c= val[cnt];
- if (c == NAMES_SEP_CHAR)
- val[cnt]= ',';
+ my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
+ MYF(0));
+ DBUG_RETURN(1);
}
- tmp.append(*pos);
- tmp.append(NAMES_SEP_CHAR);
- }
- tmp.append('\0'); // End of intervall
+ }
+
+ int_count= field->interval_id;
+ tmp.append(sep);
+ for (const char **pos=field->interval->type_names ; *pos ; pos++)
+ {
+ tmp.append(*pos);
+ tmp.append(sep);
+ }
+ tmp.append('\0'); // End of intervall
}
}
- if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW))
+ if (my_write(file,(uchar*) tmp.ptr(),tmp.length(),MYF_RW))
DBUG_RETURN(1);
}
if (comment_length)
@@ -824,7 +843,7 @@ static bool pack_fields(File file, List<create_field> &create_fields,
while ((field=it++))
{
if (field->comment.length)
- if (my_write(file, (byte*) field->comment.str, field->comment.length,
+ if (my_write(file, (uchar*) field->comment.str, field->comment.length,
MYF_RW))
DBUG_RETURN(1);
}
@@ -857,7 +876,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
bzero((char*) &share, sizeof(share));
table.s= &share;
- if (!(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL))))
+ if (!(buff=(uchar*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
{
DBUG_RETURN(1);
}
@@ -882,7 +901,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
regfield don't have to be deleted as it's allocated with sql_alloc()
*/
Field *regfield= make_field(&share,
- (char*) buff+field->offset + data_offset,
+ buff+field->offset + data_offset,
field->length,
null_pos + null_count / 8,
null_count & 7,
@@ -895,7 +914,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
field->interval,
field->field_name);
if (!regfield)
+ {
+ error= 1;
goto err; // End of memory
+ }
/* save_in_field() will access regfield->table->in_use */
regfield->init(&table);
@@ -906,16 +928,18 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
null_count++;
}
- if (field->sql_type == FIELD_TYPE_BIT && !f_bit_as_char(field->pack_flag))
+ if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag))
null_count+= field->length & 7;
type= (Field::utype) MTYP_TYPENR(field->unireg_check);
if (field->def &&
- (regfield->real_type() != FIELD_TYPE_YEAR ||
+ (regfield->real_type() != MYSQL_TYPE_YEAR ||
field->def->val_int() != 0))
{
- if (field->def->save_in_field(regfield, 1))
+ int res= field->def->save_in_field(regfield, 1);
+ /* If not ok or warning of level 'note' */
+ if (res != 0 && res != 3)
{
my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
error= 1;
@@ -923,7 +947,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
goto err;
}
}
- else if (regfield->real_type() == FIELD_TYPE_ENUM &&
+ else if (regfield->real_type() == MYSQL_TYPE_ENUM &&
(field->flags & NOT_NULL_FLAG))
{
regfield->set_notnull();
@@ -945,10 +969,10 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
if (null_count & 7)
*(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
- error=(int) my_write(file,(byte*) buff, (uint) reclength,MYF_RW);
+ error= my_write(file, buff, (size_t) reclength,MYF_RW) != 0;
err:
- my_free((gptr) buff,MYF(MY_FAE));
+ my_free(buff, MYF(MY_FAE));
thd->count_cuted_fields= old_count_cuted_fields;
DBUG_RETURN(error);
} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
index af91793e8fe..d67fa372083 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -1,9 +1,8 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2006 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.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of