summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am36
-rw-r--r--sql/examples/ha_archive.cc125
-rw-r--r--sql/examples/ha_archive.h8
-rw-r--r--sql/examples/ha_tina.cc851
-rw-r--r--sql/examples/ha_tina.h132
-rw-r--r--sql/field.cc144
-rw-r--r--sql/field.h15
-rw-r--r--sql/field_conv.cc4
-rw-r--r--sql/gen_lex_hash.cc2
-rw-r--r--sql/ha_berkeley.cc6
-rw-r--r--sql/ha_heap.cc5
-rw-r--r--sql/ha_innodb.cc83
-rw-r--r--sql/ha_innodb.h3
-rw-r--r--sql/ha_myisam.cc22
-rw-r--r--sql/ha_ndbcluster.cc1194
-rw-r--r--sql/ha_ndbcluster.h53
-rw-r--r--sql/handler.cc77
-rw-r--r--sql/handler.h5
-rw-r--r--sql/item.cc80
-rw-r--r--sql/item.h22
-rw-r--r--sql/item_cmpfunc.cc257
-rw-r--r--sql/item_cmpfunc.h11
-rw-r--r--sql/item_create.cc5
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_func.cc71
-rw-r--r--sql/item_func.h9
-rw-r--r--sql/item_row.cc3
-rw-r--r--sql/item_strfunc.cc22
-rw-r--r--sql/item_subselect.cc225
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/item_sum.cc35
-rw-r--r--sql/item_sum.h16
-rw-r--r--sql/item_timefunc.cc173
-rw-r--r--sql/item_timefunc.h16
-rw-r--r--sql/key.cc15
-rw-r--r--sql/lex.h2
-rw-r--r--sql/lock.cc73
-rw-r--r--sql/log.cc267
-rw-r--r--sql/log_event.cc4
-rw-r--r--sql/mysql_priv.h35
-rw-r--r--sql/mysqld.cc894
-rw-r--r--sql/opt_range.cc12
-rw-r--r--sql/protocol.cc10
-rw-r--r--sql/records.cc3
-rw-r--r--sql/repl_failsafe.cc9
-rw-r--r--sql/set_var.cc36
-rw-r--r--sql/set_var.h1
-rw-r--r--sql/share/charsets/cp852.xml2
-rw-r--r--sql/share/czech/errmsg.txt21
-rw-r--r--sql/share/danish/errmsg.txt22
-rw-r--r--sql/share/dutch/errmsg.txt23
-rw-r--r--sql/share/english/errmsg.txt22
-rw-r--r--sql/share/estonian/errmsg.txt24
-rw-r--r--sql/share/french/errmsg.txt22
-rw-r--r--sql/share/german/errmsg.txt25
-rw-r--r--sql/share/greek/errmsg.txt22
-rw-r--r--sql/share/hungarian/errmsg.txt25
-rw-r--r--sql/share/italian/errmsg.txt20
-rw-r--r--sql/share/japanese/errmsg.txt24
-rw-r--r--sql/share/korean/errmsg.txt22
-rw-r--r--sql/share/norwegian-ny/errmsg.txt22
-rw-r--r--sql/share/norwegian/errmsg.txt22
-rw-r--r--sql/share/polish/errmsg.txt23
-rw-r--r--sql/share/portuguese/errmsg.txt23
-rw-r--r--sql/share/romanian/errmsg.txt23
-rw-r--r--sql/share/russian/errmsg.txt25
-rw-r--r--sql/share/serbian/errmsg.txt3
-rw-r--r--sql/share/slovak/errmsg.txt22
-rw-r--r--sql/share/spanish/errmsg.txt24
-rw-r--r--sql/share/swedish/errmsg.OLD221
-rw-r--r--sql/share/swedish/errmsg.txt22
-rw-r--r--sql/share/ukrainian/errmsg.txt25
-rw-r--r--sql/slave.cc31
-rw-r--r--sql/sql_acl.cc46
-rw-r--r--sql/sql_acl.h3
-rw-r--r--sql/sql_analyse.cc3
-rw-r--r--sql/sql_base.cc241
-rw-r--r--sql/sql_class.cc151
-rw-r--r--sql/sql_class.h116
-rw-r--r--sql/sql_db.cc19
-rw-r--r--sql/sql_delete.cc8
-rw-r--r--sql/sql_insert.cc7
-rw-r--r--sql/sql_lex.cc17
-rw-r--r--sql/sql_lex.h13
-rw-r--r--sql/sql_list.h4
-rw-r--r--sql/sql_load.cc18
-rw-r--r--sql/sql_parse.cc148
-rw-r--r--sql/sql_prepare.cc207
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_select.cc260
-rw-r--r--sql/sql_select.h1
-rw-r--r--sql/sql_show.cc18
-rw-r--r--sql/sql_string.h9
-rw-r--r--sql/sql_table.cc60
-rw-r--r--sql/sql_union.cc4
-rw-r--r--sql/sql_yacc.yy163
-rw-r--r--sql/table.cc11
-rw-r--r--sql/time.cc157
-rw-r--r--sql/tztime.cc332
-rw-r--r--sql/tztime.h12
-rw-r--r--sql/unireg.cc2
101 files changed, 5338 insertions, 2528 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 175cc3786cf..7a55367c717 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -19,7 +19,7 @@
MYSQLDATAdir = $(localstatedir)
MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
-INCLUDES = @MT_INCLUDES@ \
+INCLUDES = @MT_INCLUDES@ @ZLIB_INCLUDES@ \
@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
-I$(top_srcdir)/include -I$(top_srcdir)/regex \
-I$(srcdir) $(openssl_includes)
@@ -30,14 +30,14 @@ noinst_PROGRAMS = gen_lex_hash
bin_PROGRAMS = mysql_tzinfo_to_sql
gen_lex_hash_LDFLAGS = @NOINST_LDFLAGS@
LDADD = @isam_libs@ \
- ../myisam/libmyisam.a \
- ../myisammrg/libmyisammrg.a \
- ../heap/libheap.a \
- ../vio/libvio.a \
- ../mysys/libmysys.a \
- ../dbug/libdbug.a \
- ../regex/libregex.a \
- ../strings/libmystrings.a
+ $(top_builddir)/myisam/libmyisam.a \
+ $(top_builddir)/myisammrg/libmyisammrg.a \
+ $(top_builddir)/heap/libheap.a \
+ $(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 @ZLIB_LIBS@
mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
@bdb_libs@ @innodb_libs@ @pstack_libs@ \
@@ -59,9 +59,12 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h tzfile.h \
- tztime.h examples/ha_example.h examples/ha_archive.h \
+ tztime.h \
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
- parse_file.h sql_view.h
+ parse_file.h sql_view.h \
+ examples/ha_example.h examples/ha_archive.h \
+ examples/ha_tina.h
+
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -93,13 +96,14 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
sql_olap.cc sql_view.cc \
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
tztime.cc my_time.c \
- examples/ha_example.cc examples/ha_archive.cc \
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
- sp_cache.cc parse_file.cc
+ sp_cache.cc parse_file.cc \
+ examples/ha_example.cc examples/ha_archive.cc \
+ examples/ha_tina.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 = $(LDADD) $(CXXLDFLAGS)
+mysql_tzinfo_to_sql_LDADD = @MYSQLD_EXTRA_LDFLAGS@ $(LDADD) $(CXXLDFLAGS)
DEFS = -DMYSQL_SERVER \
-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
@@ -154,8 +158,8 @@ sql_lex.o: lex_hash.h
udf_example.so: udf_example.cc
$(CXXCOMPILE) -shared -o $@ $<
-#distclean:
-# rm -f lex_hash.h
+distclean:
+ rm -f lex_hash.h
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index 9b439087259..c004330932c 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -192,7 +192,7 @@ static int free_share(ARCHIVE_SHARE *share)
thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex);
if (gzclose(share->archive_write) == Z_ERRNO)
- rc= -1;
+ rc= 1;
my_free((gptr) share, MYF(0));
}
pthread_mutex_unlock(&archive_mutex);
@@ -226,7 +226,7 @@ int ha_archive::open(const char *name, int mode, uint test_if_locked)
if ((archive= gzopen(share->data_file_name, "rb")) == NULL)
{
(void)free_share(share); //We void since we already have an error
- DBUG_RETURN(-1);
+ DBUG_RETURN(errno ? errno : -1);
}
DBUG_RETURN(0);
@@ -234,56 +234,91 @@ int ha_archive::open(const char *name, int mode, uint test_if_locked)
/*
- Closes the file. We first close this storage engines file handle to the
- archive and then remove our reference count to the table (and possibly
- free it as well).
- */
+ Closes the file.
+
+ SYNOPSIS
+ close();
+
+ IMPLEMENTATION:
+
+ We first close this storage engines file handle to the archive and
+ then remove our reference count to the table (and possibly free it
+ as well).
+
+ RETURN
+ 0 ok
+ 1 Error
+*/
+
int ha_archive::close(void)
{
+ int rc= 0;
DBUG_ENTER("ha_archive::close");
- DBUG_RETURN(((gzclose(archive) == Z_ERRNO || free_share(share)) ? -1 : 0));
+
+ /* First close stream */
+ if (gzclose(archive) == Z_ERRNO)
+ rc= 1;
+ /* then also close share */
+ rc|= free_share(share);
+
+ DBUG_RETURN(rc);
}
/*
- We create our data file here. The format is pretty simple. The first bytes in
- any file are the version number. Currently we do nothing with this, but in
- the future this gives us the ability to figure out version if we change the
- format at all. After the version we starting writing our rows. Unlike other
- storage engines we do not "pack" our data. Since we are about to do a general
- compression, packing would just be a waste of CPU time. If the table has blobs
- they are written after the row in the order of creation.
+ We create our data file here. The format is pretty simple. The first
+ bytes in any file are the version number. Currently we do nothing
+ with this, but in the future this gives us the ability to figure out
+ version if we change the format at all. After the version we
+ starting writing our rows. Unlike other storage engines we do not
+ "pack" our data. Since we are about to do a general compression,
+ packing would just be a waste of CPU time. If the table has blobs
+ they are written after the row in the order of creation.
+
So to read a row we:
Read the version
Read the record and copy it into buf
Loop through any blobs and read them
- */
-int ha_archive::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info)
+*/
+
+int ha_archive::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
{
File create_file;
char name_buff[FN_REFLEN];
size_t written;
+ int error;
DBUG_ENTER("ha_archive::create");
- if ((create_file= my_create(fn_format(name_buff,name,"",ARZ,MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
- O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
- DBUG_RETURN(-1);
+ if ((create_file= my_create(fn_format(name_buff,name,"",ARZ,
+ MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ {
+ error= my_errno;
+ goto err;
+ }
if ((archive= gzdopen(create_file, "ab")) == NULL)
{
+ error= errno;
delete_table(name);
- DBUG_RETURN(-1);
+ goto err;
}
version= ARCHIVE_VERSION;
written= gzwrite(archive, &version, sizeof(version));
- if (written != sizeof(version) || gzclose(archive))
+ if (gzclose(archive) || written != sizeof(version))
{
+ error= errno;
delete_table(name);
- DBUG_RETURN(-1);
+ goto err;
}
-
DBUG_RETURN(0);
+
+err:
+ /* Return error number, if we got one */
+ DBUG_RETURN(error ? error : -1);
}
+
/*
Look at ha_archive::open() for an explanation of the row format.
Here we just write out the row.
@@ -298,9 +333,9 @@ int ha_archive::write_row(byte * buf)
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
written= gzwrite(share->archive_write, buf, table->reclength);
- share->dirty= true;
+ share->dirty= TRUE;
if (written != table->reclength)
- DBUG_RETURN(-1);
+ DBUG_RETURN(errno ? errno : -1);
for (Field_blob **field=table->blob_field ; *field ; field++)
{
@@ -310,7 +345,7 @@ int ha_archive::write_row(byte * buf)
(*field)->get_ptr(&ptr);
written= gzwrite(share->archive_write, ptr, (unsigned)size);
if (written != size)
- DBUG_RETURN(-1);
+ DBUG_RETURN(errno ? errno : -1);
}
DBUG_RETURN(0);
@@ -322,6 +357,7 @@ int ha_archive::write_row(byte * buf)
that it is a table scan we rewind the file to the beginning, otherwise
we assume the position will be set.
*/
+
int ha_archive::rnd_init(bool scan)
{
DBUG_ENTER("ha_archive::rnd_init");
@@ -339,10 +375,10 @@ int ha_archive::rnd_init(bool scan)
If dirty, we lock, and then reset/flush the data.
I found that just calling gzflush() doesn't always work.
*/
- if (share->dirty == true)
+ if (share->dirty == TRUE)
{
pthread_mutex_lock(&share->mutex);
- if (share->dirty == true)
+ if (share->dirty == TRUE)
{
/* I was having problems with OSX, but it worked for 10.3 so I am wrapping this with and ifdef */
#ifdef BROKEN_GZFLUSH
@@ -350,12 +386,12 @@ int ha_archive::rnd_init(bool scan)
if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL)
{
pthread_mutex_unlock(&share->mutex);
- DBUG_RETURN(-1);
+ DBUG_RETURN(errno ? errno : -1);
}
#else
gzflush(share->archive_write, Z_SYNC_FLUSH);
#endif
- share->dirty= false;
+ share->dirty= FALSE;
}
pthread_mutex_unlock(&share->mutex);
}
@@ -367,8 +403,8 @@ int ha_archive::rnd_init(bool scan)
if (scan)
{
read= gzread(archive, &version, sizeof(version));
- if (read == 0 || read != sizeof(version))
- DBUG_RETURN(-1);
+ if (read != sizeof(version))
+ DBUG_RETURN(errno ? errno : -1);
}
DBUG_RETURN(0);
@@ -393,7 +429,7 @@ int ha_archive::get_row(byte *buf)
DBUG_RETURN(HA_ERR_END_OF_FILE);
/* If the record is the wrong size, the file is probably damaged */
- if (read != table->reclength)
+ if ((ulong) read != table->reclength)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
/* Calculate blob length, we use this for our buffer */
@@ -409,7 +445,7 @@ int ha_archive::get_row(byte *buf)
{
size_t size= (*field)->get_length();
read= gzread(archive, last, size);
- if (read == 0 || read != size)
+ if ((size_t) read != size)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
(*field)->set_ptr(size, last);
last += size;
@@ -417,19 +453,21 @@ int ha_archive::get_row(byte *buf)
DBUG_RETURN(0);
}
+
/*
Called during ORDER BY. Its position is either from being called sequentially
or by having had ha_archive::rnd_pos() called before it is called.
*/
+
int ha_archive::rnd_next(byte *buf)
{
- DBUG_ENTER("ha_archive::rnd_next");
int rc;
+ DBUG_ENTER("ha_archive::rnd_next");
statistic_increment(ha_read_rnd_next_count,&LOCK_status);
current_position= gztell(archive);
rc= get_row(buf);
- if (!(HA_ERR_END_OF_FILE == rc))
+ if (rc != HA_ERR_END_OF_FILE)
records++;
DBUG_RETURN(rc);
@@ -450,10 +488,12 @@ void ha_archive::position(const byte *record)
/*
- This is called after a table scan for each row if the results of the scan need
- to be ordered. It will take *pos and use it to move the cursor in the file so
- that the next row that is called is the correctly ordered row.
+ This is called after a table scan for each row if the results of the
+ scan need to be ordered. It will take *pos and use it to move the
+ cursor in the file so that the next row that is called is the
+ correctly ordered row.
*/
+
int ha_archive::rnd_pos(byte * buf, byte *pos)
{
DBUG_ENTER("ha_archive::rnd_pos");
@@ -568,11 +608,8 @@ THR_LOCK_DATA **ha_archive::store_lock(THD *thd,
return to;
}
-ha_rows ha_archive::records_in_range(int inx,
- const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag)
+ha_rows ha_archive::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
{
DBUG_ENTER("ha_archive::records_in_range ");
DBUG_RETURN(records); // HA_ERR_WRONG_COMMAND
diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h
index 2fab80f0598..f08353a5d6c 100644
--- a/sql/examples/ha_archive.h
+++ b/sql/examples/ha_archive.h
@@ -86,7 +86,8 @@ public:
*/
virtual double scan_time() { return (double) (records) / 20.0+10; }
/* The next method will never be called */
- virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; }
+ virtual double read_time(uint index, uint ranges, ha_rows rows)
+ { return (double) rows / 20.0+1; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
int write_row(byte * buf);
@@ -109,10 +110,7 @@ public:
int extra(enum ha_extra_function operation);
int reset(void);
int external_lock(THD *thd, int lock_type);
- ha_rows records_in_range(int inx, const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag);
+ ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
new file mode 100644
index 00000000000..06a19e478ae
--- /dev/null
+++ b/sql/examples/ha_tina.cc
@@ -0,0 +1,851 @@
+/* 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.
+
+ 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 */
+
+/*
+ Make sure to look at ha_tina.h for more details.
+
+ First off, this is a play thing for me, there are a number of things wrong with it:
+ *) It was designed for csv and therefor its performance is highly questionable.
+ *) Indexes have not been implemented. This is because the files can be traded in
+ and out of the table directory without having to worry about rebuilding anything.
+ *) NULLs and "" are treated equally (like a spreadsheet).
+ *) There was in the beginning no point to anyone seeing this other then me, so there
+ is a good chance that I haven't quite documented it well.
+ *) Less design, more "make it work"
+
+ Now there are a few cool things with it:
+ *) Errors can result in corrupted data files.
+ *) Data files can be read by spreadsheets directly.
+
+TODO:
+ *) Move to a block system for larger files
+ *) Error recovery, its all there, just need to finish it
+ *) Document how the chains work.
+
+ -Brian
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+#ifdef HAVE_CSV_DB
+
+#include "ha_tina.h"
+#include <sys/mman.h>
+
+/* Stuff for shares */
+pthread_mutex_t tina_mutex;
+static HASH tina_open_tables;
+static int tina_init= 0;
+
+/*****************************************************************************
+ ** TINA tables
+ *****************************************************************************/
+
+/*
+ Used for sorting chains.
+*/
+int sort_set (tina_set *a, tina_set *b)
+{
+ return ( a->begin > b->begin ? 1 : ( a->begin < b->begin ? -1 : 0 ) );
+}
+
+static byte* tina_get_key(TINA_SHARE *share,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=share->table_name_length;
+ return (byte*) share->table_name;
+}
+
+/*
+ Reloads the mmap file.
+*/
+int get_mmap(TINA_SHARE *share, int write)
+{
+ DBUG_ENTER("ha_tina::get_mmap");
+ if (share->mapped_file && munmap(share->mapped_file, share->file_stat.st_size))
+ DBUG_RETURN(1);
+
+ if (my_fstat(share->data_file, &share->file_stat, MYF(MY_WME)) == -1)
+ DBUG_RETURN(1);
+
+ if (share->file_stat.st_size)
+ {
+ if (write)
+ share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size,
+ PROT_READ|PROT_WRITE, MAP_SHARED,
+ share->data_file, 0);
+ else
+ share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size,
+ PROT_READ, MAP_PRIVATE,
+ share->data_file, 0);
+ if ((share->mapped_file ==(caddr_t)-1))
+ {
+ /*
+ Bad idea you think? See the problem is that nothing actually checks
+ the return value of ::rnd_init(), so tossing an error is about
+ it for us.
+ Never going to happen right? :)
+ */
+ my_message(errno, "Woops, blew up opening a mapped file", 0);
+ DBUG_ASSERT(0);
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ share->mapped_file= NULL;
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Simple lock controls.
+*/
+static TINA_SHARE *get_share(const char *table_name, TABLE *table)
+{
+ TINA_SHARE *share;
+ char *tmp_name;
+ uint length;
+
+ if (!tina_init)
+ {
+ /* Hijack a mutex for init'ing the storage engine */
+ pthread_mutex_lock(&LOCK_mysql_create_db);
+ if (!tina_init)
+ {
+ tina_init++;
+ VOID(pthread_mutex_init(&tina_mutex,MY_MUTEX_INIT_FAST));
+ (void) hash_init(&tina_open_tables,system_charset_info,32,0,0,
+ (hash_get_key) tina_get_key,0,0);
+ }
+ pthread_mutex_unlock(&LOCK_mysql_create_db);
+ }
+ pthread_mutex_lock(&tina_mutex);
+ length=(uint) strlen(table_name);
+ if (!(share=(TINA_SHARE*) hash_search(&tina_open_tables,
+ (byte*) table_name,
+ length)))
+ {
+ char data_file_name[FN_REFLEN];
+ if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &share, sizeof(*share),
+ &tmp_name, length+1,
+ NullS))
+ {
+ pthread_mutex_unlock(&tina_mutex);
+ return NULL;
+ }
+
+ share->use_count=0;
+ share->table_name_length=length;
+ share->table_name=tmp_name;
+ strmov(share->table_name,table_name);
+ fn_format(data_file_name, table_name, "", ".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME);
+ if (my_hash_insert(&tina_open_tables, (byte*) share))
+ goto error;
+ thr_lock_init(&share->lock);
+ pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
+
+ if ((share->data_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1)
+ goto error2;
+
+ /* We only use share->data_file for writing, so we scan to the end to append */
+ if (my_seek(share->data_file, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
+ goto error2;
+
+ share->mapped_file= NULL; // We don't know the state since we just allocated it
+ if (get_mmap(share, 0) > 0)
+ goto error3;
+ }
+ share->use_count++;
+ pthread_mutex_unlock(&tina_mutex);
+
+ return share;
+
+error3:
+ my_close(share->data_file,MYF(0));
+error2:
+ thr_lock_delete(&share->lock);
+ pthread_mutex_destroy(&share->mutex);
+error:
+ pthread_mutex_unlock(&tina_mutex);
+ my_free((gptr) share, MYF(0));
+
+ return NULL;
+}
+
+
+/*
+ Free lock controls.
+*/
+static int free_share(TINA_SHARE *share)
+{
+ DBUG_ENTER("ha_tina::free_share");
+ pthread_mutex_lock(&tina_mutex);
+ int result_code= 0;
+ if (!--share->use_count){
+ /* Drop the mapped file */
+ if (share->mapped_file)
+ munmap(share->mapped_file, share->file_stat.st_size);
+ result_code= my_close(share->data_file,MYF(0));
+ hash_delete(&tina_open_tables, (byte*) share);
+ thr_lock_delete(&share->lock);
+ pthread_mutex_destroy(&share->mutex);
+ my_free((gptr) share, MYF(0));
+ }
+ pthread_mutex_unlock(&tina_mutex);
+
+ DBUG_RETURN(result_code);
+}
+
+
+/*
+ Finds the end of a line.
+ Currently only supports files written on a UNIX OS.
+*/
+byte * find_eoln(byte *data, off_t begin, off_t end)
+{
+ for (off_t x= begin; x < end; x++)
+ if (data[x] == '\n')
+ return data + x;
+
+ return 0;
+}
+
+/*
+ Encode a buffer into the quoted format.
+*/
+int ha_tina::encode_quote(byte *buf)
+{
+ char attribute_buffer[1024];
+ String attribute(attribute_buffer, sizeof(attribute_buffer), &my_charset_bin);
+
+ buffer.length(0);
+ for (Field **field=table->field ; *field ; field++)
+ {
+ const char *ptr;
+ const char *end_ptr;
+
+ (*field)->val_str(&attribute,&attribute);
+ ptr= attribute.ptr();
+ end_ptr= attribute.length() + ptr;
+
+ buffer.append('"');
+
+ while (ptr < end_ptr)
+ {
+ if (*ptr == '"')
+ {
+ buffer.append('\\');
+ buffer.append('"');
+ *ptr++;
+ }
+ else if (*ptr == '\r')
+ {
+ buffer.append('\\');
+ buffer.append('r');
+ *ptr++;
+ }
+ else if (*ptr == '\\')
+ {
+ buffer.append('\\');
+ buffer.append('\\');
+ *ptr++;
+ }
+ else if (*ptr == '\n')
+ {
+ buffer.append('\\');
+ buffer.append('n');
+ *ptr++;
+ }
+ else
+ buffer.append(*ptr++);
+ }
+ buffer.append('"');
+ buffer.append(',');
+ }
+ // Remove the comma, add a line feed
+ buffer.length(buffer.length() - 1);
+ buffer.append('\n');
+ //buffer.replace(buffer.length(), 0, "\n", 1);
+
+ return (buffer.length());
+}
+
+/*
+ chain_append() adds delete positions to the chain that we use to keep track of space.
+*/
+int ha_tina::chain_append()
+{
+ if ( chain_ptr != chain && (chain_ptr -1)->end == current_position)
+ (chain_ptr -1)->end= next_position;
+ else
+ {
+ /* We set up for the next position */
+ if ((off_t)(chain_ptr - chain) == (chain_size -1))
+ {
+ off_t location= chain_ptr - chain;
+ chain_size += DEFAULT_CHAIN_LENGTH;
+ if (chain_alloced)
+ {
+ /* Must cast since my_malloc unlike malloc doesn't have a void ptr */
+ if ((chain= (tina_set *)my_realloc((gptr)chain,chain_size,MYF(MY_WME))) == NULL)
+ return -1;
+ }
+ else
+ {
+ tina_set *ptr= (tina_set *)my_malloc(chain_size * sizeof(tina_set),MYF(MY_WME));
+ memcpy(ptr, chain, DEFAULT_CHAIN_LENGTH * sizeof(tina_set));
+ chain= ptr;
+ chain_alloced++;
+ }
+ chain_ptr= chain + location;
+ }
+ chain_ptr->begin= current_position;
+ chain_ptr->end= next_position;
+ chain_ptr++;
+ }
+
+ return 0;
+}
+
+
+/*
+ Scans for a row.
+*/
+int ha_tina::find_current_row(byte *buf)
+{
+ byte *mapped_ptr= (byte *)share->mapped_file + current_position;
+ byte *end_ptr;
+ DBUG_ENTER("ha_tina::find_current_row");
+
+ /* EOF should be counted as new line */
+ if ((end_ptr= find_eoln(share->mapped_file, current_position, share->file_stat.st_size)) == 0)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ for (Field **field=table->field ; *field ; field++)
+ {
+ int x;
+ buffer.length(0);
+ mapped_ptr++; // Increment past the first quote
+ for(;mapped_ptr != end_ptr; mapped_ptr++)
+ {
+ //Need to convert line feeds!
+ if (*mapped_ptr == '"' &&
+ (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) || (mapped_ptr == end_ptr -1 )))
+ {
+ mapped_ptr += 2; // Move past the , and the "
+ break;
+ }
+ if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
+ {
+ mapped_ptr++;
+ if (*mapped_ptr == 'r')
+ buffer.append('\r');
+ else if (*mapped_ptr == 'n' )
+ buffer.append('\n');
+ else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
+ buffer.append(*mapped_ptr);
+ else /* This could only happed with an externally created file */
+ {
+ buffer.append('\\');
+ buffer.append(*mapped_ptr);
+ }
+ }
+ else
+ buffer.append(*mapped_ptr);
+ }
+ (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
+ }
+ next_position= (end_ptr - share->mapped_file)+1;
+ /* Maybe use \N for null? */
+ memset(buf, 0, table->null_bytes); /* We do not implement nulls! */
+
+ DBUG_RETURN(0);
+}
+
+/*
+ If frm_error() is called in table.cc this is called to find out what file
+ extensions exist for this handler.
+*/
+const char **ha_tina::bas_ext() const
+{ static const char *ext[]= { ".CSV", NullS }; return ext; }
+
+
+/*
+ Open a database file. Keep in mind that tables are caches, so
+ this will not be called for every request. Any sort of positions
+ that need to be reset should be kept in the ::extra() call.
+*/
+int ha_tina::open(const char *name, int mode, uint test_if_locked)
+{
+ DBUG_ENTER("ha_tina::open");
+
+ if (!(share= get_share(name, table)))
+ DBUG_RETURN(1);
+ thr_lock_data_init(&share->lock,&lock,NULL);
+ ref_length=sizeof(off_t);
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Close a database file. We remove ourselves from the shared strucutre.
+ If it is empty we destroy it and free the mapped file.
+*/
+int ha_tina::close(void)
+{
+ DBUG_ENTER("ha_tina::close");
+ DBUG_RETURN(free_share(share));
+}
+
+/*
+ This is an INSERT. At the moment this handler just seeks to the end
+ of the file and appends the data. In an error case it really should
+ just truncate to the original position (this is not done yet).
+*/
+int ha_tina::write_row(byte * buf)
+{
+ int size;
+ DBUG_ENTER("ha_tina::write_row");
+
+ statistic_increment(ha_write_count,&LOCK_status);
+
+ if (table->timestamp_default_now)
+ update_timestamp(buf+table->timestamp_default_now-1);
+
+ size= encode_quote(buf);
+
+ if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
+ DBUG_RETURN(-1);
+
+ /*
+ Ok, this is means that we will be doing potentially bad things
+ during a bulk insert on some OS'es. What we need is a cleanup
+ call for ::write_row that would let us fix up everything after the bulk
+ insert. The archive handler does this with an extra mutx call, which
+ might be a solution for this.
+ */
+ if (get_mmap(share, 0) > 0)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ This is called for an update.
+ Make sure you put in code to increment the auto increment, also
+ update any timestamp data. Currently auto increment is not being
+ fixed since autoincrements have yet to be added to this table handler.
+ This will be called in a table scan right before the previous ::rnd_next()
+ call.
+*/
+int ha_tina::update_row(const byte * old_data, byte * new_data)
+{
+ int size;
+ DBUG_ENTER("ha_tina::update_row");
+
+ statistic_increment(ha_update_count,&LOCK_status);
+
+ if (table->timestamp_default_now)
+ update_timestamp(new_data+table->timestamp_default_now-1);
+
+ size= encode_quote(new_data);
+
+ if (chain_append())
+ DBUG_RETURN(-1);
+
+ if (my_write(share->data_file, buffer.ptr(), size, MYF(MY_WME | MY_NABP)))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Deletes a row. First the database will find the row, and then call this method.
+ In the case of a table scan, the previous call to this will be the ::rnd_next()
+ that found this row.
+ The exception to this is an ORDER BY. This will cause the table handler to walk
+ the table noting the positions of all rows that match a query. The table will
+ then be deleted/positioned based on the ORDER (so RANDOM, DESC, ASC).
+*/
+int ha_tina::delete_row(const byte * buf)
+{
+ DBUG_ENTER("ha_tina::delete_row");
+ statistic_increment(ha_delete_count,&LOCK_status);
+
+ if (chain_append())
+ DBUG_RETURN(-1);
+
+ --records;
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Fill buf with value from key. Simply this is used for a single index read
+ with a key.
+*/
+int ha_tina::index_read(byte * buf, const byte * key,
+ uint key_len __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ DBUG_ENTER("ha_tina::index_read");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+/*
+ Fill buf with value from key. Simply this is used for a single index read
+ with a key.
+ Whatever the current key is we will use it. This is what will be in "index".
+*/
+int ha_tina::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ DBUG_ENTER("ha_tina::index_read_idx");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+
+/*
+ Read the next position in the index.
+*/
+int ha_tina::index_next(byte * buf)
+{
+ DBUG_ENTER("ha_tina::index_next");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+/*
+ Read the previous position in the index.
+*/
+int ha_tina::index_prev(byte * buf)
+{
+ DBUG_ENTER("ha_tina::index_prev");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+/*
+ Read the first position in the index
+*/
+int ha_tina::index_first(byte * buf)
+{
+ DBUG_ENTER("ha_tina::index_first");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+/*
+ Read the last position in the index
+ With this we don't need to do a filesort() with index.
+ We just read the last row and call previous.
+*/
+int ha_tina::index_last(byte * buf)
+{
+ DBUG_ENTER("ha_tina::index_last");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+/*
+ All table scans call this first.
+ The order of a table scan is:
+
+ ha_tina::store_lock
+ ha_tina::external_lock
+ ha_tina::info
+ ha_tina::rnd_init
+ ha_tina::extra
+ ENUM HA_EXTRA_CACHE Cash record in HA_rrnd()
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::rnd_next
+ ha_tina::extra
+ ENUM HA_EXTRA_NO_CACHE End cacheing of records (def)
+ ha_tina::external_lock
+ ha_tina::extra
+ ENUM HA_EXTRA_RESET Reset database to after open
+
+ Each call to ::rnd_next() represents a row returned in the can. When no more
+ rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE.
+ The ::info() call is just for the optimizer.
+
+*/
+
+int ha_tina::rnd_init(bool scan)
+{
+ DBUG_ENTER("ha_tina::rnd_init");
+
+ current_position= next_position= 0;
+ records= 0;
+ chain_ptr= chain;
+ (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL);
+
+ DBUG_RETURN(0);
+}
+
+/*
+ ::rnd_next() does all the heavy lifting for a table scan. You will need to populate *buf
+ with the correct field data. You can walk the field to determine at what position you
+ should store the data (take a look at how ::find_current_row() works). The structure
+ is something like:
+ 0Foo Dog Friend
+ The first offset is for the first attribute. All space before that is reserved for null count.
+ Basically this works as a mask for which rows are nulled (compared to just empty).
+ This table handler doesn't do nulls and does not know the difference between NULL and "". This
+ is ok since this table handler is for spreadsheets and they don't know about them either :)
+*/
+int ha_tina::rnd_next(byte *buf)
+{
+ DBUG_ENTER("ha_tina::rnd_next");
+
+ statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+
+ current_position= next_position;
+ if (!share->mapped_file)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ if (HA_ERR_END_OF_FILE == find_current_row(buf) )
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ records++;
+ DBUG_RETURN(0);
+}
+
+/*
+ In the case of an order by rows will need to be sorted.
+ ::position() is called after each call to ::rnd_next(),
+ the data it stores is to a byte array. You can store this
+ data via ha_store_ptr(). ref_length is a variable defined to the
+ class that is the sizeof() of position being stored. In our case
+ its just a position. Look at the bdb code if you want to see a case
+ where something other then a number is stored.
+*/
+void ha_tina::position(const byte *record)
+{
+ DBUG_ENTER("ha_tina::position");
+ ha_store_ptr(ref, ref_length, current_position);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Used to fetch a row from a posiion stored with ::position().
+ ha_get_ptr() retrieves the data for you.
+*/
+
+int ha_tina::rnd_pos(byte * buf, byte *pos)
+{
+ DBUG_ENTER("ha_tina::rnd_pos");
+ statistic_increment(ha_read_rnd_count,&LOCK_status);
+ current_position= ha_get_ptr(pos,ref_length);
+ DBUG_RETURN(find_current_row(buf));
+}
+
+/*
+ ::info() is used to return information to the optimizer.
+ Currently this table handler doesn't implement most of the fields
+ really needed. SHOW also makes use of this data
+*/
+void ha_tina::info(uint flag)
+{
+ DBUG_ENTER("ha_tina::info");
+ /* This is a lie, but you don't want the optimizer to see zero or 1 */
+ if (records < 2)
+ records= 2;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Grab bag of flags that are sent to the able handler every so often.
+ HA_EXTRA_RESET and HA_EXTRA_RESET_STATE are the most frequently called.
+ You are not required to implement any of these.
+*/
+int ha_tina::extra(enum ha_extra_function operation)
+{
+ DBUG_ENTER("ha_tina::extra");
+ DBUG_RETURN(0);
+}
+
+/*
+ This is no longer used.
+*/
+int ha_tina::reset(void)
+{
+ DBUG_ENTER("ha_tina::reset");
+ ha_tina::extra(HA_EXTRA_RESET);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Called after deletes, inserts, and updates. This is where we clean up all of
+ the dead space we have collected while writing the file.
+*/
+int ha_tina::rnd_end()
+{
+ DBUG_ENTER("ha_tina::rnd_end");
+
+ /* First position will be truncate position, second will be increment */
+ if ((chain_ptr - chain) > 0)
+ {
+ tina_set *ptr;
+ off_t length;
+
+ /*
+ Setting up writable map, this will contain all of the data after the
+ get_mmap call that we have added to the file.
+ */
+ if (get_mmap(share, 1) > 0)
+ DBUG_RETURN(-1);
+ length= share->file_stat.st_size;
+
+ /*
+ The sort handles updates/deletes with random orders.
+ It also sorts so that we move the final blocks to the
+ beginning so that we move the smallest amount of data possible.
+ */
+ qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
+ for (ptr= chain; ptr < chain_ptr; ptr++)
+ printf("Chain %d, %d\n", (int)ptr->begin, (int)ptr->end);
+ for (ptr= chain; ptr < chain_ptr; ptr++)
+ {
+ //memmove(share->mapped_file + ptr->begin, share->mapped_file
+ //+ ptr->end, length - (size_t)ptr->end);
+ /* We peek a head to see if this is the last chain */
+ printf("Delete %d, %d, %d\n", (int)ptr->begin, (int)ptr->end, (int)length);
+ if (ptr+1 == chain_ptr)
+ {
+ printf("Shiftina(end) %d(%d) to %d\n", (int)ptr->end, (int)(length - (size_t)ptr->end), (int)ptr->begin);
+ memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
+ length - (size_t)ptr->end);
+ }
+ else
+ {
+ printf("Shifting %d(%d) to %d\n", (int)ptr->end, (int)((ptr++)->begin - (size_t)ptr->end), (int)ptr->begin);
+ memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
+ (size_t)(ptr++)->begin - (size_t)ptr->end);
+ }
+ length= length - (size_t)(ptr->end - ptr->begin);
+ }
+ printf("Buffer %s\n",share->mapped_file);
+
+ /* Truncate the file to the new size */
+ if (my_chsize(share->data_file, length, 0, MYF(MY_WME)))
+ DBUG_RETURN(-1);
+
+ if (munmap(share->mapped_file, length))
+ DBUG_RETURN(-1);
+
+ /* We set it to null so that get_mmap() won't try to unmap it */
+ share->mapped_file= NULL;
+ if (get_mmap(share, 0) > 0)
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Truncate table and others of its ilk call this.
+*/
+int ha_tina::delete_all_rows()
+{
+ DBUG_ENTER("ha_tina::delete_all_rows");
+
+ int rc= my_chsize(share->data_file, 0, 0, MYF(MY_WME));
+
+ if (get_mmap(share, 0) > 0)
+ DBUG_RETURN(-1);
+
+ DBUG_RETURN(rc);
+}
+
+/*
+ Always called by the start of a transaction (or by "lock tables");
+*/
+int ha_tina::external_lock(THD *thd, int lock_type)
+{
+ DBUG_ENTER("ha_tina::external_lock");
+ DBUG_RETURN(0); // No external locking
+}
+
+/*
+ Called by the database to lock the table. Keep in mind that this
+ is an internal lock.
+*/
+THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ lock.type=lock_type;
+ *to++= &lock;
+ return to;
+}
+
+/*
+ Range optimizer calls this.
+ I need to update the information on this.
+*/
+ha_rows ha_tina::records_in_range(int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag)
+{
+ DBUG_ENTER("ha_tina::records_in_range ");
+ DBUG_RETURN(records); // Good guess
+}
+
+
+/*
+ Create a table. You do not want to leave the table open after a call to
+ this (the database will call ::open() if it needs to).
+*/
+
+int ha_tina::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info)
+{
+ char name_buff[FN_REFLEN];
+ File create_file;
+ DBUG_ENTER("ha_tina::create");
+
+ if ((create_file= my_create(fn_format(name_buff,name,"",".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ DBUG_RETURN(-1);
+
+ my_close(create_file,MYF(0));
+
+ DBUG_RETURN(0);
+}
+
+#endif /* enable CSV */
diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h
new file mode 100644
index 00000000000..67a907fddb6
--- /dev/null
+++ b/sql/examples/ha_tina.h
@@ -0,0 +1,132 @@
+/* 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.
+
+ 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 <sys/types.h>
+#include <sys/stat.h>
+#include <my_dir.h>
+
+#define DEFAULT_CHAIN_LENGTH 512
+
+typedef struct st_tina_share {
+ char *table_name;
+ byte *mapped_file; /* mapped region of file */
+ uint table_name_length,use_count;
+ MY_STAT file_stat; /* Stat information for the data file */
+ File data_file; /* Current open data file */
+ pthread_mutex_t mutex;
+ THR_LOCK lock;
+} TINA_SHARE;
+
+typedef struct tina_set {
+ off_t begin;
+ off_t end;
+};
+
+class ha_tina: public handler
+{
+ THR_LOCK_DATA lock; /* MySQL lock */
+ TINA_SHARE *share; /* Shared lock info */
+ off_t current_position; /* Current position in the file during a file scan */
+ off_t next_position; /* Next position in the file scan */
+ byte byte_buffer[IO_SIZE];
+ String buffer;
+ tina_set chain_buffer[DEFAULT_CHAIN_LENGTH];
+ tina_set *chain;
+ tina_set *chain_ptr;
+ byte chain_alloced;
+ uint32 chain_size;
+
+ public:
+ ha_tina(TABLE *table): handler(table),
+ /*
+ These definitions are found in hanler.h
+ Theses are not probably completely right.
+ */
+ current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH)
+ {
+ /* Set our original buffers from pre-allocated memory */
+ buffer.set(byte_buffer, IO_SIZE, system_charset_info);
+ chain = chain_buffer;
+ }
+ ~ha_tina()
+ {
+ if (chain_alloced)
+ my_free((gptr)chain,0);
+ }
+ const char *table_type() const { return "CSV"; }
+ const char *index_type(uint inx) { return "NONE"; }
+ const char **bas_ext() const;
+ ulong table_flags() const
+ {
+ return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT |
+ HA_NO_AUTO_INCREMENT );
+ }
+ ulong index_flags(uint idx, uint part, bool all_parts) const
+ {
+ /* We will never have indexes so this will never be called(AKA we return zero) */
+ return 0;
+ }
+ uint max_record_length() const { return HA_MAX_REC_LENGTH; }
+ uint max_keys() const { return 0; }
+ uint max_key_parts() const { return 0; }
+ uint max_key_length() const { return 0; }
+ /*
+ Called in test_quick_select to determine if indexes should be used.
+ */
+ virtual double scan_time() { return (double) (records+deleted) / 20.0+10; }
+ /* The next method will never be called */
+ virtual double read_time(ha_rows rows) { DBUG_ASSERT(0); return((double) rows / 20.0+1); }
+ virtual bool fast_key_read() { return 1;}
+
+ 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 index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int rnd_init(bool scan=1);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ int rnd_end();
+ void position(const byte *record);
+ void info(uint);
+ int extra(enum ha_extra_function operation);
+ int reset(void);
+ int external_lock(THD *thd, int lock_type);
+ int delete_all_rows(void);
+ ha_rows records_in_range(int inx, const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
+// int delete_table(const char *from);
+// int rename_table(const char * from, const char * to);
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+
+ /* The following methods were added just for TINA */
+ int encode_quote(byte *buf);
+ int find_current_row(byte *buf);
+ int chain_append();
+};
diff --git a/sql/field.cc b/sql/field.cc
index c96a5a6d809..5356fbc773a 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -46,6 +46,8 @@ template class List_iterator<create_field>;
uchar Field_null::null[1]={1};
const char field_separator=',';
+#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320
+
/*****************************************************************************
Static help functions
*****************************************************************************/
@@ -876,7 +878,7 @@ int Field_decimal::store(double nr)
reg4 uint i,length;
char fyllchar,*to;
- char buff[320];
+ char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
fyllchar = zerofill ? (char) '0' : (char) ' ';
#ifdef HAVE_SNPRINTF
@@ -1758,6 +1760,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
len-= tmp;
from+= tmp;
my_errno=0;
+
if (unsigned_flag)
{
if (!len || *from == '-')
@@ -1774,6 +1777,34 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
if (error ||
(from+len != end && table->in_use->count_cuted_fields &&
!test_if_int(from,len,end,cs)))
+ error= 1;
+#if SIZEOF_LONG > 4
+ if (unsigned_flag)
+ {
+ if ((ulong) tmp > UINT_MAX32)
+ {
+ tmp= UINT_MAX32;
+ error= 1;
+ my_errno=ERANGE;
+ }
+ }
+ else
+ {
+ if (tmp > INT_MAX32)
+ {
+ tmp= INT_MAX32;
+ error= 1;
+ my_errno=ERANGE;
+ }
+ else if (tmp < INT_MIN32)
+ {
+ tmp= INT_MIN32;
+ error= 1;
+ my_errno=ERANGE;
+ }
+ }
+#endif
+ if (error)
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1);
error= 1;
@@ -2695,7 +2726,7 @@ String *Field_double::val_str(String *val_buffer,
#endif
doubleget(nr,ptr);
- uint to_length=max(field_length,320);
+ uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE);
val_buffer->alloc(to_length);
char *to=(char*) val_buffer->ptr();
@@ -2707,7 +2738,8 @@ String *Field_double::val_str(String *val_buffer,
else
{
#ifdef HAVE_FCONVERT
- char buff[320],*pos=buff;
+ char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
+ char *pos= buff;
int decpt,sign,tmp_dec=dec;
VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff));
@@ -2877,7 +2909,8 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
:Field_str(ptr_arg, 19, (uchar*) 0,0,
unireg_check_arg, field_name_arg, table_arg, cs)
{
- flags|=ZEROFILL_FLAG; /* 4.0 MYD compatibility */
+ /* For 4.0 MYD and 4.0 InnoDB compatibility */
+ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
if (table && !table->timestamp_field &&
unireg_check != NONE)
{
@@ -4231,13 +4264,40 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
}
-int Field_string::store(double nr)
+/*
+ Store double value in Field_string or Field_varstring.
+
+ SYNOPSIS
+ store(double nr)
+ nr number
+
+ DESCRIPTION
+ Pretty prints double number into field_length characters buffer.
+*/
+
+int Field_str::store(double nr)
{
- char buff[MAX_FIELD_WIDTH],*end;
- int width=min(field_length,DBL_DIG+5);
- sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
- end=strcend(buff,' ');
- return Field_string::store(buff,(uint) (end - buff), &my_charset_bin);
+ char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
+ uint length;
+ bool use_scientific_notation= TRUE;
+ use_scientific_notation= TRUE;
+if (field_length < 32 && fabs(nr) < log_10[field_length]-1)
+ use_scientific_notation= FALSE;
+ length= (uint) my_sprintf(buff, (buff, "%-.*g",
+ (use_scientific_notation ?
+ max(0, (int)field_length-5) :
+ field_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 field_length < 5 is for extreme cases,
+ like inserting 500.0 in char(1)
+ */
+ DBUG_ASSERT(field_length < 5 || length <= field_length+1);
+ return store((const char *)buff, min(length, field_length), charset());
}
@@ -4313,7 +4373,7 @@ void Field_string::sql_type(String &res) const
(field_length > 3 &&
(table->db_options_in_use &
HA_OPTION_PACK_RECORD) ?
- (has_charset() ? "varchar" : "varbinary") :
+ (has_charset() ? "varchar" : "varbinary") :
(has_charset() ? "char" : "binary")),
(int) field_length / charset()->mbmaxlen);
res.length(length);
@@ -4332,6 +4392,21 @@ char *Field_string::pack(char *to, const char *from, uint max_length)
}
+char *Field_string::pack_key(char *to, const char *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);
+ while (length && from[length-1] == ' ')
+ length--;
+ *to= (uchar)length;
+ memcpy(to+1, from, length);
+ return to+1+length;
+}
+
+
const char *Field_string::unpack(char *to, const char *from)
{
uint length= (uint) (uchar) *from++;
@@ -4409,16 +4484,6 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
}
-int Field_varstring::store(double nr)
-{
- char buff[MAX_FIELD_WIDTH],*end;
- int width=min(field_length,DBL_DIG+5);
- sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
- end=strcend(buff,' ');
- return Field_varstring::store(buff,(uint) (end - buff), &my_charset_bin);
-}
-
-
int Field_varstring::store(longlong nr)
{
char buff[64];
@@ -4505,6 +4570,24 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
}
+char *Field_varstring::pack_key(char *to, const char *from, uint max_length)
+{
+ uint length=uint2korr(from);
+ uint char_length= (field_charset->mbmaxlen > 1) ?
+ max_length/field_charset->mbmaxlen : max_length;
+ from+=HA_KEY_BLOB_LENGTH;
+ if (length > char_length)
+ char_length= my_charpos(field_charset, from, from+length, char_length);
+ set_if_smaller(length, char_length);
+ *to++= (char) (length & 255);
+ if (max_length > 255)
+ *to++= (char) (length >> 8);
+ if (length)
+ memcpy(to, from, length);
+ return to+length;
+}
+
+
const char *Field_varstring::unpack(char *to, const char *from)
{
uint length;
@@ -5080,16 +5163,17 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
char *save=ptr;
ptr=(char*) from;
uint32 length=get_length(); // Length of from string
- if (length > max_length)
- length=max_length;
+ uint 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);
*to++= (uchar) length;
if (max_length > 255) // 2 byte length
*to++= (uchar) (length >> 8);
- if (length)
- {
- get_ptr((char**) &from);
- memcpy(to, from, length);
- }
+ memcpy(to, from, length);
ptr=save; // Restore org row pointer
return to+length;
}
@@ -5666,6 +5750,10 @@ void create_field::create_length_to_internal_length(void)
pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
FIELD_TYPE_STRING : sql_type, length);
break;
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ length*= charset->mbmaxlen;
+ break;
default:
/* do nothing */
break;
diff --git a/sql/field.h b/sql/field.h
index 24faee9d314..e12dd60c13b 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -38,7 +38,7 @@ class Field
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
static void operator delete(void *ptr_arg, size_t size) {
-#ifdef PEDANTIC_SAFEMALLOC
+#ifdef SAFEMALLOC
bfill(ptr_arg, size, 0x8F);
#endif
}
@@ -343,18 +343,21 @@ public:
struct st_table *table_arg,CHARSET_INFO *charset)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
- {
+ {
field_charset=charset;
if (charset->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
}
Item_result result_type () const { return STRING_RESULT; }
uint decimals() const { return NOT_FIXED_DEC; }
+ int store(double nr);
+ int store(longlong nr)=0;
+ int store(const char *to,uint length,CHARSET_INFO *cs)=0;
void make_field(Send_field *);
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
- bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; }
+ bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_length() { return field_length; }
friend class create_field;
};
@@ -904,8 +907,8 @@ public:
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(double nr);
int store(longlong nr);
+ 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 *);
@@ -913,6 +916,7 @@ public:
void sort_string(char *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);
const char *unpack(char* to, const char *from);
int pack_cmp(const char *a,const char *b,uint key_length);
int pack_cmp(const char *b,uint key_length);
@@ -950,8 +954,8 @@ public:
uint32 pack_length() const { return (uint32) field_length+2; }
uint32 key_length() const { return (uint32) field_length; }
int store(const char *to,uint length,CHARSET_INFO *charset);
- int store(double nr);
int store(longlong nr);
+ 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 *);
@@ -961,6 +965,7 @@ public:
void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
+ char *pack_key(char *to, const char *from, uint max_length);
const char *unpack(char* to, const char *from);
int pack_cmp(const char *a, const char *b, uint key_length);
int pack_cmp(const char *b, uint key_length);
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index e98068ef974..d7993939092 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -340,8 +340,10 @@ static void do_cut_string(Copy_field *copy)
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);
- bfill(copy->to_ptr+copy->from_length,copy->to_length-copy->from_length,' ');
+ cs->cset->fill(cs, copy->to_ptr+copy->from_length,
+ copy->to_length-copy->from_length, ' ');
}
static void do_varstring(Copy_field *copy)
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 7a445ed8c4d..0bbdf84c8d6 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -362,7 +362,7 @@ static int get_options(int argc, char **argv)
{
int ho_error;
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(ho_error);
if (argc >= 1)
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 00df84e3797..b4f07073afa 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -357,9 +357,11 @@ ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const
case HA_KEYTYPE_VARTEXT:
/*
As BDB stores only one copy of equal strings, we can't use key read
- on these
+ on these. Binary collations do support key read though.
*/
- flags&= ~HA_KEYREAD_ONLY;
+ if (!(table->key_info[idx].key_part[i].field->charset()->state
+ & MY_CS_BINSORT))
+ flags&= ~HA_KEYREAD_ONLY;
break;
default: // Keep compiler happy
break;
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index cc828b6e6b2..d7327362286 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -360,7 +360,8 @@ THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
int ha_heap::delete_table(const char *name)
{
- int error=heap_delete_table(name);
+ char buff[FN_REFLEN];
+ int error= heap_delete_table(fn_format(buff,name,"","",4+2));
return error == ENOENT ? 0 : error;
}
@@ -429,7 +430,7 @@ int ha_heap::create(const char *name, TABLE *table_arg,
{
if (!f_is_packed(flag) &&
f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
- !(flag & FIELDFLAG_BINARY))
+ !(field->charset() == &my_charset_bin))
seg->type= (int) HA_KEYTYPE_TEXT;
else
seg->type= (int) HA_KEYTYPE_BINARY;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 700b8fafe19..3003425a489 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -40,6 +40,7 @@ have disables the InnoDB inlining in this file. */
#include <m_ctype.h>
#include <hash.h>
#include <myisampack.h>
+#include <mysys_err.h>
#define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
@@ -117,6 +118,8 @@ my_bool innobase_log_archive = FALSE;/* unused */
my_bool innobase_use_native_aio = FALSE;
my_bool innobase_fast_shutdown = TRUE;
my_bool innobase_file_per_table = FALSE;
+my_bool innobase_locks_unsafe_for_binlog = FALSE;
+my_bool innobase_create_status_file = FALSE;
static char *internal_innobase_data_file_path = NULL;
@@ -134,6 +137,10 @@ char innodb_dummy_stmt_trx_handle = 'D';
static HASH innobase_open_tables;
+#ifdef __NETWARE__ /* some special cleanup for NetWare */
+bool nw_panic = FALSE;
+#endif
+
static mysql_byte* innobase_get_key(INNOBASE_SHARE *share,uint *length,
my_bool not_used __attribute__((unused)));
static INNOBASE_SHARE *get_share(const char *table_name);
@@ -292,8 +299,9 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) {
- return(HA_ERR_ROW_IS_REFERENCED);
-
+ return(HA_ERR_CANNOT_ADD_FOREIGN); /* TODO: This is a bit
+ misleading, a new MySQL error
+ code should be introduced */
} else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
return(HA_ERR_CRASHED);
@@ -419,6 +427,50 @@ innobase_mysql_print_thd(
}
/*************************************************************************
+Creates a temporary file. */
+extern "C"
+int
+innobase_mysql_tmpfile(void)
+/*========================*/
+ /* out: temporary file descriptor, or < 0 on error */
+{
+ char filename[FN_REFLEN];
+ int fd2 = -1;
+ File fd = create_temp_file(filename, NullS, "ib",
+#ifdef __WIN__
+ O_BINARY | O_TRUNC | O_SEQUENTIAL |
+ O_TEMPORARY | O_SHORT_LIVED |
+#endif /* __WIN__ */
+ O_CREAT | O_EXCL | O_RDWR,
+ MYF(MY_WME));
+ if (fd >= 0) {
+#ifndef __WIN__
+ /* On Windows, open files cannot be removed, but files can be
+ created with the O_TEMPORARY flag to the same effect
+ ("delete on close"). */
+ unlink(filename);
+#endif /* !__WIN__ */
+ /* Copy the file descriptor, so that the additional resources
+ allocated by create_temp_file() can be freed by invoking
+ my_close().
+
+ Because the file descriptor returned by this function
+ will be passed to fdopen(), it will be closed by invoking
+ fclose(), which in turn will invoke close() instead of
+ my_close(). */
+ fd2 = dup(fd);
+ if (fd2 < 0) {
+ DBUG_PRINT("error",("Got error %d on dup",fd2));
+ my_errno=errno;
+ my_error(EE_OUT_OF_FILERESOURCES,
+ MYF(ME_BELL+ME_WAITTANG), filename, my_errno);
+ }
+ my_close(fd, MYF(MY_WME));
+ }
+ return(fd2);
+}
+
+/*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still
lacks one. */
@@ -910,8 +962,10 @@ innobase_init(void)
srv_fast_shutdown = (ibool) innobase_fast_shutdown;
srv_file_per_table = (ibool) innobase_file_per_table;
+ srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
srv_max_n_open_files = (ulint) innobase_open_files;
+ srv_innodb_status = (ibool) innobase_create_status_file;
srv_print_verbose_log = mysql_embedded ? 0 : 1;
@@ -982,6 +1036,11 @@ innobase_end(void)
DBUG_ENTER("innobase_end");
+#ifdef __NETWARE__ /* some special cleanup for NetWare */
+ if (nw_panic) {
+ set_panic_flag_for_netware();
+ }
+#endif
if (innodb_inited)
{
innodb_inited= 0;
@@ -3645,11 +3704,19 @@ ha_innobase::create(
}
if (current_thd->query != NULL) {
-
- error = row_table_add_foreign_constraints(trx,
- current_thd->query, norm_name);
- error = convert_error_code_to_mysql(error, NULL);
+ LEX_STRING q;
+ if (thd->convert_string(&q, system_charset_info,
+ current_thd->query,
+ current_thd->query_length,
+ current_thd->charset())) {
+ error = HA_ERR_OUT_OF_MEM;
+ } else {
+ error = row_table_add_foreign_constraints(trx,
+ q.str, norm_name);
+
+ error = convert_error_code_to_mysql(error, NULL);
+ }
if (error) {
innobase_commit_low(trx);
@@ -4398,7 +4465,7 @@ ha_innobase::update_table_comment(
trx_search_latch_release_if_reserved(prebuilt->trx);
str = NULL;
- if (FILE* file = tmpfile()) {
+ if (FILE* file = os_file_create_tmpfile()) {
long flen;
/* output the data to a temporary file */
@@ -4460,7 +4527,7 @@ ha_innobase::get_foreign_key_create_info(void)
update_thd(current_thd);
- if (FILE* file = tmpfile()) {
+ if (FILE* file = os_file_create_tmpfile()) {
long flen;
prebuilt->trx->op_info = (char*)"getting info on foreign keys";
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index a158321c5df..1bfb86de944 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -190,7 +190,8 @@ extern char *innobase_unix_file_flush_method;
/* The following variables have to be my_bool for SHOW VARIABLES to work */
extern my_bool innobase_log_archive,
innobase_use_native_aio, innobase_fast_shutdown,
- innobase_file_per_table;
+ innobase_file_per_table, innobase_locks_unsafe_for_binlog,
+ innobase_create_status_file;
extern "C" {
extern ulong srv_max_buf_pool_modified_pct;
}
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 79e1d7b463b..89288d6059f 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -958,15 +958,21 @@ int ha_myisam::indexes_are_disabled(void)
start_bulk_insert(rows)
rows Rows to be inserted
0 if we don't know
+
+ NOTICE
+ Do not forget to call end_bulk_insert() later!
*/
void ha_myisam::start_bulk_insert(ha_rows rows)
{
+ DBUG_ENTER("ha_myisam::start_bulk_insert");
THD *thd=current_thd;
ulong size= min(thd->variables.read_buff_size, table->avg_row_length*rows);
+ DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
+ (ulong) rows, size));
/* don't enable row cache if too few rows */
- if (!rows && rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE)
+ if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
can_enable_indexes= (file->s->state.key_map ==
@@ -990,8 +996,22 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
}
}
+ DBUG_VOID_RETURN;
}
+/*
+ end special bulk-insert optimizations,
+ which have been activated by start_bulk_insert().
+
+ SYNOPSIS
+ end_bulk_insert()
+ no arguments
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
int ha_myisam::end_bulk_insert()
{
mi_end_bulk_insert(file);
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 5b36d6d2b55..815aed13ce3 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -41,7 +41,13 @@ static const int parallelism= 240;
// Default value for max number of transactions
// createable against NDB from this handler
-static const int max_transactions = 256;
+static const int max_transactions= 256;
+
+// Default value for prefetch of autoincrement values
+static const ha_rows autoincrement_prefetch= 32;
+
+// connectstring to cluster if given by mysqld
+const char *ndbcluster_connectstring= 0;
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
@@ -138,6 +144,7 @@ static int ndb_to_mysql_error(const NdbError *err)
int ha_ndbcluster::ndb_err(NdbConnection *trans)
{
+ int res;
const NdbError err= trans->getNdbError();
if (!err.code)
return 0; // Don't log things to DBUG log if no error
@@ -155,7 +162,13 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans)
default:
break;
}
- DBUG_RETURN(ndb_to_mysql_error(&err));
+ res= ndb_to_mysql_error(&err);
+ DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
+ err.code, res));
+ if (res == HA_ERR_FOUND_DUPP_KEY)
+ dupkey= table->primary_key;
+
+ DBUG_RETURN(res);
}
@@ -182,6 +195,45 @@ bool ha_ndbcluster::get_error_message(int error,
/*
+ Check if type is supported by NDB.
+ TODO Use this once, not in every operation
+*/
+
+static inline bool ndb_supported_type(enum_field_types type)
+{
+ switch (type) {
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ return true;
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_GEOMETRY:
+ break;
+ }
+ return false;
+}
+
+
+/*
Instruct NDB to set the value of the hidden primary key
*/
@@ -208,40 +260,15 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
pack_len));
DBUG_DUMP("key", (char*)field_ptr, pack_len);
- switch (field->type()) {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- // Common implementation for most field types
- DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
-
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_GEOMETRY:
- default:
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
+ if (ndb_supported_type(field->type()))
+ {
+ if (! (field->flags & BLOB_FLAG))
+ // Common implementation for most field types
+ DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
}
- DBUG_RETURN(3);
+ // Unhandled field types
+ DBUG_PRINT("error", ("Field type %d not supported", field->type()));
+ DBUG_RETURN(2);
}
@@ -259,63 +286,197 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
fieldnr, field->field_name, field->type(),
pack_len, field->is_null()?"Y":"N"));
DBUG_DUMP("value", (char*) field_ptr, pack_len);
-
- if (field->is_null())
+
+ if (ndb_supported_type(field->type()))
{
- // Set value to NULL
- DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0));
- }
-
- switch (field->type()) {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- // Common implementation for most field types
- DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)field_ptr, pack_len) != 0);
-
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_GEOMETRY:
- default:
- // Unhandled field types
- DBUG_PRINT("error", ("Field type %d not supported", field->type()));
- DBUG_RETURN(2);
+ if (! (field->flags & BLOB_FLAG))
+ {
+ if (field->is_null())
+ // Set value to NULL
+ DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0));
+ // Common implementation for most field types
+ DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)field_ptr, pack_len) != 0);
+ }
+
+ // Blob type
+ NdbBlob *ndb_blob= ndb_op->getBlobHandle(fieldnr);
+ if (ndb_blob != NULL)
+ {
+ if (field->is_null())
+ DBUG_RETURN(ndb_blob->setNull() != 0);
+
+ Field_blob *field_blob= (Field_blob*)field;
+
+ // Get length and pointer to data
+ uint32 blob_len= field_blob->get_length(field_ptr);
+ char* blob_ptr= NULL;
+ field_blob->get_ptr(&blob_ptr);
+
+ // Looks like NULL blob can also be signaled in this way
+ if (blob_ptr == NULL)
+ DBUG_RETURN(ndb_blob->setNull() != 0);
+
+ DBUG_PRINT("value", ("set blob ptr=%x len=%u",
+ (unsigned)blob_ptr, blob_len));
+ DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26));
+
+ // No callback needed to write value
+ DBUG_RETURN(ndb_blob->setValue(blob_ptr, blob_len) != 0);
+ }
+ DBUG_RETURN(1);
}
- DBUG_RETURN(3);
+ // Unhandled field types
+ DBUG_PRINT("error", ("Field type %d not supported", field->type()));
+ DBUG_RETURN(2);
+}
+
+
+/*
+ Callback to read all blob values.
+ - not done in unpack_record because unpack_record is valid
+ after execute(Commit) but reading blobs is not
+ - may only generate read operations; they have to be executed
+ somewhere before the data is available
+ - due to single buffer for all blobs, we let the last blob
+ process all blobs (last so that all are active)
+ - null bit is still set in unpack_record
+ - TODO allocate blob part aligned buffers
+*/
+
+NdbBlob::ActiveHook g_get_ndb_blobs_value;
+
+int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
+{
+ DBUG_ENTER("g_get_ndb_blobs_value");
+ if (ndb_blob->blobsNextBlob() != NULL)
+ DBUG_RETURN(0);
+ ha_ndbcluster *ha= (ha_ndbcluster *)arg;
+ DBUG_RETURN(ha->get_ndb_blobs_value(ndb_blob));
+}
+
+int ha_ndbcluster::get_ndb_blobs_value(NdbBlob *last_ndb_blob)
+{
+ DBUG_ENTER("get_ndb_blobs_value");
+
+ // Field has no field number so cannot use TABLE blob_field
+ // Loop twice, first only counting total buffer size
+ for (int loop= 0; loop <= 1; loop++)
+ {
+ uint32 offset= 0;
+ for (uint i= 0; i < table->fields; i++)
+ {
+ Field *field= table->field[i];
+ NdbValue value= m_value[i];
+ if (value.ptr != NULL && (field->flags & BLOB_FLAG))
+ {
+ Field_blob *field_blob= (Field_blob *)field;
+ NdbBlob *ndb_blob= value.blob;
+ Uint64 blob_len= 0;
+ if (ndb_blob->getLength(blob_len) != 0)
+ DBUG_RETURN(-1);
+ // Align to Uint64
+ uint32 blob_size= blob_len;
+ if (blob_size % 8 != 0)
+ blob_size+= 8 - blob_size % 8;
+ if (loop == 1)
+ {
+ char *buf= blobs_buffer + offset;
+ uint32 len= 0xffffffff; // Max uint32
+ DBUG_PRINT("value", ("read blob ptr=%x len=%u",
+ (uint)buf, (uint)blob_len));
+ if (ndb_blob->readData(buf, len) != 0)
+ DBUG_RETURN(-1);
+ DBUG_ASSERT(len == blob_len);
+ field_blob->set_ptr(len, buf);
+ }
+ offset+= blob_size;
+ }
+ }
+ if (loop == 0 && offset > blobs_buffer_size)
+ {
+ my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ blobs_buffer_size= 0;
+ DBUG_PRINT("value", ("allocate blobs buffer size %u", offset));
+ blobs_buffer= my_malloc(offset, MYF(MY_WME));
+ if (blobs_buffer == NULL)
+ DBUG_RETURN(-1);
+ blobs_buffer_size= offset;
+ }
+ }
+ DBUG_RETURN(0);
}
/*
Instruct NDB to fetch one field
- - data is read directly into buffer provided by field_ptr
- if it's NULL, data is read into memory provided by NDBAPI
+ - data is read directly into buffer provided by field
+ if field is NULL, data is read into memory provided by NDBAPI
*/
-int ha_ndbcluster::get_ndb_value(NdbOperation *op,
- uint field_no, byte *field_ptr)
+int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
+ uint fieldnr)
{
DBUG_ENTER("get_ndb_value");
- DBUG_PRINT("enter", ("field_no: %d", field_no));
- m_value[field_no]= op->getValue(field_no, field_ptr);
- DBUG_RETURN(m_value == NULL);
+ DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr,
+ (int)(field != NULL ? field->flags : 0)));
+
+ if (field != NULL)
+ {
+ if (ndb_supported_type(field->type()))
+ {
+ DBUG_ASSERT(field->ptr != NULL);
+ if (! (field->flags & BLOB_FLAG))
+ {
+ m_value[fieldnr].rec= ndb_op->getValue(fieldnr, field->ptr);
+ DBUG_RETURN(m_value[fieldnr].rec == NULL);
+ }
+
+ // Blob type
+ NdbBlob *ndb_blob= ndb_op->getBlobHandle(fieldnr);
+ m_value[fieldnr].blob= ndb_blob;
+ if (ndb_blob != NULL)
+ {
+ // Set callback
+ void *arg= (void *)this;
+ DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0);
+ }
+ DBUG_RETURN(1);
+ }
+ // Unhandled field types
+ DBUG_PRINT("error", ("Field type %d not supported", field->type()));
+ DBUG_RETURN(2);
+ }
+
+ // Used for hidden key only
+ m_value[fieldnr].rec= ndb_op->getValue(fieldnr, NULL);
+ DBUG_RETURN(m_value[fieldnr].rec == NULL);
+}
+
+
+/*
+ Check if any set or get of blob value in current query.
+*/
+bool ha_ndbcluster::uses_blob_value(bool all_fields)
+{
+ if (table->blob_fields == 0)
+ return false;
+ if (all_fields)
+ return true;
+ {
+ uint no_fields= table->fields;
+ int i;
+ THD *thd= current_thd;
+ // They always put blobs at the end..
+ for (i= no_fields - 1; i >= 0; i--)
+ {
+ Field *field= table->field[i];
+ if (thd->query_id == field->query_id)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
}
@@ -391,41 +552,95 @@ int ha_ndbcluster::get_metadata(const char *path)
// All checks OK, lets use the table
m_table= (void*)tab;
- DBUG_RETURN(build_index_list());
+ DBUG_RETURN(build_index_list(table, ILBP_OPEN));
}
-int ha_ndbcluster::build_index_list()
+
+int ha_ndbcluster::build_index_list(TABLE *tab, enum ILBP phase)
{
+ int error= 0;
char *name;
const char *index_name;
static const char* unique_suffix= "$unique";
uint i, name_len;
+ KEY* key_info= tab->key_info;
+ const char **key_name= tab->keynames.type_names;
+ NdbDictionary::Dictionary *dict= m_ndb->getDictionary();
DBUG_ENTER("build_index_list");
// Save information about all known indexes
- for (uint i= 0; i < table->keys; i++)
+ for (i= 0; i < tab->keys; i++, key_info++, key_name++)
{
+ index_name= *key_name;
NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
- m_indextype[i]= idx_type;
-
+ m_index[i].type= idx_type;
if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
{
- index_name= get_index_name(i);
name_len= strlen(index_name)+strlen(unique_suffix)+1;
// Create name for unique index by appending "$unique";
if (!(name= my_malloc(name_len, MYF(MY_WME))))
DBUG_RETURN(2);
strxnmov(name, name_len, index_name, unique_suffix, NullS);
- m_unique_index_name[i]= name;
+ m_index[i].unique_name= name;
DBUG_PRINT("info", ("Created unique index name: %s for index %d",
name, i));
}
+ // Create secondary indexes if in create phase
+ if (phase == ILBP_CREATE)
+ {
+ DBUG_PRINT("info", ("Creating index %u: %s", i, index_name));
+
+ switch (m_index[i].type){
+
+ case PRIMARY_KEY_INDEX:
+ // Do nothing, already created
+ break;
+ case PRIMARY_KEY_ORDERED_INDEX:
+ error= create_ordered_index(index_name, key_info);
+ break;
+ case UNIQUE_ORDERED_INDEX:
+ if (!(error= create_ordered_index(index_name, key_info)))
+ error= create_unique_index(get_unique_index_name(i), key_info);
+ break;
+ case UNIQUE_INDEX:
+ error= create_unique_index(get_unique_index_name(i), key_info);
+ break;
+ case ORDERED_INDEX:
+ error= create_ordered_index(index_name, key_info);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+ if (error)
+ {
+ DBUG_PRINT("error", ("Failed to create index %u", i));
+ drop_table();
+ break;
+ }
+ }
+ // Add handles to index objects
+ DBUG_PRINT("info", ("Trying to add handle to index %s", index_name));
+ if ((m_index[i].type != PRIMARY_KEY_INDEX) &&
+ (m_index[i].type != UNIQUE_INDEX))
+ {
+ const NDBINDEX *index= dict->getIndex(index_name, m_tabname);
+ if (!index) DBUG_RETURN(1);
+ m_index[i].index= (void *) index;
+ }
+ if (m_index[i].unique_name)
+ {
+ const NDBINDEX *index= dict->getIndex(m_index[i].unique_name, m_tabname);
+ if (!index) DBUG_RETURN(1);
+ m_index[i].unique_index= (void *) index;
+ }
+ DBUG_PRINT("info", ("Added handle to index %s", index_name));
}
- DBUG_RETURN(0);
+
+ DBUG_RETURN(error);
}
-
/*
Decode the type of an index from information
provided in table object
@@ -454,18 +669,29 @@ void ha_ndbcluster::release_metadata()
// Release index list
for (i= 0; i < MAX_KEY; i++)
{
- if (m_unique_index_name[i])
- my_free((char*)m_unique_index_name[i], MYF(0));
- m_unique_index_name[i]= NULL;
+ if (m_index[i].unique_name)
+ my_free((char*)m_index[i].unique_name, MYF(0));
+ m_index[i].unique_name= NULL;
+ m_index[i].unique_index= NULL;
+ m_index[i].index= NULL;
}
DBUG_VOID_RETURN;
}
-NdbCursorOperation::LockMode get_ndb_lock_type(enum thr_lock_type type)
+int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type)
{
- return (type == TL_WRITE_ALLOW_WRITE) ?
- NdbCursorOperation::LM_Exclusive : NdbCursorOperation::LM_Read;
+ int lm;
+ if (type == TL_WRITE_ALLOW_WRITE)
+ lm= NdbScanOperation::LM_Exclusive;
+ else if (uses_blob_value(retrieve_all_fields))
+ /*
+ TODO use a new scan mode to read + lock + keyinfo
+ */
+ lm= NdbScanOperation::LM_Exclusive;
+ else
+ lm= NdbScanOperation::LM_CommittedRead;
+ return lm;
}
static const ulong index_type_flags[]=
@@ -507,13 +733,13 @@ inline const char* ha_ndbcluster::get_index_name(uint idx_no) const
inline const char* ha_ndbcluster::get_unique_index_name(uint idx_no) const
{
- return m_unique_index_name[idx_no];
+ return m_index[idx_no].unique_name;
}
inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const
{
DBUG_ASSERT(idx_no < MAX_KEY);
- return m_indextype[idx_no];
+ return m_index[idx_no].type;
}
@@ -593,7 +819,7 @@ int ha_ndbcluster::set_primary_key(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 byte *key, uint key_len, byte *buf)
{
uint no_fields= table->fields, i;
NdbConnection *trans= m_active_trans;
@@ -603,8 +829,9 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
DBUG_PRINT("enter", ("key_len: %u", key_len));
DBUG_DUMP("key", (char*)key, key_len);
- if (!(op= trans->getNdbOperation(m_tabname)) || op->readTuple() != 0)
- goto err;
+ if (!(op= trans->getNdbOperation((NDBTAB *) m_table)) ||
+ op->readTuple() != 0)
+ ERR_RETURN(trans->getNdbError());
if (table->primary_key == MAX_KEY)
{
@@ -612,10 +839,11 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
DBUG_PRINT("info", ("Using hidden key"));
DBUG_DUMP("key", (char*)key, 8);
if (set_hidden_key(op, no_fields, key))
- goto err;
+ ERR_RETURN(trans->getNdbError());
+
// Read key at the same time, for future reference
- if (get_ndb_value(op, no_fields, NULL))
- goto err;
+ if (get_ndb_value(op, NULL, no_fields))
+ ERR_RETURN(trans->getNdbError());
}
else
{
@@ -624,19 +852,20 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
return res;
}
- // Read non-key field(s)
+ // Read all wanted non-key field(s) unless HA_EXTRA_RETRIEVE_ALL_COLS
for (i= 0; i < no_fields; i++)
{
Field *field= table->field[i];
- if (thd->query_id == field->query_id)
+ if ((thd->query_id == field->query_id) ||
+ retrieve_all_fields)
{
- if (get_ndb_value(op, i, field->ptr))
- goto err;
+ if (get_ndb_value(op, field, i))
+ ERR_RETURN(trans->getNdbError());
}
else
{
// Attribute was not to be read
- m_value[i]= NULL;
+ m_value[i].ptr= NULL;
}
}
@@ -650,9 +879,55 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf)
unpack_record(buf);
table->status= 0;
DBUG_RETURN(0);
+}
+
+
+/*
+ Read one complementing record from NDB using primary key from old_data
+*/
+
+int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data)
+{
+ uint no_fields= table->fields, i;
+ NdbConnection *trans= m_active_trans;
+ NdbOperation *op;
+ THD *thd= current_thd;
+ DBUG_ENTER("complemented_pk_read");
+
+ if (retrieve_all_fields)
+ // We have allready retrieved all fields, nothing to complement
+ DBUG_RETURN(0);
+
+ if (!(op= trans->getNdbOperation((NDBTAB *) m_table)) ||
+ op->readTuple() != 0)
+ ERR_RETURN(trans->getNdbError());
+
+ int res;
+ if ((res= set_primary_key_from_old_data(op, old_data)))
+ ERR_RETURN(trans->getNdbError());
+
+ // Read all unreferenced non-key field(s)
+ for (i= 0; i < no_fields; i++)
+ {
+ Field *field= table->field[i];
+ if (!(field->flags & PRI_KEY_FLAG) &&
+ (thd->query_id != field->query_id))
+ {
+ if (get_ndb_value(op, field, i))
+ ERR_RETURN(trans->getNdbError());
+ }
+ }
+
+ if (trans->execute(NoCommit) != 0)
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(ndb_err(trans));
+ }
- err:
- ERR_RETURN(trans->getNdbError());
+ // The value have now been fetched from NDB
+ unpack_record(new_data);
+ table->status= 0;
+ DBUG_RETURN(0);
}
@@ -675,8 +950,9 @@ int ha_ndbcluster::unique_index_read(const byte *key,
DBUG_DUMP("key", (char*)key, key_len);
DBUG_PRINT("enter", ("name: %s", get_unique_index_name(active_index)));
- if (!(op= trans->getNdbIndexOperation(get_unique_index_name(active_index),
- m_tabname)) ||
+ if (!(op= trans->getNdbIndexOperation((NDBINDEX *)
+ m_index[active_index].unique_index,
+ (NDBTAB *) m_table)) ||
op->readTuple() != 0)
ERR_RETURN(trans->getNdbError());
@@ -700,13 +976,13 @@ int ha_ndbcluster::unique_index_read(const byte *key,
if ((thd->query_id == field->query_id) ||
(field->flags & PRI_KEY_FLAG))
{
- if (get_ndb_value(op, i, field->ptr))
+ if (get_ndb_value(op, field, i))
ERR_RETURN(op->getNdbError());
}
else
{
// Attribute was not to be read
- m_value[i]= NULL;
+ m_value[i].ptr= NULL;
}
}
@@ -746,14 +1022,25 @@ inline int ha_ndbcluster::next_result(byte *buf)
If this an update or delete, call nextResult with false
to process any records already cached in NdbApi
*/
- bool contact_ndb = m_lock.type != TL_WRITE_ALLOW_WRITE;
+ bool contact_ndb= m_lock.type != TL_WRITE_ALLOW_WRITE;
do {
DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb));
+ /*
+ We can only handle one tuple with blobs at a time.
+ */
+ if (ops_pending && blobs_pending)
+ {
+ if (trans->execute(NoCommit) != 0)
+ DBUG_RETURN(ndb_err(trans));
+ ops_pending= 0;
+ blobs_pending= false;
+ }
check= cursor->nextResult(contact_ndb);
if (check == 0)
{
// One more record found
DBUG_PRINT("info", ("One more record found"));
+
unpack_record(buf);
table->status= 0;
DBUG_RETURN(0);
@@ -791,15 +1078,17 @@ inline int ha_ndbcluster::next_result(byte *buf)
Set bounds for a ordered index scan, use key_range
*/
-int ha_ndbcluster::set_bounds(NdbOperation *op,
+int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
const key_range *key,
int bound)
{
- uint i, tot_len;
+ uint key_len, key_store_len, tot_len, key_tot_len;
byte *key_ptr;
KEY* key_info= table->key_info + active_index;
KEY_PART_INFO* key_part= key_info->key_part;
KEY_PART_INFO* end= key_part+key_info->key_parts;
+ Field* field;
+ bool key_nullable, key_null;
DBUG_ENTER("set_bounds");
DBUG_PRINT("enter", ("bound: %d", bound));
@@ -809,29 +1098,37 @@ int ha_ndbcluster::set_bounds(NdbOperation *op,
// Set bounds using key data
tot_len= 0;
- key_ptr= (byte *) key->key;
+ key_ptr= (byte *) key->key;
+ key_tot_len= key->length;
for (; key_part != end; key_part++)
{
- Field* field= key_part->field;
- uint32 field_len= field->pack_length();
- tot_len+= field_len;
+ field= key_part->field;
+ key_len= key_part->length;
+ key_store_len= key_part->store_length;
+ key_nullable= (bool) key_part->null_bit;
+ key_null= (field->maybe_null() && *key_ptr);
+ tot_len+= key_store_len;
const char* bounds[]= {"LE", "LT", "GE", "GT", "EQ"};
DBUG_ASSERT(bound >= 0 && bound <= 4);
- DBUG_PRINT("info", ("Set Bound%s on %s",
+ DBUG_PRINT("info", ("Set Bound%s on %s %s %s %s",
bounds[bound],
- field->field_name));
- DBUG_DUMP("key", (char*)key_ptr, field_len);
-
+ field->field_name,
+ key_nullable ? "NULLABLE" : "",
+ key_null ? "NULL":""));
+ DBUG_PRINT("info", ("Total length %ds", tot_len));
+
+ DBUG_DUMP("key", (char*) key_ptr, key_store_len);
+
if (op->setBound(field->field_name,
bound,
- key_ptr,
- field_len) != 0)
+ key_null ? 0 : (key_nullable ? key_ptr + 1 : key_ptr),
+ key_null ? 0 : key_len) != 0)
ERR_RETURN(op->getNdbError());
- key_ptr+= field_len;
-
- if (tot_len >= key->length)
+ key_ptr+= key_store_len;
+
+ if (tot_len >= key_tot_len)
break;
/*
@@ -839,7 +1136,7 @@ int ha_ndbcluster::set_bounds(NdbOperation *op,
so if this bound was not EQ, bail out and make
a best effort attempt
*/
- if (bound != NdbOperation::BoundEQ)
+ if (bound != NdbIndexScanOperation::BoundEQ)
break;
}
@@ -857,7 +1154,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
{
NdbConnection *trans= m_active_trans;
NdbResultSet *cursor;
- NdbScanOperation *op;
+ NdbIndexScanOperation *op;
const char *index_name;
DBUG_ENTER("ordered_index_scan");
@@ -865,19 +1162,24 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname));
index_name= get_index_name(active_index);
- if (!(op= trans->getNdbScanOperation(index_name, m_tabname)))
+ if (!(op= trans->getNdbIndexScanOperation((NDBINDEX *)
+ m_index[active_index].index,
+ (NDBTAB *) m_table)))
ERR_RETURN(trans->getNdbError());
- if (!(cursor= op->readTuples(parallelism, get_ndb_lock_type(m_lock.type))))
+
+ NdbScanOperation::LockMode lm= (NdbScanOperation::LockMode)
+ get_ndb_lock_type(m_lock.type);
+ if (!(cursor= op->readTuples(lm, 0, parallelism, sorted)))
ERR_RETURN(trans->getNdbError());
m_active_cursor= cursor;
if (start_key &&
set_bounds(op, start_key,
(start_key->flag == HA_READ_KEY_EXACT) ?
- NdbOperation::BoundEQ :
+ NdbIndexScanOperation::BoundEQ :
(start_key->flag == HA_READ_AFTER_KEY) ?
- NdbOperation::BoundLT :
- NdbOperation::BoundLE))
+ NdbIndexScanOperation::BoundLT :
+ NdbIndexScanOperation::BoundLE))
DBUG_RETURN(1);
if (end_key)
@@ -888,8 +1190,8 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
}
else if (set_bounds(op, end_key,
(end_key->flag == HA_READ_AFTER_KEY) ?
- NdbOperation::BoundGE :
- NdbOperation::BoundGT))
+ NdbIndexScanOperation::BoundGE :
+ NdbIndexScanOperation::BoundGT))
DBUG_RETURN(1);
}
DBUG_RETURN(define_read_attrs(buf, op));
@@ -925,12 +1227,14 @@ int ha_ndbcluster::filtered_scan(const byte *key, uint key_len,
DBUG_PRINT("info", ("Starting a new filtered scan on %s",
m_tabname));
- if (!(op= trans->getNdbScanOperation(m_tabname)))
+ if (!(op= trans->getNdbScanOperation((NDBTAB *) m_table)))
ERR_RETURN(trans->getNdbError());
- if (!(cursor= op->readTuples(parallelism, get_ndb_lock_type(m_lock.type))))
+ NdbScanOperation::LockMode lm= (NdbScanOperation::LockMode)
+ get_ndb_lock_type(m_lock.type);
+ if (!(cursor= op->readTuples(lm, 0, parallelism)))
ERR_RETURN(trans->getNdbError());
m_active_cursor= cursor;
-
+
{
// Start scan filter
NdbScanFilter sf(op);
@@ -994,9 +1298,11 @@ int ha_ndbcluster::full_table_scan(byte *buf)
DBUG_ENTER("full_table_scan");
DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
- if (!(op=trans->getNdbScanOperation(m_tabname)))
+ if (!(op=trans->getNdbScanOperation((NDBTAB *) m_table)))
ERR_RETURN(trans->getNdbError());
- if (!(cursor= op->readTuples(parallelism, get_ndb_lock_type(m_lock.type))))
+ NdbScanOperation::LockMode lm= (NdbScanOperation::LockMode)
+ get_ndb_lock_type(m_lock.type);
+ if (!(cursor= op->readTuples(lm, 0, parallelism)))
ERR_RETURN(trans->getNdbError());
m_active_cursor= cursor;
DBUG_RETURN(define_read_attrs(buf, op));
@@ -1020,12 +1326,12 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
(field->flags & PRI_KEY_FLAG) ||
retrieve_all_fields)
{
- if (get_ndb_value(op, i, field->ptr))
+ if (get_ndb_value(op, field, i))
ERR_RETURN(op->getNdbError());
}
else
{
- m_value[i]= NULL;
+ m_value[i].ptr= NULL;
}
}
@@ -1039,7 +1345,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
if (!tab->getColumn(hidden_no))
DBUG_RETURN(1);
#endif
- if (get_ndb_value(op, hidden_no, NULL))
+ if (get_ndb_value(op, NULL, hidden_no))
ERR_RETURN(op->getNdbError());
}
@@ -1056,6 +1362,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op)
int ha_ndbcluster::write_row(byte *record)
{
+ bool has_auto_increment;
uint i;
NdbConnection *trans= m_active_trans;
NdbOperation *op;
@@ -1065,10 +1372,10 @@ int ha_ndbcluster::write_row(byte *record)
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record+table->timestamp_default_now-1);
- if (table->next_number_field && record == table->record[0])
- update_auto_increment();
+ has_auto_increment= (table->next_number_field && record == table->record[0]);
+ skip_auto_increment= table->auto_increment_field_not_null;
- if (!(op= trans->getNdbOperation(m_tabname)))
+ if (!(op= trans->getNdbOperation((NDBTAB *) m_table)))
ERR_RETURN(trans->getNdbError());
res= (m_use_write) ? op->writeTuple() :op->insertTuple();
@@ -1078,13 +1385,17 @@ int ha_ndbcluster::write_row(byte *record)
if (table->primary_key == MAX_KEY)
{
// Table has hidden primary key
- Uint64 auto_value= m_ndb->getAutoIncrementValue(m_tabname);
+ Uint64 auto_value= m_ndb->getAutoIncrementValue((NDBTAB *) m_table);
if (set_hidden_key(op, table->fields, (const byte*)&auto_value))
ERR_RETURN(op->getNdbError());
}
else
{
int res;
+
+ if ((has_auto_increment) && (!skip_auto_increment))
+ update_auto_increment();
+
if ((res= set_primary_key(op)))
return res;
}
@@ -1095,7 +1406,10 @@ int ha_ndbcluster::write_row(byte *record)
Field *field= table->field[i];
if (!(field->flags & PRI_KEY_FLAG) &&
set_ndb_value(op, field, i))
+ {
+ skip_auto_increment= true;
ERR_RETURN(op->getNdbError());
+ }
}
/*
@@ -1106,16 +1420,34 @@ int ha_ndbcluster::write_row(byte *record)
Find out how this is detected!
*/
rows_inserted++;
- if ((rows_inserted == rows_to_insert) ||
- ((rows_inserted % bulk_insert_rows) == 0))
+ bulk_insert_not_flushed= true;
+ if ((rows_to_insert == 1) ||
+ ((rows_inserted % bulk_insert_rows) == 0) ||
+ uses_blob_value(false) != 0)
{
// Send rows to NDB
DBUG_PRINT("info", ("Sending inserts to NDB, "\
"rows_inserted:%d, bulk_insert_rows: %d",
- rows_inserted, bulk_insert_rows));
+ (int)rows_inserted, (int)bulk_insert_rows));
+ bulk_insert_not_flushed= false;
if (trans->execute(NoCommit) != 0)
+ {
+ skip_auto_increment= true;
DBUG_RETURN(ndb_err(trans));
+ }
}
+ if ((has_auto_increment) && (skip_auto_increment))
+ {
+ Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1;
+ DBUG_PRINT("info",
+ ("Trying to set next auto increment value to %lu",
+ (ulong) next_val));
+ if (m_ndb->setAutoIncrementValue((NDBTAB *) m_table, next_val, true))
+ DBUG_PRINT("info",
+ ("Setting next auto increment value to %u", next_val));
+ }
+ skip_auto_increment= true;
+
DBUG_RETURN(0);
}
@@ -1171,11 +1503,40 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
- /* Check for update of primary key and return error */
+ /* Check for update of primary key for special handling */
if ((table->primary_key != MAX_KEY) &&
(key_cmp(table->primary_key, old_data, new_data)))
- DBUG_RETURN(HA_ERR_UNSUPPORTED);
-
+ {
+ int read_res, insert_res, delete_res;
+
+ DBUG_PRINT("info", ("primary key update, doing pk read+insert+delete"));
+ // Get all old fields, since we optimize away fields not in query
+ read_res= complemented_pk_read(old_data, new_data);
+ if (read_res)
+ {
+ DBUG_PRINT("info", ("pk read failed"));
+ DBUG_RETURN(read_res);
+ }
+ // Insert new row
+ insert_res= write_row(new_data);
+ if (insert_res)
+ {
+ DBUG_PRINT("info", ("insert failed"));
+ DBUG_RETURN(insert_res);
+ }
+ // Delete old row
+ DBUG_PRINT("info", ("insert succeded"));
+ delete_res= delete_row(old_data);
+ if (delete_res)
+ {
+ DBUG_PRINT("info", ("delete failed"));
+ // Undo write_row(new_data)
+ DBUG_RETURN(delete_row(new_data));
+ }
+ DBUG_PRINT("info", ("insert+delete succeeded"));
+ DBUG_RETURN(0);
+ }
+
if (cursor)
{
/*
@@ -1189,10 +1550,12 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
if (!(op= cursor->updateTuple()))
ERR_RETURN(trans->getNdbError());
ops_pending++;
+ if (uses_blob_value(false))
+ blobs_pending= true;
}
else
{
- if (!(op= trans->getNdbOperation(m_tabname)) ||
+ if (!(op= trans->getNdbOperation((NDBTAB *) m_table)) ||
op->updateTuple() != 0)
ERR_RETURN(trans->getNdbError());
@@ -1204,7 +1567,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
// Require that the PK for this record has previously been
// read into m_value
uint no_fields= table->fields;
- NdbRecAttr* rec= m_value[no_fields];
+ NdbRecAttr* rec= m_value[no_fields].rec;
DBUG_ASSERT(rec);
DBUG_DUMP("key", (char*)rec->aRef(), NDB_HIDDEN_PRIMARY_KEY_LENGTH);
@@ -1253,9 +1616,9 @@ int ha_ndbcluster::delete_row(const byte *record)
if (cursor)
{
/*
- We are scanning records and want to update the record
+ We are scanning records and want to delete the record
that was just found, call deleteTuple on the cursor
- to take over the lock to a new update operation
+ to take over the lock to a new delete operation
And thus setting the primary key of the record from
the active record in cursor
*/
@@ -1270,7 +1633,7 @@ int ha_ndbcluster::delete_row(const byte *record)
else
{
- if (!(op=trans->getNdbOperation(m_tabname)) ||
+ if (!(op=trans->getNdbOperation((NDBTAB *) m_table)) ||
op->deleteTuple() != 0)
ERR_RETURN(trans->getNdbError());
@@ -1279,7 +1642,7 @@ int ha_ndbcluster::delete_row(const byte *record)
// This table has no primary key, use "hidden" primary key
DBUG_PRINT("info", ("Using hidden key"));
uint no_fields= table->fields;
- NdbRecAttr* rec= m_value[no_fields];
+ NdbRecAttr* rec= m_value[no_fields].rec;
DBUG_ASSERT(rec != NULL);
if (set_hidden_key(op, no_fields, rec->aRef()))
@@ -1317,7 +1680,7 @@ void ha_ndbcluster::unpack_record(byte* buf)
{
uint row_offset= (uint) (buf - table->record[0]);
Field **field, **end;
- NdbRecAttr **value= m_value;
+ NdbValue *value= m_value;
DBUG_ENTER("unpack_record");
// Set null flag(s)
@@ -1326,8 +1689,23 @@ void ha_ndbcluster::unpack_record(byte* buf)
field < end;
field++, value++)
{
- if (*value && (*value)->isNULL())
- (*field)->set_null(row_offset);
+ if ((*value).ptr)
+ {
+ if (! ((*field)->flags & BLOB_FLAG))
+ {
+ if ((*value).rec->isNULL())
+ (*field)->set_null(row_offset);
+ }
+ else
+ {
+ NdbBlob* ndb_blob= (*value).blob;
+ bool isNull= true;
+ int ret= ndb_blob->getNull(isNull);
+ DBUG_ASSERT(ret == 0);
+ if (isNull)
+ (*field)->set_null(row_offset);
+ }
+ }
}
#ifndef DBUG_OFF
@@ -1338,7 +1716,7 @@ void ha_ndbcluster::unpack_record(byte* buf)
int hidden_no= table->fields;
const NDBTAB *tab= (NDBTAB *) m_table;
const NDBCOL *hidden_col= tab->getColumn(hidden_no);
- NdbRecAttr* rec= m_value[hidden_no];
+ NdbRecAttr* rec= m_value[hidden_no].rec;
DBUG_ASSERT(rec);
DBUG_PRINT("hidden", ("%d: %s \"%llu\"", hidden_no,
hidden_col->getName(), rec->u_64_value()));
@@ -1348,7 +1726,6 @@ void ha_ndbcluster::unpack_record(byte* buf)
DBUG_VOID_RETURN;
}
-
/*
Utility function to print/dump the fetched field
*/
@@ -1366,9 +1743,9 @@ void ha_ndbcluster::print_results()
{
Field *field;
const NDBCOL *col;
- NdbRecAttr *value;
+ NdbValue value;
- if (!(value= m_value[f]))
+ if (!(value= m_value[f]).ptr)
{
fprintf(DBUG_FILE, "Field %d was not read\n", f);
continue;
@@ -1377,19 +1754,28 @@ void ha_ndbcluster::print_results()
DBUG_DUMP("field->ptr", (char*)field->ptr, field->pack_length());
col= tab->getColumn(f);
fprintf(DBUG_FILE, "%d: %s\t", f, col->getName());
-
- if (value->isNULL())
+
+ NdbBlob *ndb_blob= NULL;
+ if (! (field->flags & BLOB_FLAG))
{
- fprintf(DBUG_FILE, "NULL\n");
- continue;
+ if (value.rec->isNULL())
+ {
+ fprintf(DBUG_FILE, "NULL\n");
+ continue;
+ }
+ }
+ else
+ {
+ ndb_blob= value.blob;
+ bool isNull= true;
+ ndb_blob->getNull(isNull);
+ if (isNull) {
+ fprintf(DBUG_FILE, "NULL\n");
+ continue;
+ }
}
switch (col->getType()) {
- case NdbDictionary::Column::Blob:
- case NdbDictionary::Column::Clob:
- case NdbDictionary::Column::Undefined:
- fprintf(DBUG_FILE, "Unknown type: %d", col->getType());
- break;
case NdbDictionary::Column::Tinyint: {
char value= *field->ptr;
fprintf(DBUG_FILE, "Tinyint\t%d", value);
@@ -1481,6 +1867,21 @@ void ha_ndbcluster::print_results()
fprintf(DBUG_FILE, "Timespec\t%llu", value);
break;
}
+ case NdbDictionary::Column::Blob: {
+ Uint64 len= 0;
+ ndb_blob->getLength(len);
+ fprintf(DBUG_FILE, "Blob\t[len=%u]", (unsigned)len);
+ break;
+ }
+ case NdbDictionary::Column::Text: {
+ Uint64 len= 0;
+ ndb_blob->getLength(len);
+ fprintf(DBUG_FILE, "Text\t[len=%u]", (unsigned)len);
+ break;
+ }
+ case NdbDictionary::Column::Undefined:
+ fprintf(DBUG_FILE, "Unknown type: %d", col->getType());
+ break;
}
fprintf(DBUG_FILE, "\n");
@@ -1537,7 +1938,7 @@ int ha_ndbcluster::index_next(byte *buf)
{
DBUG_ENTER("index_next");
- int error = 1;
+ int error= 1;
statistic_increment(ha_read_next_count,&LOCK_status);
DBUG_RETURN(next_result(buf));
}
@@ -1628,9 +2029,13 @@ int ha_ndbcluster::rnd_init(bool scan)
NdbResultSet *cursor= m_active_cursor;
DBUG_ENTER("rnd_init");
DBUG_PRINT("enter", ("scan: %d", scan));
- // Check that cursor is not defined
+ // Check if scan is to be restarted
if (cursor)
- DBUG_RETURN(1);
+ {
+ if (!scan)
+ DBUG_RETURN(1);
+ cursor->restart();
+ }
index_init(table->primary_key);
DBUG_RETURN(0);
}
@@ -1638,11 +2043,25 @@ int ha_ndbcluster::rnd_init(bool scan)
int ha_ndbcluster::close_scan()
{
NdbResultSet *cursor= m_active_cursor;
+ NdbConnection *trans= m_active_trans;
DBUG_ENTER("close_scan");
if (!cursor)
DBUG_RETURN(1);
+
+ if (ops_pending)
+ {
+ /*
+ Take over any pending transactions to the
+ deleteing/updating transaction before closing the scan
+ */
+ DBUG_PRINT("info", ("ops_pending: %d", ops_pending));
+ if (trans->execute(NoCommit) != 0)
+ DBUG_RETURN(ndb_err(trans));
+ ops_pending= 0;
+ }
+
cursor->close();
m_active_cursor= NULL;
DBUG_RETURN(0);
@@ -1724,7 +2143,7 @@ void ha_ndbcluster::position(const byte *record)
// No primary key, get hidden key
DBUG_PRINT("info", ("Getting hidden key"));
int hidden_no= table->fields;
- NdbRecAttr* rec= m_value[hidden_no];
+ NdbRecAttr* rec= m_value[hidden_no].rec;
const NDBTAB *tab= (NDBTAB *) m_table;
const NDBCOL *hidden_col= tab->getColumn(hidden_no);
DBUG_ASSERT(hidden_col->getPrimaryKey() &&
@@ -1755,7 +2174,10 @@ void ha_ndbcluster::info(uint flag)
if (flag & HA_STATUS_VARIABLE)
DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
if (flag & HA_STATUS_ERRKEY)
+ {
DBUG_PRINT("info", ("HA_STATUS_ERRKEY"));
+ errkey= dupkey;
+ }
if (flag & HA_STATUS_AUTO)
DBUG_PRINT("info", ("HA_STATUS_AUTO"));
DBUG_VOID_RETURN;
@@ -1898,7 +2320,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
const NDBTAB *tab= (NDBTAB *) m_table;
DBUG_ENTER("start_bulk_insert");
- DBUG_PRINT("enter", ("rows: %d", rows));
+ DBUG_PRINT("enter", ("rows: %d", (int)rows));
rows_inserted= 0;
rows_to_insert= rows;
@@ -1910,7 +2332,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
degrade if too many bytes are inserted, thus it's limited by this
calculation.
*/
- const int bytesperbatch = 8192;
+ const int bytesperbatch= 8192;
bytes= 12 + tab->getRowSizeInBytes() + 4 * tab->getNoOfColumns();
batch= bytesperbatch/bytes;
batch= batch == 0 ? 1 : batch;
@@ -1925,15 +2347,32 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
*/
int ha_ndbcluster::end_bulk_insert()
{
+ int error= 0;
+
DBUG_ENTER("end_bulk_insert");
- DBUG_RETURN(0);
+ // Check if last inserts need to be flushed
+ if (bulk_insert_not_flushed)
+ {
+ NdbConnection *trans= m_active_trans;
+ // Send rows to NDB
+ DBUG_PRINT("info", ("Sending inserts to NDB, "\
+ "rows_inserted:%d, bulk_insert_rows: %d",
+ rows_inserted, bulk_insert_rows));
+ bulk_insert_not_flushed= false;
+ if (trans->execute(NoCommit) != 0)
+ error= ndb_err(trans);
+ }
+
+ rows_inserted= 0;
+ rows_to_insert= 1;
+ DBUG_RETURN(error);
}
int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size)
{
DBUG_ENTER("extra_opt");
- DBUG_PRINT("enter", ("cache_size: %d", cache_size));
+ DBUG_PRINT("enter", ("cache_size: %lu", cache_size));
DBUG_RETURN(extra(operation));
}
@@ -1947,7 +2386,7 @@ int ha_ndbcluster::reset()
const char **ha_ndbcluster::bas_ext() const
-{ static const char *ext[1] = { NullS }; return ext; }
+{ static const char *ext[1]= { NullS }; return ext; }
/*
@@ -2154,7 +2593,7 @@ int ha_ndbcluster::start_stmt(THD *thd)
NdbConnection *tablock_trans=
(NdbConnection*)thd->transaction.all.ndb_tid;
- DBUG_PRINT("info", ("tablock_trans: %x", tablock_trans));
+ DBUG_PRINT("info", ("tablock_trans: %x", (uint)tablock_trans));
DBUG_ASSERT(tablock_trans); trans= m_ndb->hupp(tablock_trans);
if (trans == NULL)
ERR_RETURN(m_ndb->getNdbError());
@@ -2189,8 +2628,11 @@ int ndbcluster_commit(THD *thd, void *ndb_transaction)
if (trans->execute(Commit) != 0)
{
const NdbError err= trans->getNdbError();
+ const NdbOperation *error_op= trans->getNdbErrorOperation();
ERR_PRINT(err);
res= ndb_to_mysql_error(&err);
+ if (res != -1)
+ ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
DBUG_RETURN(res);
@@ -2216,8 +2658,11 @@ int ndbcluster_rollback(THD *thd, void *ndb_transaction)
if (trans->execute(Rollback) != 0)
{
const NdbError err= trans->getNdbError();
+ const NdbOperation *error_op= trans->getNdbErrorOperation();
ERR_PRINT(err);
res= ndb_to_mysql_error(&err);
+ if (res != -1)
+ ndbcluster_print_error(res, error_op);
}
ndb->closeTransaction(trans);
DBUG_RETURN(0);
@@ -2225,71 +2670,184 @@ int ndbcluster_rollback(THD *thd, void *ndb_transaction)
/*
- Map MySQL type to the corresponding NDB type
+ Define NDB column based on Field.
+ Returns 0 or mysql error code.
+ Not member of ha_ndbcluster because NDBCOL cannot be declared.
*/
-inline NdbDictionary::Column::Type
-mysql_to_ndb_type(enum enum_field_types mysql_type, bool unsigned_flg)
+static int create_ndb_column(NDBCOL &col,
+ Field *field,
+ HA_CREATE_INFO *info)
{
- switch(mysql_type) {
+ // Set name
+ col.setName(field->field_name);
+ // Set type and sizes
+ const enum enum_field_types mysql_type= field->real_type();
+ switch (mysql_type) {
+ // Numeric types
case MYSQL_TYPE_DECIMAL:
- return NdbDictionary::Column::Char;
+ col.setType(NDBCOL::Char);
+ col.setLength(field->pack_length());
+ break;
case MYSQL_TYPE_TINY:
- return (unsigned_flg) ?
- NdbDictionary::Column::Tinyunsigned :
- NdbDictionary::Column::Tinyint;
+ if (field->flags & UNSIGNED_FLAG)
+ col.setType(NDBCOL::Tinyunsigned);
+ else
+ col.setType(NDBCOL::Tinyint);
+ col.setLength(1);
+ break;
case MYSQL_TYPE_SHORT:
- return (unsigned_flg) ?
- NdbDictionary::Column::Smallunsigned :
- NdbDictionary::Column::Smallint;
+ if (field->flags & UNSIGNED_FLAG)
+ col.setType(NDBCOL::Smallunsigned);
+ else
+ col.setType(NDBCOL::Smallint);
+ col.setLength(1);
+ break;
case MYSQL_TYPE_LONG:
- return (unsigned_flg) ?
- NdbDictionary::Column::Unsigned :
- NdbDictionary::Column::Int;
- case MYSQL_TYPE_TIMESTAMP:
- return NdbDictionary::Column::Unsigned;
- case MYSQL_TYPE_LONGLONG:
- return (unsigned_flg) ?
- NdbDictionary::Column::Bigunsigned :
- NdbDictionary::Column::Bigint;
+ if (field->flags & UNSIGNED_FLAG)
+ col.setType(NDBCOL::Unsigned);
+ else
+ col.setType(NDBCOL::Int);
+ col.setLength(1);
+ break;
case MYSQL_TYPE_INT24:
- return (unsigned_flg) ?
- NdbDictionary::Column::Mediumunsigned :
- NdbDictionary::Column::Mediumint;
+ if (field->flags & UNSIGNED_FLAG)
+ col.setType(NDBCOL::Mediumunsigned);
+ else
+ col.setType(NDBCOL::Mediumint);
+ col.setLength(1);
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ if (field->flags & UNSIGNED_FLAG)
+ col.setType(NDBCOL::Bigunsigned);
+ else
+ col.setType(NDBCOL::Bigint);
+ col.setLength(1);
break;
case MYSQL_TYPE_FLOAT:
- return NdbDictionary::Column::Float;
+ col.setType(NDBCOL::Float);
+ col.setLength(1);
+ break;
case MYSQL_TYPE_DOUBLE:
- return NdbDictionary::Column::Double;
- case MYSQL_TYPE_DATETIME :
- return NdbDictionary::Column::Datetime;
- case MYSQL_TYPE_DATE :
- case MYSQL_TYPE_NEWDATE :
- case MYSQL_TYPE_TIME :
- case MYSQL_TYPE_YEAR :
- // Missing NDB data types, mapped to char
- return NdbDictionary::Column::Char;
- case MYSQL_TYPE_ENUM :
- return NdbDictionary::Column::Char;
- case MYSQL_TYPE_SET :
- return NdbDictionary::Column::Char;
- case MYSQL_TYPE_TINY_BLOB :
- case MYSQL_TYPE_MEDIUM_BLOB :
- case MYSQL_TYPE_LONG_BLOB :
- case MYSQL_TYPE_BLOB :
- return NdbDictionary::Column::Blob;
- case MYSQL_TYPE_VAR_STRING :
- return NdbDictionary::Column::Varchar;
- case MYSQL_TYPE_STRING :
- return NdbDictionary::Column::Char;
- case MYSQL_TYPE_NULL :
- case MYSQL_TYPE_GEOMETRY :
- return NdbDictionary::Column::Undefined;
- }
- return NdbDictionary::Column::Undefined;
+ col.setType(NDBCOL::Double);
+ col.setLength(1);
+ break;
+ // Date types
+ case MYSQL_TYPE_TIMESTAMP:
+ col.setType(NDBCOL::Unsigned);
+ col.setLength(1);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ col.setType(NDBCOL::Datetime);
+ col.setLength(1);
+ break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_YEAR:
+ col.setType(NDBCOL::Char);
+ col.setLength(field->pack_length());
+ break;
+ // Char types
+ case MYSQL_TYPE_STRING:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Binary);
+ else
+ col.setType(NDBCOL::Char);
+ col.setLength(field->pack_length());
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Varbinary);
+ else
+ col.setType(NDBCOL::Varchar);
+ col.setLength(field->pack_length());
+ break;
+ // Blob types (all come in as MYSQL_TYPE_BLOB)
+ mysql_type_tiny_blob:
+ case MYSQL_TYPE_TINY_BLOB:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Blob);
+ else
+ col.setType(NDBCOL::Text);
+ col.setInlineSize(256);
+ // No parts
+ col.setPartSize(0);
+ col.setStripeSize(0);
+ break;
+ mysql_type_blob:
+ case MYSQL_TYPE_BLOB:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Blob);
+ else
+ col.setType(NDBCOL::Text);
+ // 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);
+ }
+ 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:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Blob);
+ else
+ col.setType(NDBCOL::Text);
+ col.setInlineSize(256);
+ col.setPartSize(4000);
+ col.setStripeSize(8);
+ break;
+ mysql_type_long_blob:
+ case MYSQL_TYPE_LONG_BLOB:
+ if (field->flags & BINARY_FLAG)
+ col.setType(NDBCOL::Blob);
+ else
+ col.setType(NDBCOL::Text);
+ col.setInlineSize(256);
+ col.setPartSize(8000);
+ col.setStripeSize(4);
+ break;
+ // Other types
+ case MYSQL_TYPE_ENUM:
+ col.setType(NDBCOL::Char);
+ col.setLength(field->pack_length());
+ break;
+ case MYSQL_TYPE_SET:
+ col.setType(NDBCOL::Char);
+ col.setLength(field->pack_length());
+ break;
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_GEOMETRY:
+ goto mysql_type_unsupported;
+ mysql_type_unsupported:
+ default:
+ return HA_ERR_UNSUPPORTED;
+ }
+ // Set nullable and pk
+ col.setNullable(field->maybe_null());
+ col.setPrimaryKey(field->flags & PRI_KEY_FLAG);
+ // Set autoincrement
+ if (field->flags & AUTO_INCREMENT_FLAG)
+ {
+ col.setAutoIncrement(TRUE);
+ ulonglong value= info->auto_increment_value ?
+ info->auto_increment_value -1 : (ulonglong) 0;
+ DBUG_PRINT("info", ("Autoincrement key, initial: %llu", value));
+ col.setAutoIncrementInitialValue(value);
+ }
+ else
+ col.setAutoIncrement(false);
+ return 0;
}
-
/*
Create a table in NDB Cluster
*/
@@ -2299,7 +2857,6 @@ int ha_ndbcluster::create(const char *name,
HA_CREATE_INFO *info)
{
NDBTAB tab;
- NdbDictionary::Column::Type ndb_type;
NDBCOL col;
uint pack_length, length, i;
const void *data, *pack_data;
@@ -2330,31 +2887,11 @@ int ha_ndbcluster::create(const char *name,
for (i= 0; i < form->fields; i++)
{
Field *field= form->field[i];
- ndb_type= mysql_to_ndb_type(field->real_type(),
- field->flags & UNSIGNED_FLAG);
DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
field->field_name, field->real_type(),
field->pack_length()));
- col.setName(field->field_name);
- col.setType(ndb_type);
- if ((ndb_type == NdbDictionary::Column::Char) ||
- (ndb_type == NdbDictionary::Column::Varchar))
- col.setLength(field->pack_length());
- else
- col.setLength(1);
- col.setNullable(field->maybe_null());
- col.setPrimaryKey(field->flags & PRI_KEY_FLAG);
- if (field->flags & AUTO_INCREMENT_FLAG)
- {
- col.setAutoIncrement(TRUE);
- ulonglong value= info->auto_increment_value ?
- info->auto_increment_value -1 : (ulonglong) 0;
- DBUG_PRINT("info", ("Autoincrement key, initial: %d", value));
- col.setAutoIncrementInitialValue(value);
- }
- else
- col.setAutoIncrement(false);
-
+ if ((my_errno= create_ndb_column(col, field, info)))
+ DBUG_RETURN(my_errno);
tab.addColumn(col);
}
@@ -2389,50 +2926,10 @@ int ha_ndbcluster::create(const char *name,
}
DBUG_PRINT("info", ("Table %s/%s created successfully",
m_dbname, m_tabname));
-
- if ((my_errno= build_index_list()))
- DBUG_RETURN(my_errno);
-
- // Create secondary indexes
- KEY* key_info= form->key_info;
- const char** key_name= key_names;
- for (i= 0; i < form->keys; i++, key_info++, key_name++)
- {
- int error= 0;
- DBUG_PRINT("info", ("Index %u: %s", i, *key_name));
-
- switch (get_index_type_from_table(i)){
- case PRIMARY_KEY_INDEX:
- // Do nothing, already created
- break;
- case PRIMARY_KEY_ORDERED_INDEX:
- error= create_ordered_index(*key_name, key_info);
- break;
- case UNIQUE_ORDERED_INDEX:
- if (!(error= create_ordered_index(*key_name, key_info)))
- error= create_unique_index(get_unique_index_name(i), key_info);
- break;
- case UNIQUE_INDEX:
- error= create_unique_index(get_unique_index_name(i), key_info);
- break;
- case ORDERED_INDEX:
- error= create_ordered_index(*key_name, key_info);
- break;
- default:
- DBUG_ASSERT(false);
- break;
- }
+ // Create secondary indexes
+ my_errno= build_index_list(form, ILBP_CREATE);
- if (error)
- {
- DBUG_PRINT("error", ("Failed to create index %u", i));
- drop_table();
- my_errno= error;
- break;
- }
- }
-
DBUG_RETURN(my_errno);
}
@@ -2468,6 +2965,7 @@ int ha_ndbcluster::create_index(const char *name,
DBUG_ENTER("create_index");
DBUG_PRINT("enter", ("name: %s ", name));
+ // NdbDictionary::Index ndb_index(name);
NdbDictionary::Index ndb_index(name);
if (unique)
ndb_index.setType(NdbDictionary::Index::UniqueHashIndex);
@@ -2601,10 +3099,17 @@ int ndbcluster_drop_database(const char *path)
longlong ha_ndbcluster::get_auto_increment()
{
- int cache_size = rows_to_insert ? rows_to_insert : 32;
+ DBUG_ENTER("get_auto_increment");
+ DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
+ int cache_size=
+ (rows_to_insert > autoincrement_prefetch) ?
+ rows_to_insert
+ : autoincrement_prefetch;
Uint64 auto_value=
- m_ndb->getAutoIncrementValue(m_tabname, cache_size);
- return (longlong)auto_value;
+ (skip_auto_increment) ?
+ m_ndb->readAutoIncrementValue((NDBTAB *) m_table)
+ : m_ndb->getAutoIncrementValue((NDBTAB *) m_table, cache_size);
+ DBUG_RETURN((longlong)auto_value);
}
@@ -2619,15 +3124,20 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_ndb(NULL),
m_table(NULL),
m_table_flags(HA_REC_NOT_IN_SEQ |
+ HA_NULL_IN_KEY |
HA_NOT_EXACT_COUNT |
- HA_NO_PREFIX_CHAR_KEYS |
- HA_NO_BLOBS),
+ HA_NO_PREFIX_CHAR_KEYS),
m_use_write(false),
retrieve_all_fields(FALSE),
- rows_to_insert(0),
+ rows_to_insert(1),
rows_inserted(0),
bulk_insert_rows(1024),
- ops_pending(0)
+ bulk_insert_not_flushed(false),
+ ops_pending(0),
+ skip_auto_increment(true),
+ blobs_buffer(0),
+ blobs_buffer_size(0),
+ dupkey((uint) -1)
{
int i;
@@ -2643,8 +3153,10 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
for (i= 0; i < MAX_KEY; i++)
{
- m_indextype[i]= UNDEFINED_INDEX;
- m_unique_index_name[i]= NULL;
+ m_index[i].type= UNDEFINED_INDEX;
+ m_index[i].unique_name= NULL;
+ m_index[i].unique_index= NULL;
+ m_index[i].index= NULL;
}
DBUG_VOID_RETURN;
@@ -2660,6 +3172,8 @@ ha_ndbcluster::~ha_ndbcluster()
DBUG_ENTER("~ha_ndbcluster");
release_metadata();
+ my_free(blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ blobs_buffer= 0;
// Check for open cursor/transaction
DBUG_ASSERT(m_active_cursor == NULL);
@@ -2888,6 +3402,12 @@ int ndb_discover_tables()
bool ndbcluster_init()
{
DBUG_ENTER("ndbcluster_init");
+ // Set connectstring if specified
+ if (ndbcluster_connectstring != 0)
+ {
+ DBUG_PRINT("connectstring", ("%s", ndbcluster_connectstring));
+ Ndb::setConnectString(ndbcluster_connectstring);
+ }
// Create a Ndb object to open the connection to NDB
g_ndb= new Ndb("sys");
if (g_ndb->init() != 0)
@@ -2921,6 +3441,7 @@ bool ndbcluster_init()
bool ndbcluster_end()
{
DBUG_ENTER("ndbcluster_end");
+
delete g_ndb;
g_ndb= NULL;
if (!ndbcluster_inited)
@@ -2934,13 +3455,22 @@ bool ndbcluster_end()
DBUG_RETURN(0);
}
-void ndbcluster_print_error(int error)
+/*
+ Static error print function called from
+ static handler method ndbcluster_commit
+ and ndbcluster_rollback
+*/
+
+void ndbcluster_print_error(int error, const NdbOperation *error_op)
{
DBUG_ENTER("ndbcluster_print_error");
TABLE tab;
- tab.table_name = NULL;
+ const char *tab_name= (error_op) ? error_op->getTableName() : "";
+ tab.table_name= (char *) tab_name;
ha_ndbcluster error_handler(&tab);
+ tab.file= &error_handler;
error_handler.print_error(error, MYF(0));
+ DBUG_VOID_RETURN;
}
/*
@@ -2965,7 +3495,7 @@ void ha_ndbcluster::set_tabname(const char *path_name)
ptr= m_tabname;
while (*ptr != '\0') {
- *ptr = tolower(*ptr);
+ *ptr= tolower(*ptr);
ptr++;
}
#endif
@@ -2981,17 +3511,17 @@ ha_ndbcluster::set_tabname(const char *path_name, char * tabname)
char *end, *ptr;
/* Scan name from the end */
- end = strend(path_name)-1;
- ptr = end;
+ end= strend(path_name)-1;
+ ptr= end;
while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
ptr--;
}
- uint name_len = end - ptr;
+ uint name_len= end - ptr;
memcpy(tabname, ptr + 1, end - ptr);
- tabname[name_len] = '\0';
+ tabname[name_len]= '\0';
#ifdef __WIN__
/* Put to lower case */
- ptr = tabname;
+ ptr= tabname;
while (*ptr != '\0') {
*ptr= tolower(*ptr);
@@ -3154,7 +3684,7 @@ static int packfrm(const void *data, uint len,
DBUG_PRINT("enter", ("data: %x, len: %d", data, len));
error= 1;
- org_len = len;
+ org_len= len;
if (my_compress((byte*)data, &org_len, &comp_len))
goto err;
@@ -3174,9 +3704,9 @@ static int packfrm(const void *data, uint len,
// Copy frm data into blob, already in machine independent format
memcpy(blob->data, data, org_len);
- *pack_data = blob;
- *pack_len = blob_len;
- error = 0;
+ *pack_data= blob;
+ *pack_len= blob_len;
+ error= 0;
DBUG_PRINT("exit", ("pack_data: %x, pack_len: %d", *pack_data, *pack_len));
err:
@@ -3188,7 +3718,7 @@ err:
static int unpackfrm(const void **unpack_data, uint *unpack_len,
const void *pack_data)
{
- const frm_blob_struct *blob = (frm_blob_struct*)pack_data;
+ const frm_blob_struct *blob= (frm_blob_struct*)pack_data;
byte *data;
ulong complen, orglen, ver;
DBUG_ENTER("unpackfrm");
@@ -3204,7 +3734,7 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len,
if (ver != 1)
DBUG_RETURN(1);
- if (!(data = my_malloc(max(orglen, complen), MYF(MY_WME))))
+ if (!(data= my_malloc(max(orglen, complen), MYF(MY_WME))))
DBUG_RETURN(2);
memcpy(data, blob->data, complen);
@@ -3214,8 +3744,8 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len,
DBUG_RETURN(3);
}
- *unpack_data = data;
- *unpack_len = complen;
+ *unpack_data= data;
+ *unpack_len= complen;
DBUG_PRINT("exit", ("frmdata: %x, len: %d", *unpack_data, *unpack_len));
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index f094b79ef35..c49a6078e7a 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -33,6 +33,12 @@ class NdbOperation; // Forward declaration
class NdbConnection; // Forward declaration
class NdbRecAttr; // Forward declaration
class NdbResultSet; // Forward declaration
+class NdbScanOperation;
+class NdbIndexScanOperation;
+class NdbBlob;
+
+// connectstring to cluster if given by mysqld
+extern const char *ndbcluster_connectstring;
typedef enum ndb_index_type {
UNDEFINED_INDEX = 0,
@@ -43,6 +49,12 @@ typedef enum ndb_index_type {
ORDERED_INDEX = 5
} NDB_INDEX_TYPE;
+typedef struct ndb_index_data {
+ NDB_INDEX_TYPE type;
+ void *index;
+ const char * unique_name;
+ void *unique_index;
+} NDB_INDEX_DATA;
typedef struct st_ndbcluster_share {
THR_LOCK lock;
@@ -145,8 +157,9 @@ class ha_ndbcluster: public handler
int create_index(const char *name, KEY *key_info, bool unique);
int create_ordered_index(const char *name, KEY *key_info);
int create_unique_index(const char *name, KEY *key_info);
- int initialize_autoincrement(const void* table);
- int build_index_list();
+ int initialize_autoincrement(const void *table);
+ enum ILBP {ILBP_CREATE = 0, ILBP_OPEN = 1}; // Index List Build Phase
+ int build_index_list(TABLE *tab, enum ILBP phase);
int get_metadata(const char* path);
void release_metadata();
const char* get_index_name(uint idx_no) const;
@@ -154,8 +167,8 @@ class ha_ndbcluster: public handler
NDB_INDEX_TYPE get_index_type(uint idx_no) const;
NDB_INDEX_TYPE get_index_type_from_table(uint index_no) const;
- int pk_read(const byte *key, uint key_len,
- byte *buf);
+ int pk_read(const byte *key, uint key_len, byte *buf);
+ int complemented_pk_read(const byte *old_data, byte *new_data);
int unique_index_read(const byte *key, uint key_len,
byte *buf);
int ordered_index_scan(const key_range *start_key,
@@ -169,6 +182,7 @@ class ha_ndbcluster: public handler
enum ha_rkey_function find_flag);
int close_scan();
void unpack_record(byte *buf);
+ int get_ndb_lock_type(enum thr_lock_type type);
void set_dbname(const char *pathname);
void set_tabname(const char *pathname);
@@ -179,18 +193,20 @@ class ha_ndbcluster: public handler
int set_ndb_key(NdbOperation*, Field *field,
uint fieldnr, const byte* field_ptr);
int set_ndb_value(NdbOperation*, Field *field, uint fieldnr);
- int get_ndb_value(NdbOperation*, uint fieldnr, byte *field_ptr);
+ int get_ndb_value(NdbOperation*, Field *field, uint fieldnr);
+ friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg);
+ int get_ndb_blobs_value(NdbBlob *last_ndb_blob);
int set_primary_key(NdbOperation *op, const byte *key);
int set_primary_key(NdbOperation *op);
int set_primary_key_from_old_data(NdbOperation *op, const byte *old_data);
- int set_bounds(NdbOperation *ndb_op, const key_range *key,
+ int set_bounds(NdbIndexScanOperation *ndb_op, const key_range *key,
int bound);
int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
void print_results();
longlong get_auto_increment();
-
int ndb_err(NdbConnection*);
+ bool uses_blob_value(bool all_fields);
private:
int check_ndb_connection();
@@ -205,15 +221,23 @@ class ha_ndbcluster: public handler
ulong m_table_flags;
THR_LOCK_DATA m_lock;
NDB_SHARE *m_share;
- NDB_INDEX_TYPE m_indextype[MAX_KEY];
- const char* m_unique_index_name[MAX_KEY];
- NdbRecAttr *m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
+ NDB_INDEX_DATA m_index[MAX_KEY];
+ // NdbRecAttr has no reference to blob
+ typedef union { NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue;
+ NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
bool m_use_write;
bool retrieve_all_fields;
ha_rows rows_to_insert;
ha_rows rows_inserted;
ha_rows bulk_insert_rows;
+ bool bulk_insert_not_flushed;
ha_rows ops_pending;
+ bool skip_auto_increment;
+ bool blobs_pending;
+ // memory for blobs in one tuple
+ char *blobs_buffer;
+ uint32 blobs_buffer_size;
+ uint dupkey;
};
bool ndbcluster_init(void);
@@ -228,11 +252,4 @@ int ndbcluster_discover(const char* dbname, const char* name,
const void** frmblob, uint* frmlen);
int ndbcluster_drop_database(const char* path);
-void ndbcluster_print_error(int error);
-
-
-
-
-
-
-
+void ndbcluster_print_error(int error, const NdbOperation *error_op);
diff --git a/sql/handler.cc b/sql/handler.cc
index 9342d20ec24..640c4f3710d 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -38,6 +38,9 @@
#ifdef HAVE_ARCHIVE_DB
#include "examples/ha_archive.h"
#endif
+#ifdef HAVE_CSV_DB
+#include "examples/ha_tina.h"
+#endif
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
#endif
@@ -91,6 +94,8 @@ struct show_table_type_st sys_table_types[]=
"Example storage engine", DB_TYPE_EXAMPLE_DB},
{"ARCHIVE",&have_archive_db,
"Archive storage engine", DB_TYPE_ARCHIVE_DB},
+ {"CSV",&have_csv_db,
+ "CSV storage engine", DB_TYPE_CSV_DB},
{NullS, NULL, NullS, DB_TYPE_UNKNOWN}
};
@@ -196,6 +201,10 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
case DB_TYPE_ARCHIVE_DB:
return new ha_archive(table);
#endif
+#ifdef HAVE_CSV_DB
+ case DB_TYPE_CSV_DB:
+ return new ha_tina(table);
+#endif
#ifdef HAVE_NDBCLUSTER_DB
case DB_TYPE_NDBCLUSTER:
return new ha_ndbcluster(table);
@@ -463,31 +472,45 @@ int ha_release_temporary_latches(THD *thd)
int ha_commit_trans(THD *thd, THD_TRANS* trans)
{
int error=0;
- DBUG_ENTER("ha_commit");
+ DBUG_ENTER("ha_commit_trans");
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
- bool operation_done= 0;
bool transaction_commited= 0;
+ bool operation_done= 0, need_start_waiters= 0;
- /* Update the binary log if we have cached some queries */
+ /* If transaction has done some updates to tables */
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
- my_b_tell(&thd->transaction.trans_log))
+ my_b_tell(&thd->transaction.trans_log))
{
- mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (thd->transaction.trans_log.disk_writes != 0)
+ if (error= wait_if_global_read_lock(thd, 0, 0))
{
- /*
- We have to do this after addition of trans_log to main binlog since
- this operation can cause flushing of end of trans_log to disk.
+ /*
+ Note that ROLLBACK [TO SAVEPOINT] does not have this test; it's
+ because ROLLBACK never updates data, so needn't wait on the lock.
*/
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- thd->transaction.trans_log.disk_writes= 0;
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
+ error= 1;
+ }
+ else
+ need_start_waiters= 1;
+ if (mysql_bin_log.is_open())
+ {
+ mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
+ statistic_increment(binlog_cache_use, &LOCK_status);
+ if (thd->transaction.trans_log.disk_writes != 0)
+ {
+ /*
+ We have to do this after addition of trans_log to main binlog since
+ this operation can cause flushing of end of trans_log to disk.
+ */
+ statistic_increment(binlog_cache_disk_use, &LOCK_status);
+ thd->transaction.trans_log.disk_writes= 0;
+ }
+ reinit_io_cache(&thd->transaction.trans_log,
+ WRITE_CACHE, (my_off_t) 0, 0, 1);
+ thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
}
- reinit_io_cache(&thd->transaction.trans_log,
- WRITE_CACHE, (my_off_t) 0, 0, 1);
- thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
}
#ifdef HAVE_NDBCLUSTER_DB
if (trans->ndb_tid)
@@ -495,9 +518,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
if ((error=ndbcluster_commit(thd,trans->ndb_tid)))
{
if (error == -1)
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
- else
- ndbcluster_print_error(error);
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0));
error=1;
}
if (trans == &thd->transaction.all)
@@ -544,6 +565,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
statistic_increment(ha_commit_count,&LOCK_status);
thd->transaction.cleanup();
}
+ if (need_start_waiters)
+ start_waiting_global_read_lock(thd);
}
#endif // using transactions
DBUG_RETURN(error);
@@ -553,7 +576,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
int ha_rollback_trans(THD *thd, THD_TRANS *trans)
{
int error=0;
- DBUG_ENTER("ha_rollback");
+ DBUG_ENTER("ha_rollback_trans");
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
@@ -564,9 +587,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
if ((error=ndbcluster_rollback(thd, trans->ndb_tid)))
{
if (error == -1)
- my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
- else
- ndbcluster_print_error(error);
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0));
error=1;
}
trans->ndb_tid = 0;
@@ -747,12 +768,12 @@ bool ha_flush_logs()
{
bool result=0;
#ifdef HAVE_BERKELEY_DB
- if ((have_berkeley_db == SHOW_OPTION_YES) &&
+ if ((have_berkeley_db == SHOW_OPTION_YES) &&
berkeley_flush_logs())
result=1;
#endif
#ifdef HAVE_INNOBASE_DB
- if ((have_innodb == SHOW_OPTION_YES) &&
+ if ((have_innodb == SHOW_OPTION_YES) &&
innobase_flush_logs())
result=1;
#endif
@@ -847,7 +868,7 @@ my_off_t ha_get_ptr(byte *ptr, uint pack_length)
int handler::ha_open(const char *name, int mode, int test_if_locked)
{
int error;
- DBUG_ENTER("handler::open");
+ DBUG_ENTER("handler::ha_open");
DBUG_PRINT("enter",("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d",
name, table->db_type, table->db_stat, mode,
test_if_locked));
@@ -946,7 +967,7 @@ void handler::update_auto_increment()
{
longlong nr;
THD *thd;
- DBUG_ENTER("update_auto_increment");
+ DBUG_ENTER("handler::update_auto_increment");
if (table->next_number_field->val_int() != 0 ||
table->auto_increment_field_not_null &&
current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
@@ -1004,7 +1025,7 @@ longlong handler::get_auto_increment()
void handler::print_error(int error, myf errflag)
{
- DBUG_ENTER("print_error");
+ DBUG_ENTER("handler::print_error");
DBUG_PRINT("enter",("error: %d",error));
int textno=ER_GET_ERRNO;
@@ -1143,7 +1164,7 @@ bool handler::get_error_message(int error, String* buf)
uint handler::get_dup_key(int error)
{
- DBUG_ENTER("get_dup_key");
+ DBUG_ENTER("handler::get_dup_key");
table->file->errkey = (uint) -1;
if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
diff --git a/sql/handler.h b/sql/handler.h
index 092ea47ef4d..7e5e626f713 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -147,7 +147,7 @@ enum db_type
DB_TYPE_MRG_ISAM, DB_TYPE_MYISAM, DB_TYPE_MRG_MYISAM,
DB_TYPE_BERKELEY_DB, DB_TYPE_INNODB,
DB_TYPE_GEMINI, DB_TYPE_NDBCLUSTER,
- DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB,
+ DB_TYPE_EXAMPLE_DB, DB_TYPE_ARCHIVE_DB, DB_TYPE_CSV_DB,
DB_TYPE_DEFAULT // Must be last
};
@@ -529,7 +529,8 @@ extern TYPELIB tx_isolation_typelib;
#define ha_rollback(thd) (ha_rollback_trans((thd), &((thd)->transaction.all)))
#define ha_supports_generate(T) (T != DB_TYPE_INNODB && \
- T != DB_TYPE_BERKELEY_DB)
+ T != DB_TYPE_BERKELEY_DB && \
+ T != DB_TYPE_NDBCLUSTER)
bool ha_caching_allowed(THD* thd, char* table_key,
uint key_length, uint8 cache_type);
diff --git a/sql/item.cc b/sql/item.cc
index 099e6b977d6..ecbe2d22fa4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -62,10 +62,10 @@ Item::Item():
*/
if (thd->lex->current_select)
{
- SELECT_LEX_NODE::enum_parsing_place place=
+ enum_parsing_place place=
thd->lex->current_select->parsing_place;
- if (place == SELECT_LEX_NODE::SELECT_LIST ||
- place == SELECT_LEX_NODE::IN_HAVING)
+ if (place == SELECT_LIST ||
+ place == IN_HAVING)
thd->lex->current_select->select_n_having_items++;
}
}
@@ -179,10 +179,17 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
name_length= 0;
return;
}
- while (length && !my_isgraph(cs,*str))
- { // Fix problem with yacc
- length--;
- str++;
+ if (cs->ctype)
+ {
+ /*
+ This will probably need a better implementation in the future:
+ a function in CHARSET_INFO structure.
+ */
+ while (length && !my_isgraph(cs,*str))
+ { // Fix problem with yacc
+ length--;
+ str++;
+ }
}
if (!my_charset_same(cs, system_charset_info))
{
@@ -291,8 +298,9 @@ Item_splocal::type() const
}
-bool DTCollation::aggregate(DTCollation &dt)
+bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion)
{
+ nagg++;
if (!my_charset_same(collation, dt.collation))
{
/*
@@ -306,15 +314,39 @@ bool DTCollation::aggregate(DTCollation &dt)
if (derivation <= dt.derivation)
; // Do nothing
else
- set(dt);
+ {
+ set(dt);
+ strong= nagg;
+ }
}
else if (dt.collation == &my_charset_bin)
{
if (dt.derivation <= derivation)
+ {
set(dt);
+ strong= nagg;
+ }
else
; // Do nothing
}
+ else if (superset_conversion)
+ {
+ if (derivation < dt.derivation &&
+ collation->state & MY_CS_UNICODE)
+ ; // Do nothing
+ else if (dt.derivation < derivation &&
+ dt.collation->state & MY_CS_UNICODE)
+ {
+ set(dt);
+ strong= nagg;
+ }
+ else
+ {
+ // Cannot convert to superset
+ set(0, DERIVATION_NONE);
+ return 1;
+ }
+ }
else
{
set(0, DERIVATION_NONE);
@@ -328,6 +360,7 @@ bool DTCollation::aggregate(DTCollation &dt)
else if (dt.derivation < derivation)
{
set(dt);
+ strong= nagg;
}
else
{
@@ -979,7 +1012,7 @@ double Item_param::val()
This works for example when user says SELECT ?+0.0 and supplies
time value for the placeholder.
*/
- return (double) TIME_to_ulonglong(&value.time);
+ return ulonglong2double(TIME_to_ulonglong(&value.time));
case NULL_VALUE:
return 0.0;
default:
@@ -1312,12 +1345,24 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
table_list= (last= sl)->get_table_list();
if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{
- // it is primary INSERT st_select_lex => skip first table resolving
+ /*
+ it is primary INSERT st_select_lex => skip first table
+ resolving
+ */
table_list= table_list->next_local;
}
Item_subselect *prev_subselect_item= prev_unit->item;
- if ((tmp= find_field_in_tables(thd, this,
+ enum_parsing_place place= prev_subselect_item->parsing_place;
+ /*
+ check table fields only if subquery used somewhere out of HAVING
+ or SELECT list or outer SELECT do not use groupping (i.e. tables
+ are accessable)
+ */
+ if (((place != IN_HAVING &&
+ place != SELECT_LIST) ||
+ (sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
+ (tmp= find_field_in_tables(thd, this,
table_list, ref,
0, 1)) != not_found_field)
{
@@ -2029,7 +2074,16 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
// it is primary INSERT st_select_lex => skip first table resolving
table_list= table_list->next_local;
}
- if ((tmp= find_field_in_tables(thd, this,
+ enum_parsing_place place= prev_subselect_item->parsing_place;
+ /*
+ Check table fields only if subquery used somewhere out of HAVING
+ or SELECT list or outer SELECT do not use groupping (i.e. tables
+ are accessable)
+ */
+ if (((place != IN_HAVING &&
+ place != SELECT_LIST) ||
+ (sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
+ (tmp= find_field_in_tables(thd, this,
table_list, reference,
0, 1)) != not_found_field)
{
diff --git a/sql/item.h b/sql/item.h
index 63463c6cc41..4d3f1736b4e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -41,16 +41,22 @@ class DTCollation {
public:
CHARSET_INFO *collation;
enum Derivation derivation;
+ uint nagg; // Total number of aggregated collations.
+ uint strong; // Number of the strongest collation.
DTCollation()
{
collation= &my_charset_bin;
derivation= DERIVATION_NONE;
+ nagg= 0;
+ strong= 0;
}
DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
{
collation= collation_arg;
derivation= derivation_arg;
+ nagg= 0;
+ strong= 0;
}
void set(DTCollation &dt)
{
@@ -66,9 +72,9 @@ public:
{ collation= collation_arg; }
void set(Derivation derivation_arg)
{ derivation= derivation_arg; }
- bool aggregate(DTCollation &dt);
- bool set(DTCollation &dt1, DTCollation &dt2)
- { set(dt1); return aggregate(dt2); }
+ bool aggregate(DTCollation &dt, bool superset_conversion= FALSE);
+ bool set(DTCollation &dt1, DTCollation &dt2, bool superset_conversion= FALSE)
+ { set(dt1); return aggregate(dt2, superset_conversion); }
const char *derivation_name() const
{
switch(derivation)
@@ -243,6 +249,7 @@ public:
virtual void top_level_item() {}
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
+ virtual bool is_bool_func() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
@@ -275,8 +282,7 @@ public:
virtual void bring_value() {}
Field *tmp_table_field_from_field_type(TABLE *table);
-
- /* Used in sql_select.cc:eliminate_not_funcs() */
+
virtual Item *neg_transformer(THD *thd) { return NULL; }
void delete_self()
{
@@ -1020,7 +1026,7 @@ public:
};
/*
- The following class is used to optimize comparing of date columns
+ The following class is used to optimize comparing of date and bigint columns
We need to save the original item, to be able to set the field to the
original value in 'opt_range'.
*/
@@ -1030,7 +1036,9 @@ class Item_int_with_ref :public Item_int
Item *ref;
public:
Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg)
- {}
+ {
+ unsigned_flag= ref_arg->unsigned_flag;
+ }
int save_in_field(Field *field, bool no_conversions)
{
return ref->save_in_field(field, no_conversions);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 976cd07cdbe..f6daf0f5ed4 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -188,25 +188,17 @@ void Item_bool_func2::fix_length_and_dec()
{
uint strong= 0;
uint weak= 0;
+ DTCollation coll;
- if ((args[0]->collation.derivation < args[1]->collation.derivation) &&
- !my_charset_same(args[0]->collation.collation,
- args[1]->collation.collation) &&
- (args[0]->collation.collation->state & MY_CS_UNICODE))
- {
- weak= 1;
- }
- else if ((args[1]->collation.derivation < args[0]->collation.derivation) &&
- !my_charset_same(args[0]->collation.collation,
- args[1]->collation.collation) &&
- (args[1]->collation.collation->state & MY_CS_UNICODE))
- {
- strong= 1;
- }
-
- if (strong || weak)
+ if (args[0]->result_type() == STRING_RESULT &&
+ args[1]->result_type() == STRING_RESULT &&
+ !my_charset_same(args[0]->collation.collation,
+ args[1]->collation.collation) &&
+ !coll.set(args[0]->collation, args[1]->collation, TRUE))
{
Item* conv= 0;
+ strong= coll.strong;
+ weak= strong ? 0 : 1;
if (args[weak]->type() == STRING_ITEM)
{
String tmp, cstr;
@@ -219,9 +211,22 @@ void Item_bool_func2::fix_length_and_dec()
}
else
{
- conv= new Item_func_conv_charset(args[weak],args[strong]->collation.collation);
+ THD *thd= current_thd;
+ /*
+ In case we're in statement prepare, create conversion item
+ in its memory: it will be reused on each execute.
+ */
+ Item_arena *arena= thd->current_arena, backup;
+ if (!arena->is_stmt_prepare())
+ arena= 0;
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
+ conv= new Item_func_conv_charset(args[weak],
+ args[strong]->collation.collation);
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
conv->collation.set(args[weak]->collation.derivation);
- conv->fix_fields(current_thd, 0, &conv);
+ conv->fix_fields(thd, 0, &conv);
}
args[weak]= conv ? conv : args[weak];
}
@@ -268,8 +273,8 @@ void Item_bool_func2::fix_length_and_dec()
int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
{
owner= item;
- func= comparator_matrix[type][(owner->functype() == Item_func::EQUAL_FUNC)?
- 1:0];
+ func= comparator_matrix[type]
+ [test(owner->functype() == Item_func::EQUAL_FUNC)];
if (type == ROW_RESULT)
{
uint n= (*a)->cols();
@@ -303,10 +308,10 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return 1;
}
- if (my_binary_compare(cmp_collation.collation))
+ if (cmp_collation.collation == &my_charset_bin)
{
/*
- We are using binary collation, change to compare byte by byte,
+ We are using BLOB/BINARY/VARBINARY, change to compare byte by byte,
without removing end space
*/
if (func == &Arg_comparator::compare_string)
@@ -315,6 +320,22 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
func= &Arg_comparator::compare_e_binary_string;
}
}
+ else if (type == INT_RESULT)
+ {
+ if (func == &Arg_comparator::compare_int_signed)
+ {
+ if ((*a)->unsigned_flag)
+ func= ((*b)->unsigned_flag)? &Arg_comparator::compare_int_unsigned :
+ &Arg_comparator::compare_int_unsigned_signed;
+ else if ((*b)->unsigned_flag)
+ func= &Arg_comparator::compare_int_signed_unsigned;
+ }
+ else if (func== &Arg_comparator::compare_e_int)
+ {
+ if ((*a)->unsigned_flag ^ (*b)->unsigned_flag)
+ func= &Arg_comparator::compare_e_int_diff_signedness;
+ }
+ }
return 0;
}
@@ -416,7 +437,7 @@ int Arg_comparator::compare_e_real()
return test(val1 == val2);
}
-int Arg_comparator::compare_int()
+int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
if (!(*a)->null_value)
@@ -434,6 +455,82 @@ int Arg_comparator::compare_int()
return -1;
}
+
+/*
+ Compare values as BIGINT UNSIGNED.
+*/
+
+int Arg_comparator::compare_int_unsigned()
+{
+ ulonglong val1= (*a)->val_int();
+ if (!(*a)->null_value)
+ {
+ ulonglong val2= (*b)->val_int();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (val1 < val2) return -1;
+ if (val1 == val2) return 0;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+/*
+ Compare signed (*a) with unsigned (*B)
+*/
+
+int Arg_comparator::compare_int_signed_unsigned()
+{
+ longlong sval1= (*a)->val_int();
+ if (!(*a)->null_value)
+ {
+ ulonglong uval2= (ulonglong)(*b)->val_int();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (sval1 < 0 || (ulonglong)sval1 < uval2)
+ return -1;
+ if ((ulonglong)sval1 == uval2)
+ return 0;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+/*
+ Compare unsigned (*a) with signed (*B)
+*/
+
+int Arg_comparator::compare_int_unsigned_signed()
+{
+ ulonglong uval1= (ulonglong)(*a)->val_int();
+ if (!(*a)->null_value)
+ {
+ longlong sval2= (*b)->val_int();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (sval2 < 0)
+ return 1;
+ if (uval1 < (ulonglong)sval2)
+ return -1;
+ if (uval1 == (ulonglong)sval2)
+ return 0;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
int Arg_comparator::compare_e_int()
{
longlong val1= (*a)->val_int();
@@ -443,6 +540,17 @@ int Arg_comparator::compare_e_int()
return test(val1 == val2);
}
+/*
+ Compare unsigned *a with signed *b or signed *a with unsigned *b.
+*/
+int Arg_comparator::compare_e_int_diff_signedness()
+{
+ longlong val1= (*a)->val_int();
+ longlong val2= (*b)->val_int();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return (val1 >= 0) && test(val1 == val2);
+}
int Arg_comparator::compare_row()
{
@@ -1629,8 +1737,8 @@ bool Item_func_in::nulls_in_row()
static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
return cs->coll->strnncollsp(cs,
- (unsigned char *) x->ptr(),x->length(),
- (unsigned char *) y->ptr(),y->length());
+ (uchar *) x->ptr(),x->length(),
+ (uchar *) y->ptr(),y->length());
}
@@ -1640,12 +1748,58 @@ void Item_func_in::fix_length_and_dec()
uint const_itm= 1;
agg_cmp_type(&cmp_type, args, arg_count);
- if ((cmp_type == STRING_RESULT) &&
- (agg_arg_collations_for_comparison(cmp_collation, args, arg_count)))
- return;
-
+
for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
const_itm&= arg[0]->const_item();
+
+
+ if (cmp_type == STRING_RESULT)
+ {
+ /*
+ We allow consts character set conversion for
+
+ item IN (const1, const2, const3, ...)
+
+ if item is in a superset for all arguments,
+ and if it is a stong side according to coercibility rules.
+
+ TODO: add covnersion for non-constant IN values
+ via creating Item_func_conv_charset().
+ */
+
+ if (agg_arg_collations_for_comparison(cmp_collation,
+ args, arg_count, TRUE))
+ return;
+ if ((!my_charset_same(args[0]->collation.collation,
+ cmp_collation.collation) || !const_itm))
+ {
+ if (agg_arg_collations_for_comparison(cmp_collation,
+ args, arg_count, FALSE))
+ return;
+ }
+ else
+ {
+ /*
+ Conversion is possible:
+ All IN arguments are constants.
+ */
+ for (arg= args+1, arg_end= args+arg_count; arg < arg_end; arg++)
+ {
+ if (!my_charset_same(cmp_collation.collation,
+ arg[0]->collation.collation))
+ {
+ Item_string *conv;
+ String tmp, cstr, *ostr= arg[0]->val_str(&tmp);
+ cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(),
+ cmp_collation.collation);
+ conv= new Item_string(cstr.ptr(),cstr.length(), cstr.charset(),
+ arg[0]->collation.derivation);
+ conv->str_value.copy();
+ arg[0]= conv;
+ }
+ }
+ }
+ }
/*
Row item with NULLs inside can return NULL or FALSE =>
@@ -1927,15 +2081,6 @@ void Item_cond::neg_arguments(THD *thd)
{
if (!(new_item= new Item_func_not(item)))
return; // Fatal OEM error
- /*
- We can use 0 as tables list because Item_func_not do not use it
- on fix_fields and its arguments are already fixed.
-
- We do not check results of fix_fields, because there are not way
- to return error in this functions interface, thd->net.report_error
- will be checked on upper level call.
- */
- new_item->fix_fields(thd, 0, &new_item);
}
VOID(li.replace(new_item));
}
@@ -2354,7 +2499,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
*splm1 = pattern_len;
- if (cs == &my_charset_bin)
+ if (!cs->sort_order)
{
int i;
for (i = pattern_len - 2; i >= 0; i--)
@@ -2457,7 +2602,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
for (i = bmBc; i < end; i++)
*i = pattern_len;
- if (cs == &my_charset_bin)
+ if (!cs->sort_order)
{
for (j = 0; j < plm1; j++)
bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
@@ -2488,7 +2633,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
const int tlmpl= text_len - pattern_len;
/* Searching */
- if (cs == &my_charset_bin)
+ if (!cs->sort_order)
{
while (j <= tlmpl)
{
@@ -2613,9 +2758,6 @@ longlong Item_cond_xor::val_int()
IS NULL(a) -> IS NOT NULL(a)
IS NOT NULL(a) -> IS NULL(a)
- NOTE
- This method is used in the eliminate_not_funcs() function.
-
RETURN
New item or
NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
@@ -2623,26 +2765,13 @@ longlong Item_cond_xor::val_int()
Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
{
- // We should apply negation elimination to the argument of the NOT function
- return eliminate_not_funcs(thd, args[0]);
+ return args[0];
}
Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
{
Item *item= negated_item();
- if (item)
- {
- /*
- We can use 0 as tables list because Item_func* family do not use it
- on fix_fields and its arguments are already fixed.
-
- We do not check results of fix_fields, because there are not way
- to return error in this functions interface, thd->net.report_error
- will be checked on upper level call.
- */
- item->fix_fields(thd, 0, &item);
- }
return item;
}
@@ -2651,9 +2780,6 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
Item *Item_func_isnull::neg_transformer(THD *thd)
{
Item *item= new Item_func_isnotnull(args[0]);
- // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
- if (item)
- item->fix_fields(thd, 0, &item);
return item;
}
@@ -2662,9 +2788,6 @@ Item *Item_func_isnull::neg_transformer(THD *thd)
Item *Item_func_isnotnull::neg_transformer(THD *thd)
{
Item *item= new Item_func_isnull(args[0]);
- // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
- if (item)
- item->fix_fields(thd, 0, &item);
return item;
}
@@ -2674,9 +2797,6 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
{
neg_arguments(thd);
Item *item= new Item_cond_or(list);
- // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
- if (item)
- item->fix_fields(thd, 0, &item);
return item;
}
@@ -2686,9 +2806,6 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
{
neg_arguments(thd);
Item *item= new Item_cond_and(list);
- // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
- if (item)
- item->fix_fields(thd, 0, &item);
return item;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 23ac82e79e6..e7bef18e629 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -65,12 +65,16 @@ public:
int compare_string(); // compare args[0] & args[1]
int compare_binary_string(); // compare args[0] & args[1]
int compare_real(); // compare args[0] & args[1]
- int compare_int(); // compare args[0] & args[1]
+ int compare_int_signed(); // compare args[0] & args[1]
+ int compare_int_signed_unsigned();
+ int compare_int_unsigned_signed();
+ int compare_int_unsigned();
int compare_row(); // compare args[0] & args[1]
int compare_e_string(); // compare args[0] & args[1]
int compare_e_binary_string(); // compare args[0] & args[1]
int compare_e_real(); // compare args[0] & args[1]
int compare_e_int(); // compare args[0] & args[1]
+ int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
static arg_cmp_func comparator_matrix [4][2];
@@ -85,6 +89,7 @@ public:
Item_bool_func(Item *a) :Item_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
+ bool is_bool_func() { return 1; }
void fix_length_and_dec() { decimals=0; max_length=1; }
};
@@ -197,6 +202,7 @@ public:
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
+ bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
friend class Arg_comparator;
@@ -304,7 +310,7 @@ public:
enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "<=>"; }
- Item* neg_transformer(THD *thd) { return 0; }
+ Item *neg_transformer(THD *thd) { return 0; }
};
@@ -778,6 +784,7 @@ class Item_func_in :public Item_int_func
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; }
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 02cface827b..e21364045ba 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -86,11 +86,6 @@ Item *create_func_conv(Item* a, Item *b, Item *c)
return new Item_func_conv(a,b,c);
}
-Item *create_func_convert_tz(Item* a, Item *b, Item *c)
-{
- return new Item_func_convert_tz(a,b,c);
-}
-
Item *create_func_cos(Item* a)
{
return new Item_func_cos(a);
diff --git a/sql/item_create.h b/sql/item_create.h
index 18c5b3239f3..d48aed5284a 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -31,7 +31,6 @@ Item *create_func_char_length(Item* a);
Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
-Item *create_func_convert_tz(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
Item *create_func_cot(Item* a);
Item *create_func_crc32(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c2c93586af8..7c5b584e645 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -78,13 +78,16 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname)
}
-bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count)
+bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
+ bool allow_superset_conversion)
{
uint i;
+ c.nagg= 0;
+ c.strong= 0;
c.set(av[0]->collation);
for (i= 1; i < count; i++)
{
- if (c.aggregate(av[i]->collation))
+ if (c.aggregate(av[i]->collation, allow_superset_conversion))
{
my_coll_agg_error(av, count, func_name());
return TRUE;
@@ -95,9 +98,10 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count)
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
- Item **av, uint count)
+ Item **av, uint count,
+ bool allow_superset_conv)
{
- if (agg_arg_collations(c, av, count))
+ if (agg_arg_collations(c, av, count, allow_superset_conv))
return TRUE;
if (c.derivation == DERIVATION_NONE)
@@ -972,7 +976,7 @@ void Item_func_round::fix_length_and_dec()
if (tmp < 0)
decimals=0;
else
- decimals=tmp;
+ decimals=min(tmp,NOT_FIXED_DEC);
}
}
@@ -1438,30 +1442,43 @@ longlong Item_func_find_in_set::val_int()
int diff;
if ((diff=buffer->length() - find->length()) >= 0)
{
- const char *f_pos=find->ptr();
- const char *f_end=f_pos+find->length();
- const char *str=buffer->ptr();
- const char *end=str+diff+1;
- const char *real_end=str+buffer->length();
- uint position=1;
- do
+ my_wc_t wc;
+ CHARSET_INFO *cs= cmp_collation.collation;
+ const char *str_begin= buffer->ptr();
+ const char *str_end= buffer->ptr();
+ const char *real_end= str_end+buffer->length();
+ const uchar *find_str= (const uchar *) find->ptr();
+ uint find_str_len= find->length();
+ int position= 0;
+ while (1)
{
- const char *pos= f_pos;
- while (pos != f_end)
+ int symbol_len;
+ if ((symbol_len= cs->cset->mb_wc(cs, &wc, (uchar*) str_end,
+ (uchar*) real_end)) > 0)
{
- if (my_toupper(cmp_collation.collation,*str) !=
- my_toupper(cmp_collation.collation,*pos))
- goto not_found;
- str++;
- pos++;
+ const char *substr_end= str_end + symbol_len;
+ bool is_last_item= (substr_end == real_end);
+ if (wc == (my_wc_t) separator || is_last_item)
+ {
+ position++;
+ if (is_last_item)
+ str_end= substr_end;
+ if (!my_strnncoll(cs, (const uchar *) str_begin,
+ str_end - str_begin,
+ find_str, find_str_len))
+ return (longlong) position;
+ else
+ str_begin= substr_end;
+ }
+ str_end= substr_end;
}
- if (str == real_end || str[0] == separator)
- return (longlong) position;
- not_found:
- while (str < end && str[0] != separator)
- str++;
- position++;
- } while (++str <= end);
+ else if (str_end - str_begin == 0 &&
+ find_str_len == 0 &&
+ wc == (my_wc_t) separator)
+ return (longlong) ++position;
+ else
+ return (longlong) 0;
+ }
}
return 0;
}
@@ -1649,7 +1666,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
func->max_length=min(initid.max_length,MAX_BLOB_WIDTH);
func->maybe_null=initid.maybe_null;
const_item_cache=initid.const_item;
- func->decimals=min(initid.decimals,31);
+ func->decimals=min(initid.decimals,NOT_FIXED_DEC);
}
initialized=1;
if (error)
diff --git a/sql/item_func.h b/sql/item_func.h
index 8636bcd6507..76d0346531e 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -142,8 +142,11 @@ public:
Field *tmp_table_field(TABLE *t_arg);
Item *get_tmp_table_item(THD *thd);
- bool agg_arg_collations(DTCollation &c, Item **items, uint nitems);
- bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems);
+ bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
+ bool allow_superset_conversion= FALSE);
+ bool agg_arg_collations_for_comparison(DTCollation &c,
+ Item **items, uint nitems,
+ bool allow_superset_comversion= FALSE);
bool walk(Item_processor processor, byte *arg);
};
@@ -337,7 +340,7 @@ class Item_dec_func :public Item_real_func
Item_dec_func(Item *a,Item *b) :Item_real_func(a,b) {}
void fix_length_and_dec()
{
- decimals=6; max_length=float_length(decimals);
+ decimals=NOT_FIXED_DEC; max_length=float_length(decimals);
maybe_null=1;
}
inline double fix_result(double value)
diff --git a/sql/item_row.cc b/sql/item_row.cc
index c7e4bc0acf4..f6623e80734 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -66,7 +66,8 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
used_tables_cache |= item->used_tables();
- if (const_item_cache&= item->const_item() && !with_null)
+ const_item_cache&= item->const_item() && !with_null;
+ if (const_item_cache)
{
if (item->cols() > 1)
with_null|= item->null_inside();
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index d3493e1fad1..fac73a1a759 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -39,7 +39,8 @@ C_MODE_END
String my_empty_string("",default_charset_info);
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
+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(),
@@ -62,8 +63,9 @@ double Item_str_func::val()
{
DBUG_ASSERT(fixed == 1);
int err;
- String *res;
- res=val_str(&str_value);
+ char buff[64];
+ String *res, tmp(buff,sizeof(buff), &my_charset_bin);
+ res= val_str(&tmp);
return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
NULL, &err) : 0.0;
}
@@ -72,8 +74,9 @@ longlong Item_str_func::val_int()
{
DBUG_ASSERT(fixed == 1);
int err;
- String *res;
- res=val_str(&str_value);
+ char buff[22];
+ String *res, tmp(buff,sizeof(buff), &my_charset_bin);
+ res= val_str(&tmp);
return (res ?
my_strntoll(res->charset(), res->ptr(), res->length(), 10, NULL,
&err) :
@@ -977,14 +980,16 @@ String *Item_func_left::val_str(String *str)
DBUG_ASSERT(fixed == 1);
String *res =args[0]->val_str(str);
long length =(long) args[1]->val_int();
+ uint char_pos;
if ((null_value=args[0]->null_value))
return 0;
if (length <= 0)
return &my_empty_string;
- if (res->length() <= (uint) length)
+ if (res->length() <= (uint) length ||
+ res->length() <= (char_pos= res->charpos(length)))
return res;
- str_value.set(*res, 0, res->charpos(length));
+ str_value.set(*res, 0, char_pos);
return &str_value;
}
@@ -2195,7 +2200,8 @@ String *Item_func_conv_charset::val_str(String *str)
null_value=1;
return 0;
}
- null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(),conv_charset);
+ null_value= str_value.copy(arg->ptr(),arg->length(),arg->charset(),
+ conv_charset);
return null_value ? 0 : &str_value;
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index c615bcf7e0f..6d86d7d4b2d 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -63,12 +63,21 @@ void Item_subselect::init(st_select_lex *select_lex,
=> we do not copy old_engine here
*/
engine= unit->item->engine;
+ parsing_place= unit->item->parsing_place;
unit->item->engine= 0;
unit->item= this;
engine->change_item(this, result);
}
else
{
+ SELECT_LEX *outer_select= unit->outer_select();
+ /*
+ do not take into account expression inside aggregate functions because
+ they can access original table fields
+ */
+ parsing_place= (outer_select->in_sum_expr ?
+ NO_MATTER :
+ outer_select->parsing_place);
if (select_lex->next_select())
engine= new subselect_union_engine(unit, result, this);
else
@@ -76,7 +85,7 @@ void Item_subselect::init(st_select_lex *select_lex,
}
{
SELECT_LEX *upper= unit->outer_select();
- if (upper->parsing_place == SELECT_LEX_NODE::IN_HAVING)
+ if (upper->parsing_place == IN_HAVING)
upper->subquery_in_having= 1;
}
DBUG_VOID_RETURN;
@@ -123,13 +132,13 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
+ char const *save_where= thd_param->where;
+ int res;
+
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
arena= thd->current_arena;
- char const *save_where= thd->where;
- int res;
-
if (check_stack_overrun(thd, (gptr)&res))
return 1;
@@ -306,7 +315,12 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex;
- Statement backup;
+
+ /* Juggle with current arena only if we're in prepared statement prepare */
+ Item_arena *arena= join->thd->current_arena;
+ Item_arena backup;
+ if (!arena->is_stmt_prepare())
+ arena= 0; // For easier test
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
@@ -632,6 +646,7 @@ Item_subselect::trans_res
Item_in_subselect::single_value_transformer(JOIN *join,
Comp_creator *func)
{
+ Item_subselect::trans_res result= RES_ERROR;
DBUG_ENTER("Item_in_subselect::single_value_transformer");
if (changed)
@@ -640,10 +655,13 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
SELECT_LEX *select_lex= join->select_lex;
- Statement backup;
+ Item_arena *arena= join->thd->current_arena, backup;
thd->where= "scalar IN/ALL/ANY subquery";
- if (arena)
+
+ if (!arena->is_stmt_prepare())
+ arena= 0; // For easier test
+ else
thd->set_n_backup_item_arena(arena, &backup);
if (select_lex->item_list.elements > 1)
@@ -751,18 +769,17 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
- Item *item;
-
- item= (Item*) select_lex->item_list.head();
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.elements)
{
- item= func->create(expr,
- new Item_ref_null_helper(this,
- select_lex->ref_pointer_array,
- (char *)"<ref>",
- this->full_name()));
+ bool tmp;
+ Item *item= func->create(expr,
+ new Item_ref_null_helper(this,
+ select_lex->
+ ref_pointer_array,
+ (char *)"<ref>",
+ this->full_name()));
/*
AND and comparison functions can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last
@@ -770,21 +787,22 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list, 0))
- {
- select_lex->having_fix_field= 0;
- goto err;
- }
+ tmp= join->having->fix_fields(thd, join->tables_list, 0);
select_lex->having_fix_field= 0;
+ if (tmp)
+ goto err;
}
else
{
+ Item *item= (Item*) select_lex->item_list.head();
+
select_lex->item_list.empty();
select_lex->item_list.push_back(new Item_int("Not_used",
(longlong) 1, 21));
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
if (select_lex->table_list.elements)
{
+ bool tmp;
Item *having= item, *orig_item= item;
item= func->create(expr, item);
if (!abort_on_null && orig_item->maybe_null)
@@ -800,12 +818,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list, 0))
- {
- select_lex->having_fix_field= 0;
+ tmp= join->having->fix_fields(thd, join->tables_list, 0);
+ select_lex->having_fix_field= 0;
+ if (tmp)
goto err;
- }
- select_lex->having_fix_field= 0;
item= new Item_cond_or(item,
new Item_func_isnull(orig_item));
}
@@ -821,6 +837,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
else
{
+ bool tmp;
if (select_lex->master_unit()->first_select()->next_select())
{
/*
@@ -835,13 +852,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
(char *)"<no matter>",
(char *)"<result>"));
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd, join->tables_list,
- 0))
- {
- select_lex->having_fix_field= 0;
+ tmp= join->having->fix_fields(thd, join->tables_list, 0);
+ select_lex->having_fix_field= 0;
+ if (tmp)
goto err;
- }
- select_lex->having_fix_field= 0;
}
else
{
@@ -857,42 +871,40 @@ Item_in_subselect::single_value_transformer(JOIN *join,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- DBUG_RETURN(RES_REDUCE);
+ result= RES_REDUCE;
+ goto end;
}
}
}
ok:
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- DBUG_RETURN(RES_OK);
+ result= RES_OK;
err:
if (arena)
thd->restore_backup_item_arena(arena, &backup);
- DBUG_RETURN(RES_ERROR);
+ DBUG_RETURN(result);
}
Item_subselect::trans_res
Item_in_subselect::row_value_transformer(JOIN *join)
{
+ Item *item= 0;
+ SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::row_value_transformer");
if (changed)
{
DBUG_RETURN(RES_OK);
}
- Statement backup;
- Item *item= 0;
-
thd->where= "row IN/ALL/ANY subquery";
- if (arena)
- thd->set_n_backup_item_arena(arena, &backup);
- SELECT_LEX *select_lex= join->select_lex;
+ Item_arena *arena= join->thd->current_arena, backup;
+ if (!arena->is_stmt_prepare())
+ arena= 0;
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
if (select_lex->item_list.elements != left_expr->cols())
{
@@ -1237,29 +1249,31 @@ int subselect_uniquesubquery_engine::exec()
DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error;
TABLE *table= tab->table;
- if ((tab->ref.key_err= (*tab->ref.key_copy)->copy()))
+ for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
- table->status= STATUS_NOT_FOUND;
- error= -1;
+ if (tab->ref.key_err= (*copy)->copy())
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(1);
+ }
}
+
+ if (!table->file->inited)
+ table->file->ha_index_init(tab->ref.key);
+ error= table->file->index_read(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length,HA_READ_KEY_EXACT);
+ if (error && error != HA_ERR_KEY_NOT_FOUND)
+ error= report_error(table, error);
else
{
- if (!table->file->inited)
- table->file->ha_index_init(tab->ref.key);
- error= table->file->index_read(table->record[0],
- tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
- if (error && error != HA_ERR_KEY_NOT_FOUND)
- error= report_error(table, error);
- else
- {
- error= 0;
- table->null_row= 0;
- ((Item_in_subselect *) item)->value= (!table->status &&
- (!cond || cond->val_int()) ? 1 :
- 0);
- }
+ error= 0;
+ table->null_row= 0;
+ ((Item_in_subselect *) item)->value= (!table->status &&
+ (!cond || cond->val_int()) ? 1 :
+ 0);
}
+
DBUG_RETURN(error != 0);
}
@@ -1287,55 +1301,56 @@ int subselect_indexsubquery_engine::exec()
((Item_in_subselect *) item)->was_null= 0;
}
- if ((*tab->ref.key_copy) && (tab->ref.key_err= (*tab->ref.key_copy)->copy()))
+ for (store_key **copy=tab->ref.key_copy ; *copy ; copy++)
{
- table->status= STATUS_NOT_FOUND;
- error= -1;
+ if (tab->ref.key_err= (*copy)->copy())
+ {
+ table->status= STATUS_NOT_FOUND;
+ DBUG_RETURN(1);
+ }
}
+
+ if (!table->file->inited)
+ table->file->ha_index_init(tab->ref.key);
+ error= table->file->index_read(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length,HA_READ_KEY_EXACT);
+ if (error && error != HA_ERR_KEY_NOT_FOUND)
+ error= report_error(table, error);
else
{
- if (!table->file->inited)
- table->file->ha_index_init(tab->ref.key);
- error= table->file->index_read(table->record[0],
- tab->ref.key_buff,
- tab->ref.key_length,HA_READ_KEY_EXACT);
- if (error && error != HA_ERR_KEY_NOT_FOUND)
- error= report_error(table, error);
- else
+ for (;;)
{
- for (;;)
+ error= 0;
+ table->null_row= 0;
+ if (!table->status)
{
- error= 0;
- table->null_row= 0;
- if (!table->status)
- {
- if (!cond || cond->val_int())
- {
- if (null_finding)
- ((Item_in_subselect *) item)->was_null= 1;
- else
- ((Item_in_subselect *) item)->value= 1;
- break;
- }
- error= table->file->index_next_same(table->record[0],
- tab->ref.key_buff,
- tab->ref.key_length);
- if (error && error != HA_ERR_END_OF_FILE)
- {
- error= report_error(table, error);
- break;
- }
- }
- else
- {
- if (!check_null || null_finding)
- break; /* We don't need to check nulls */
- *tab->ref.null_ref_key= 1;
- null_finding= 1;
- /* Check if there exists a row with a null value in the index */
- if ((error= (safe_index_read(tab) == 1)))
- break;
- }
+ if (!cond || cond->val_int())
+ {
+ if (null_finding)
+ ((Item_in_subselect *) item)->was_null= 1;
+ else
+ ((Item_in_subselect *) item)->value= 1;
+ break;
+ }
+ error= table->file->index_next_same(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length);
+ if (error && error != HA_ERR_END_OF_FILE)
+ {
+ error= report_error(table, error);
+ break;
+ }
+ }
+ else
+ {
+ if (!check_null || null_finding)
+ break; /* We don't need to check nulls */
+ *tab->ref.null_ref_key= 1;
+ null_finding= 1;
+ /* Check if there exists a row with a null value in the index */
+ if ((error= (safe_index_read(tab) == 1)))
+ break;
}
}
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index e5defe24756..e870feddedf 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -50,6 +50,8 @@ protected:
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
+ /* where subquery is placed */
+ enum_parsing_place parsing_place;
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constant state */
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b92a7f2ba80..13b6329daae 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -64,20 +64,20 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
/*
- Save copy of arguments if we are prepare prepared statement
+ Save copy of arguments if we prepare prepared statement
(arguments can be rewritten in get_tmp_table_item())
SYNOPSIS
- Item_sum::save_args_for_prepared_statements()
+ Item_sum::save_args_for_prepared_statement()
thd - thread handler
RETURN
0 - OK
1 - Error
*/
-bool Item_sum::save_args_for_prepared_statements(THD *thd)
+bool Item_sum::save_args_for_prepared_statement(THD *thd)
{
- if (thd->current_arena && args_copy == 0)
+ if (thd->current_arena->is_stmt_prepare() && args_copy == 0)
return save_args(thd->current_arena);
return 0;
}
@@ -214,7 +214,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (save_args_for_prepared_statements(thd))
+ if (save_args_for_prepared_statement(thd))
return 1;
if (!thd->allow_sum_func)
@@ -248,7 +248,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (save_args_for_prepared_statements(thd))
+ if (save_args_for_prepared_statement(thd))
return 1;
Item *item= args[0];
@@ -2056,13 +2056,12 @@ void Item_func_group_concat::reset_field()
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ uint i; /* for loop variable */
DBUG_ASSERT(fixed == 0);
- if (save_args_for_prepared_statements(thd))
+ if (save_args_for_prepared_statement(thd))
return 1;
- uint i; /* for loop variable */
-
if (!thd->allow_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
@@ -2077,12 +2076,12 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Fix fields for select list and ORDER clause
*/
- for (i= 0 ; i < arg_count ; i++)
+ for (i=0 ; i < arg_count ; i++)
{
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
return 1;
- if (i < arg_count_field && args[i]->maybe_null)
- maybe_null= 0;
+ if (i < arg_count_field)
+ maybe_null|= args[i]->maybe_null;
}
result_field= 0;
@@ -2153,10 +2152,14 @@ bool Item_func_group_concat::setup(THD *thd)
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, 0,
- 0, 0, 0,select_lex->options | thd->options,
- (char *) "")))
+ if (!(table=create_tmp_table(thd, tmp_table_param, all_fields,
+ (ORDER*) 0, 0, TRUE,
+ select_lex->options | thd->options,
+ HA_POS_ERROR,(char *) "")))
DBUG_RETURN(1);
table->file->extra(HA_EXTRA_NO_ROWS);
table->no_rows= 1;
@@ -2263,7 +2266,7 @@ void Item_func_group_concat::print(String *str)
(*order[i]->item)->print(str);
}
}
- str->append(" seperator \'", 12);
+ str->append(" separator \'", 12);
str->append(*separator);
str->append("\')", 2);
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 2dde6f73425..9046a215c86 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -94,8 +94,8 @@ public:
virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
- bool save_args_for_prepared_statements(THD *);
- bool save_args(Item_arena* stmt);
+ bool save_args_for_prepared_statement(THD *);
+ bool save_args(Item_arena *arena);
bool walk (Item_processor processor, byte *argument);
};
@@ -317,7 +317,11 @@ public:
class Item_sum_avg :public Item_sum_num
{
- void fix_length_and_dec() { decimals+=4; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=min(decimals+4, NOT_FIXED_DEC);
+ maybe_null=1;
+ }
double sum;
ulonglong count;
@@ -372,7 +376,11 @@ class Item_sum_variance : public Item_sum_num
{
double sum, sum_sqr;
ulonglong count;
- void fix_length_and_dec() { decimals+=4; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=min(decimals+4, NOT_FIXED_DEC);
+ maybe_null=1;
+ }
public:
Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 5aa14010058..c558c935090 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -114,6 +114,17 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
/*
+ Date formats corresponding to compound %r and %T conversion specifiers
+
+ Note: We should init at least first element of "positions" array
+ (first member) or hpux11 compiler will die horribly.
+*/
+static DATE_TIME_FORMAT time_ampm_format= {{0}, '\0', 0,
+ {(char *)"%I:%i:%S %p", 11}};
+static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
+ {(char *)"%H:%i:%S", 8}};
+
+/*
Extract datetime value to TIME struct from string value
according to format string.
@@ -126,6 +137,17 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
cached_timestamp_type
It uses to get an appropriate warning
in the case when the value is truncated.
+ sub_pattern_end if non-zero then we are parsing string which
+ should correspond compound specifier (like %T or
+ %r) and this parameter is pointer to place where
+ pointer to end of string matching this specifier
+ should be stored.
+ NOTE
+ Possibility to parse strings matching to patterns equivalent to compound
+ specifiers is mainly intended for use from inside of this function in
+ order to understand %T and %r conversion specifiers, so number of
+ conversion specifiers that can be used in such sub-patterns is limited.
+ Also most of checks are skipped in this case.
RETURN
0 ok
@@ -134,14 +156,18 @@ static bool make_datetime(date_time_format_types format, TIME *ltime,
static bool extract_date_time(DATE_TIME_FORMAT *format,
const char *val, uint length, TIME *l_time,
- timestamp_type cached_timestamp_type)
+ timestamp_type cached_timestamp_type,
+ const char **sub_pattern_end)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
CHARSET_INFO *cs= &my_charset_bin;
int error= 0;
bool usa_time= 0;
- bool sunday_first= 0;
+ bool sunday_first_n_first_week_non_iso;
+ bool strict_week_number;
+ int strict_week_number_year= -1;
+ bool strict_week_number_year_type;
int frac_part;
const char *val_begin= val;
const char *val_end= val + length;
@@ -149,7 +175,12 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
const char *end= ptr + format->format.length;
DBUG_ENTER("extract_date_time");
- bzero((char*) l_time, sizeof(*l_time));
+ LINT_INIT(sunday_first_n_first_week_non_iso);
+ LINT_INIT(strict_week_number);
+ LINT_INIT(strict_week_number_year_type);
+
+ if (!sub_pattern_end)
+ bzero((char*) l_time, sizeof(*l_time));
for (; ptr != end && val != val_end; ptr++)
{
@@ -160,7 +191,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
char *tmp;
/* Skip pre-space between each argument */
- while (my_isspace(cs, *val) && val != val_end)
+ while (val != val_end && my_isspace(cs, *val))
val++;
val_len= (uint) (val_end - val);
@@ -268,9 +299,12 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
break;
case 'w':
tmp= (char*) val + 1;
- if ((weekday= (int) my_strtoll10(val, &tmp, &error)) <= 0 ||
+ if ((weekday= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
weekday >= 7)
goto err;
+ /* We should use the same 1 - 7 scale for %w as for %W */
+ if (!weekday)
+ weekday= 7;
val= tmp;
break;
case 'j':
@@ -279,15 +313,45 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
val= tmp;
break;
+ /* Week numbers */
+ case 'V':
case 'U':
- sunday_first= 1;
- /* Fall through */
+ case 'v':
case 'u':
+ sunday_first_n_first_week_non_iso= (*ptr=='U' || *ptr== 'V');
+ strict_week_number= (*ptr=='V' || *ptr=='v');
tmp= (char*) val + min(val_len, 2);
- week_number= (int) my_strtoll10(val, &tmp, &error);
+ if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
+ strict_week_number && !week_number ||
+ week_number > 53)
+ goto err;
val= tmp;
break;
+ /* Year used with 'strict' %V and %v week numbers */
+ case 'X':
+ case 'x':
+ strict_week_number_year_type= (*ptr=='X');
+ tmp= (char*) val + min(4, val_len);
+ strict_week_number_year= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
+ break;
+
+ /* Time in AM/PM notation */
+ case 'r':
+ error= extract_date_time(&time_ampm_format, val,
+ (uint)(val_end - val), l_time,
+ cached_timestamp_type, &val);
+ break;
+
+ /* Time in 24-hour notation */
+ case 'T':
+ error= extract_date_time(&time_24hrs_format, val,
+ (uint)(val_end - val), l_time,
+ cached_timestamp_type, &val);
+ break;
+
+ /* Conversion specifiers that match classes of characters */
case '.':
while (my_ispunct(cs, *val) && val != val_end)
val++;
@@ -320,6 +384,16 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
l_time->hour= l_time->hour%12+daypart;
}
+ /*
+ If we are recursively called for parsing string matching compound
+ specifiers we are already done.
+ */
+ if (sub_pattern_end)
+ {
+ *sub_pattern_end= val;
+ DBUG_RETURN(0);
+ }
+
if (yearday > 0)
{
uint days= calc_daynr(l_time->year,1,1) + yearday - 1;
@@ -330,34 +404,45 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
if (week_number >= 0 && weekday)
{
- int days= calc_daynr(l_time->year,1,1);
+ int days;
uint weekday_b;
-
- if (weekday > 7 || weekday < 0)
- goto err;
- if (sunday_first)
- weekday = weekday%7;
- if (week_number == 53)
- {
- days+= (week_number - 1)*7;
- weekday_b= calc_weekday(days, sunday_first);
- weekday = weekday - weekday_b - !sunday_first;
- days+= weekday;
- }
- else if (week_number == 0)
+ /*
+ %V,%v require %X,%x resprectively,
+ %U,%u should be used with %Y and not %X or %x
+ */
+ if (strict_week_number &&
+ (strict_week_number_year < 0 ||
+ strict_week_number_year_type != sunday_first_n_first_week_non_iso) ||
+ !strict_week_number && strict_week_number_year >= 0)
+ goto err;
+
+ /* Number of days since year 0 till 1st Jan of this year */
+ days= calc_daynr((strict_week_number ? strict_week_number_year :
+ l_time->year),
+ 1, 1);
+ /* Which day of week is 1st Jan of this year */
+ weekday_b= calc_weekday(days, sunday_first_n_first_week_non_iso);
+
+ /*
+ Below we are going to sum:
+ 1) number of days since year 0 till 1st day of 1st week of this year
+ 2) number of days between 1st week and our week
+ 3) and position of our day in the week
+ */
+ if (sunday_first_n_first_week_non_iso)
{
- weekday_b= calc_weekday(days, sunday_first);
- weekday = weekday - weekday_b - !sunday_first;
- days+= weekday;
+ days+= ((weekday_b == 0) ? 0 : 7) - weekday_b +
+ (week_number - 1) * 7 +
+ weekday % 7;
}
else
{
- days+= (week_number - !sunday_first)*7;
- weekday_b= calc_weekday(days, sunday_first);
- weekday =weekday - weekday_b - !sunday_first;
- days+= weekday;
+ days+= ((weekday_b <= 3) ? 0 : 7) - weekday_b +
+ (week_number - 1) * 7 +
+ (weekday - 1);
}
+
if (days <= 0 || days >= MAX_DAY_NUMBER)
goto err;
get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
@@ -1574,19 +1659,29 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
void Item_func_convert_tz::fix_length_and_dec()
-{
- String str;
-
- thd= current_thd;
+{
collation.set(&my_charset_bin);
decimals= 0;
max_length= MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+}
+
+
+bool
+Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref)
+{
+ String str;
+ if (Item_date_func::fix_fields(thd_arg, tables_arg, ref))
+ return 1;
+
+ tz_tables= thd_arg->lex->time_zone_tables_used;
if (args[1]->const_item())
- from_tz= my_tz_find(thd, args[1]->val_str(&str));
-
+ from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
+
if (args[2]->const_item())
- to_tz= my_tz_find(thd, args[2]->val_str(&str));
+ to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
+
+ return 0;
}
@@ -1627,10 +1722,10 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
String str;
if (!args[1]->const_item())
- from_tz= my_tz_find(thd, args[1]->val_str(&str));
+ from_tz= my_tz_find(args[1]->val_str(&str), tz_tables);
if (!args[2]->const_item())
- to_tz= my_tz_find(thd, args[2]->val_str(&str));
+ to_tz= my_tz_find(args[2]->val_str(&str), tz_tables);
if (from_tz==0 || to_tz==0 || get_arg0_date(ltime, 0))
{
@@ -2825,7 +2920,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
- ltime, cached_timestamp_type))
+ ltime, cached_timestamp_type, 0))
goto null_date;
if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
{
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index fe72ac6193b..5f71045ef27 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -531,9 +531,22 @@ class Item_func_from_unixtime :public Item_date_func
*/
class Time_zone;
+/*
+ This class represents CONVERT_TZ() function.
+ The important fact about this function that it is handled in special way.
+ When such function is met in expression time_zone system tables are added
+ to global list of tables to open, so later those already opened and locked
+ tables can be used during this function calculation for loading time zone
+ descriptions.
+*/
class Item_func_convert_tz :public Item_date_func
{
- THD *thd;
+ /* 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.
+ */
Time_zone *from_tz, *to_tz;
public:
Item_func_convert_tz(Item *a, Item *b, Item *c):
@@ -542,6 +555,7 @@ class Item_func_convert_tz :public Item_date_func
double val() { return (double) val_int(); }
String *val_str(String *str);
const char *func_name() const { return "convert_tz"; }
+ bool fix_fields(THD *, struct st_table_list *, Item **);
void fix_length_and_dec();
bool get_date(TIME *res, uint fuzzy_date);
};
diff --git a/sql/key.cc b/sql/key.cc
index 9425a368669..b1f4c9533a9 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -211,10 +211,17 @@ bool key_cmp_if_same(TABLE *table,const byte *key,uint idx,uint key_length)
if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
FIELDFLAG_PACK)))
{
- if (my_strnncoll(key_part->field->charset(),
- (const uchar*) key, length,
- (const uchar*) table->record[0]+key_part->offset,
- 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;
+ if (length > char_length)
+ {
+ char_length= my_charpos(cs, pos, pos + length, char_length);
+ set_if_smaller(char_length, length);
+ }
+ if (cs->coll->strnncollsp(cs,
+ (const uchar*) key, length,
+ (const uchar*) pos, char_length))
return 1;
}
else if (memcmp(key,table->record[0]+key_part->offset,length))
diff --git a/sql/lex.h b/sql/lex.h
index 957aa3159e7..4c44d53d5b1 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -553,7 +553,7 @@ static SYMBOL sql_functions[] = {
{ "CONNECTION_ID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
{ "CONTAINS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_contains)},
{ "CONV", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
- { "CONVERT_TZ", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_convert_tz)},
+ { "CONVERT_TZ", SYM(CONVERT_TZ_SYM)},
{ "COUNT", SYM(COUNT_SYM)},
{ "COS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
diff --git a/sql/lock.cc b/sql/lock.cc
index bcf61fde1a6..debfb900c23 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -99,7 +99,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
Wait until the lock is gone
*/
- if (wait_if_global_read_lock(thd, 1))
+ if (wait_if_global_read_lock(thd, 1, 1))
{
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
@@ -474,7 +474,7 @@ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
int error= -1;
DBUG_ENTER("lock_and_wait_for_table_name");
- if (wait_if_global_read_lock(thd,0))
+ if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&LOCK_open));
if ((lock_retcode = lock_table_name(thd, table_list)) < 0)
@@ -709,14 +709,23 @@ static void print_lock_error(int error)
The global locks are handled through the global variables:
global_read_lock
+ global_read_lock_blocks_commit
waiting_for_read_lock
protect_against_global_read_lock
+
+ Taking the global read lock is TWO steps (2nd step is optional; without
+ it, COMMIT of existing transactions will be allowed):
+ lock_global_read_lock() THEN make_global_read_lock_block_commit().
****************************************************************************/
volatile uint global_read_lock=0;
+volatile uint global_read_lock_blocks_commit=0;
static volatile uint protect_against_global_read_lock=0;
static volatile uint waiting_for_read_lock=0;
+#define GOT_GLOBAL_READ_LOCK 1
+#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
+
bool lock_global_read_lock(THD *thd)
{
DBUG_ENTER("lock_global_read_lock");
@@ -734,40 +743,54 @@ bool lock_global_read_lock(THD *thd)
while (protect_against_global_read_lock && !thd->killed)
pthread_cond_wait(&COND_refresh, &LOCK_open);
waiting_for_read_lock--;
- thd->exit_cond(old_message);
if (thd->killed)
{
- (void) pthread_mutex_unlock(&LOCK_open);
+ thd->exit_cond(old_message);
DBUG_RETURN(1);
}
- thd->global_read_lock=1;
+ thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
global_read_lock++;
- (void) pthread_mutex_unlock(&LOCK_open);
+ thd->exit_cond(old_message);
}
+ /*
+ We DON'T set global_read_lock_blocks_commit now, it will be set after
+ tables are flushed (as the present function serves for FLUSH TABLES WITH
+ READ LOCK only). Doing things in this order is necessary to avoid
+ deadlocks (we must allow COMMIT until all tables are closed; we should not
+ forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
+ UPDATE and one does FLUSH TABLES WITH READ LOCK).
+ */
DBUG_RETURN(0);
}
void unlock_global_read_lock(THD *thd)
{
uint tmp;
- thd->global_read_lock=0;
pthread_mutex_lock(&LOCK_open);
tmp= --global_read_lock;
+ if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
+ --global_read_lock_blocks_commit;
pthread_mutex_unlock(&LOCK_open);
/* Send the signal outside the mutex to avoid a context switch */
if (!tmp)
pthread_cond_broadcast(&COND_refresh);
+ thd->global_read_lock= 0;
}
+#define must_wait (global_read_lock && \
+ (is_not_commit || \
+ global_read_lock_blocks_commit))
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
+ bool is_not_commit)
{
const char *old_message;
- bool result=0;
+ bool result= 0, need_exit_cond;
DBUG_ENTER("wait_if_global_read_lock");
+ LINT_INIT(old_message);
(void) pthread_mutex_lock(&LOCK_open);
- if (global_read_lock)
+ if ((need_exit_cond= must_wait))
{
if (thd->global_read_lock) // This thread had the read locks
{
@@ -777,16 +800,22 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh)
}
old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
"Waiting for release of readlock");
- while (global_read_lock && ! thd->killed &&
+ while (must_wait && ! thd->killed &&
(!abort_on_refresh || thd->version == refresh_version))
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
if (thd->killed)
result=1;
- thd->exit_cond(old_message);
}
if (!abort_on_refresh && !result)
protect_against_global_read_lock++;
- pthread_mutex_unlock(&LOCK_open);
+ /*
+ The following is only true in case of a global read locks (which is rare)
+ and if old_message is set
+ */
+ if (unlikely(need_exit_cond))
+ thd->exit_cond(old_message);
+ else
+ pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(result);
}
@@ -802,3 +831,21 @@ void start_waiting_global_read_lock(THD *thd)
pthread_cond_broadcast(&COND_refresh);
DBUG_VOID_RETURN;
}
+
+
+void make_global_read_lock_block_commit(THD *thd)
+{
+ /*
+ If we didn't succeed lock_global_read_lock(), or if we already suceeded
+ make_global_read_lock_block_commit(), do nothing.
+ */
+ if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
+ return;
+ pthread_mutex_lock(&LOCK_open);
+ /* increment this BEFORE waiting on cond (otherwise race cond) */
+ global_read_lock_blocks_commit++;
+ while (protect_against_global_read_lock)
+ pthread_cond_wait(&COND_refresh, &LOCK_open);
+ pthread_mutex_unlock(&LOCK_open);
+ thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
+}
diff --git a/sql/log.cc b/sql/log.cc
index 44c8ce59aaf..16381c8e26c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000-2003 MySQL AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -31,12 +31,55 @@
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
+#ifdef __NT__
+#include "message.h"
+#endif
+
MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
ulong sync_binlog_counter= 0;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
+#ifdef __NT__
+static int eventSource = 0;
+
+void setup_windows_event_source()
+{
+ HKEY hRegKey= NULL;
+ DWORD dwError= 0;
+ TCHAR szPath[MAX_PATH];
+ DWORD dwTypes;
+
+ if (eventSource) // Ensure that we are only called once
+ return;
+ eventSource= 1;
+
+ // Create the event source registry key
+ dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL",
+ &hRegKey);
+
+ /* Name of the PE module that contains the message resource */
+ GetModuleFileName(NULL, szPath, MAX_PATH);
+
+ /* Register EventMessageFile */
+ dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
+ (PBYTE) szPath, strlen(szPath)+1);
+
+
+ /* Register supported event types */
+ dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
+ EVENTLOG_INFORMATION_TYPE);
+ dwError= RegSetValueEx(hRegKey, "TypesSupported", 0, REG_DWORD,
+ (LPBYTE) &dwTypes, sizeof dwTypes);
+
+ RegCloseKey(hRegKey);
+}
+
+#endif /* __NT__ */
+
+
/****************************************************************************
** Find a uniq filename for 'filename.#'.
** Set # to a number as low as possible
@@ -234,7 +277,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
"started with:\nTcp port: %d Unix socket: %s\n",
my_progname,server_version,mysqld_port,mysqld_unix_port
#endif
- );
+ );
end=strnmov(buff+len,"Time Id Command Argument\n",
sizeof(buff)-len);
if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) ||
@@ -1405,29 +1448,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
goto err;
}
#endif
-
-#if MYSQL_VERSION_ID < 50000
- /*
- In 5.0 this is not needed anymore as we store the value of
- FOREIGN_KEY_CHECKS in a binary way in the Query event's header.
- The code below was enabled in 4.0 and 4.1.
- */
- /*
- If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL
- command in the binlog inside:
- SET FOREIGN_KEY_CHECKS=0;
- <command>;
- SET FOREIGN_KEY_CHECKS=1;
- */
-
- if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
- {
- Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0);
- e.set_log_pos(this);
- if (e.write(file))
- goto err;
- }
-#endif
}
/* Write the SQL command */
@@ -1436,18 +1456,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
if (event_info->write(file))
goto err;
- /* Write log events to reset the 'run environment' of the SQL command */
-
-#if MYSQL_VERSION_ID < 50000
- if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
- {
- Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0);
- e.set_log_pos(this);
- if (e.write(file))
- goto err;
- }
-#endif
-
/*
Tell for transactional table handlers up to which position in the
binlog file we wrote. The table handler can store this info, and
@@ -1842,17 +1850,12 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
NOTES
One must have a lock on LOCK_log before calling this function.
- This lock will be freed before return!
-
- The reason for the above is that for enter_cond() / exit_cond() to
- work the mutex must be got before enter_cond() but releases before
- exit_cond().
- If you don't do it this way, you will get a deadlock in THD::awake()
+ This lock will be freed before return! That's required by
+ THD::enter_cond() (see NOTES in sql_class.h).
*/
void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave)
{
- safe_mutex_assert_owner(&LOCK_log);
const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
master_or_slave ?
"Has read all relay log; waiting for \
@@ -1860,7 +1863,6 @@ the slave I/O thread to update it" :
"Has sent all binlog to slave; \
waiting for binlog to be updated");
pthread_cond_wait(&update_cond, &LOCK_log);
- pthread_mutex_unlock(&LOCK_log); // See NOTES
thd->exit_cond(old_msg);
}
@@ -1944,6 +1946,19 @@ void MYSQL_LOG::set_max_size(ulong max_size_arg)
}
+Disable_binlog::Disable_binlog(THD *thd_arg) :
+ thd(thd_arg), save_options(thd_arg->options)
+{
+ thd_arg->options&= ~OPTION_BIN_LOG;
+}
+
+
+Disable_binlog::~Disable_binlog()
+{
+ thd->options= save_options;
+}
+
+
/*
Check if a string is a valid number
@@ -1994,39 +2009,31 @@ static bool test_if_number(register const char *str,
} /* test_if_number */
-void sql_print_error(const char *format,...)
+void print_buffer_to_file(enum loglevel level, const char *buffer)
{
- va_list args;
time_t skr;
struct tm tm_tmp;
struct tm *start;
- va_start(args,format);
- DBUG_ENTER("sql_print_error");
+ DBUG_ENTER("print_buffer_to_file");
+ DBUG_PRINT("enter",("buffer: %s", buffer));
VOID(pthread_mutex_lock(&LOCK_error_log));
-#ifndef DBUG_OFF
- {
- char buff[1024];
- my_vsnprintf(buff,sizeof(buff)-1,format,args);
- DBUG_PRINT("error",("%s",buff));
- va_end(args);
- va_start(args,format);
- }
-#endif
+
skr=time(NULL);
- localtime_r(&skr,&tm_tmp);
+ localtime_r(&skr, &tm_tmp);
start=&tm_tmp;
- fprintf(stderr,"%02d%02d%02d %2d:%02d:%02d ",
- start->tm_year % 100,
- start->tm_mon+1,
+ 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);
- (void) vfprintf(stderr,format,args);
- (void) fputc('\n',stderr);
+ start->tm_sec,
+ (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
+ "WARNING" : "INFORMATION"),
+ buffer);
+
fflush(stderr);
- va_end(args);
VOID(pthread_mutex_unlock(&LOCK_error_log));
DBUG_VOID_RETURN;
@@ -2042,6 +2049,7 @@ void sql_perror(const char *message)
#endif
}
+
bool flush_error_log()
{
bool result=0;
@@ -2225,3 +2233,126 @@ void MYSQL_LOG::report_pos_in_innodb()
#endif
DBUG_VOID_RETURN;
}
+
+#ifdef __NT__
+void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
+ uint length, int buffLen)
+{
+ HANDLE event;
+ char *buffptr;
+ LPCSTR *buffmsgptr;
+ DBUG_ENTER("print_buffer_to_nt_eventlog");
+
+ buffptr= buff;
+ if (length > (uint)(buffLen-4))
+ {
+ char *newBuff= new char[length + 4];
+ strcpy(newBuff, buff);
+ buffptr= newBuff;
+ }
+ strmov(buffptr+length, "\r\n\r\n");
+ buffmsgptr= (LPCSTR*) &buffptr; // Keep windows happy
+
+ setup_windows_event_source();
+ if ((event= RegisterEventSource(NULL,"MySQL")))
+ {
+ switch (level) {
+ case ERROR_LEVEL:
+ ReportEvent(event, EVENTLOG_ERROR_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
+ buffmsgptr, NULL);
+ break;
+ case WARNING_LEVEL:
+ ReportEvent(event, EVENTLOG_WARNING_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
+ buffmsgptr, NULL);
+ break;
+ case INFORMATION_LEVEL:
+ ReportEvent(event, EVENTLOG_INFORMATION_TYPE, 0, MSG_DEFAULT, NULL, 1,
+ 0, buffmsgptr, NULL);
+ break;
+ }
+ DeregisterEventSource(event);
+ }
+
+ /* if we created a string buffer, then delete it */
+ if (buffptr != buff)
+ delete[] buffptr;
+
+ DBUG_VOID_RETURN;
+}
+#endif /* __NT__ */
+
+
+/*
+ Prints a printf style message to the error log and, under NT, to the
+ Windows event log.
+
+ SYNOPSIS
+ vprint_msg_to_log()
+ event_type Type of event to write (Error, Warning, or Info)
+ format Printf style format of message
+ args va_list list of arguments for the message
+
+ NOTE
+
+ IMPLEMENTATION
+ This function prints the message into a buffer and then sends that buffer
+ to other functions to write that message to other logging sources.
+
+ RETURN VALUES
+ void
+*/
+
+void vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
+{
+ char buff[1024];
+ uint length;
+ DBUG_ENTER("vprint_msg_to_log");
+
+ length= my_vsnprintf(buff, sizeof(buff)-5, format, args);
+ print_buffer_to_file(level, buff);
+
+#ifdef __NT__
+ print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff));
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+
+void sql_print_error(const char *format, ...)
+{
+ va_list args;
+ DBUG_ENTER("sql_print_error");
+
+ va_start(args, format);
+ vprint_msg_to_log(ERROR_LEVEL, format, args);
+ va_end(args);
+
+ DBUG_VOID_RETURN;
+}
+
+
+void sql_print_warning(const char *format, ...)
+{
+ va_list args;
+ DBUG_ENTER("sql_print_warning");
+
+ va_start(args, format);
+ vprint_msg_to_log(WARNING_LEVEL, format, args);
+ va_end(args);
+
+ DBUG_VOID_RETURN;
+}
+
+
+void sql_print_information(const char *format, ...)
+{
+ va_list args;
+ DBUG_ENTER("sql_print_information");
+
+ va_start(args, format);
+ vprint_msg_to_log(INFORMATION_LEVEL, format, args);
+ va_end(args);
+
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 2f3471fee17..97e041774f8 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1540,10 +1540,6 @@ end:
thd->query= 0; // just to be sure
thd->query_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- // assume no convert for next query unless set explictly
-#ifdef TO_BE_REMOVED
- thd->variables.convert_set = 0;
-#endif
close_thread_tables(thd);
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
return (thd->query_error ? thd->query_error : Log_event::exec_event(rli));
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a100aa0cd3a..c668e152df5 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -333,9 +333,17 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
*/
#define MAX_DATE_REP_LENGTH 30
+enum enum_parsing_place
+{
+ NO_MATTER,
+ IN_HAVING,
+ SELECT_LIST,
+ IN_WHERE
+};
+
struct st_table;
class THD;
-class Statement;
+class Item_arena;
/* Struct to handle simple linked lists */
@@ -414,6 +422,7 @@ int delete_precheck(THD *thd, TABLE_LIST *tables);
int insert_precheck(THD *thd, TABLE_LIST *tables, bool update);
int create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table);
+Item *negate_expression(THD *thd, Item *expr);
#include "sql_class.h"
#include "opt_range.h"
@@ -563,7 +572,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys,
- bool tmp_table, bool no_log, uint select_field_count);
+ bool tmp_table, uint select_field_count);
+
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE_LIST *create_table,
List<create_field> *extra_fields,
@@ -611,7 +621,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order,
ha_rows rows, ulong options);
-int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0);
+int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
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);
@@ -841,8 +851,14 @@ int key_cmp(KEY_PART_INFO *key_part, const byte *key, uint key_length);
bool init_errmessage(void);
void sql_perror(const char *message);
-void sql_print_error(const char *format,...)
- __attribute__ ((format (printf, 1, 2)));
+
+void vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
+void sql_print_error(const char *format, ...);
+void sql_print_warning(const char *format, ...);
+void sql_print_information(const char *format, ...);
+
+
+
bool fn_format_relative_to_data_home(my_string to, const char *name,
const char *dir, const char *extension);
bool open_log(MYSQL_LOG *log, const char *hostname,
@@ -894,7 +910,6 @@ extern Gt_creator gt_creator;
extern Lt_creator lt_creator;
extern Ge_creator ge_creator;
extern Le_creator le_creator;
-extern uchar *days_in_month;
extern char language[LIBLEN],reg_ext[FN_EXTLEN];
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
@@ -998,7 +1013,7 @@ extern struct my_option my_long_options[];
/* optional things, have_* variables */
extern SHOW_COMP_OPTION have_isam, have_innodb, have_berkeley_db;
-extern SHOW_COMP_OPTION have_example_db, have_archive_db;
+extern SHOW_COMP_OPTION have_example_db, have_archive_db, have_csv_db;
extern SHOW_COMP_OPTION have_raid, have_openssl, have_symlink;
extern SHOW_COMP_OPTION have_query_cache, have_berkeley_db, have_innodb;
extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
@@ -1023,8 +1038,9 @@ void mysql_lock_abort_for_thread(THD *thd, TABLE *table);
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
bool lock_global_read_lock(THD *thd);
void unlock_global_read_lock(THD *thd);
-bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh);
+bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit);
void start_waiting_global_read_lock(THD *thd);
+void make_global_read_lock_block_commit(THD *thd);
/* Lock based on name */
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
@@ -1062,12 +1078,9 @@ 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);
-long calc_daynr(uint year,uint month,uint day);
uint calc_days_in_year(uint year);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
-void init_time(void);
-my_time_t my_system_gmt_sec(const TIME *, long *current_timezone, bool *not_exist);
my_time_t TIME_to_timestamp(THD *thd, const TIME *t, bool *not_exist);
bool str_to_time_with_warn(const char *str,uint length,TIME *l_time);
timestamp_type str_to_datetime_with_warn(const char *str, uint length,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ac275f0d765..81651862255 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -92,7 +92,7 @@ extern "C" { // Because of SCO 3.2V4.2
#if defined(OS2)
# include <sys/un.h>
-#elif !defined( __WIN__)
+#elif !defined(__WIN__)
# ifndef __NETWARE__
#include <sys/resource.h>
# endif /* __NETWARE__ */
@@ -240,10 +240,10 @@ bool opt_help= 0;
bool opt_verbose= 0;
arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
-{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
- {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
- {&Arg_comparator::compare_int, &Arg_comparator::compare_e_int},
- {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
+{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
+ {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
+ {&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int},
+ {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
/* Global variables */
@@ -370,7 +370,7 @@ CHARSET_INFO *system_charset_info, *files_charset_info ;
CHARSET_INFO *national_charset_info, *table_alias_charset;
SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam, have_ndbcluster,
- have_example_db, have_archive_db;
+ have_example_db, have_archive_db, have_csv_db;
SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
SHOW_COMP_OPTION have_geometry, have_rtree_keys;
SHOW_COMP_OPTION have_crypt, have_compress;
@@ -569,7 +569,7 @@ static void close_connections(void)
/* Abort listening to new connections */
DBUG_PRINT("quit",("Closing sockets"));
- if ( !opt_disable_networking )
+ if (!opt_disable_networking )
{
if (ip_sock != INVALID_SOCKET)
{
@@ -582,7 +582,7 @@ static void close_connections(void)
if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
HANDLE temp;
- DBUG_PRINT( "quit", ("Closing named pipes") );
+ DBUG_PRINT("quit", ("Closing named pipes") );
/* Create connection to the handle named pipe handler to break the loop */
if ((temp = CreateFile(pipe_name,
@@ -748,7 +748,7 @@ void kill_mysql(void)
}
#endif
#elif defined(OS2)
- pthread_cond_signal( &eventShutdown); // post semaphore
+ pthread_cond_signal(&eventShutdown); // post semaphore
#elif defined(HAVE_PTHREAD_KILL)
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
{
@@ -766,7 +766,7 @@ void kill_mysql(void)
abort_loop=1;
if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
(void*) 0))
- sql_print_error("Error: Can't create thread to kill server");
+ sql_print_error("Can't create thread to kill server");
}
#endif
DBUG_VOID_RETURN;
@@ -795,7 +795,7 @@ static void __cdecl kill_server(int sig_ptr)
abort_loop=1; // This should be set
signal(sig,SIG_IGN);
if (sig == MYSQL_KILL_SIGNAL || sig == 0)
- sql_print_error(ER(ER_NORMAL_SHUTDOWN),my_progname);
+ sql_print_information(ER(ER_NORMAL_SHUTDOWN),my_progname);
else
sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
@@ -811,7 +811,7 @@ static void __cdecl kill_server(int sig_ptr)
#ifdef __NETWARE__
pthread_join(select_thread, NULL); // wait for main thread
#endif /* __NETWARE__ */
-
+
pthread_exit(0); /* purecov: deadcode */
#endif /* EMBEDDED_LIBRARY */
@@ -839,7 +839,7 @@ extern "C" sig_handler print_signal_warning(int sig)
if (!DBUG_IN_USE)
{
if (global_system_variables.log_warnings)
- sql_print_error("Warning: Got signal %d from thread %d",
+ sql_print_warning("Got signal %d from thread %d",
sig,my_thread_id());
}
#ifdef DONT_REMEMBER_SIGNAL
@@ -965,7 +965,7 @@ void clean_up(bool print_message)
#endif
if (print_message && errmesg)
- sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
+ sql_print_information(ER(ER_SHUTDOWN_COMPLETE),my_progname);
#if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(0)); // This may not always exist
@@ -1066,8 +1066,8 @@ static void set_user(const char *user)
struct passwd *user_info= getpwnam(user);
if ((!user_info || user_id != user_info->pw_uid) &&
global_system_variables.log_warnings)
- fprintf(stderr,
- "Warning: One can only use the --user switch if running as root\n");
+ sql_print_warning(
+ "One can only use the --user switch if running as root\n");
}
return;
}
@@ -1141,7 +1141,7 @@ static void server_init(void)
DBUG_ENTER("server_init");
#ifdef __WIN__
- if ( !opt_disable_networking )
+ if (!opt_disable_networking)
{
WSADATA WsaData;
if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
@@ -1187,7 +1187,7 @@ static void server_init(void)
if (listen(ip_sock,(int) back_log) < 0)
{
sql_perror("Can't start server: listen() on TCP/IP port");
- sql_print_error("Error: listen() on TCP/IP failed with error %d",
+ sql_print_error("listen() on TCP/IP failed with error %d",
socket_errno);
unireg_abort(1);
}
@@ -1216,7 +1216,7 @@ static void server_init(void)
sql_perror("Can't start server : Set security descriptor");
unireg_abort(1);
}
- saPipeSecurity.nLength = sizeof( SECURITY_ATTRIBUTES );
+ saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor;
saPipeSecurity.bInheritHandle = FALSE;
if ((hPipe= CreateNamedPipe(pipe_name,
@@ -1236,9 +1236,9 @@ static void server_init(void)
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL );
- MessageBox( NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
- MB_OK|MB_ICONINFORMATION );
- LocalFree( lpMsgBuf );
+ MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
+ MB_OK|MB_ICONINFORMATION);
+ LocalFree(lpMsgBuf);
unireg_abort(1);
}
}
@@ -1282,7 +1282,7 @@ static void server_init(void)
(void) chmod(mysqld_unix_port,S_IFSOCK); /* Fix solaris 2.6 bug */
#endif
if (listen(unix_sock,(int) back_log) < 0)
- sql_print_error("Warning: listen() on Unix socket failed with error %d",
+ sql_print_warning("listen() on Unix socket failed with error %d",
socket_errno);
}
#endif
@@ -1459,7 +1459,7 @@ static void init_signals(void)
{
int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
- signal( signals[i], kill_server) ;
+ signal(signals[i], kill_server) ;
#if defined(__WIN__)
signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
#else
@@ -1594,6 +1594,8 @@ static void registerwithneb()
ulong neb_event_callback(struct EventBlock *eblock)
{
EventChangeVolStateEnter_s *voldata;
+ extern bool nw_panic;
+
voldata= (EventChangeVolStateEnter_s *)eblock->EBEventData;
/* Deactivation of a volume */
@@ -1606,6 +1608,7 @@ ulong neb_event_callback(struct EventBlock *eblock)
if (!memcmp(&voldata->volID, &datavolid, sizeof(VolumeID_t)))
{
consoleprintf("MySQL data volume is deactivated, shutting down MySQL Server \n");
+ nw_panic = TRUE;
kill_server(0);
}
}
@@ -1792,7 +1795,7 @@ bytes of memory\n", ((ulong) sql_key_cache->key_cache_mem_size +
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
-the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
+the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n",
thread_count);
}
#endif /* HAVE_LINUXTHREADS */
@@ -1871,7 +1874,7 @@ static void init_signals(void)
struct rlimit rl;
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings)
- sql_print_error("Warning: setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals");
+ sql_print_warning("setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals");
}
#endif
(void) sigemptyset(&set);
@@ -1883,9 +1886,11 @@ static void init_signals(void)
sigaddset(&set,SIGPIPE);
#endif
sigaddset(&set,SIGINT);
+#ifndef IGNORE_SIGHUP_SIGQUIT
sigaddset(&set,SIGQUIT);
- sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
+#endif
+ sigaddset(&set,SIGTERM);
/* Fix signals if blocked by parents (can happen on Mac OS X) */
sigemptyset(&sa.sa_mask);
@@ -1969,11 +1974,13 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
#ifdef USE_ONE_SIGNAL_HAND
(void) sigaddset(&set,THR_SERVER_ALARM); // For alarms
#endif
+#ifndef IGNORE_SIGHUP_SIGQUIT
(void) sigaddset(&set,SIGQUIT);
- (void) sigaddset(&set,SIGTERM);
#if THR_CLIENT_ALARM != SIGHUP
(void) sigaddset(&set,SIGHUP);
#endif
+#endif
+ (void) sigaddset(&set,SIGTERM);
(void) sigaddset(&set,SIGTSTP);
/* Save pid to this process (or thread on Linux) */
@@ -2021,7 +2028,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
case SIGQUIT:
case SIGKILL:
#ifdef EXTRA_DEBUG
- sql_print_error("Got signal %d to shutdown mysqld",sig);
+ sql_print_information("Got signal %d to shutdown mysqld",sig);
#endif
DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop));
if (!abort_loop)
@@ -2033,7 +2040,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR);
if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
(void*) sig))
- sql_print_error("Error: Can't create thread to kill server");
+ sql_print_error("Can't create thread to kill server");
#else
kill_server((void*) sig); // MIT THREAD has a alarm thread
#endif
@@ -2057,7 +2064,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
#endif
default:
#ifdef EXTRA_DEBUG
- sql_print_error("Warning: Got signal: %d error: %d",sig,error); /* purecov: tested */
+ sql_print_warning("Got signal: %d error: %d",sig,error); /* purecov: tested */
#endif
break; /* purecov: tested */
}
@@ -2165,10 +2172,10 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
my_thread_init();
// wait semaphore
- pthread_cond_wait( &eventShutdown, NULL);
+ pthread_cond_wait(&eventShutdown, NULL);
// close semaphore and kill server
- pthread_cond_destroy( &eventShutdown);
+ pthread_cond_destroy(&eventShutdown);
/*
Exit main loop on main thread, so kill will be done from
@@ -2339,11 +2346,11 @@ static int init_common_variables(const char *conf_file_name, int argc,
("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
files, max_connections, table_cache_size));
if (global_system_variables.log_warnings)
- sql_print_error("Warning: Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
+ sql_print_warning("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
files, max_connections, table_cache_size);
}
else if (global_system_variables.log_warnings)
- sql_print_error("Warning: Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files);
+ sql_print_warning("Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files);
}
open_files_limit= files;
}
@@ -2521,8 +2528,8 @@ static int init_server_components()
does nothing, and we don't take into account if he used this option or
not; but internally we give this variable a value to have the behaviour we
want (i.e. have SQL_LOG_UPDATE influence SQL_LOG_BIN or not).
- As sql-bin-update-same, log-update and log-bin cannot be changed by the user
- after starting the server (they are not variables), the user will not
+ As sql-bin-update-same, log-update and log-bin cannot be changed by the
+ user after starting the server (they are not variables), the user will not
later interfere with the settings we do here.
*/
if (opt_bin_log)
@@ -2570,8 +2577,8 @@ with --log-bin instead.");
}
else if (opt_log_slave_updates)
{
- sql_print_error("\
-Warning: you need to use --log-bin to make --log-slave-updates work. \
+ sql_print_warning("\
+you need to use --log-bin to make --log-slave-updates work. \
Now disabling --log-slave-updates.");
}
@@ -2579,7 +2586,7 @@ Now disabling --log-slave-updates.");
if (opt_log_slave_updates && replicate_same_server_id)
{
sql_print_error("\
-Error: using --replicate-same-server-id in conjunction with \
+using --replicate-same-server-id in conjunction with \
--log-slave-updates is impossible, it would lead to infinite loops in this \
server.");
unireg_abort(1);
@@ -2589,7 +2596,8 @@ server.");
if (opt_error_log)
{
if (!log_error_file_ptr[0])
- fn_format(log_error_file, glob_hostname, mysql_data_home, ".err", 0);
+ fn_format(log_error_file, glob_hostname, 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",
MY_UNPACK_FILENAME | MY_SAFE_PATH);
@@ -2607,12 +2615,12 @@ server.");
if (opt_innodb_safe_binlog)
{
if (have_innodb != SHOW_OPTION_YES)
- sql_print_error("Warning: --innodb-safe-binlog is meaningful only if "
+ sql_print_warning("--innodb-safe-binlog is meaningful only if "
"the InnoDB storage engine is enabled in the server.");
#ifdef HAVE_INNOBASE_DB
if (innobase_flush_log_at_trx_commit != 1)
{
- sql_print_error("Warning: --innodb-safe-binlog is meaningful only if "
+ sql_print_warning("--innodb-safe-binlog is meaningful only if "
"innodb_flush_log_at_trx_commit is 1; now setting it "
"to 1.");
innobase_flush_log_at_trx_commit= 1;
@@ -2624,14 +2632,14 @@ server.");
good (especially "littlesync", and on Windows... see
srv/srv0start.c).
*/
- sql_print_error("Warning: --innodb-safe-binlog requires that "
+ sql_print_warning("--innodb-safe-binlog requires that "
"the innodb_flush_method actually synchronizes the "
"InnoDB log to disk; it is your responsibility "
"to verify that the method you chose does it.");
}
if (sync_binlog_period != 1)
{
- sql_print_error("Warning: --innodb-safe-binlog is meaningful only if "
+ sql_print_warning("--innodb-safe-binlog is meaningful only if "
"the global sync_binlog variable is 1; now setting it "
"to 1.");
sync_binlog_period= 1;
@@ -2670,7 +2678,7 @@ server.");
if (mlockall(MCL_CURRENT))
{
if (global_system_variables.log_warnings)
- sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno);
+ sql_print_warning("Failed to lock memory. Errno: %d\n",errno);
locked_in_memory= 0;
}
}
@@ -2696,7 +2704,7 @@ static void create_maintenance_thread()
{
pthread_t hThread;
if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
- sql_print_error("Warning: Can't create thread to manage maintenance");
+ sql_print_warning("Can't create thread to manage maintenance");
}
}
@@ -2708,7 +2716,7 @@ static void create_shutdown_thread()
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
pthread_t hThread;
if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
- sql_print_error("Warning: Can't create thread to handle shutdown requests");
+ sql_print_warning("Can't create thread to handle shutdown requests");
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
@@ -2717,7 +2725,7 @@ static void create_shutdown_thread()
pthread_cond_init(&eventShutdown, NULL);
pthread_t hThread;
if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
- sql_print_error("Warning: Can't create thread to handle shutdown requests");
+ sql_print_warning("Can't create thread to handle shutdown requests");
#endif
#endif // EMBEDDED_LIBRARY
}
@@ -2733,7 +2741,7 @@ static void handle_connections_methods()
(!have_tcpip || opt_disable_networking) &&
!opt_enable_shared_memory)
{
- sql_print_error("TCP/IP,--shared-memory or --named-pipe should be configured on NT OS");
+ sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS");
unireg_abort(1); // Will not return
}
#endif
@@ -2748,7 +2756,7 @@ static void handle_connections_methods()
if (pthread_create(&hThread,&connection_attrib,
handle_connections_namedpipes, 0))
{
- sql_print_error("Warning: Can't create thread to handle named pipes");
+ sql_print_warning("Can't create thread to handle named pipes");
handler_count--;
}
}
@@ -2759,7 +2767,7 @@ static void handle_connections_methods()
if (pthread_create(&hThread,&connection_attrib,
handle_connections_sockets, 0))
{
- sql_print_error("Warning: Can't create thread to handle TCP/IP");
+ sql_print_warning("Can't create thread to handle TCP/IP");
handler_count--;
}
}
@@ -2770,7 +2778,7 @@ static void handle_connections_methods()
if (pthread_create(&hThread,&connection_attrib,
handle_connections_shared_memory, 0))
{
- sql_print_error("Warning: Can't create thread to handle shared memory");
+ sql_print_warning("Can't create thread to handle shared memory");
handler_count--;
}
}
@@ -2809,7 +2817,7 @@ int main(int argc, char **argv)
if (_cust_check_startup())
{
/ * _cust_check_startup will report startup failure error * /
- exit( 1 );
+ exit(1);
}
#endif
@@ -2830,7 +2838,7 @@ int main(int argc, char **argv)
if (stack_size && stack_size < thread_stack)
{
if (global_system_variables.log_warnings)
- sql_print_error("Warning: Asked for %ld thread stack, but got %ld",
+ sql_print_warning("Asked for %ld thread stack, but got %ld",
thread_stack, stack_size);
thread_stack= stack_size;
}
@@ -2853,8 +2861,8 @@ int main(int argc, char **argv)
if (lower_case_table_names_used)
{
if (global_system_variables.log_warnings)
- sql_print_error("\
-Warning: You have forced lower_case_table_names to 0 through a command-line \
+ sql_print_warning("\
+You have forced lower_case_table_names to 0 through a command-line \
option, even though your file system '%s' is case insensitive. This means \
that you can corrupt a MyISAM table by accessing it with different cases. \
You should consider changing lower_case_table_names to 1 or 2",
@@ -2863,7 +2871,7 @@ You should consider changing lower_case_table_names to 1 or 2",
else
{
if (global_system_variables.log_warnings)
- sql_print_error("Warning: Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home);
+ sql_print_warning("Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home);
lower_case_table_names= 2;
}
}
@@ -2896,14 +2904,14 @@ You should consider changing lower_case_table_names to 1 or 2",
#ifdef EXTRA_DEBUG
switch (server_id) {
case 1:
- sql_print_error("\
-Warning: You have enabled the binary log, but you haven't set server-id to \
+ sql_print_warning("\
+You have enabled the binary log, but you haven't set server-id to \
a non-zero value: we force server id to 1; updates will be logged to the \
binary log, but connections from slaves will not be accepted.");
break;
case 2:
- sql_print_error("\
-Warning: You should set server-id to a non-0 value if master_host is set; \
+ sql_print_warning("\
+You should set server-id to a non-0 value if master_host is set; \
we force server id to 2, but this MySQL server will not act as a slave.");
break;
}
@@ -2978,11 +2986,21 @@ we force server id to 2, but this MySQL server will not act as a slave.");
printf(ER(ER_READY),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) "" : mysqld_unix_port),
mysqld_port);
+ if (MYSQL_COMPILATION_COMMENT[0] != '\0')
+ fputs(" " MYSQL_COMPILATION_COMMENT, stdout);
+ putchar('\n');
fflush(stdout);
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
#else
+#ifdef __WIN__
+ if (!have_tcpip || opt_disable_networking)
+ {
+ sql_print_error("TCP/IP unavailable or disabled with --skip-networking; no available interfaces");
+ unireg_abort(1);
+ }
+#endif
handle_connections_sockets(0);
#endif /* __NT__ */
@@ -3265,7 +3283,7 @@ static int bootstrap(FILE *file)
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
- sql_print_error("Warning: Can't create thread to handle bootstrap");
+ sql_print_warning("Can't create thread to handle bootstrap");
DBUG_RETURN(-1);
}
/* Wait for thread to die */
@@ -3637,25 +3655,27 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
while (!abort_loop)
{
/* wait for named pipe connection */
- fConnected = ConnectNamedPipe( hPipe, NULL );
+ fConnected = ConnectNamedPipe(hPipe, NULL);
if (abort_loop)
break;
if (!fConnected)
fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
if (!fConnected)
{
- CloseHandle( hPipe );
- if ((hPipe = CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity )) ==
- INVALID_HANDLE_VALUE )
+ CloseHandle(hPipe);
+ if ((hPipe= CreateNamedPipe(pipe_name,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int) global_system_variables.
+ net_buffer_length,
+ (int) global_system_variables.
+ net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &saPipeSecurity)) ==
+ INVALID_HANDLE_VALUE)
{
sql_perror("Can't create new named pipe!");
break; // Abort
@@ -3682,8 +3702,8 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
if (!(thd = new THD))
{
- DisconnectNamedPipe( hConnectedPipe );
- CloseHandle( hConnectedPipe );
+ DisconnectNamedPipe(hConnectedPipe);
+ CloseHandle(hConnectedPipe);
continue;
}
if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) ||
@@ -3959,8 +3979,9 @@ enum options_mysqld
OPT_INNODB_FLUSH_METHOD,
OPT_INNODB_FAST_SHUTDOWN,
OPT_INNODB_FILE_PER_TABLE, OPT_CRASH_BINLOG_INNODB,
+ OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG,
- OPT_INNODB, OPT_ISAM, OPT_NDBCLUSTER, OPT_SKIP_SAFEMALLOC,
+ OPT_INNODB, OPT_ISAM, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
@@ -4019,6 +4040,7 @@ enum options_mysqld
OPT_INNODB_LOCK_WAIT_TIMEOUT,
OPT_INNODB_THREAD_CONCURRENCY,
OPT_INNODB_FORCE_RECOVERY,
+ OPT_INNODB_STATUS_FILE,
OPT_INNODB_MAX_DIRTY_PAGES_PCT,
OPT_INNODB_OPEN_FILES,
OPT_BDB_CACHE_SIZE,
@@ -4054,12 +4076,25 @@ 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,
+ 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,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif /* HAVE_REPLICATION */
{"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 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,
0, 0, 0, 0, 0, 0},
+ {"bdb", OPT_BDB, "Enable Berkeley DB (if this version of MySQL supports it). \
+Disable with --skip-bdb (will save memory).",
+ (gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, 1, 0, 0,
+ 0, 0, 0},
#ifdef HAVE_BERKELEY_DB
{"bdb-home", OPT_BDB_HOME, "Berkeley home directory.", (gptr*) &berkeley_home,
(gptr*) &berkeley_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4076,10 +4111,6 @@ struct my_option my_long_options[] =
"Disable synchronously flushing logs. This option is deprecated, use --skip-sync-bdb-logs or sync-bdb-logs=0 instead",
// (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"sync-bdb-logs", OPT_BDB_SYNC,
- "Synchronously flush logs. Enabled by default",
- (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
- NO_ARG, 1, 0, 0, 0, 0, 0},
{"bdb-shared-data", OPT_BDB_SHARED,
"Start Berkeley DB in multi-process mode.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
@@ -4087,77 +4118,58 @@ struct my_option my_long_options[] =
(gptr*) &berkeley_tmpdir, (gptr*) &berkeley_tmpdir, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif /* HAVE_BERKELEY_DB */
- {"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,
- 0, 0, 0, 0},
- {"bdb", OPT_BDB, "Enable Berkeley DB (if this version of MySQL supports it). \
-Disable with --skip-bdb (will save memory).",
- (gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, 1, 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,
+ 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},
{"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
"Tells the master that updates to the given database should not be logged tothe binary log.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.",
- (gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"character_set_server", 'C', "Set the default character set.",
+ {"character-set-server", 'C', "Set the default character set.",
(gptr*) &default_character_set_name, (gptr*) &default_character_set_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"collation_server", OPT_DEFAULT_COLLATION, "Set the default collation.",
+ {"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},
+ {"chroot", 'r', "Chroot mysqld daemon during startup.",
+ (gptr*) &mysqld_chroot, (gptr*) &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,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ {"concurrent-insert", OPT_CONCURRENT_INSERT,
+ "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
+ (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 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,
0, 0, 0},
-#ifdef __WIN__
- {"standalone", OPT_STANDALONE,
- "Dummy option to start as a standalone program (NT).", 0, 0, 0, GET_NO_ARG,
- NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
{"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG,
NO_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,
- 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},
{"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},
#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},
-#ifdef SAFEMALLOC
- {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
- "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
- 0, 0, 0, 0, 0, 0},
#endif
-#endif
-#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,
- 0, 0, 0, 0, 0, 0},
-#endif /* HAVE_OPENSSL */
- {"default-character-set", 'C', "Set the default character set (Deprecated option, use character_set_server instead).",
+ {"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,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation (Deprecated option, use character_set_server instead).",
+ {"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation (deprecated option, use --collation-server instead).",
(gptr*) &default_collation_name, (gptr*) &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 tyoe) for tables.", 0, 0,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"default-table-type", OPT_STORAGE_ENGINE,
- "(deprecated) Use default-storage-engine.", 0, 0,
+ "(deprecated) Use --default-storage-engine.", 0, 0,
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,
@@ -4167,6 +4179,19 @@ Disable with --skip-bdb (will save memory).",
{"delay-key-write-for-all-tables", OPT_DELAY_KEY_WRITE_ALL,
"Don't flush key buffers between writes for any MyISAM table (Deprecated option, use --delay-key-write=all instead).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#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,
+ 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,
+ 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,
@@ -4179,46 +4204,49 @@ Disable with --skip-bdb (will save memory).",
{"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.",
(gptr*) &opt_do_pstack, (gptr*) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
-#ifdef HAVE_SMEM
- {"shared-memory", OPT_ENABLE_SHARED_MEMORY,
- "Enable the shared memory.",(gptr*) &opt_enable_shared_memory, (gptr*) &opt_enable_shared_memory,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
+ (gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0,
GET_NO_ARG, NO_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,
- REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0},
/* We must always support the next option to make scripts like mysqltest
easier to do */
{"gdb", OPT_DEBUGGING,
"Set up signals usable for debugging",
(gptr*) &opt_debugging, (gptr*) &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"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,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"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,
+ 0, 0, 0, 0, 0, 0},
{"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,
+ 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, 1, 0, 0,
+ 0, 0, 0},
{"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 HAVE_INNOBASE_DB
{"innodb_data_home_dir", OPT_INNODB_DATA_HOME_DIR,
- "The common part for Innodb table spaces.", (gptr*) &innobase_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_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_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_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN,
+ "Speeds up server shutdown process.", (gptr*) &innobase_fast_shutdown,
+ (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 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*) &innobase_flush_log_at_trx_commit,
@@ -4228,34 +4256,32 @@ Disable with --skip-bdb (will save memory).",
"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_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN,
- "Speeds up server shutdown process.", (gptr*) &innobase_fast_shutdown,
- (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"innodb_locks_unsafe_for_binlog", OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
+ "Force InnoDB not to use next-key locking. Instead 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_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_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},
#endif /* End HAVE_INNOBASE_DB */
- {"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,
- 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,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"help", '?', "Display this help and exit.",
- (gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_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,
- 0, 0},
- {"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,
- 0, 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},
+ {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \
+Disable with --skip-isam.",
+ (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 1, 0, 0,
+ 0, 0, 0},
{"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,
@@ -4265,6 +4291,8 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &opt_local_infile,
(gptr*) &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-bin", OPT_BIN_LOG,
"Log update queries in binary format.",
(gptr*) &opt_bin_logname, (gptr*) &opt_bin_logname, 0, GET_STR_ALLOC,
@@ -4273,46 +4301,54 @@ Disable with --skip-bdb (will save memory).",
"File that holds the names for last binary log files.",
(gptr*) &opt_binlog_index_name, (gptr*) &opt_binlog_index_name, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"log-error", OPT_ERROR_LOG_FILE, "Log error file.",
+ (gptr*) &log_error_file_ptr, (gptr*) &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,
OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"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,
- OPT_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.",
- (gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 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.",
0, 0, 0, GET_NO_ARG, 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,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-queries-not-using-indexes", OPT_LOG_QUERIES_NOT_USING_INDEXES,
"Log queries that are executed without benefit of any index.",
(gptr*) &opt_log_queries_not_using_indexes, (gptr*) &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,
+ 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,
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.",
+ (gptr*) &opt_slow_logname, (gptr*) &opt_slow_logname, 0, GET_STR, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"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,
+ OPT_ARG, 0, 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,
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,
+ 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,
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,
- 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,
+ 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,
@@ -4321,32 +4357,14 @@ log and this option justs turns on --log-bin instead.",
"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,
MYSQL_PORT, 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,
- REQUIRED_ARG, 60, 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,
REQUIRED_ARG, 3600*24, 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,
- REQUIRED_ARG, 0, 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,
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,
- 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,
- 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,
@@ -4355,39 +4373,44 @@ master-ssl",
"Master SSL CA path. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
+ {"master-ssl-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,
+ 0, 0, 0, 0, 0, 0},
{"master-ssl-cipher", OPT_MASTER_SSL_CIPHER,
"Master SSL cipher. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
- {"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
- (gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
- GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
- {"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (gptr*) &locked_in_memory,
- (gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"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,
+ 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,
+ 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
- {"disconnect-slave-event-count", OPT_DISCONNECT_SLAVE_EVENT_COUNT,
- "Option used by mysql-test for debugging and testing of replication.",
- (gptr*) &disconnect_slave_event_count,
- (gptr*) &disconnect_slave_event_count, 0, GET_INT, REQUIRED_ARG, 0, 0, 0,
- 0, 0, 0},
- {"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,
- 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"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,
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"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,
- 0},
#endif /* HAVE_REPLICATION */
- {"safemalloc-mem-limit", OPT_SAFEMALLOC_MEM_LIMIT,
- "Simulate memory shortage when compiled with the --with-debug=full option.",
- 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"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},
+ {"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,
+ 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, 1, 0, 0,
+ 0, 0, 0},
+#ifdef HAVE_NDBCLUSTER_DB
+ {"ndb-connectstring", OPT_NDB_CONNECTSTRING, "Connect string for ndbcluster.",
+ (gptr*) &ndbcluster_connectstring, (gptr*) &ndbcluster_connectstring, 0, GET_STR,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"new", 'n', "Use very new possible 'unsafe' functions.",
(gptr*) &global_system_variables.new_mode,
(gptr*) &max_system_variables.new_mode,
@@ -4409,32 +4432,43 @@ master-ssl",
{"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.",
(gptr*) &pidfile_name_ptr, (gptr*) &pidfile_name_ptr, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"log-error", OPT_ERROR_LOG_FILE, "Log error file.",
- (gptr*) &log_error_file_ptr, (gptr*) &log_error_file_ptr, 0, GET_STR,
- OPT_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},
+ {"relay-log", OPT_RELAY_LOG,
+ "The location and name to use for relay logs.",
+ (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
+ GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"relay-log-index", OPT_RELAY_LOG_INDEX,
+ "The location and name to use for the file that keeps a list of the last \
+relay logs.",
+ (gptr*) &opt_relaylog_index_name, (gptr*) &opt_relaylog_index_name, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE,
+ "The location and name of the file that remembers where the SQL replication \
+thread is in the relay logs.",
+ (gptr*) &relay_log_info_file, (gptr*) &relay_log_info_file, 0, GET_STR,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"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.%.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-do-table", OPT_REPLICATE_DO_TABLE,
"Tells the slave thread to restrict replication to the specified table. To specify more than one table, use the directive multiple times, once for each table. This will work for cross-database updates, in contrast to replicate-do-db.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE,
- "Tells the slave thread to restrict replication to the tables that match the specified wildcard pattern. To specify more than one table, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-do-table=foo%.bar% will replicate only updates to tables in all databases that start with foo and whose table names start with bar.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-ignore-db", OPT_REPLICATE_IGNORE_DB,
"Tells the slave thread to not replicate to the specified database. To specify more than one database to ignore, use the directive multiple times, once for each database. This option will not work if you use cross database updates. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-ignore-table=db_name.%. ",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE,
"Tells the slave thread to not replicate to the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-datbase updates, in contrast to replicate-ignore-db.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"replicate-wild-ignore-table", OPT_REPLICATE_WILD_IGNORE_TABLE,
- "Tells the slave thread to not replicate to the tables that match the given wildcard pattern. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% will not do updates to tables in databases that start with foo and whose table names start with bar.",
- 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB,
"Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"replicate-wild-do-table", OPT_REPLICATE_WILD_DO_TABLE,
+ "Tells the slave thread to restrict replication to the tables that match the specified wildcard pattern. To specify more than one table, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-do-table=foo%.bar% will replicate only updates to tables in all databases that start with foo and whose table names start with bar.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"replicate-wild-ignore-table", OPT_REPLICATE_WILD_IGNORE_TABLE,
+ "Tells the slave thread to not replicate to the tables that match the given wildcard pattern. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-database updates. Example: replicate-wild-ignore-table=foo%.bar% will not do updates to tables in databases that start with foo and whose table names start with bar.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
{"replicate-same-server-id", OPT_REPLICATE_SAME_SERVER_ID,
"In replication, if set to 1, do not skip events having our server id. \
@@ -4449,8 +4483,6 @@ Can't be set to 1 if --log-slave-updates is used.",
"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,
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-password", OPT_REPORT_PASSWORD, "Undocumented.",
(gptr*) &report_password, (gptr*) &report_password, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -4458,29 +4490,25 @@ Can't be set to 1 if --log-slave-updates is used.",
"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,
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},
{"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.",
(gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"relay-log", OPT_RELAY_LOG,
- "The location and name to use for relay logs.",
- (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
- GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"relay-log-index", OPT_RELAY_LOG_INDEX,
- "The location and name to use for the file that keeps a list of the last \
-relay logs.",
- (gptr*) &opt_relaylog_index_name, (gptr*) &opt_relaylog_index_name, 0,
- GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_DELETED
{"safe-show-database", OPT_SAFE_SHOW_DB,
- "Deprecated option; One should use GRANT SHOW DATABASES instead...",
+ "Deprecated option; use GRANT SHOW DATABASES instead...",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"safe-user-create", OPT_SAFE_USER_CREATE,
"Don't allow new user creation by the user who has no write privileges to the mysql.user table.",
(gptr*) &opt_safe_user_create, (gptr*) &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,
my_bool(0), 0, 0, 0, 0, 0},
@@ -4492,7 +4520,12 @@ relay logs.",
"Change the value of a variable. Please note that this option is deprecated;you can set variables directly with --variable-name=value.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_SMEM
- {"shared_memory_base_name",OPT_SHARED_MEMORY_BASE_NAME,
+ {"shared-memory", OPT_ENABLE_SHARED_MEMORY,
+ "Enable the shared memory.",(gptr*) &opt_enable_shared_memory, (gptr*) &opt_enable_shared_memory,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+#ifdef HAVE_SMEM
+ {"shared-memory-base-name",OPT_SHARED_MEMORY_BASE_NAME,
"Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
@@ -4500,31 +4533,15 @@ relay logs.",
"Show user and password in SHOW SLAVE HOSTS on this master",
(gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"concurrent-insert", OPT_CONCURRENT_INSERT,
- "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
- (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
- 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"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,
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, 1, 0, 0,
- 0, 0, 0},
- {"isam", OPT_ISAM, "Enable isam (if this version of MySQL supports it). \
-Disable with --skip-isam.",
- (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 1, 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, 1, 0, 0,
- 0, 0, 0},
+ {"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,
"Deprecated option, use --skip-external-locking instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"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-name-resolve", OPT_SKIP_RESOLVE,
"Don't resolve hostnames. All hostnames are IP's or 'localhost'.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -4533,6 +4550,13 @@ Disable with --skip-ndbcluster (will save memory).",
0, 0, 0},
{"skip-new", OPT_SKIP_NEW, "Don't use new, possible wrong routines.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+#ifdef SAFEMALLOC
+ {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
+ "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+#endif
+#endif
{"skip-show-database", OPT_SKIP_SHOW_DB,
"Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
0, 0, 0, 0},
@@ -4547,11 +4571,6 @@ Disable with --skip-ndbcluster (will save memory).",
{"skip-thread-priority", OPT_SKIP_PRIOR,
"Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
- {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE,
- "The location and name of the file that remembers where the SQL replication \
-thread is in the relay logs.",
- (gptr*) &relay_log_info_file, (gptr*) &relay_log_info_file, 0, GET_STR,
- REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_REPLICATION
{"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR,
"The location where the slave should put its temporary files when \
@@ -4565,6 +4584,13 @@ replicating a LOAD DATA INFILE command.",
{"socket", OPT_SOCKET, "Socket file to use for connection.",
(gptr*) &mysqld_unix_port, (gptr*) &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,
+ 0},
+#endif /* HAVE_REPLICATION */
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option does nothing anymore.",
@@ -4576,13 +4602,21 @@ log and this option does nothing anymore.",
#ifdef HAVE_OPENSSL
#include "sslopt-longopts.h"
#endif
+#ifdef __WIN__
+ {"standalone", OPT_STANDALONE,
+ "Dummy option to start as a standalone program (NT).", 0, 0, 0, GET_NO_ARG,
+ 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,
+ IF_PURIFY(0,1), 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,
0, 0, 0, 0, 0},
{"tmpdir", 't',
"Path for temporary files. Several paths may be specified, separated by a "
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
"semicolon (;)"
#else
"colon (:)"
@@ -4593,26 +4627,19 @@ log and this option does nothing anymore.",
{"transaction-isolation", OPT_TX_ISOLATION,
"Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
- {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
- (gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"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,
- IF_PURIFY(0,1), 0, 0, 0, 0, 0},
- {"symbolic-links", 's', "Enable symbolic link support.",
+ {"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,
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,
+ 0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
NO_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,
- 0, 0, 0},
- {"warnings", 'W', "Deprecated ; Use --log-warnings instead.",
+ {"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, 0,
+ (gptr*) &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.",
@@ -4623,6 +4650,10 @@ log and this option does nothing anymore.",
"The buffer that is allocated to cache index and rows for BDB tables.",
(gptr*) &berkeley_cache_size, (gptr*) &berkeley_cache_size, 0, GET_ULONG,
REQUIRED_ARG, KEY_CACHE_SIZE, 20*1024, (long) ~0, 0, IO_SIZE, 0},
+ /* QQ: The following should be removed soon! (bdb_max_lock preferred) */
+ {"bdb_lock_max", OPT_BDB_MAX_LOCK, "Synonym for bdb_max_lock.",
+ (gptr*) &berkeley_max_lock, (gptr*) &berkeley_max_lock, 0, GET_ULONG,
+ REQUIRED_ARG, 10000, 0, (long) ~0, 0, 1, 0},
{"bdb_log_buffer_size", OPT_BDB_LOG_BUFFER_SIZE,
"The buffer that is allocated to cache index and rows for BDB tables.",
(gptr*) &berkeley_log_buffer_size, (gptr*) &berkeley_log_buffer_size, 0,
@@ -4631,15 +4662,16 @@ log and this option does nothing anymore.",
"The maximum number of locks you can have active on a BDB table.",
(gptr*) &berkeley_max_lock, (gptr*) &berkeley_max_lock, 0, GET_ULONG,
REQUIRED_ARG, 10000, 0, (long) ~0, 0, 1, 0},
- /* QQ: The following should be removed soon! */
- {"bdb_lock_max", OPT_BDB_MAX_LOCK, "Synonym for bdb_max_lock.",
- (gptr*) &berkeley_max_lock, (gptr*) &berkeley_max_lock, 0, GET_ULONG,
- REQUIRED_ARG, 10000, 0, (long) ~0, 0, 1, 0},
#endif /* HAVE_BERKELEY_DB */
{"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,
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,
+ 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,
@@ -4650,18 +4682,38 @@ log and this option does nothing anymore.",
(gptr*) &opt_crash_binlog_innodb, (gptr*) &opt_crash_binlog_innodb,
0, GET_UINT, REQUIRED_ARG, 0, 0, ~(uint)0, 0, 1, 0},
#endif
- {"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,
- GET_ULONG, REQUIRED_ARG, DELAYED_WAIT_TIMEOUT, 1, 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],
+ 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],
+ 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,
+ 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,
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,
+ 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,
REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1, 0},
+ {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
+ "Binary logs will be rotated after expire-log-days days ",
+ (gptr*) &expire_logs_days,
+ (gptr*) &expire_logs_days, 0, GET_ULONG,
+ REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
{ "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,
@@ -4670,14 +4722,14 @@ log and this option does nothing anymore.",
"List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE)",
0, 0, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 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,
- REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN, 0, 1, 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,
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,
+ 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,
@@ -4686,49 +4738,58 @@ log and this option does nothing anymore.",
"Use stopwords from this file instead of built-in list.",
(gptr*) &ft_stopword_file, (gptr*) &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,
+ REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0},
#ifdef HAVE_INNOBASE_DB
- {"innodb_mirrored_log_groups", OPT_INNODB_MIRRORED_LOG_GROUPS,
- "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
- (gptr*) &innobase_mirrored_log_groups,
- (gptr*) &innobase_mirrored_log_groups, 0, GET_LONG, REQUIRED_ARG, 1, 1, 10,
- 0, 1, 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_log_file_size", OPT_INNODB_LOG_FILE_SIZE,
- "Size of each log file in a log group in megabytes.",
- (gptr*) &innobase_log_file_size, (gptr*) &innobase_log_file_size, 0,
- GET_LONG, REQUIRED_ARG, 5*1024*1024L, 1*1024*1024L, ~0L, 0, 1024*1024L, 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_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_LONG, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, ~0L, 0, 1024*1024L, 0},
- {"innodb_buffer_pool_awe_mem_mb", OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
- "If Windows AWE is used, the size of InnoDB buffer pool allocated from the AWE memory.",
- (gptr*) &innobase_buffer_pool_awe_mem_mb, (gptr*) &innobase_buffer_pool_awe_mem_mb, 0,
- GET_LONG, REQUIRED_ARG, 0, 0, 63000, 0, 1, 0},
{"innodb_additional_mem_pool_size", OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
(gptr*) &innobase_additional_mem_pool_size,
(gptr*) &innobase_additional_mem_pool_size, 0, GET_LONG, REQUIRED_ARG,
1*1024*1024L, 512*1024L, ~0L, 0, 1024, 0},
+ {"innodb_buffer_pool_awe_mem_mb", OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
+ "If Windows AWE is used, the size of InnoDB buffer pool allocated from the AWE memory.",
+ (gptr*) &innobase_buffer_pool_awe_mem_mb, (gptr*) &innobase_buffer_pool_awe_mem_mb, 0,
+ GET_LONG, REQUIRED_ARG, 0, 0, 63000, 0, 1, 0},
+ {"innodb_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_LONG, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, ~0L, 0, 1024*1024L, 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_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_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 in megabytes.",
+ (gptr*) &innobase_log_file_size, (gptr*) &innobase_log_file_size, 0,
+ GET_LONG, REQUIRED_ARG, 5*1024*1024L, 1*1024*1024L, ~0L, 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},
#ifdef HAVE_REPLICATION
/*
Disabled for the 4.1.3 release. Disabling just this paragraph of code is
@@ -4753,10 +4814,6 @@ log and this option does nothing anymore.",
"Helps in performance tuning in heavily concurrent environments.",
(gptr*) &innobase_thread_concurrency, (gptr*) &innobase_thread_concurrency,
0, GET_LONG, REQUIRED_ARG, 8, 1, 1000, 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},
#endif /* HAVE_INNOBASE_DB */
{"interactive_timeout", OPT_INTERACTIVE_TIMEOUT,
"The number of seconds the server waits for activity on an interactive connection before closing it.",
@@ -4776,6 +4833,12 @@ log and this option does nothing anymore.",
0, (GET_ULL | GET_ASK_ADDR),
REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~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,
+ 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,
@@ -4788,12 +4851,6 @@ log and this option does nothing anymore.",
(gptr*) 0,
0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100,
1, 100, 0, 1, 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,
- 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG,
- 300, 100, ~0L, 0, 100, 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,
@@ -4824,14 +4881,14 @@ 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,
REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0},
- {"max_connections", OPT_MAX_CONNECTIONS,
- "The number of simultaneous clients allowed.", (gptr*) &max_connections,
- (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1,
- 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,
REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0},
+ {"max_connections", OPT_MAX_CONNECTIONS,
+ "The number of simultaneous clients allowed.", (gptr*) &max_connections,
+ (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 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,
@@ -4884,11 +4941,6 @@ The minimum value for this variable is 4096.",
"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,
REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 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,
- 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, ~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,
@@ -4927,16 +4979,16 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.net_buffer_length,
(gptr*) &max_system_variables.net_buffer_length, 0, GET_ULONG,
REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0},
- {"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,
- GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, ~0L, 0, 1, 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,
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,
+ 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,
@@ -4998,11 +5050,21 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.query_prealloc_size,
(gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~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,
+ REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~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,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0},
+ {"read_only", OPT_READONLY,
+ "Make all tables readonly, with the exception for replication (slave) threads and users with the SUPER privilege",
+ (gptr*) &opt_readonly,
+ (gptr*) &opt_readonly,
+ 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
{"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,
@@ -5035,16 +5097,6 @@ The minimum value for this variable is 4096.",
(gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
#endif /* HAVE_REPLICATION */
- {"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,
- REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0},
- {"read-only", OPT_READONLY,
- "Make all tables readonly, with the exception for replication (slave) threads and users with the SUPER privilege",
- (gptr*) &opt_readonly,
- (gptr*) &opt_readonly,
- 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
(gptr*) &slow_launch_time, (gptr*) &slow_launch_time, 0, GET_ULONG,
@@ -5055,33 +5107,52 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD,
1, 0},
+ {"sql_updatable_view_key", OPT_SQL_UPDATABLE_VIEW_KEY,
+ "0 = NO = Don't check presence of key in updatable VIEW. 1 = YES = Prohibit update of VIEW which does not contain key of underlying table. 2 = LIMIT1 = Same as YES but prohibited only operation with LIMIT 1 (usually get from GUI tools).",
+ (gptr*) &global_system_variables.sql_updatable_view_key,
+ (gptr*) &max_system_variables.sql_updatable_view_key,
+ 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0},
+#ifdef HAVE_BERKELEY_DB
+ {"sync-bdb-logs", OPT_BDB_SYNC,
+ "Synchronously flush logs. Enabled by default",
+ (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
+ NO_ARG, 1, 0, 0, 0, 0, 0},
+#endif /* HAVE_BERKELEY_DB */
{"sync-binlog", OPT_SYNC_BINLOG,
"Sync the binlog to disk after every #th event. \
#=0 (the default) does no sync. Syncing slows MySQL down",
(gptr*) &sync_binlog_period,
(gptr*) &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,
+ 0, 0, 0, 0},
{"table_cache", OPT_TABLE_CACHE,
"The number of open tables for all threads.", (gptr*) &table_cache_size,
(gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L,
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,
- DEFAULT_CONCURRENCY, 1, 512, 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,
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,
+ DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0},
+ {"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,
+ 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],
+ 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_ULONG,
REQUIRED_ARG, 32*1024*1024L, 1024, ~0L, 0, 1, 0},
- {"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,
- 1024L*128L, ~0L, 0, 1024, 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,
@@ -5098,36 +5169,6 @@ The minimum value for this variable is 4096.",
(gptr*) &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},
- {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
- "Binary logs will be rotated after expire-log-days days ",
- (gptr*) &expire_logs_days,
- (gptr*) &expire_logs_days, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
- { "default-week-format", OPT_DEFAULT_WEEK_FORMAT,
- "The default week format used by WEEK() functions.",
- (gptr*) &global_system_variables.default_week_format,
- (gptr*) &max_system_variables.default_week_format,
- 0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 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],
- 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],
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 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],
- 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"sql_updatable_view_key", OPT_SQL_UPDATABLE_VIEW_KEY,
- "0 = NO = Don't check presence of key in updatable VIEW. 1 = YES = Prohibit update of VIEW which does not contain key of underlying table. 2 = LIMIT1 = Same as YES but prohibited only operation with LIMIT 1 (usually get from GUI tools).",
- (gptr*) &global_system_variables.sql_updatable_view_key,
- (gptr*) &max_system_variables.sql_updatable_view_key,
- 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -5154,6 +5195,8 @@ struct show_var_st status_vars[]= {
{"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG},
{"Com_create_index", (char*) (com_stat+(uint) SQLCOM_CREATE_INDEX),SHOW_LONG},
{"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
+ {"Com_dealloc_sql", (char*) (com_stat+(uint)
+ SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG},
{"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
{"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
{"Com_do", (char*) (com_stat+(uint) SQLCOM_DO),SHOW_LONG},
@@ -5162,6 +5205,8 @@ struct show_var_st status_vars[]= {
{"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
{"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG},
{"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG},
+ {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE),
+ SHOW_LONG},
{"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG},
{"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG},
{"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
@@ -5177,6 +5222,8 @@ struct show_var_st status_vars[]= {
{"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
{"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
{"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG},
+ {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE),
+ SHOW_LONG},
{"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
{"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG},
{"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
@@ -5223,12 +5270,6 @@ struct show_var_st status_vars[]= {
{"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
{"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
{"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
- {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE),
- SHOW_LONG},
- {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE),
- SHOW_LONG},
- {"Com_dealloc_sql", (char*) (com_stat+(uint)
- SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
{"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
{"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG},
@@ -5239,6 +5280,7 @@ struct show_var_st status_vars[]= {
{"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST},
{"Handler_commit", (char*) &ha_commit_count, SHOW_LONG},
{"Handler_delete", (char*) &ha_delete_count, SHOW_LONG},
+ {"Handler_discover", (char*) &ha_discover_count, SHOW_LONG},
{"Handler_read_first", (char*) &ha_read_first_count, SHOW_LONG},
{"Handler_read_key", (char*) &ha_read_key_count, SHOW_LONG},
{"Handler_read_next", (char*) &ha_read_next_count, SHOW_LONG},
@@ -5248,13 +5290,12 @@ struct show_var_st status_vars[]= {
{"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG},
{"Handler_update", (char*) &ha_update_count, SHOW_LONG},
{"Handler_write", (char*) &ha_write_count, SHOW_LONG},
- {"Handler_discover", (char*) &ha_discover_count, SHOW_LONG},
{"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed,
SHOW_KEY_CACHE_LONG},
- {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used,
- SHOW_KEY_CACHE_CONST_LONG},
{"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused,
SHOW_KEY_CACHE_CONST_LONG},
+ {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used,
+ SHOW_KEY_CACHE_CONST_LONG},
{"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests,
SHOW_KEY_CACHE_LONG},
{"Key_reads", (char*) &dflt_key_cache_var.global_cache_read,
@@ -5555,6 +5596,11 @@ static void mysql_init_variables(void)
#else
have_archive_db= SHOW_OPTION_NO;
#endif
+#ifdef HAVE_CSV_DB
+ have_csv_db= SHOW_OPTION_YES;
+#else
+ have_csv_db= SHOW_OPTION_NO;
+#endif
#ifdef HAVE_NDBCLUSTER_DB
have_ndbcluster=SHOW_OPTION_DISABLED;
#else
@@ -5664,7 +5710,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
if (!mysqld_user || !strcmp(mysqld_user, argument))
mysqld_user= argument;
else
- fprintf(stderr, "Warning: Ignoring user change to '%s' because the user was set to '%s' earlier on the command line\n", argument, mysqld_user);
+ sql_print_warning("Ignoring user change to '%s' because the user was set to '%s' earlier on the command line\n", argument, mysqld_user);
break;
case 'L':
strmake(language, argument, sizeof(language)-1);
@@ -5682,9 +5728,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
#ifdef EMBEDDED_LIBRARY
case OPT_MAX_ALLOWED_PACKET:
max_allowed_packet= atoi(argument);
+ global_system_variables.max_allowed_packet= max_allowed_packet;
break;
case OPT_NET_BUFFER_LENGTH:
net_buffer_length= atoi(argument);
+ global_system_variables.net_buffer_length= net_buffer_length;
break;
#endif
#include <sslopt-case.h>
@@ -6033,15 +6081,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
case OPT_BDB_SHARED:
berkeley_init_flags&= ~(DB_PRIVATE);
- berkeley_shared_data=1;
+ berkeley_shared_data= 1;
break;
#endif /* HAVE_BERKELEY_DB */
case OPT_BDB:
#ifdef HAVE_BERKELEY_DB
if (opt_bdb)
- have_berkeley_db=SHOW_OPTION_YES;
+ have_berkeley_db= SHOW_OPTION_YES;
else
- have_berkeley_db=SHOW_OPTION_DISABLED;
+ have_berkeley_db= SHOW_OPTION_DISABLED;
#endif
break;
case OPT_ISAM:
@@ -6055,22 +6103,22 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_NDBCLUSTER:
#ifdef HAVE_NDBCLUSTER_DB
if (opt_ndbcluster)
- have_ndbcluster=SHOW_OPTION_YES;
+ have_ndbcluster= SHOW_OPTION_YES;
else
- have_ndbcluster=SHOW_OPTION_DISABLED;
+ have_ndbcluster= SHOW_OPTION_DISABLED;
#endif
break;
case OPT_INNODB:
#ifdef HAVE_INNOBASE_DB
if (opt_innodb)
- have_innodb=SHOW_OPTION_YES;
+ have_innodb= SHOW_OPTION_YES;
else
- have_innodb=SHOW_OPTION_DISABLED;
+ have_innodb= SHOW_OPTION_DISABLED;
#endif
break;
case OPT_INNODB_DATA_FILE_PATH:
#ifdef HAVE_INNOBASE_DB
- innobase_data_file_path=argument;
+ innobase_data_file_path= argument;
#endif
break;
#ifdef HAVE_INNOBASE_DB
@@ -6134,7 +6182,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
return 0;
}
-
+ /* Initiates DEBUG - but no debugging here ! */
extern "C" gptr *
mysql_getopt_value(const char *keyname, uint key_length,
@@ -6165,6 +6213,15 @@ mysql_getopt_value(const char *keyname, uint key_length,
}
+void option_error_reporter(enum loglevel level, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprint_msg_to_log(level, format, args);
+ va_end(args);
+}
+
+
static void get_options(int argc,char **argv)
{
int ho_error;
@@ -6172,12 +6229,15 @@ static void get_options(int argc,char **argv)
my_getopt_register_get_addr(mysql_getopt_value);
strmake(def_ft_boolean_syntax, ft_boolean_syntax,
sizeof(ft_boolean_syntax)-1);
- if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ my_getopt_error_reporter= option_error_reporter;
+ if ((ho_error= handle_options(&argc, &argv, my_long_options,
+ get_one_option)))
exit(ho_error);
if (argc > 0)
{
fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv);
- exit(ho_error);
+ /* FIXME add EXIT_TOO_MANY_ARGUMENTS to "mysys_err.h" and return that code? */
+ exit(1);
}
if (opt_help)
@@ -6439,7 +6499,7 @@ static int test_if_case_insensitive(const char *dir_name)
(void) my_delete(buff2, MYF(0));
if ((file= my_create(buff, 0666, O_RDWR, MYF(0))) < 0)
{
- sql_print_error("Warning: Can't create test file %s", buff);
+ sql_print_warning("Can't create test file %s", buff);
DBUG_RETURN(-1);
}
my_close(file, MYF(0));
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index d2190c35bc6..e0e2b5c8045 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3666,7 +3666,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
if (*key2 && !(*key2)->simple_key())
flag|=CLONE_KEY2_MAYBE;
*key1=key_and(*key1,*key2,flag);
- if ((*key1)->type == SEL_ARG::IMPOSSIBLE)
+ if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{
tree1->type= SEL_TREE::IMPOSSIBLE;
DBUG_RETURN(tree1);
@@ -3904,6 +3904,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
return key1;
}
+ if ((key1->min_flag | key2->min_flag) & GEOM_FLAG)
+ {
+ key1->free_tree();
+ key2->free_tree();
+ return 0; // Can't optimize this
+ }
+
key1->use_count--;
key2->use_count--;
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
@@ -3986,7 +3993,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
key1->use_count--;
key2->use_count--;
- if (key1->part != key2->part)
+ if (key1->part != key2->part ||
+ (key1->min_flag | key2->min_flag) & GEOM_FLAG)
{
key1->free_tree();
key2->free_tree();
diff --git a/sql/protocol.cc b/sql/protocol.cc
index e14eafc86a2..bceac780037 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -213,11 +213,13 @@ net_printf(THD *thd, uint errcode, ...)
2+SQLSTATE_LENGTH+1 : 2) : 0);
#ifndef EMBEDDED_LIBRARY
text_pos=(char*) net->buff + head_length + offset + 1;
+ length= (uint) ((char*)net->buff_end - text_pos);
+#else
+ length=sizeof(text_pos)-1;
#endif
- (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
- length=(uint) strlen((char*) text_pos);
- if (length >= sizeof(net->last_error))
- length=sizeof(net->last_error)-1; /* purecov: inspected */
+ length=my_vsnprintf(my_const_cast(char*) (text_pos),
+ min(length, sizeof(net->last_error)),
+ format,args);
va_end(args);
#ifndef EMBEDDED_LIBRARY
diff --git a/sql/records.cc b/sql/records.cc
index 37fbc7570ed..8dd4f548093 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -101,6 +101,9 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
else if (select && select->quick)
{
DBUG_PRINT("info",("using rr_quick"));
+
+ if (!table->file->inited)
+ table->file->ha_index_init(select->quick->index);
info->read_record=rr_quick;
}
else if (table->sort.record_pointers)
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index bb70b793d3b..10ff5fa3596 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -590,6 +590,8 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
THD *thd = new THD;
thd->thread_stack = (char*)&thd;
MYSQL* recovery_captain = 0;
+ const char* msg;
+
pthread_detach_this_thread();
if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0)))
{
@@ -597,11 +599,11 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
goto err;
}
pthread_mutex_lock(&LOCK_rpl_status);
+ msg= thd->enter_cond(&COND_rpl_status,
+ &LOCK_rpl_status, "Waiting for request");
while (!thd->killed && !abort_loop)
{
bool break_req_chain = 0;
- const char* msg = thd->enter_cond(&COND_rpl_status,
- &LOCK_rpl_status, "Waiting for request");
pthread_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
thd->proc_info="Processing request";
while (!break_req_chain)
@@ -619,9 +621,8 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
break;
}
}
- thd->exit_cond(msg);
}
- pthread_mutex_unlock(&LOCK_rpl_status);
+ thd->exit_cond(msg);
err:
if (recovery_captain)
mysql_close(recovery_captain);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 458f1a3b08e..d92d5eb42b2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -34,6 +34,12 @@
- 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
+ ulonglong_value; so other members of the union are garbage then; to use
+ them you must first assign a value to them (in specific ::check() for
+ example).
+
TODO:
- Add full support for the variable character_set (for 4.1)
@@ -623,8 +629,8 @@ struct show_var_st init_vars[]= {
#ifdef HAVE_BERKELEY_DB
{"bdb_cache_size", (char*) &berkeley_cache_size, SHOW_LONG},
{"bdb_home", (char*) &berkeley_home, SHOW_CHAR_PTR},
- {"bdb_logdir", (char*) &berkeley_logdir, SHOW_CHAR_PTR},
{"bdb_log_buffer_size", (char*) &berkeley_log_buffer_size, SHOW_LONG},
+ {"bdb_logdir", (char*) &berkeley_logdir, SHOW_CHAR_PTR},
{"bdb_max_lock", (char*) &berkeley_max_lock, SHOW_LONG},
{"bdb_shared_data", (char*) &berkeley_shared_data, SHOW_BOOL},
{"bdb_tmpdir", (char*) &berkeley_tmpdir, SHOW_CHAR_PTR},
@@ -664,9 +670,11 @@ struct show_var_st init_vars[]= {
{"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE},
{"have_compress", (char*) &have_compress, SHOW_HAVE},
{"have_crypt", (char*) &have_crypt, SHOW_HAVE},
+ {"have_csv", (char*) &have_csv_db, SHOW_HAVE},
+ {"have_example_engine", (char*) &have_example_db, SHOW_HAVE},
+ {"have_geometry", (char*) &have_geometry, SHOW_HAVE},
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
{"have_isam", (char*) &have_isam, SHOW_HAVE},
- {"have_geometry", (char*) &have_geometry, SHOW_HAVE},
{"have_ndbcluster", (char*) &have_ndbcluster, SHOW_HAVE},
{"have_openssl", (char*) &have_openssl, SHOW_HAVE},
{"have_query_cache", (char*) &have_query_cache, SHOW_HAVE},
@@ -685,6 +693,7 @@ struct show_var_st init_vars[]= {
{"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL},
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
{"innodb_file_per_table", (char*) &innobase_file_per_table, SHOW_MY_BOOL},
+ {"innodb_locks_unsafe_for_binlog", (char*) &innobase_locks_unsafe_for_binlog, SHOW_MY_BOOL},
{"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT},
{"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR},
{"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
@@ -784,6 +793,8 @@ struct show_var_st init_vars[]= {
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,
@@ -1147,8 +1158,10 @@ static int check_max_delayed_threads(THD *thd, set_var *var)
static void fix_max_connections(THD *thd, enum_var_type type)
{
+#ifndef EMBEDDED_LIBRARY
resize_thr_alarm(max_connections +
global_system_variables.max_insert_delayed_threads + 10);
+#endif
}
@@ -2347,7 +2360,7 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
bool sys_var_sync_binlog_period::update(THD *thd, set_var *var)
{
pthread_mutex_t *lock_log= mysql_bin_log.get_log_lock();
- sync_binlog_period= var->save_result.ulong_value;
+ sync_binlog_period= (ulong) var->save_result.ulonglong_value;
/*
Must reset the counter otherwise it may already be beyond the new period
and so the new period will not be taken into account. Need mutex otherwise
@@ -2389,8 +2402,9 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
return 1;
}
#endif
-
- if (!(var->save_result.time_zone= my_tz_find(thd, res)))
+
+ if (!(var->save_result.time_zone=
+ my_tz_find(res, thd->lex->time_zone_tables_used)))
{
my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
return 1;
@@ -2435,7 +2449,8 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
if (default_tz_name)
{
String str(default_tz_name, &my_charset_latin1);
- global_system_variables.time_zone= my_tz_find(thd, &str);
+ global_system_variables.time_zone=
+ my_tz_find(&str, thd->lex->time_zone_tables_used);
}
else
global_system_variables.time_zone= my_tz_SYSTEM;
@@ -2892,8 +2907,9 @@ int set_var_password::check(THD *thd)
if (!user->host.str)
user->host.str= (char*) thd->host_or_ip;
/* Returns 1 as the function sends error to client */
- return check_change_password(thd, user->host.str, user->user.str) ? 1 : 0;
-#else
+ return check_change_password(thd, user->host.str, user->user.str, password) ?
+ 1 : 0;
+#else
return 0;
#endif
}
@@ -2902,8 +2918,8 @@ int set_var_password::update(THD *thd)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Returns 1 as the function sends error to client */
- return (change_password(thd, user->host.str, user->user.str, password) ?
- 1 : 0);
+ return change_password(thd, user->host.str, user->user.str, password) ?
+ 1 : 0;
#else
return 0;
#endif
diff --git a/sql/set_var.h b/sql/set_var.h
index 1374492526e..c34ebbca4b2 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -892,6 +892,7 @@ ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
extern sys_var_str sys_init_connect;
extern sys_var_str sys_init_slave;
+extern sys_var_thd_time_zone sys_time_zone;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
NAMED_LIST **found);
diff --git a/sql/share/charsets/cp852.xml b/sql/share/charsets/cp852.xml
index ee434859233..958587d0399 100644
--- a/sql/share/charsets/cp852.xml
+++ b/sql/share/charsets/cp852.xml
@@ -114,6 +114,8 @@
</map>
</collation>
+<collation name="cp852_bin" flag="binary"/>
+
</charset>
</charsets>
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 9d1c429d5b6..587a8be7ac8 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -1,3 +1,19 @@
+/* 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.
+
+ 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 */
+
/*
Modifikoval Petr -B©najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01
ISO LATIN-8852-2
@@ -88,7 +104,7 @@ character-set=latin2
"Blob sloupec '%-.64s' nem-Bù¾e být pou¾it jako klíè",
"P-Bøíli¹ velká délka sloupce '%-.64s' (nejvíce %d). Pou¾ijte BLOB",
"M-Bù¾ete mít pouze jedno AUTO pole a to musí být definováno jako klíè",
-"%s: p-Bøipraven na spojení\n",
+"%s: p-Bøipraven na spojení",
"%s: norm-Bální ukonèení\n",
"%s: p-Bøijat signal %d, konèím\n",
"%s: ukon-Bèení práce hotovo\n",
@@ -313,7 +329,8 @@ character-set=latin2
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index b2d2fdf4d77..8d6e23d449e 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
/* Knud Riishøjgård knudriis@post.tele.dk 99 &&
Carsten H. Pedersen, carsten.pedersen@bitbybit.dk oct. 1999 / aug. 2001. */
@@ -82,7 +95,7 @@ character-set=latin1
"BLOB feltet '%-.64s' kan ikke bruges ved specifikation af indeks",
"For stor feltlængde for kolonne '%-.64s' (maks = %d). Brug BLOB i stedet",
"Der kan kun specificeres eet AUTO_INCREMENT-felt, og det skal være indekseret",
-"%s: klar til tilslutninger\n",
+"%s: klar til tilslutninger",
"%s: Normal nedlukning\n",
"%s: Fangede signal %d. Afslutter!!\n",
"%s: Server lukket\n",
@@ -307,7 +320,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 85c0443869f..0c60c63de64 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -1,6 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
Dutch error messages (share/dutch/errmsg.txt)
2001-08-02 - Arjen Lentz (agl@bitbike.com)
Completed earlier partial translation; worked on consistency and spelling.
@@ -90,7 +104,7 @@ character-set=latin1
"BLOB kolom '%-.64s' kan niet gebruikt worden bij zoeksleutel specificatie",
"Te grote kolomlengte voor '%-.64s' (max = %d). Maak hiervoor gebruik van het type BLOB",
"Er kan slechts 1 autofield zijn en deze moet als zoeksleutel worden gedefinieerd.",
-"%s: klaar voor verbindingen\n",
+"%s: klaar voor verbindingen",
"%s: Normaal afgesloten \n",
"%s: Signaal %d. Systeem breekt af!\n",
"%s: Afsluiten afgerond\n",
@@ -315,7 +329,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 641f267d67e..b850c2d36d0 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=latin1
@@ -79,7 +92,7 @@ character-set=latin1
"BLOB column '%-.64s' can't be used in key specification with the used table type",
"Column length too big for column '%-.64s' (max = %d); use BLOB instead",
"Incorrect table definition; there can be only one auto column and it must be defined as a key",
-"%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d\n",
+"%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d",
"%s: Normal shutdown\n",
"%s: Got signal %d. Aborting!\n",
"%s: Shutdown complete\n",
@@ -304,7 +317,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index e64c0c17e74..ef958921b5e 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -1,9 +1,22 @@
+/* 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.
+
+ 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 */
+
/*
- Copyright Abandoned 1997 MySQL AB
- This file is public domain and comes with NO WARRANTY of any kind
Esialgne tõlge: Tõnu Samuel (tonu@spam.ee)
Parandanud ja täiendanud: Indrek Siitan (tfr@mysql.com)
-
*/
character-set=latin7
@@ -84,7 +97,7 @@ character-set=latin7
"BLOB-tüüpi tulpa '%-.64s' ei saa kasutada võtmena",
"Tulba '%-.64s' pikkus on liiga pikk (maksimaalne pikkus: %d). Kasuta BLOB väljatüüpi",
"Vigane tabelikirjeldus; Tabelis tohib olla üks auto_increment tüüpi tulp ning see peab olema defineeritud võtmena",
-"%s: ootab ühendusi\n",
+"%s: ootab ühendusi",
"%s: MySQL lõpetas\n",
"%s: sain signaali %d. Lõpetan!\n",
"%s: Lõpp\n",
@@ -309,7 +322,8 @@ character-set=latin7
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index f3443457346..8723919ab47 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=latin1
@@ -79,7 +92,7 @@ character-set=latin1
"Champ BLOB '%-.64s' ne peut être utilisé dans une clé",
"Champ '%-.64s' trop long (max = %d). Utilisez un BLOB",
"Un seul champ automatique est permis et il doit être indexé",
-"%s: Prêt pour des connections\n",
+"%s: Prêt pour des connections",
"%s: Arrêt normal du serveur\n",
"%s: Reçu le signal %d. Abandonne!\n",
"%s: Arrêt du serveur terminé\n",
@@ -304,7 +317,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 498a230faed..74274ebfc8c 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -1,6 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
Dirk Munzinger (dmun@4t2.com)
2001-06-07
@@ -11,7 +25,7 @@
Stefan Hinz (stefan@mysql.com)
2003-10-01
- */
+*/
character-set=latin1
@@ -91,7 +105,7 @@ character-set=latin1
"BLOB-Feld '%-.64s' kann beim verwendeten Tabellentyp nicht als Schlüssel verwendet werden",
"Feldlänge für Feld '%-.64s' zu groß (maximal %d). BLOB-Feld verwenden!",
"Falsche Tabellendefinition. Es darf nur ein Auto-Feld geben und dieses muss als Schlüssel definiert werden",
-"%-.64s: Bereit für Verbindungen\n",
+"%-.64s: Bereit für Verbindungen",
"%-.64s: Normal heruntergefahren\n",
"%-.64s: Signal %d erhalten. Abbruch!\n",
"%-.64s: Heruntergefahren (shutdown)\n",
@@ -316,7 +330,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 2827517ba9a..ea148999fc4 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=greek
@@ -79,7 +92,7 @@ character-set=greek
"Ðåäßï ôýðïõ Blob '%-.64s' äåí ìðïñåß íá ÷ñçóéìïðïéçèåß óôïí ïñéóìü åíüò êëåéäéïý (key specification)",
"Ðïëý ìåãÜëï ìÞêïò ãéá ôï ðåäßï '%-.64s' (max = %d). Ðáñáêáëþ ÷ñçóéìïðïéåßóôå ôïí ôýðï BLOB",
"Ìðïñåß íá õðÜñ÷åé ìüíï Ýíá auto field êáé ðñÝðåé íá Ý÷åé ïñéóèåß óáí key",
-"%s: óå áíáìïíÞ óõíäÝóåùí\n",
+"%s: óå áíáìïíÞ óõíäÝóåùí",
"%s: ÖõóéïëïãéêÞ äéáäéêáóßá shutdown\n",
"%s: ÅëÞöèç ôï ìÞíõìá %d. Ç äéáäéêáóßá åãêáôáëåßðåôáé!\n",
"%s: Ç äéáäéêáóßá Shutdown ïëïêëçñþèçêå\n",
@@ -304,7 +317,8 @@ character-set=greek
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index fab0b156322..ede873f21c0 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -1,7 +1,23 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+/* 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.
+
+ 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 */
+
+/*
Translated by Feher Peter. Forditotta Feher Peter (feherp@mail.matav.hu) 1998
Updated May, 2000
- This file is public domain and comes with NO WARRANTY of any kind */
+*/
character-set=latin2
@@ -81,7 +97,7 @@ character-set=latin2
"Blob objektum '%-.64s' nem hasznalhato kulcskent",
"A(z) '%-.64s' oszlop tul hosszu. (maximum = %d). Hasznaljon BLOB tipust inkabb.",
"Csak egy auto mezo lehetseges, es azt kulcskent kell definialni.",
-"%s: kapcsolatra kesz\n",
+"%s: kapcsolatra kesz",
"%s: Normal leallitas\n",
"%s: %d jelzes. Megszakitva!\n",
"%s: A leallitas kesz\n",
@@ -306,7 +322,8 @@ character-set=latin2
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 24634514a23..7898503dc03 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=latin1
@@ -304,7 +317,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 68f2857aeca..f73eca2a183 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -1,5 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
3.22.10-beta euc-japanese (ujis) text
*/
@@ -81,7 +96,7 @@ character-set=ujis
"BLOB column '%-.64s' can't be used in key specification with the used table type",
"column '%-.64s' ¤Ï,³ÎÊݤ¹¤ë column ¤ÎÂ礭¤µ¤¬Â¿¤¹¤®¤Þ¤¹. (ºÇÂç %d ¤Þ¤Ç). BLOB ¤ò¤«¤ï¤ê¤Ë»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤.",
"¥Æ¡¼¥Ö¥ë¤ÎÄêµÁ¤¬°ã¤¤¤Þ¤¹; there can be only one auto column and it must be defined as a key",
-"%s: ½àÈ÷´°Î»\n",
+"%s: ½àÈ÷´°Î»",
"%s: Normal shutdown\n",
"%s: Got signal %d. ̾̂!\n",
"%s: Shutdown ´°Î»\n",
@@ -306,7 +321,8 @@ character-set=ujis
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 70267c82364..6c8a5c2661a 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This È­ÀÏ is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=euckr
@@ -79,7 +92,7 @@ character-set=euckr
"BLOB Ä®·³ '%-.64s'´Â Å° Á¤ÀÇ¿¡¼­ »ç¿ëµÉ ¼ö ¾ø½À´Ï´Ù.",
"Ä®·³ '%-.64s'ÀÇ Ä®·³ ±æÀÌ°¡ ³Ê¹« ±é´Ï´Ù (ÃÖ´ë = %d). ´ë½Å¿¡ BLOB¸¦ »ç¿ëÇϼ¼¿ä.",
"ºÎÁ¤È®ÇÑ Å×À̺í Á¤ÀÇ; Å×À̺íÀº ÇϳªÀÇ auto Ä®·³ÀÌ Á¸ÀçÇÏ°í Å°·Î Á¤ÀǵǾîÁ®¾ß ÇÕ´Ï´Ù.",
-"%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù.\n",
+"%s: ¿¬°á ÁغñÁßÀÔ´Ï´Ù",
"%s: Á¤»óÀûÀÎ shutdown\n",
"%s: %d ½ÅÈ£°¡ µé¾î¿ÔÀ½. ÁßÁö!\n",
"%s: Shutdown ÀÌ ¿Ï·áµÊ!\n",
@@ -304,7 +317,8 @@ character-set=euckr
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 1d84a3a5e5a..48ade24703b 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
/* Roy-Magne Mo rmo@www.hivolda.no 97 */
@@ -81,7 +94,7 @@ character-set=latin1
"Blob kolonne '%-.64s' kan ikkje brukast ved spesifikasjon av nyklar",
"For stor nykkellengde for felt '%-.64s' (maks = %d). Bruk BLOB istadenfor",
"Bare eitt auto felt kan være definert som nøkkel.",
-"%s: klar for tilkoblingar\n",
+"%s: klar for tilkoblingar",
"%s: Normal nedkopling\n",
"%s: Oppdaga signal %d. Avsluttar!\n",
"%s: Nedkopling komplett\n",
@@ -306,7 +319,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index be881d54473..e217155a4df 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
/* Roy-Magne Mo rmo@www.hivolda.no 97 */
@@ -81,7 +94,7 @@ character-set=latin1
"Blob felt '%-.64s' kan ikke brukes ved spesifikasjon av nøkler",
"For stor nøkkellengde for kolonne '%-.64s' (maks = %d). Bruk BLOB istedenfor",
"Bare ett auto felt kan være definert som nøkkel.",
-"%s: klar for tilkoblinger\n",
+"%s: klar for tilkoblinger",
"%s: Normal avslutning\n",
"%s: Oppdaget signal %d. Avslutter!\n",
"%s: Avslutning komplett\n",
@@ -306,7 +319,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 8a576b5bf82..c514581ec1c 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -1,6 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
Changed by Jaroslaw Lewandowski <jotel@itnet.com.pl>
Charset ISO-8859-2
*/
@@ -83,7 +97,7 @@ character-set=latin2
"Kolumna typu Blob '%-.64s' nie mo¿e byæ u¿yta w specyfikacji klucza",
"Zbyt du¿a d³ugo?æ kolumny '%-.64s' (maks. = %d). W zamian u¿yj typu BLOB",
"W tabeli mo¿e byæ tylko jedno pole auto i musi ono byæ zdefiniowane jako klucz",
-"%s: gotowe do po³?czenia\n",
+"%s: gotowe do po³?czenia",
"%s: Standardowe zakoñczenie dzia³ania\n",
"%s: Otrzymano sygna³ %d. Koñczenie dzia³ania!\n",
"%s: Zakoñczenie dzia³ania wykonane\n",
@@ -308,7 +322,8 @@ character-set=latin2
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 6794db726cc..ca6cccb7471 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -1,5 +1,19 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
+
/* Updated by Thiago Delgado Pinto - thiagodp@ieg.com.br - 06.07.2002 */
character-set=latin1
@@ -80,7 +94,7 @@ character-set=latin1
"Coluna BLOB '%-.64s' não pode ser utilizada na especificação de chave para o tipo de tabela usado",
"Comprimento da coluna '%-.64s' grande demais (max = %d); use BLOB em seu lugar",
"Definição incorreta de tabela. Somente é permitido um único campo auto-incrementado e ele tem que ser definido como chave",
-"%s: Pronto para conexões\n",
+"%s: Pronto para conexões",
"%s: 'Shutdown' normal\n",
"%s: Obteve sinal %d. Abortando!\n",
"%s: 'Shutdown' completo\n",
@@ -305,7 +319,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 9eaa4860b64..3c69e33a222 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -1,6 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
Translated into Romanian by Stefan Saroiu
e-mail: tzoompy@cs.washington.edu
*/
@@ -83,7 +97,7 @@ character-set=latin2
"Coloana de tip BLOB '%-.64s' nu poate fi folosita in specificarea cheii cu tipul de tabla folosit",
"Lungimea coloanei '%-.64s' este prea lunga (maximum = %d). Foloseste BLOB mai bine",
"Definitia tabelei este incorecta; Nu pot fi mai mult de o singura coloana de tip auto si aceasta trebuie definita ca cheie",
-"%s: sint gata pentru conectii\n",
+"%s: sint gata pentru conectii",
"%s: Terminare normala\n",
"%s: Semnal %d obtinut. Aborting!\n",
"%s: Terminare completa\n",
@@ -308,7 +322,8 @@ character-set=latin2
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index eec85d611fc..13c7a410443 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -1,6 +1,22 @@
-/* Copyright 2003 MySQL 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.
+
+ 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 */
+
+/*
Translation done in 2003 by Egor Egorov; Ensita.NET, http://www.ensita.net/
- This file is public domain and comes with NO WARRANTY of any kind */
+*/
/* charset: KOI8-R */
character-set=koi8r
@@ -81,7 +97,7 @@ character-set=koi8r
"óÔÏÌÂÅà ÔÉÐÁ BLOB '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ËÁË ÚÎÁÞÅÎÉÅ ËÌÀÞÁ × ÔÁÂÌÉÃÅ ÔÁËÏÇÏ ÔÉÐÁ",
"óÌÉÛËÏÍ ÂÏÌØÛÁÑ ÄÌÉÎÁ ÓÔÏÌÂÃÁ '%-.64s' (ÍÁËÓÉÍÕÍ = %d). éÓÐÏÌØÚÕÊÔÅ ÔÉÐ BLOB ×ÍÅÓÔÏ ÔÅËÕÝÅÇÏ",
"îÅËÏÒÒÅËÔÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ: ÍÏÖÅÔ ÓÕÝÅÓÔ×Ï×ÁÔØ ÔÏÌØËÏ ÏÄÉÎ Á×ÔÏÉÎËÒÅÍÅÎÔÎÙÊ ÓÔÏÌÂÅÃ, É ÏÎ ÄÏÌÖÅÎ ÂÙÔØ ÏÐÒÅÄÅÌÅÎ ËÁË ËÌÀÞ",
-"%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d\n",
+"%s: çÏÔÏ× ÐÒÉÎÉÍÁÔØ ÓÏÅÄÉÎÅÎÉÑ.\n÷ÅÒÓÉÑ: '%s' ÓÏËÅÔ: '%s' ÐÏÒÔ: %d",
"%s: ëÏÒÒÅËÔÎÁÑ ÏÓÔÁÎÏ×ËÁ\n",
"%s: ðÏÌÕÞÅÎ ÓÉÇÎÁÌ %d. ðÒÅËÒÁÝÁÅÍ!\n",
"%s: ïÓÔÁÎÏ×ËÁ ÚÁ×ÅÒÛÅÎÁ\n",
@@ -306,7 +322,8 @@ character-set=koi8r
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 4039268f446..b1fa4d86b54 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -310,7 +310,8 @@ character-set=cp1250
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 9be5ce01d6a..9570ba1fef6 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
/*
Translated from both E n g l i s h & C z e c h error messages
@@ -87,7 +100,7 @@ character-set=latin2
"Blob pole '%-.64s' nemô¾e by» pou¾ité ako kµúè",
"Príli¹ veµká då¾ka pre pole '%-.64s' (maximum = %d). Pou¾ite BLOB",
"Mô¾ete ma» iba jedno AUTO pole a to musí by» definované ako kµúè",
-"%s: pripravený na spojenie\n",
+"%s: pripravený na spojenie",
"%s: normálne ukonèenie\n",
"%s: prijatý signál %d, ukonèenie (Abort)!\n",
"%s: práca ukonèená\n",
@@ -312,7 +325,8 @@ character-set=latin2
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index dc15f8b8d5e..4058fcc7c4e 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -1,5 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind
+/* 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.
+
+ 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 */
+
+/*
Traduccion por Miguel Angel Fernandez Roiz -- LoboCom Sistemas, s.l.
From June 28, 2001 translated by Miguel Solorzano miguel@mysql.com */
@@ -81,7 +96,7 @@ character-set=latin1
"La columna Blob '%-.64s' no puede ser usada en una declaracion de clave",
"Longitud de columna demasiado grande para la columna '%-.64s' (maximo = %d).Usar BLOB en su lugar",
"Puede ser solamente un campo automatico y este debe ser definido como una clave",
-"%s: preparado para conexiones\n",
+"%s: preparado para conexiones",
"%s: Apagado normal\n",
"%s: Recibiendo signal %d. Abortando!\n",
"%s: Apagado completado\n",
@@ -306,7 +321,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/swedish/errmsg.OLD b/sql/share/swedish/errmsg.OLD
deleted file mode 100644
index 3dd14c8b613..00000000000
--- a/sql/share/swedish/errmsg.OLD
+++ /dev/null
@@ -1,221 +0,0 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
-
-"hashchk",
-"isamchk",
-"NO",
-"YES",
-"Kan inte skapa filen: '%-.64s' (Felkod: %d)",
-"Kan inte skapa tabellen: '%-.64s' (Felkod: %d)",
-"Kan inte skapa databasen '%-.64s'. (Felkod: %d)",
-"Databasen '%-.64s' existerar redan",
-"Kan inte radera databasen '%-.64s'. Databasen finns inte",
-"Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)",
-"Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)",
-"Kan inte radera filen: '%-.64s' (Felkod: %d)",
-"Hittar inte posten i systemregistret",
-"Kan inte läsa filinformationen (stat) från '%-.64s' (Felkod: %d)",
-"Kan inte inte läsa aktivt bibliotek. (Felkod: %d)",
-"Kan inte låsa filen. (Felkod: %d)",
-"Kan inte använda: '%-.64s'. (Felkod: %d)",
-"Hittar inte filen: '%-.64s'. (Felkod: %d)",
-"Kan inte läsa från bibliotek '%-.64s'. (Felkod: %d)",
-"Kan inte byta till: '%-.64s'. (Felkod: %d)",
-"Posten har förändrats sedan den lästes i register '%-.64s'",
-"Disken är full (%s). Väntar tills det finns ledigt utrymme....",
-"Kan inte skriva, dubbel söknyckel i register '%-.64s'",
-"Fick fel vid stängning av '%-.64s' (Felkod: %d)",
-"Fick fel vid läsning av '%-.64s' (Felkod %d)",
-"Kan inte byta namn från '%-.64s' till '%-.64s' (Felkod: %d)",
-"Fick fel vid skrivning till '%-.64s' (Felkod %d)",
-"'%-.64s' är låst mot användning",
-"Sorteringen avbruten",
-"Formulär '%-.64s' finns inte i '%-.64s'",
-"Fick felkod %d från databashanteraren",
-"Registrets databas har inte denna facilitet",
-"Hittar inte posten",
-"Felaktig fil: '%-.64s'",
-"Fatalt fel vid hantering av register '%-.64s'. Kör en reparation",
-"Gammal nyckelfil '%-.64s'; Reparera registret",
-"'%-.64s' är skyddad mot förändring",
-"Oväntat slut på minnet, starta om programmet och försök på nytt (Behövde %d bytes)",
-"Sorteringsbufferten räcker inte till. Kontrollera startparametrarna",
-"Oväntat filslut vid läsning från '%-.64s' (Felkod: %d)",
-"För många anslutningar",
-"Fick slut på minnet. Kontrollera ifall mysqld eller någon annan process använder allt tillgängligt minne. Ifall inte, försök använda 'ulimit' eller allokera mera swap",
-"Kan inte hitta 'hostname' för din adress",
-"Fel vid initiering av kommunikationen med klienten",
-"Användare '%-.32s@%-.64s' är ej berättigad att använda databasen %-.64s",
-"Användare '%-.32s@%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
-"Ingen databas i användning",
-"Okänt commando",
-"Kolumn '%-.64s' får inte vara NULL",
-"Okänd database '%-.64s'",
-"Tabellen '%-.64s' finns redan",
-"Okänd tabell '%-.64s'",
-"Kolumn: '%-.64s' i %s är inte unik",
-"Servern går nu ned",
-"Okänd kolumn '%-.64s' i %s",
-"'%-.64s' finns inte i GROUP BY",
-"Kan inte använda GROUP BY med '%-.64s'",
-"Kommandot har både sum functions och enkla funktioner",
-"Antalet kolumner motsvarar inte antalet värden",
-"Kolumn namn '%-.64s' är för långt",
-"Kolumn namn '%-64s finns flera gånger",
-"Nyckel namn '%-.64s' finns flera gånger",
-"Dubbel nyckel '%-.64s' för nyckel: %d",
-"Felaktigt kolumn typ för kolumn: '%-.64s'",
-"%s nära '%-.64s' på rad %d",
-"Frågan var tom",
-"Icke unikt tabell/alias: '%-.64s'",
-"Ogiltigt DEFAULT värde för '%-.64s'",
-"Flera PRIMARY KEY använda",
-"För många nycklar använda. Man får ha högst %d nycklar",
-"För många nyckel delar använda. Man får ha högst %d nyckeldelar",
-"För lång nyckel. Högsta tillåtna nyckellängd är %d",
-"Nyckel kolumn '%-.64s' finns inte",
-"En BLOB '%-.64s' kan inte vara nyckel med den använda tabellen typen",
-"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället",
-"Det får finnas endast ett AUTO_INCREMENT fält och detta måste vara en nyckel",
-"%s: klar att ta emot klienter\n",
-"%s: Normal avslutning\n",
-"%s: Fick signal %d. Avslutar!\n",
-"%s: Avslutning klar\n",
-"%s: Stänger av tråd %ld användare: '%-.64s'\n",
-"Kan inte skapa IP socket",
-"Tabellen '%-.64s' har inget index som motsvarar det angivna i CREATE INDEX. Skapa om tabellen",
-"Fält separatorerna är inte emotsägande eller för långa. Kontrollera mot manualen",
-"Man kan inte använda fast radlängd med blobs. Använd 'fields terminated by'."
-"Textfilen '%' måste finnas i databas biblioteket eller vara läsbar för alla",
-"Filen '%-.64s' existerar redan",
-"Rader: %ld Bortagna: %ld Dubletter: %ld Varningar: %ld",
-"Rader: %ld Dubletter: %ld",
-"Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden",
-"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
-"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
-"Rader: %ld Dubletter: %ld Varningar: %ld",
-"INSERT table '%-.64s' får inte finnas i FROM tabell-listan",
-"Finns inget thread med id %lu",
-"Du är inte ägare till thread %lu",
-"Inga tabeller angivna",
-"För många alternativ till kolumn %s för SET",
-"Kan inte generera ett unikt filnamn %s.(1-999)\n",
-"Tabell '%-.64s' kan inte uppdateras emedan den är låst för läsning",
-"Tabell '%-.64s' är inte låst med LOCK TABLES",
-"BLOB fält '%-.64s' kan inte ha ett DEFAULT värde"
-"Felaktigt databas namn '%-.64s'",
-"Felaktigt tabell namn '%-.64s'",
-"Den angivna frågan skulle troligen ta mycket long tid! Kontrollar din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins",
-"Oidentifierat fel",
-"Okänd procedur: %s",
-"Felaktigt antal parametrar till procedur %s",
-"Felaktiga parametrar till procedur %s",
-"Okänd tabell '%-.64s' i '%-.64s'",
-"Fält '%-.64s' är redan använt",
-"Felaktig användning av SQL grupp function",
-"Tabell '%-.64s' har en extension som inte finns i denna version av MySQL",
-"Tabeller måste ha minst 1 kolumn",
-"Tabellen '%-.64s' är full",
-"Okänt karaktärset: '%-.64s'",
-"För många tabeller. MySQL can ha högst %d tabeller i en och samma join"
-"För många fält",
-"För stor total rad längd. Den högst tillåtna rad-längden, förutom BLOBs, är %d. Ändra några av dina fält till BLOB",
-"Tråd-stacken tog slut: Har använt %ld av %ld bytes. Använd 'mysqld -O thread_stack=#' ifall du behöver en större stack",
-"Felaktigt referens i OUTER JOIN. Kontrollera ON uttrycket",
-"Kolumn '%-.32s' är använd med UNIQUE eller INDEX men är inte definerad med NOT NULL",
-"Kan inte ladda funktionen '%-.64s'",
-"Kan inte initialisera funktionen '%-.64s'; '%-.80s'",
-"Man får inte ange sökväg för dynamiska bibliotek",
-"Funktionen '%-.64s' finns redan",
-"Kan inte öppna det dynamiska biblioteket '%-.64s' (Felkod: %d %s)",
-"Hittar inte funktionen '%-.64s' in det dynamiska biblioteket",
-"Funktionen '%-.64s' är inte definierad",
-"Denna dator '%-.64s' är blockerad pga många felaktig paket. Gör 'mysqladmin flush-hosts' för att ta bort alla blockeringarna",
-"Denna dator '%-.64s' har inte privileger att använda denna MySQL server",
-"Du använder MySQL som en anonym användare och som sådan får du inte ändra ditt lösenord",
-"För att ändra lösenord för andra måste du ha rättigheter att uppdatera mysql databasen",
-"Hittade inte användaren i 'user' tabellen",
-"Rader: %ld Uppdaterade: %ld Varningar: %ld",
-"Kan inte skapa en ny tråd (errno %d)"
-"Antalet kolumner motsvarar inte antalet värden på rad: %ld",
-"Kunde inte stänga och öppna tabell: '%-.64s',
-"Felaktig använding av NULL",
-"Fix fel '%-.64s' från REGEXP",
-"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",
-"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s@%-.64s' för tabell '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s@%-.64s'\n för kolumn '%-.64s' i tabell '%-.64s'",
-"Felaktigt GRANT privilegium använt",
-"Felaktigt maskinnamn eller användarnamn använt med GRANT",
-"Det finns ingen tabell som heter '%-64s.%s'"
-"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s' för tabell '%-.64s'",
-"Du kan inte använda detta kommando med denna MySQL version",
-"Du har något fel i din syntax",
-"DELAYED INSERT tråden kunde inte låsa tabell '%-.64s'",
-"Det finns redan 'max_delayed_threads' trådar i använding",
-"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.64s' (%s)",
-"Kommunkationspaketet är större än 'max_allowed_packet'",
-"Fick läsfel från klienten vid läsning från 'PIPE'",
-"Fick fatalt fel från 'fcntl()'",
-"Kommunikationspaketen kom i fel ordning",
-"Kunde inte packa up kommunikationspaketet",
-"Fick ett fel vid läsning från klienten",
-"Fick 'timeout' vid läsning från klienten",
-"Fick ett fel vid skrivning till klienten",
-"Fick 'timeout' vid skrivning till klienten",
-"Resultat strängen är längre än max_allowed_packet",
-"Den använda tabell typen kan inte hantera BLOB/TEXT kolumner",
-"Den använda tabell typen kan inte hantera AUTO_INCREMENT kolumner",
-"INSERT DELAYED kan inte användas med tabell '%-.64s', emedan den är låst med LOCK TABLES",
-"Felaktigt column namn '%-.100s'",
-"Den använda tabell typen kan inte indexera kolumn '%-.64s'",
-"Tabellerna i MERGE tabellen är inte identiskt definierade",
-"Kan inte skriva till tabell '%-.64s'; UNIQUE test",
-"Du har inte angett en nyckel längd för BLOB '%-.64s'",
-"Alla delar av en PRIMARY KEY måste vara NOT NULL; Om du vill ha en nyckel med NULL, använd UNIQUE istället",
-"Resultet bestod av mera än en rad",
-"Denna tabell typ kräver en PRIMARY KEY",
-"Denna version av MySQL är inte kompilerad med RAID",
-"Du använder 'säker uppdaterings mod' och försökte uppdatera en table utan en WHERE sats som använder sig av en nyckel",
-"Nyckel '%-.64s' finns inte in tabell '%-.64s'",
-"Kan inte öppna tabellen",
-"Tabellhanteraren för denna tabell kan inte göra check/repair",
-"Du får inte utföra detta kommando i en transaktion",
-"Fick fel %d vid COMMIT",
-"Fick fel %d vid ROLLBACK",
-"Fick fel %d vid FLUSH_LOGS",
-"Fick fel %d vid CHECKPOINT",
-"Avbröt länken för tråd %ld till db: '%-.64s' användare: '%-.32s' Host: '%-.64s' (%.-64s)",
-"Tabellhanteraren klarar inte en binär kopiering av tabellen",
-"Binärloggen stängdes medan vi gjorde FLUSH MASTER",
-"Failed rebuilding the index of dumped table '%-.64s'",
-"Fick en master: '%-.64s'",
-"Fick nätverksfel vid läsning från master",
-"Fick nätverksfel vid skrivning till master",
-"Hittar inte ett FULLTEXT index i kolumnlistan",
-"Kan inte exekvera kommandot emedan du har en låst tabell eller an aktiv transaktion",
-"Okänd system variabel '%-.64'",
-"Tabell '%-.64s' är crashad och bör repareras med REPAIR TABLE",
-"Tabell '%-.64s' är crashad och senast (automatiska?) reparation misslyckades",
-"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK",
-"Transaktionen krävde mera än 'max_binlog_cache_size' minne. Utöka denna mysqld variabel och försök på nytt",
-"Denna operation kan inte göras under replikering; Gör SLAVE STOP först",
-"Denna operation kan endast göras under replikering; Konfigurera slaven och gör SLAVE START",
-"Servern är inte konfigurerade som en replikations slav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO",
-"Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'",
-"Kunde inte starta en tråd för replikering",
-"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
-"Man kan endast använda konstant-uttryck med SET",
-"Fick inte ett lås i tid",
-"Antal lås överskrider antalet reserverade lås",
-"Updaterings-lås kan inte göras när man använder READ UNCOMMITTED",
-"DROP DATABASE är inte tillåtet när man har ett globalt läs-lås",
-"CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås",
-"Felaktiga argument till %s",
-"%-.32s@%-.64s har inte rättigheter att skapa nya användare",
-"Fick fel vid anslutning till master: %-.128s",
-"Fick fel vid utförande av command på mastern: %-.128s",
-"Fick fel vid utförande av %s: %-.128s",
-"Felaktig använding av %s and %s",
-"SELECT kommandona har olika antal kolumner"
-"Kan inte utföra kommandot emedan du har ett READ lås",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index ee5436c3b80..e03af70d03c 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -1,5 +1,18 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- This file is public domain and comes with NO WARRANTY of any kind */
+/* 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.
+
+ 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 */
character-set=latin1
@@ -79,7 +92,7 @@ character-set=latin1
"En BLOB '%-.64s' kan inte vara nyckel med den använda tabelltypen",
"För stor kolumnlängd angiven för '%-.64s' (max= %d). Använd en BLOB instället",
"Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel",
-"%s: klar att ta emot klienter\n",
+"%s: klar att ta emot klienter",
"%s: Normal avslutning\n",
"%s: Fick signal %d. Avslutar!\n",
"%s: Avslutning klar\n",
@@ -304,7 +317,8 @@ character-set=latin1
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index cb1d99e2fec..a919422a6cf 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -1,6 +1,20 @@
-/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
- * This ÆÁÊÌ is public domain and comes with NO WARRANTY of any kind
- *
+/* 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.
+
+ 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 */
+
+/*
* Ukrainian translation by Roman Festchook <roma@orta.zt.ua>
* Encoding: KOI8-U
* Version: 13/09/2001 mysql-3.23.41
@@ -84,7 +98,7 @@ character-set=koi8u
"BLOB ÓÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÒÉÓÔÁÎÉÊ Õ ×ÉÚÎÁÞÅÎΦ ËÌÀÞÁ × ÃØÏÍÕ ÔÉЦ ÔÁÂÌÉæ",
"úÁÄÏ×ÇÁ ÄÏ×ÖÉÎÁ ÓÔÏ×ÂÃÑ '%-.64s' (max = %d). ÷ÉËÏÒÉÓÔÁÊÔÅ ÔÉÐ BLOB",
"îÅצÒÎÅ ×ÉÚÎÁÞÅÎÎÑ ÔÁÂÌÉæ; íÏÖÅ ÂÕÔÉ ÌÉÛÅ ÏÄÉÎ Á×ÔÏÍÁÔÉÞÎÉÊ ÓÔÏ×ÂÅÃØ, ÝÏ ÐÏ×ÉÎÅÎ ÂÕÔÉ ×ÉÚÎÁÞÅÎÉÊ ÑË ËÌÀÞ",
-"%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!\n",
+"%s: çÏÔÏ×ÉÊ ÄÌÑ Ú'¤ÄÎÁÎØ!",
"%s: îÏÒÍÁÌØÎÅ ÚÁ×ÅÒÛÅÎÎÑ\n",
"%s: ïÔÒÉÍÁÎÏ ÓÉÇÎÁÌ %d. ðÅÒÅÒÉ×ÁÀÓØ!\n",
"%s: òÏÂÏÔÕ ÚÁ×ÅÒÛÅÎÏ\n",
@@ -309,7 +323,8 @@ character-set=koi8u
"Unknown or incorrect time zone: '%-.64s'",
"Invalid TIMESTAMP value in column '%s' at row %ld",
"Invalid %s character string: '%.64s'",
-"Result of %s() was larger than max_allowed_packet (%d) - truncated"
+"Result of %s() was larger than max_allowed_packet (%ld) - truncated"
+"Conflicting declarations: '%s%s' and '%s%s'"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
diff --git a/sql/slave.cc b/sql/slave.cc
index 0defbe35163..d7b60107096 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -749,7 +749,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
pthread_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_THREAD);
}
- if (start_cond && cond_lock)
+ if (start_cond && cond_lock) // caller has cond_lock
{
THD* thd = current_thd;
while (start_id == *slave_run_id)
@@ -759,11 +759,9 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
"Waiting for slave thread to start");
pthread_cond_wait(start_cond,cond_lock);
thd->exit_cond(old_msg);
+ pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
if (thd->killed)
- {
- pthread_mutex_unlock(cond_lock);
DBUG_RETURN(thd->killed_errno());
- }
}
}
if (start_lock)
@@ -1424,6 +1422,12 @@ not always make sense; please check the manual before using it).";
/*
Check that the master's global character_set_server and ours are the same.
Not fatal if query fails (old master?).
+ Note that we don't check for equality of global character_set_client and
+ collation_connection (neither do we prevent their setting in
+ set_var.cc). That's because from what I (Guilhem) have tested, the global
+ values of these 2 are never used (new connections don't use them).
+ We don't test equality of global collation_database either as it's is
+ going to be deprecated (made read-only) in 4.1 very soon.
*/
if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
(master_res= mysql_store_result(mysql)))
@@ -1897,7 +1901,6 @@ Waiting for the slave SQL thread to free enough relay log space");
!rli->ignore_log_space_limit)
pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
thd->exit_cond(save_proc_info);
- pthread_mutex_unlock(&rli->log_space_lock);
DBUG_RETURN(slave_killed);
}
@@ -2574,6 +2577,9 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
(long) timeout));
pthread_mutex_lock(&data_lock);
+ const char *msg= thd->enter_cond(&data_cond, &data_lock,
+ "Waiting for the slave SQL thread to "
+ "advance position");
/*
This function will abort when it notices that some CHANGE MASTER or
RESET MASTER has changed the master info.
@@ -2675,9 +2681,6 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
//wait for master update, with optional timeout.
DBUG_PRINT("info",("Waiting for master update"));
- const char* msg = thd->enter_cond(&data_cond, &data_lock,
- "Waiting for the slave SQL thread to \
-advance position");
/*
We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
will wake us up.
@@ -2699,8 +2702,7 @@ advance position");
}
else
pthread_cond_wait(&data_cond, &data_lock);
- DBUG_PRINT("info",("Got signal of master update"));
- thd->exit_cond(msg);
+ DBUG_PRINT("info",("Got signal of master update or timed out"));
if (error == ETIMEDOUT || error == ETIME)
{
error= -1;
@@ -2712,7 +2714,7 @@ advance position");
}
err:
- pthread_mutex_unlock(&data_lock);
+ thd->exit_cond(msg);
DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
improper_arguments: %d timed_out: %d",
thd->killed_errno(),
@@ -3305,6 +3307,9 @@ dump");
}
thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
+#ifdef SIGNAL_WITH_VIO_CLOSE
+ thd->clear_active_vio();
+#endif
end_server(mysql);
/*
First time retry immediately, assuming that we can recover
@@ -3378,6 +3383,9 @@ max_allowed_packet",
goto err;
}
thd->proc_info = "Waiting to reconnect after a failed master event read";
+#ifdef SIGNAL_WITH_VIO_CLOSE
+ thd->clear_active_vio();
+#endif
end_server(mysql);
if (retry_count++)
{
@@ -4825,4 +4833,5 @@ template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
#endif
+
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0a970640e32..e7b4772c3ab 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -251,9 +251,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
global_system_variables.old_passwords= 1;
pthread_mutex_unlock(&LOCK_global_system_variables);
- sql_print_error("mysql.user table is not updated to new password format; "
- "Disabling new password usage until "
- "mysql_fix_privilege_tables is run");
+ sql_print_warning("mysql.user table is not updated to new password format; "
+ "Disabling new password usage until "
+ "mysql_fix_privilege_tables is run");
}
thd->variables.old_passwords= 1;
}
@@ -543,22 +543,28 @@ static ulong get_sort(uint count,...)
va_start(args,count);
ulong sort=0;
+ /* Should not use this function with more than 4 arguments for compare. */
+ DBUG_ASSERT(count <= 4);
+
while (count--)
{
- char *str=va_arg(args,char*);
- uint chars=0,wild=0;
+ char *start, *str= va_arg(args,char*);
+ uint chars= 0;
+ uint wild_pos= 0; /* first wildcard position */
- if (str)
+ if ((start= str))
{
for (; *str ; str++)
{
if (*str == wild_many || *str == wild_one || *str == wild_prefix)
- wild++;
- else
- chars++;
+ {
+ wild_pos= (uint) (str - start) + 1;
+ break;
+ }
+ chars= 128; // Marker that chars existed
}
}
- sort= (sort << 8) + (wild ? 1 : chars ? 2 : 0);
+ sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars);
}
va_end(args);
return sort;
@@ -1208,13 +1214,14 @@ bool acl_check_host(const char *host, const char *ip)
1 ERROR ; In this case the error is sent to the client.
*/
-bool check_change_password(THD *thd, const char *host, const char *user)
+bool check_change_password(THD *thd, const char *host, const char *user,
+ char *new_password)
{
if (!initialized)
{
net_printf(thd,ER_OPTION_PREVENTS_STATEMENT,
- "--skip-grant-tables"); /* purecov: inspected */
- return(1); /* purecov: inspected */
+ "--skip-grant-tables");
+ return(1);
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
@@ -1228,6 +1235,15 @@ bool check_change_password(THD *thd, const char *host, const char *user)
send_error(thd, ER_PASSWORD_ANONYMOUS_USER);
return(1);
}
+ uint len=strlen(new_password);
+ if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
+ len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ {
+ net_printf(thd, 0,
+ "Password hash should be a %d-digit hexadecimal number",
+ SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ return -1;
+ }
return(0);
}
@@ -1255,7 +1271,7 @@ bool change_password(THD *thd, const char *host, const char *user,
host,user,new_password));
DBUG_ASSERT(host != 0); // Ensured by parent
- if (check_change_password(thd, host, user))
+ if (check_change_password(thd, host, user, new_password))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -1513,7 +1529,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
- my_printf_error(ER_PASSWORD_NO_MATCH,
+ my_printf_error(ER_UNKNOWN_ERROR,
"Password hash should be a %d-digit hexadecimal number",
MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
DBUG_RETURN(-1);
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 77702cc375a..390106c1546 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -154,7 +154,8 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
uint passwd_len);
int acl_getroot_no_password(THD *thd);
bool acl_check_host(const char *host, const char *ip);
-bool check_change_password(THD *thd, const char *host, const char *user);
+bool check_change_password(THD *thd, const char *host, const char *user,
+ char *password);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
int mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 68f7d45e81c..3f75dadb6f0 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -34,9 +34,6 @@
#define MAX_TREEMEM 8192
#define MAX_TREE_ELEMENTS 256
-#define UINT_MAX16 0xffff
-#define UINT_MAX24 0xffffff
-#define UINT_MAX32 0xffffffff
int sortcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 61cbe432909..0aee91af0da 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1719,6 +1719,26 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
uint counter;
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(thd->net.report_error ? -1 : 1); /* purecov: inspected */
+ /*
+ Let us propagate pointers to open tables from global table list
+ to table lists in particular selects if needed.
+ */
+ if (thd->lex->all_selects_list->next_select_in_list() ||
+ thd->lex->time_zone_tables_used)
+ {
+ for (SELECT_LEX *sl= thd->lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ {
+ if (cursor->table_list)
+ cursor->table= cursor->table_list->table;
+ }
+ }
+ }
DBUG_RETURN(mysql_handle_derived(thd->lex));
}
@@ -1929,7 +1949,9 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
else
{
Item_arena *arena= thd->current_arena, backup;
- if (arena)
+ if (!arena->is_stmt_prepare())
+ arena= 0;
+ else
thd->set_n_backup_item_arena(arena, &backup);
*ref= new Item_ref(trans + i, 0, table_list->view_name.str,
item_name);
@@ -2261,10 +2283,12 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
- Item **found=0,*item;
+ Item **found=0, **found_unaliased= 0, *item;
const char *db_name=0;
const char *field_name=0;
const char *table_name=0;
+ bool found_unaliased_non_uniq= 0;
+ uint unaliased_counter;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
{
field_name= ((Item_ident*) find)->field_name;
@@ -2277,42 +2301,93 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (field_name && item->type() == Item::FIELD_ITEM)
{
Item_field *item_field= (Item_field*) item;
+
/*
In case of group_concat() with ORDER BY condition in the QUERY
item_field can be field of temporary table without item name
(if this field created from expression argument of group_concat()),
=> we have to check presence of name before compare
*/
- if (item_field->name &&
- (!my_strcasecmp(system_charset_info, item_field->name, field_name) ||
- !my_strcasecmp(system_charset_info,
- item_field->field_name, field_name)))
+ if (!item_field->name)
+ continue;
+
+ if (table_name)
{
- if (!table_name)
- {
- if (found)
- {
- if ((*found)->eq(item,0))
- continue; // Same field twice (Access?)
- if (report_error != IGNORE_ERRORS)
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- find->full_name(), current_thd->where);
- return (Item**) 0;
- }
- found= li.ref();
- *counter= i;
- }
- else
- {
- if (!strcmp(item_field->table_name,table_name) &&
- (!db_name || (db_name && item_field->db_name &&
- !strcmp(item_field->db_name, db_name))))
- {
- found= li.ref();
- *counter= i;
- break;
- }
- }
+ /*
+ If table name is specified we should find field 'field_name' in
+ table 'table_name'. According to SQL-standard we should ignore
+ aliases in this case. Note that we should prefer fields from the
+ select list over other fields from the tables participating in
+ this select in case of ambiguity.
+
+ We use strcmp for table names and database names as these may be
+ case sensitive.
+ In cases where they are not case sensitive, they are always in lower
+ case.
+ */
+ if (!my_strcasecmp(system_charset_info, item_field->field_name,
+ field_name) &&
+ !strcmp(item_field->table_name, table_name) &&
+ (!db_name || (item_field->db_name &&
+ !strcmp(item_field->db_name, db_name))))
+ {
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
+ MYF(0), find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ 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_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
+ MYF(0), find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ }
+ else if (!my_strcasecmp(system_charset_info, item_field->field_name,
+ field_name))
+ {
+ /*
+ 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)
+ {
+ if ((*found_unaliased)->eq(item, 0))
+ continue; // Same field twice
+ found_unaliased_non_uniq= 1;
+ }
+ else
+ {
+ found_unaliased= li.ref();
+ unaliased_counter= i;
+ }
}
}
else if (!table_name && (item->eq(find,0) ||
@@ -2325,9 +2400,24 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
break;
}
}
+ if (!found)
+ {
+ if (found_unaliased_non_uniq)
+ {
+ if (report_error != IGNORE_ERRORS)
+ my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR), MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item **) 0;
+ }
+ if (found_unaliased)
+ {
+ found= found_unaliased;
+ *counter= unaliased_counter;
+ }
+ }
if (found)
return found;
- else if (report_error != REPORT_EXCEPT_NOT_FOUND)
+ if (report_error != REPORT_EXCEPT_NOT_FOUND)
{
if (report_error == REPORT_ALL_ERRORS)
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
@@ -2346,9 +2436,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
+ Item *item;
if (!wild_num)
return 0;
Item_arena *arena= thd->current_arena, backup;
+ if (!arena->is_stmt_prepare())
+ arena= 0; // For easier test
/*
If we are in preparing prepared statement phase then we have change
@@ -2356,9 +2449,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
- reg2 Item *item;
+
List_iterator<Item> it(fields);
- while ( wild_num && (item= it++))
+ while (wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*' &&
@@ -2580,8 +2673,21 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
Field_iterator_table table_iter;
Field_iterator_view view_iter;
uint found;
+ char name_buff[NAME_LEN+1];
DBUG_ENTER("insert_fields");
+ if (db_name && lower_case_table_names)
+ {
+ /*
+ convert database to lower case for comparison
+ We can't do this in Item_field as this would change the
+ 'name' of the item which may be used in the select list
+ */
+ strmake(name_buff, db_name, sizeof(name_buff)-1);
+ my_casedn_str(files_charset_info, name_buff);
+ db_name= name_buff;
+ }
+
found= 0;
for (; tables; tables= tables->next_local)
{
@@ -2721,7 +2827,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
field->query_id=thd->query_id;
table->used_keys.intersect(field->part_of_key);
}
- else if (thd->current_arena &&
+ else if (thd->current_arena->is_stmt_prepare() &&
thd->lex->current_select->first_execution)
{
Item_field *item= new Item_field(thd->strdup(tables->view_db.str),
@@ -2761,13 +2867,14 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table_map not_null_tables= 0;
SELECT_LEX *select_lex= thd->lex->current_select;
- Item_arena *arena= ((thd->current_arena &&
- !select_lex->conds_processed_with_permanent_arena) ?
- thd->current_arena :
- 0);
+ Item_arena *arena= thd->current_arena;
Item_arena backup;
DBUG_ENTER("setup_conds");
+ if (select_lex->conds_processed_with_permanent_arena ||
+ !arena->is_stmt_prepare())
+ arena= 0; // For easier test
+
thd->set_query_id=1;
select_lex->cond_count= 0;
@@ -2779,7 +2886,6 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(1);
}
-
/* Check if we are using outer joins */
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
@@ -2900,31 +3006,34 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// to prevent natural join processing during PS re-execution
embedding->natural_join= 0;
- COND *on_expr= cond_and;
- on_expr->fix_fields(thd, 0, &on_expr);
- if (!embedded->outer_join) // Not left join
- {
- *conds= and_conds(*conds, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (*conds && !(*conds)->fixed)
- {
- if ((*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
- }
- }
- else
+ if (cond_and->list.elements)
{
- embedded->on_expr= and_conds(embedded->on_expr, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (embedded->on_expr && !embedded->on_expr->fixed)
- {
- if (embedded->on_expr->fix_fields(thd, tables, &table->on_expr))
- DBUG_RETURN(1);
- }
+ COND *on_expr= cond_and;
+ on_expr->fix_fields(thd, 0, &on_expr);
+ if (!embedded->outer_join) // Not left join
+ {
+ *conds= and_conds(*conds, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (*conds && !(*conds)->fixed)
+ {
+ if ((*conds)->fix_fields(thd, tables, conds))
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ embedded->on_expr= and_conds(embedded->on_expr, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (embedded->on_expr && !embedded->on_expr->fixed)
+ {
+ if (embedded->on_expr->fix_fields(thd, tables, &table->on_expr))
+ DBUG_RETURN(1);
+ }
+ }
}
}
embedding= embedded->embedding;
@@ -2972,7 +3081,7 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
Field *rfield= field->field;
TABLE *table= rfield->table;
if (rfield == table->next_number_field)
- table->auto_increment_field_not_null= true;
+ table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
DBUG_RETURN(1);
}
@@ -2993,7 +3102,7 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
value=v++;
TABLE *table= field->table;
if (field == table->next_number_field)
- table->auto_increment_field_not_null= true;
+ table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(field, 0) < 0) && !ignore_errors)
DBUG_RETURN(1);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index da64479abf2..456b58ee95e 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -158,12 +158,13 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
-THD::THD():user_time(0), current_arena(0), is_fatal_error(0),
- last_insert_id_used(0),
- insert_id_used(0), rand_used(0), time_zone_used(0),
- in_lock_tables(0), global_read_lock(0), bootstrap(0),
- spcont(NULL)
+THD::THD()
+ :user_time(0), global_read_lock(0), is_fatal_error(0),
+ last_insert_id_used(0),
+ insert_id_used(0), rand_used(0), time_zone_used(0),
+ in_lock_tables(0), bootstrap(0), spcont(NULL)
{
+ current_arena= this;
host= user= priv_user= db= ip= 0;
catalog= (char*)"std"; // the only catalog we have for now
host_or_ip= "connecting host";
@@ -450,8 +451,21 @@ void THD::awake(THD::killed_state state_to_set)
exits the cond in the time between read and broadcast, but that is
ok since all we want to do is to make the victim thread get out
of waiting on current_cond.
+ If we see a non-zero current_cond: it cannot be an old value (because
+ then exit_cond() should have run and it can't because we have mutex); so
+ it is the true value but maybe current_mutex is not yet non-zero (we're
+ in the middle of enter_cond() and there is a "memory order
+ inversion"). So we test the mutex too to not lock 0.
+
+ Note that there is a small chance we fail to kill. If victim has locked
+ current_mutex, but hasn't yet entered enter_cond() (which means that
+ current_cond and current_mutex are 0), then the victim will not get
+ a signal and it may wait "forever" on the cond (until
+ we issue a second KILL or the status it's waiting for happens).
+ It's true that we have set its thd->killed but it may not
+ see it immediately and so may have time to reach the cond_wait().
*/
- if (mysys_var->current_cond)
+ if (mysys_var->current_cond && mysys_var->current_mutex)
{
pthread_mutex_lock(mysys_var->current_mutex);
pthread_cond_broadcast(mysys_var->current_cond);
@@ -710,6 +724,12 @@ void select_result::send_error(uint errcode,const char *err)
::send_error(thd, errcode, err);
}
+
+void select_result::cleanup()
+{
+ /* do nothing */
+}
+
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);
@@ -815,6 +835,32 @@ void select_to_file::send_error(uint errcode,const char *err)
}
+bool select_to_file::send_eof()
+{
+ int error= test(end_io_cache(&cache));
+ if (my_close(file,MYF(MY_WME)))
+ error= 1;
+ if (!error)
+ ::send_ok(thd,row_count);
+ file= -1;
+ return error;
+}
+
+
+void select_to_file::cleanup()
+{
+ /* In case of error send_eof() may be not called: close the file here. */
+ if (file >= 0)
+ {
+ (void) end_io_cache(&cache);
+ (void) my_close(file,MYF(0));
+ file= -1;
+ }
+ path[0]= '\0';
+ row_count= 0;
+}
+
+
select_to_file::~select_to_file()
{
if (file >= 0)
@@ -860,8 +906,10 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|= MY_REPLACE_DIR; // Force use of db directory
#endif
- (void) fn_format(path, exchange->file_name, thd->db ? thd->db : "", "",
- option);
+
+ strxnmov(path, FN_REFLEN, mysql_real_data_home, thd->db ? thd->db : "",
+ NullS);
+ (void) fn_format(path, exchange->file_name, path, "", option);
if (!access(path, F_OK))
{
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
@@ -1065,18 +1113,6 @@ err:
}
-bool select_export::send_eof()
-{
- int error=test(end_io_cache(&cache));
- if (my_close(file,MYF(MY_WME)))
- error=1;
- if (!error)
- ::send_ok(thd,row_count);
- file= -1;
- return error;
-}
-
-
/***************************************************************************
** Dump of select to a binary file
***************************************************************************/
@@ -1130,18 +1166,6 @@ err:
}
-bool select_dump::send_eof()
-{
- int error=test(end_io_cache(&cache));
- if (my_close(file,MYF(MY_WME)))
- error=1;
- if (!error)
- ::send_ok(thd,row_count);
- file= -1;
- return error;
-}
-
-
select_subselect::select_subselect(Item_subselect *item_arg)
{
item= item_arg;
@@ -1316,8 +1340,16 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
+void select_dumpvar::cleanup()
+{
+ vars.empty();
+ row_count=0;
+}
+
+
Item_arena::Item_arena(THD* thd)
- :free_list(0)
+ :free_list(0),
+ state(INITIALIZED)
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
@@ -1325,18 +1357,28 @@ Item_arena::Item_arena(THD* thd)
}
+/* This constructor is called when Item_arena is a subobject of THD */
+
Item_arena::Item_arena()
- :free_list(0)
+ :free_list(0),
+ state(CONVENTIONAL_EXECUTION)
{
- bzero((char *) &mem_root, sizeof(mem_root));
+ clear_alloc_root(&mem_root);
}
Item_arena::Item_arena(bool init_mem_root)
- :free_list(0)
+ :free_list(0),
+ state(INITIALIZED)
{
if (init_mem_root)
- bzero((char *) &mem_root, sizeof(mem_root));
+ clear_alloc_root(&mem_root);
+}
+
+Item_arena::Type Item_arena::type() const
+{
+ DBUG_ASSERT(0); /* Should never be called */
+ return STATEMENT;
}
@@ -1380,7 +1422,7 @@ Statement::Statement()
}
-Statement::Type Statement::type() const
+Item_arena::Type Statement::type() const
{
return STATEMENT;
}
@@ -1398,6 +1440,36 @@ void Statement::set_statement(Statement *stmt)
}
+void
+Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
+{
+ backup->set_statement(this);
+ set_statement(stmt);
+}
+
+
+void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
+{
+ stmt->set_statement(this);
+ set_statement(backup);
+}
+
+
+void Statement::end_statement()
+{
+ /* Cleanup SQL processing state to resuse this statement in next query. */
+ lex_end(lex);
+ delete lex->result;
+ lex->result= 0;
+ free_items(free_list);
+ free_list= 0;
+ /*
+ Don't free mem_root, as mem_root is freed in the end of dispatch_command
+ (once for any command).
+ */
+}
+
+
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
{
backup->set_item_arena(this);
@@ -1417,6 +1489,7 @@ void Item_arena::set_item_arena(Item_arena *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
+ state= set->state;
}
Statement::~Statement()
@@ -1460,7 +1533,7 @@ Statement_map::Statement_map() :
hash_init(&st_hash, default_charset_info, START_STMT_HASH_SIZE, 0, 0,
get_statement_id_as_hash_key,
delete_statement_as_hash_key, MYF(0));
- hash_init(&names_hash, &my_charset_bin, START_NAME_HASH_SIZE, 0, 0,
+ hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
(hash_get_key) get_stmt_name_hash_key,
NULL,MYF(0));
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index eccaf072008..2b941b317f6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -454,12 +454,28 @@ public:
*/
Item *free_list;
MEM_ROOT mem_root;
+ enum enum_state
+ {
+ INITIALIZED= 0, PREPARED= 1, EXECUTED= 3, CONVENTIONAL_EXECUTION= 2,
+ ERROR= -1
+ };
+ enum_state state;
+
+ /* We build without RTTI, so dynamic_cast can't be used. */
+ enum Type
+ {
+ STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
+ };
+
Item_arena(THD *thd);
Item_arena();
Item_arena(bool init_mem_root);
- ~Item_arena();
+ virtual Type type() const;
+ virtual ~Item_arena();
+ inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; }
+ inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
@@ -549,12 +565,6 @@ public:
Cursor *cursor;
public:
- /* We build without RTTI, so dynamic_cast can't be used. */
- enum Type
- {
- STATEMENT,
- PREPARED_STATEMENT
- };
/*
This constructor is called when statement is a subobject of THD:
@@ -567,9 +577,16 @@ public:
/* Assign execution context (note: not all members) of given stmt to self */
void set_statement(Statement *stmt);
+ void set_n_backup_statement(Statement *stmt, Statement *backup);
+ void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
virtual Type type() const;
+ /*
+ Cleanup statement parse state (parse tree, lex) after execution of
+ a non-prepared SQL statement.
+ */
+ void end_statement();
};
@@ -862,7 +879,7 @@ public:
ulong row_count; // Row counter, mainly for errors and warnings
long dbug_thread_id;
pthread_t real_id;
- uint current_tablenr,tmp_table;
+ uint current_tablenr,tmp_table,global_read_lock;
uint server_status,open_options,system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
@@ -881,7 +898,7 @@ public:
bool no_errors, password, is_fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
bool time_zone_used;
- bool in_lock_tables,global_read_lock;
+ bool in_lock_tables;
bool query_error, bootstrap, cleanup_done;
enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
@@ -951,6 +968,12 @@ public:
void close_active_vio();
#endif
void awake(THD::killed_state state_to_set);
+ /*
+ For enter_cond() / exit_cond() to work the mutex must be got before
+ enter_cond() (in 4.1 an assertion will soon ensure this); this mutex is
+ then released by exit_cond(). Use must be:
+ lock mutex; enter_cond(); your code; exit_cond().
+ */
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
const char* msg)
{
@@ -962,6 +985,13 @@ public:
}
inline void exit_cond(const char* old_msg)
{
+ /*
+ Putting the mutex unlock in exit_cond() ensures that
+ mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
+ locked (if that would not be the case, you'll get a deadlock if someone
+ does a THD::awake() on you).
+ */
+ pthread_mutex_unlock(mysys_var->current_mutex);
pthread_mutex_lock(&mysys_var->mutex);
mysys_var->current_mutex = 0;
mysys_var->current_cond = 0;
@@ -1036,38 +1066,6 @@ public:
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
-
- inline void allocate_temporary_memory_pool_for_ps_preparing()
- {
- DBUG_ASSERT(current_arena!=0);
- /*
- We do not want to have in PS memory all that junk,
- which will be created by preparation => substitute memory
- from original thread pool.
-
- We know that PS memory pool is now copied to THD, we move it back
- to allow some code use it.
- */
- current_arena->set_item_arena(this);
- init_sql_alloc(&mem_root,
- variables.query_alloc_block_size,
- variables.query_prealloc_size);
- free_list= 0;
- }
- inline void free_temporary_memory_pool_for_ps_preparing()
- {
- DBUG_ASSERT(current_arena!=0);
- cleanup_items(current_arena->free_list);
- /* no need to reset free_list as it won't be used anymore */
- free_items(free_list);
- close_thread_tables(this); // to close derived tables
- free_root(&mem_root, MYF(0));
- set_item_arena(current_arena);
- }
- inline bool only_prepare()
- {
- return command == COM_PREPARE;
- }
};
/* Flags for the THD::system_thread (bitmap) variable */
@@ -1076,9 +1074,32 @@ public:
#define SYSTEM_THREAD_SLAVE_SQL 4
/*
+ Disables binary logging for one thread, and resets it back to what it was
+ before being disabled.
+ Some functions (like the internal mysql_create_table() when it's called by
+ mysql_alter_table()) must NOT write to the binlog (binlogging is done at the
+ at a later stage of the command already, and must be, for locking reasons);
+ so we internally disable it temporarily by creating the Disable_binlog
+ object and reset the state by destroying the object (don't forget that! or
+ write code so that the object gets automatically destroyed when leaving a
+ block, see example in sql_table.cc).
+*/
+class Disable_binlog {
+private:
+ THD *thd;
+ ulong save_options;
+public:
+ Disable_binlog(THD *thd_arg);
+ ~Disable_binlog();
+};
+
+
+/*
Used to hold information about file and file structure in exchainge
via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
+ XXX: We never call destructor for objects of this class.
*/
+
class sql_exchange :public Sql_alloc
{
public:
@@ -1088,7 +1109,6 @@ public:
bool dumpfile;
ulong skip_lines;
sql_exchange(char *name,bool dumpfile_flag);
- ~sql_exchange() {}
};
#include "log_event.h"
@@ -1119,6 +1139,11 @@ public:
virtual void send_error(uint errcode,const char *err);
virtual bool send_eof()=0;
virtual void abort() {}
+ /*
+ Cleanup instance of this class for next execution of a prepared
+ statement/stored procedure.
+ */
+ virtual void cleanup();
};
@@ -1145,6 +1170,8 @@ public:
~select_to_file();
bool send_fields(List<Item> &list, uint flags) { return 0; }
void send_error(uint errcode,const char *err);
+ bool send_eof();
+ void cleanup();
};
@@ -1157,7 +1184,6 @@ public:
~select_export();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
- bool send_eof();
};
@@ -1166,7 +1192,6 @@ public:
select_dump(sql_exchange *ex) :select_to_file(ex) {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
- bool send_eof();
};
@@ -1194,6 +1219,8 @@ class select_insert :public select_result {
bool send_data(List<Item> &items);
void send_error(uint errcode,const char *err);
bool send_eof();
+ /* not implemented: select_insert is never re-used in prepared statements */
+ void cleanup();
};
@@ -1520,4 +1547,5 @@ public:
bool send_fields(List<Item> &list, uint flags) { return 0; }
bool send_data(List<Item> &items);
bool send_eof();
+ void cleanup();
};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index dad39da271b..f41e03b0602 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -322,10 +322,17 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
{
if (!strncmp(buf,"default-character-set", (pos-buf)))
{
+ /*
+ Try character set name, and if it fails
+ try collation name, probably it's an old
+ 4.1.0 db.opt file, which didn't have
+ separate default-character-set and
+ default-collation commands.
+ */
if (!(create->default_table_charset=
- get_charset_by_csname(pos+1,
- MY_CS_PRIMARY,
- MYF(0))))
+ get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) &&
+ !(create->default_table_charset=
+ get_charset_by_name(pos+1, MYF(0))))
{
sql_print_error("Error while loading database options: '%s':",path);
sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
@@ -391,7 +398,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not create database if another thread is holding read lock
- if (wait_if_global_read_lock(thd,0))
+ if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
goto exit2;
@@ -492,7 +499,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not alter database if another thread is holding read lock
- if ((error=wait_if_global_read_lock(thd,0)))
+ if ((error=wait_if_global_read_lock(thd,0,1)))
goto exit2;
/* Check directory */
@@ -557,7 +564,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not drop database if another thread is holding read lock
- if (wait_if_global_read_lock(thd,0))
+ if (wait_if_global_read_lock(thd, 0, 1))
{
error= -1;
goto exit2;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d9d60be162a..05b2de8adfd 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -693,17 +693,13 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
int error;
DBUG_ENTER("mysql_truncate");
+ bzero((char*) &create_info,sizeof(create_info));
/* If it is a temporary table, close and regenerate it */
if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db,
table_list->real_name)))
{
TABLE *table= *table_ptr;
- HA_CREATE_INFO create_info;
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
- bzero((char*) &create_info,sizeof(create_info));
- create_info.auto_increment_value= table->file->auto_increment_value;
- create_info.default_table_charset= table->table_charset;
-
db_type table_type=table->db_type;
strmov(path,table->path);
*table_ptr= table->next; // Unlink table from list
@@ -745,8 +741,6 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
DBUG_RETURN(-1);
}
- bzero((char*) &create_info,sizeof(create_info));
-
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1) ? -1 : 0;
query_cache_invalidate3(thd, table_list, 0);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index b7940e2d9d0..0e4f803536d 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1627,6 +1627,13 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_RETURN(0);
}
+
+void select_insert::cleanup()
+{
+ /* select_insert/select_create are never re-used in prepared statement */
+ DBUG_ASSERT(0);
+}
+
select_insert::~select_insert()
{
if (table)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d650f696d14..b0707955522 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -24,6 +24,16 @@
#include "sp.h"
#include "sp_head.h"
+
+/*
+ Fake table list object, pointer to which is used as special value for
+ st_lex::time_zone_tables_used indicating that we implicitly use time
+ zone tables in this statement but real table list was not yet created.
+ Pointer to it is also returned by my_tz_get_tables_list() as indication
+ of transient error;
+*/
+TABLE_LIST fake_time_zone_tables_list;
+
/* Macros to look like lex */
#define yyGet() *(lex->ptr++)
@@ -1376,7 +1386,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
We have to create array in prepared statement memory if it is
prepared statement
*/
- Item_arena *arena= thd->current_arena ? thd->current_arena : thd;
+ Item_arena *arena= thd->current_arena;
return (ref_pointer_array=
(Item **)arena->alloc(sizeof(Item*) *
(item_list.elements +
@@ -1649,6 +1659,11 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
}
+st_lex::st_lex()
+ :result(0)
+{}
+
+
/*
Unlink first table from global table list and first table from outer select
list (lex->select_lex)
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 84b5cf3454b..de0d5d90f16 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -249,12 +249,6 @@ protected:
*master, *slave, /* vertical links */
*link_next, **link_prev; /* list of whole SELECT_LEX */
public:
- enum enum_parsing_place
- {
- NO_MATTER,
- IN_HAVING,
- SELECT_LIST
- };
ulong options;
/*
@@ -700,6 +694,12 @@ typedef struct st_lex
bool prepared_stmt_code_is_varref;
/* Names of user variables holding parameters (in EXECUTE) */
List<LEX_STRING> prepared_stmt_params;
+ /*
+ If points to fake_time_zone_tables_list indicates that time zone
+ tables are implicitly used by statement, also is used for holding
+ list of those tables after they are opened.
+ */
+ 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 */
@@ -753,6 +753,7 @@ typedef struct st_lex
bool only_view_structure();
} LEX;
+extern TABLE_LIST fake_time_zone_tables_list;
struct st_lex_local: public st_lex
{
static void *operator new(size_t size)
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 6dee38e9192..a4379b74c17 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -19,9 +19,9 @@
#pragma interface /* gcc class implementation */
#endif
-/* mysql standard class memoryallocator */
+/* mysql standard class memory allocator */
-#ifdef PEDANTIC_SAFEMALLOC
+#ifdef SAFEMALLOC
#define TRASH(XX,YY) bfill((XX), (YY), 0x8F)
#else
#define TRASH(XX,YY) /* no-op */
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index fa3adf236fe..44c6f71c9bd 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -190,26 +190,16 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
ex->file_name+=dirname_length(ex->file_name);
#endif
if (!dirname_length(ex->file_name) &&
- strlen(ex->file_name)+strlen(mysql_data_home)+strlen(tdb)+3 <
+ strlen(ex->file_name)+strlen(mysql_real_data_home)+strlen(tdb)+3 <
FN_REFLEN)
{
- (void) sprintf(name,"%s/%s/%s",mysql_data_home,tdb,ex->file_name);
+ (void) sprintf(name,"%s%s/%s",mysql_real_data_home,tdb,ex->file_name);
unpack_filename(name,name); /* Convert to system format */
}
else
{
-#ifdef EMBEDDED_LIBRARY
- char *chk_name= ex->file_name;
- while ((*chk_name == ' ') || (*chk_name == 't'))
- chk_name++;
- if (*chk_name == FN_CURLIB)
- {
- sprintf(name, "%s%s", mysql_data_home, ex->file_name);
- unpack_filename(name, name);
- }
- else
-#endif /*EMBEDDED_LIBRARY*/
- unpack_filename(name,ex->file_name);
+ my_load_path(name, ex->file_name, mysql_real_data_home);
+ unpack_filename(name, name);
#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__)
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(MY_WME)))
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 98f1810adc3..59a3e4b545b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1572,7 +1572,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list);
- thd->free_list=0; /* free_list should never point to garbage */
+ thd->free_list= 0; /* free_list should never point to garbage */
break;
}
#endif
@@ -1673,8 +1673,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in
packet[0].
*/
- enum enum_shutdown_level level=
- (enum enum_shutdown_level) (uchar) packet[0];
+ 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
@@ -2011,8 +2011,6 @@ mysql_execute_command(THD *thd)
else
thd->send_explain_fields(result);
res= mysql_explain_union(thd, &thd->lex->unit, result);
- MYSQL_LOCK *save_lock= thd->lock;
- thd->lock= (MYSQL_LOCK *)0;
if (lex->describe & DESCRIBE_EXTENDED)
{
char buff[1024];
@@ -2024,20 +2022,19 @@ mysql_execute_command(THD *thd)
ER_YES, str.ptr());
}
result->send_eof();
- thd->lock= save_lock;
+ delete result;
}
else
{
- if (!result)
+ if (!result && !(result= new select_send()))
{
- if (!(result=new select_send()))
- {
- res= -1;
- break;
- }
+ res= -1;
+ break;
}
query_cache_store_query(thd, all_tables);
- res=handle_select(thd, lex, result);
+ res= handle_select(thd, lex, result);
+ if (result != lex->result)
+ delete result;
}
}
break;
@@ -2393,6 +2390,21 @@ mysql_execute_command(THD *thd)
net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
goto create_error;
}
+ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ {
+ TABLE_LIST *tab;
+ for (tab= select_tables; tab; tab= tab->next)
+ {
+ if (find_real_table_in_list((TABLE_LIST*) lex->create_info.
+ merge_list.first,
+ select_tables->db, tab->real_name))
+ {
+ net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
+ goto create_error;
+ }
+ }
+ }
+
if (select_tables &&
check_table_access(thd, SELECT_ACL, select_tables, 0))
goto create_error; // Error message is given
@@ -2433,7 +2445,7 @@ mysql_execute_command(THD *thd)
res= mysql_create_table(thd, create_table->db,
create_table->real_name, &lex->create_info,
lex->create_list,
- lex->key_list, 0, 0, 0); // do logging
+ lex->key_list, 0, 0);
}
if (!res)
send_ok(thd);
@@ -2759,31 +2771,30 @@ unsent_create_error:
// is table which we are changing used somewhere in other parts of query
if (find_table_in_global_list(all_tables->next_global,
- first_table->db, first_table->real_name))
+ first_table->db, first_table->real_name))
{
/* Using same table for INSERT and SELECT */
select_lex->options |= OPTION_BUFFER_RESULT;
}
- if (!(res= open_and_lock_tables(thd, all_tables)))
+ if (!(res= open_and_lock_tables(thd, all_tables)) &&
+ !(res= mysql_insert_select_prepare(thd)) &&
+ (result= new select_insert(first_table, first_table->table,
+ &lex->field_list, lex->duplicates)))
{
- if ((res= mysql_insert_select_prepare(thd)))
- break;
- if ((result= new select_insert(first_table, first_table->table,
- &lex->field_list, lex->duplicates)))
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_table->next_local;
- /*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
- */
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
- res= handle_select(thd, lex, result);
- /* revert changes for SP */
- lex->select_lex.table_list.first= (byte*) first_table;
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (byte*) first_table->next_local;
+ /*
+ insert/replace from SELECT give its SELECT_LEX for SELECT,
+ and item_list belong to SELECT
+ */
+ lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
+ res= handle_select(thd, lex, result);
+ lex->select_lex.table_list.first= (byte*) first_table;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
+ delete result;
if (thd->net.report_error)
- res= -1;
+ res= -1;
}
else
res= -1;
@@ -2807,7 +2818,7 @@ unsent_create_error:
goto error;
}
- res= mysql_truncate(thd, first_table);
+ res= mysql_truncate(thd, first_table, 0);
break;
case SQLCOM_DELETE:
{
@@ -4290,6 +4301,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length, bool lexonly)
lex->lock_option= TL_READ;
lex->found_colon= 0;
lex->safe_to_cache_query= 1;
+ lex->time_zone_tables_used= 0;
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
lex->variables_used= 0;
@@ -4324,8 +4336,8 @@ mysql_init_select(LEX *lex)
select_lex->select_limit= HA_POS_ERROR;
if (select_lex == &lex->select_lex)
{
+ DBUG_ASSERT(lex->result == 0);
lex->exchange= 0;
- lex->result= 0;
lex->proc_list.first= 0;
}
}
@@ -4494,9 +4506,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
}
}
thd->proc_info="freeing items";
- free_items(thd->free_list); /* Free strings used by items */
- thd->free_list= 0; /* free_list should never point to garbage */
- lex_end(lex);
+ thd->end_statement();
}
DBUG_VOID_RETURN;
}
@@ -4522,10 +4532,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
- free_items(thd->free_list); /* Free strings used by items */
- thd->free_list= 0; /* free_list should never point to garbage */
- lex_end(lex);
-
+ thd->end_statement();
DBUG_RETURN(error);
}
#endif
@@ -4770,8 +4777,12 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
case FIELD_TYPE_TIMESTAMP:
if (!length)
new_field->length= 14; // Full date YYYYMMDDHHMMSS
- else
+ else if (new_field->length != 19)
{
+ /*
+ We support only even TIMESTAMP lengths less or equal than 14
+ and 19 as length of 4.1 compatible representation.
+ */
new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
new_field->length= min(new_field->length,14); /* purecov: inspected */
}
@@ -4832,7 +4843,10 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length=0;
for (const char **pos=interval->type_names; *pos ; pos++)
{
- new_field->length+=(uint) strip_sp((char*) *pos)+1;
+ uint length= (uint) strip_sp((char*) *pos)+1;
+ CHARSET_INFO *cs= thd->variables.character_set_client;
+ length= cs->cset->numchars(cs, *pos, *pos+length);
+ new_field->length+= length;
}
new_field->length--;
set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
@@ -4862,8 +4876,10 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length=(uint) strip_sp((char*) interval->type_names[0]);
for (const char **pos=interval->type_names+1; *pos ; pos++)
{
- uint length=(uint) strip_sp((char*) *pos);
- set_if_bigger(new_field->length,length);
+ uint length=(uint) strip_sp((char*) *pos);
+ CHARSET_INFO *cs= thd->variables.character_set_client;
+ length= cs->cset->numchars(cs, *pos, *pos+length);
+ set_if_bigger(new_field->length,length);
}
set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
if (default_value)
@@ -5493,9 +5509,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
tmp_write_to_binlog= 0;
if (lock_global_read_lock(thd))
return 1;
+ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1,
+ tables);
+ make_global_read_lock_block_commit(thd);
}
+ else
+ result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
my_dbopt_cleanup();
- result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables);
}
if (options & REFRESH_HOSTS)
hostname_cache_refresh();
@@ -6056,3 +6076,39 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables,
check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ?
1 : 0);
}
+
+
+/*
+ negate given expression
+
+ SYNOPSIS
+ negate_expression()
+ thd therad handler
+ expr expression for negation
+
+ RETURN
+ negated expression
+*/
+
+Item *negate_expression(THD *thd, Item *expr)
+{
+ Item *negated;
+ if (expr->type() == Item::FUNC_ITEM &&
+ ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
+ {
+ /* it is NOT(NOT( ... )) */
+ Item *arg= ((Item_func *) expr)->arguments()[0];
+ enum_parsing_place place= thd->lex->current_select->parsing_place;
+ if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
+ return arg;
+ /*
+ if it is not boolean function then we have to emulate value of
+ not(not(a)), it will be a != 0
+ */
+ return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
+ }
+
+ if ((negated= expr->neg_transformer(thd)) != 0)
+ return negated;
+ return new Item_func_not(expr);
+}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2cc2d881cca..5fccdd624de 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -91,7 +91,6 @@ public:
uint param_count;
uint last_errno;
char last_error[MYSQL_ERRMSG_SIZE];
- bool get_longdata_error;
#ifndef EMBEDDED_LIBRARY
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
uchar *read_pos, String *expanded_query);
@@ -105,7 +104,7 @@ public:
Prepared_statement(THD *thd_arg);
virtual ~Prepared_statement();
void setup_set_params();
- virtual Statement::Type type() const;
+ virtual Item_arena::Type type() const;
};
static void execute_stmt(THD *thd, Prepared_statement *stmt,
@@ -136,7 +135,7 @@ find_prepared_statement(THD *thd, ulong id, const char *where,
{
Statement *stmt= thd->stmt_map.find(id);
- if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT)
+ if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT)
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where);
@@ -334,15 +333,22 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
}
#ifndef EMBEDDED_LIBRARY
+
+/*
+ Read date/time/datetime parameter values from network (binary
+ protocol). See writing counterparts of these functions in
+ libmysql.c (store_param_{time,date,datetime}).
+*/
+
static void set_param_time(Item_param *param, uchar **pos, ulong len)
{
- ulong length;
- uint day;
+ MYSQL_TIME tm;
+ ulong length= get_param_length(pos, len);
- if ((length= get_param_length(pos, len)) >= 8)
+ if (length >= 8)
{
uchar *to= *pos;
- TIME tm;
+ uint day;
tm.neg= (bool) to[0];
day= (uint) sint4korr(to+1);
@@ -364,21 +370,22 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.second= 59;
}
tm.day= tm.year= tm.month= 0;
-
- param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
- MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
+ else
+ set_zero_time(&tm);
+ param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
+ MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
}
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
- uint length;
+ MYSQL_TIME tm;
+ ulong length= get_param_length(pos, len);
- if ((length= get_param_length(pos, len)) >= 4)
+ if (length >= 4)
{
uchar *to= *pos;
- TIME tm;
tm.neg= 0;
tm.year= (uint) sint2korr(to);
@@ -399,21 +406,22 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.hour= tm.minute= tm.second= 0;
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
-
- param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
- MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
+ else
+ set_zero_time(&tm);
+ param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
+ MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
}
static void set_param_date(Item_param *param, uchar **pos, ulong len)
{
- ulong length;
-
- if ((length= get_param_length(pos, len)) >= 4)
+ MYSQL_TIME tm;
+ ulong length= get_param_length(pos, len);
+
+ if (length >= 4)
{
uchar *to= *pos;
- TIME tm;
/*
Note, that though ranges of hour, minute and second are not checked
here we rely on them being < 256: otherwise
@@ -426,10 +434,11 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.hour= tm.minute= tm.second= 0;
tm.second_part= 0;
tm.neg= 0;
-
- param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
- MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
+ else
+ set_zero_time(&tm);
+ param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
+ MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
}
@@ -700,6 +709,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
else
{
uchar *buff= (uchar*) client_param->buffer;
+ param->unsigned_flag= client_param->is_unsigned;
param->set_param_func(param, &buff,
client_param->length ?
*client_param->length :
@@ -740,6 +750,7 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
else
{
uchar *buff= (uchar*)client_param->buffer;
+ param->unsigned_flag= client_param->is_unsigned;
param->set_param_func(param, &buff,
client_param->length ?
*client_param->length :
@@ -896,10 +907,8 @@ static int mysql_test_insert(Prepared_statement *stmt,
open temporary memory pool for temporary data allocated by derived
tables & preparation procedure
*/
- thd->allocate_temporary_memory_pool_for_ps_preparing();
if (open_and_lock_tables(thd, table_list))
{
- thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(-1);
}
@@ -934,7 +943,6 @@ static int mysql_test_insert(Prepared_statement *stmt,
res= 0;
error:
lex->unit.cleanup();
- thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(res);
}
@@ -963,12 +971,6 @@ static int mysql_test_update(Prepared_statement *stmt,
if ((res= update_precheck(thd, table_list)))
DBUG_RETURN(res);
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
-
if (open_and_lock_tables(thd, table_list))
res= -1;
else
@@ -994,7 +996,6 @@ static int mysql_test_update(Prepared_statement *stmt,
}
stmt->lex->unit.cleanup();
}
- thd->free_temporary_memory_pool_for_ps_preparing();
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(res);
}
@@ -1024,12 +1025,6 @@ static int mysql_test_delete(Prepared_statement *stmt,
if ((res= delete_precheck(thd, table_list)))
DBUG_RETURN(res);
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
-
if (open_and_lock_tables(thd, table_list))
res= -1;
else
@@ -1037,7 +1032,6 @@ static int mysql_test_delete(Prepared_statement *stmt,
res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
lex->unit.cleanup();
}
- thd->free_temporary_memory_pool_for_ps_preparing();
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(res);
}
@@ -1065,7 +1059,7 @@ static int mysql_test_select(Prepared_statement *stmt,
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX_UNIT *unit= &lex->unit;
-
+ int result= 1;
DBUG_ENTER("mysql_test_select");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1079,11 +1073,6 @@ static int mysql_test_select(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
if (open_and_lock_tables(thd, tables))
{
send_error(thd);
@@ -1098,15 +1087,14 @@ static int mysql_test_select(Prepared_statement *stmt,
send_error(thd);
goto err_prep;
}
- if (lex->describe)
+ if (!text_protocol)
{
- if (!text_protocol && send_prep_stmt(stmt, 0))
- goto err_prep;
- unit->cleanup();
- }
- else
- {
- if (!text_protocol)
+ if (lex->describe)
+ {
+ if (send_prep_stmt(stmt, 0))
+ goto err_prep;
+ }
+ else
{
if (send_prep_stmt(stmt, lex->select_lex.item_list.elements) ||
thd->protocol_simple.send_fields(&lex->select_lex.item_list,
@@ -1117,16 +1105,13 @@ static int mysql_test_select(Prepared_statement *stmt,
)
goto err_prep;
}
- unit->cleanup();
}
- thd->free_temporary_memory_pool_for_ps_preparing();
- DBUG_RETURN(0);
+ result= 0; // ok
err_prep:
unit->cleanup();
err:
- thd->free_temporary_memory_pool_for_ps_preparing();
- DBUG_RETURN(1);
+ DBUG_RETURN(result);
}
@@ -1154,19 +1139,13 @@ static int mysql_test_do_fields(Prepared_statement *stmt,
int res= 0;
if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
DBUG_RETURN(res);
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
+
if (tables && (res= open_and_lock_tables(thd, tables)))
{
- thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(res);
}
res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
stmt->lex->unit.cleanup();
- thd->free_temporary_memory_pool_for_ps_preparing();
if (res)
DBUG_RETURN(-1);
DBUG_RETURN(0);
@@ -1199,11 +1178,7 @@ static int mysql_test_set_fields(Prepared_statement *stmt,
if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
DBUG_RETURN(res);
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
+
if (tables && (res= open_and_lock_tables(thd, tables)))
goto error;
while ((var= it++))
@@ -1217,7 +1192,6 @@ static int mysql_test_set_fields(Prepared_statement *stmt,
}
error:
stmt->lex->unit.cleanup();
- thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(res);
}
@@ -1244,11 +1218,7 @@ static int select_like_statement_test(Prepared_statement *stmt,
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
int res= 0;
- /*
- open temporary memory pool for temporary data allocated by derived
- tables & preparation procedure
- */
- thd->allocate_temporary_memory_pool_for_ps_preparing();
+
if (tables && (res= open_and_lock_tables(thd, tables)))
goto end;
@@ -1264,7 +1234,6 @@ static int select_like_statement_test(Prepared_statement *stmt,
}
end:
lex->unit.cleanup();
- thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(res);
}
@@ -1609,17 +1578,13 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
DBUG_RETURN(1);
}
- thd->stmt_backup.set_statement(thd);
- thd->stmt_backup.set_item_arena(thd);
- thd->set_statement(stmt);
- thd->set_item_arena(stmt);
+ thd->set_n_backup_statement(stmt, &thd->stmt_backup);
+ thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
if (alloc_query(thd, packet, packet_length))
{
- stmt->set_statement(thd);
- stmt->set_item_arena(thd);
- thd->set_statement(&thd->stmt_backup);
- thd->set_item_arena(&thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
send_error(thd, ER_OUT_OF_RESOURCES);
@@ -1634,8 +1599,19 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
lex->safe_to_cache_query= 0;
error= yyparse((void *)thd) || thd->is_fatal_error ||
- init_param_array(stmt) ||
- send_prepare_results(stmt, test(name));
+ init_param_array(stmt);
+ /*
+ While doing context analysis of the query (in send_prepare_results) we
+ allocate a lot of additional memory: for open tables, JOINs, derived
+ tables, etc. Let's save a snapshot of current parse tree to the
+ statement and restore original THD. In cases when some tree
+ transformation can be reused on execute, we set again thd->mem_root from
+ stmt->mem_root (see setup_wild for one place where we do that).
+ */
+ thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+
+ if (!error)
+ error= send_prepare_results(stmt, test(name));
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1648,11 +1624,12 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
thd->lex->sphead= NULL;
}
lex_end(lex);
- stmt->set_statement(thd);
- stmt->set_item_arena(thd);
- thd->set_statement(&thd->stmt_backup);
- thd->set_item_arena(&thd->stmt_backup);
- thd->current_arena= 0;
+ thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ cleanup_items(stmt->free_list);
+ close_thread_tables(thd);
+ free_items(thd->free_list);
+ thd->free_list= 0;
+ thd->current_arena= thd;
if (error)
{
@@ -1671,6 +1648,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
*/
for (; sl; sl= sl->next_select_in_list())
sl->prep_where= sl->where;
+ stmt->state= Item_arena::PREPARED;
}
DBUG_RETURN(!stmt);
}
@@ -1740,6 +1718,8 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
tables->table= 0;
}
lex->current_select= &lex->select_lex;
+ if (lex->result)
+ lex->result->cleanup();
}
@@ -1795,7 +1775,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_PRINT("exec_query:", ("%s", stmt->query));
/* Check if we got an error when sending long data */
- if (stmt->get_longdata_error)
+ if (stmt->state == Item_arena::ERROR)
{
send_error(thd, stmt->last_errno, stmt->last_error);
DBUG_VOID_RETURN;
@@ -1841,6 +1821,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
+ DBUG_ASSERT(thd->free_list == NULL);
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_arena= stmt;
@@ -1925,8 +1906,9 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
DBUG_VOID_RETURN;
}
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
+ DBUG_ASSERT(thd->free_list == NULL);
+
+ thd->set_n_backup_statement(stmt, &thd->stmt_backup);
if (stmt->set_params_from_vars(stmt,
thd->stmt_backup.lex->prepared_stmt_params,
&expanded_query))
@@ -1958,6 +1940,8 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
String *expanded_query)
{
DBUG_ENTER("execute_stmt");
+
+ thd->set_n_backup_statement(stmt, &thd->stmt_backup);
reset_stmt_for_execute(thd, stmt->lex);
if (expanded_query->length() &&
@@ -1967,6 +1951,13 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
DBUG_VOID_RETURN;
}
+ /*
+ At first execution of prepared statement we will perform logical
+ transformations of the query tree (i.e. negations elimination).
+ This should be done permanently on the parse tree of this statement.
+ */
+ if (stmt->state == Item_arena::PREPARED)
+ thd->current_arena= stmt;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
@@ -1986,6 +1977,11 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
never points to garbage: keep this predicate true.
*/
thd->free_list= 0;
+ if (stmt->state == Item_arena::PREPARED)
+ {
+ thd->current_arena= thd;
+ stmt->state= Item_arena::EXECUTED;
+ }
DBUG_VOID_RETURN;
}
@@ -2070,7 +2066,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
SEND_ERROR)))
DBUG_VOID_RETURN;
- stmt->get_longdata_error= 0;
+ stmt->state= Item_arena::PREPARED;
/*
Clear parameters from data which could be set by
@@ -2158,7 +2154,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
- stmt->get_longdata_error= 1;
+ stmt->state= Item_arena::ERROR;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysql_stmt_send_long_data");
@@ -2169,10 +2165,15 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
param= stmt->param_array[param_number];
#ifndef EMBEDDED_LIBRARY
- param->set_longdata(packet, (ulong) (packet_end - packet));
+ if (param->set_longdata(packet, (ulong) (packet_end - packet)))
#else
- param->set_longdata(thd->extra_data, thd->extra_length);
+ if (param->set_longdata(thd->extra_data, thd->extra_length))
#endif
+ {
+ stmt->state= Item_arena::ERROR;
+ stmt->last_errno= ER_OUTOFMEMORY;
+ sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
+ }
DBUG_VOID_RETURN;
}
@@ -2182,8 +2183,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
thd(thd_arg),
param_array(0),
param_count(0),
- last_errno(0),
- get_longdata_error(0)
+ last_errno(0)
{
*last_error= '\0';
}
@@ -2217,10 +2217,11 @@ Prepared_statement::~Prepared_statement()
if (cursor)
cursor->Cursor::~Cursor();
free_items(free_list);
+ delete lex->result;
}
-Statement::Type Prepared_statement::type() const
+Item_arena::Type Prepared_statement::type() const
{
return PREPARED_STATEMENT;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 97c4e39874c..3298eb68a91 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -48,7 +48,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(1);
}
- if (wait_if_global_read_lock(thd,0))
+ if (wait_if_global_read_lock(thd,0,1))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&LOCK_open));
if (lock_table_names(thd, table_list))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5bd7cb62667..db3a0c90141 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -227,14 +227,9 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
res= 1;
if (unlikely(res))
{
- if (result)
- {
- if (res > 0)
- result->send_error(0, NullS);
- result->abort();
- }
- else if (res > 0)
- send_error(thd, 0, NullS);
+ if (res > 0)
+ result->send_error(0, NullS);
+ result->abort();
res= 1; // Error sent to client
}
if (result != lex->result)
@@ -772,6 +767,10 @@ JOIN::optimize()
(select_lex->ftfunc_list->elements ?
SELECT_NO_JOIN_CACHE : 0));
+ /* Perform FULLTEXT search before all regular searches */
+ if (!(select_options & SELECT_DESCRIBE))
+ init_ftfuncs(thd, select_lex, test(order));
+
/*
is this simple IN subquery?
*/
@@ -827,7 +826,7 @@ JOIN::optimize()
join_tab->info= "Using index; Using where";
else
join_tab->info= "Using index";
-
+
DBUG_RETURN(unit->item->
change_engine(new subselect_indexsubquery_engine(thd,
join_tab,
@@ -864,7 +863,7 @@ JOIN::optimize()
as in other cases the join is done before the sort.
*/
if (const_tables != tables &&
- (order || group_list) &&
+ (order || group_list) &&
join_tab[const_tables].type != JT_ALL &&
join_tab[const_tables].type != JT_FT &&
join_tab[const_tables].type != JT_REF_OR_NULL &&
@@ -878,8 +877,7 @@ JOIN::optimize()
((group_list && const_tables != tables &&
(!simple_group ||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
- unit->select_limit_cnt,
- 0))) ||
+ unit->select_limit_cnt, 0))) ||
select_distinct) &&
tmp_table_param.quick_group && !procedure)
{
@@ -894,8 +892,6 @@ JOIN::optimize()
}
having= 0;
- /* Perform FULLTEXT search before all regular searches */
- init_ftfuncs(thd, select_lex, test(order));
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
{
@@ -903,7 +899,7 @@ JOIN::optimize()
thd->proc_info="Creating tmp table";
init_items_ref_array();
-
+
tmp_table_param.hidden_field_count= (all_fields.elements -
fields_list.elements);
if (!(exec_tmp_table1 =
@@ -2432,7 +2428,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
}
else if (old->eq_func && new_fields->eq_func &&
old->val->eq(new_fields->val, old->field->binary()))
-
+
{
old->level= and_level;
old->optimize= ((old->optimize & new_fields->optimize &
@@ -2491,7 +2487,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
field Field used in comparision
eq_func True if we used =, <=> or IS NULL
value Value used for comparison with field
- Is NULL for BETWEEN and IN
+ Is NULL for BETWEEN and IN
usable_tables Tables which can be used for key optimization
NOTES
@@ -2565,22 +2561,32 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
number. cmp_type() is checked to allow compare of dates to numbers.
eq_func is NEVER true when num_values > 1
*/
- if (!eq_func ||
- field->result_type() == STRING_RESULT &&
- (*value)->result_type() != STRING_RESULT &&
- field->cmp_type() != (*value)->result_type())
- return;
-
- /*
- We can't use indexes if the effective collation
- of the operation differ from the field collation.
- */
- if (field->result_type() == STRING_RESULT &&
- (*value)->result_type() == STRING_RESULT &&
- field->cmp_type() == STRING_RESULT &&
- ((Field_str*)field)->charset() != cond->compare_collation())
- return;
+ if (!eq_func)
+ return;
+ if (field->result_type() == STRING_RESULT)
+ {
+ if ((*value)->result_type() != STRING_RESULT)
+ {
+ if (field->cmp_type() != (*value)->result_type())
+ return;
+ }
+ else
+ {
+ /*
+ We can't use indexes if the effective collation
+ of the operation differ from the field collation.
+ We can also not used 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())))
+ return;
+ }
+ }
}
}
DBUG_ASSERT(num_values == 1);
@@ -2683,7 +2689,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
{
Item *tmp=new Item_null;
- if (!tmp) // Should never be true
+ if (unlikely(!tmp)) // Should never be true
return;
add_key_field(key_fields,*and_level,cond_func,
((Item_field*) (cond_func->arguments()[0])->real_item())
@@ -4055,7 +4061,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec= keyuse->ref_table_rows;
/*
If there is one 'key_column IS NULL' expression, we can
- use this ref_or_null optimsation of this field
+ use this ref_or_null optimisation of this field
*/
found_ref_or_null|= (keyuse->optimize &
KEY_OPTIMIZE_REF_OR_NULL);
@@ -4572,6 +4578,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
store_key **ref_key= j->ref.key_copy;
byte *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();
@@ -4591,6 +4598,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
+ keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
if (!keyuse->used_tables &&
!(join->select_options & SELECT_DESCRIBE))
{ // Compare against constant
@@ -4630,7 +4638,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
j->ref.null_ref_key= null_ref_key;
}
- else if (ref_key == j->ref.key_copy)
+ else if (keyuse_uses_no_tables)
{
/*
This happen if we are using a constant expression in the ON part
@@ -5425,6 +5433,10 @@ JOIN::join_free(bool full)
if (full)
{
group_fields.delete_elements();
+ /*
+ We can't call delete_elements() on copy_funcs as this will cause
+ problems in free_elements() as some of the elements are then deleted.
+ */
tmp_table_param.copy_funcs.empty();
tmp_table_param.cleanup();
}
@@ -5609,7 +5621,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
}
if ((ref=order_tables & (not_const_tables ^ first_table)))
{
- if (only_eq_ref_tables(join,first_order,ref))
+ if (!(order_tables & first_table) && only_eq_ref_tables(join,first_order,ref))
{
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
continue;
@@ -5732,7 +5744,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
Item *right_item= func->arguments()[1];
Item_func::Functype functype= func->functype();
- if (right_item->eq(field,0) && left_item != value)
+ if (right_item->eq(field,0) && left_item != value &&
+ (left_item->result_type() != STRING_RESULT ||
+ value->result_type() != STRING_RESULT ||
+ left_item->collation.collation == value->collation.collation))
{
Item *tmp=value->new_item();
if (tmp)
@@ -5750,7 +5765,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
func->set_cmp_func();
}
}
- else if (left_item->eq(field,0) && right_item != value)
+ else if (left_item->eq(field,0) && right_item != value &&
+ (right_item->result_type() != STRING_RESULT ||
+ value->result_type() != STRING_RESULT ||
+ right_item->collation.collation == value->collation.collation))
{
Item *tmp=value->new_item();
if (tmp)
@@ -5871,62 +5889,6 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
/*
- Eliminate NOT functions from the condition tree.
-
- SYNPOSIS
- eliminate_not_funcs()
- thd thread handler
- cond condition tree
-
- DESCRIPTION
- Eliminate NOT functions from the condition tree where it's possible.
- Recursively traverse condition tree to find all NOT functions.
- Call neg_transformer() method for negated arguments.
-
- NOTE
- If neg_transformer() returned a new condition we call fix_fields().
- We don't delete any items as it's not needed. They will be deleted
- later at once.
-
- RETURN
- New condition tree
-*/
-
-COND *eliminate_not_funcs(THD *thd, COND *cond)
-{
- DBUG_ENTER("eliminate_not_funcs");
-
- if (!cond)
- DBUG_RETURN(cond);
- if (cond->type() == Item::COND_ITEM) /* OR or AND */
- {
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
- Item *item;
- while ((item= li++))
- {
- Item *new_item= eliminate_not_funcs(thd, item);
- if (item != new_item)
- VOID(li.replace(new_item)); /* replace item with a new condition */
- }
- }
- else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */
- ((Item_func*) cond)->functype() == Item_func::NOT_FUNC)
- {
- COND *new_cond= ((Item_func*) cond)->arguments()[0]->neg_transformer(thd);
- if (new_cond)
- {
- /*
- Here we can delete the NOT function. Something like: delete cond;
- But we don't need to do it. All items will be deleted later at once.
- */
- cond= new_cond;
- }
- }
- DBUG_RETURN(cond);
-}
-
-
-/*
Simplify joins replacing outer joins by inner joins whenever it's possible
SYNOPSIS
@@ -5990,9 +5952,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
The function removes all unnecessary braces from the expression
produced by the conversions.
- E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
+ E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
finally is converted to:
- SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
+ SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
It also will remove braces from the following queries:
SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
@@ -6162,27 +6124,26 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
return conds;
}
-
+
+
static COND *
optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
{
+ SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
THD *thd= join->thd;
SELECT_LEX *select= thd->lex->current_select;
if (select->first_cond_optimization)
{
- Item_arena *arena= thd->current_arena;
- Item_arena backup;
- if (arena)
- thd->set_n_backup_item_arena(arena, &backup);
+ Item_arena *arena, backup;
+ select->first_cond_optimization= 0;
- if (conds)
- {
- DBUG_EXECUTE("where",print_where(conds,"original"););
- /* eliminate NOT operators */
- conds= eliminate_not_funcs(thd, conds);
- }
+ arena= thd->current_arena;
+ if (!arena->is_stmt_prepare())
+ arena= 0;
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
/* Convert all outer joins to inner joins if possible */
conds= simplify_joins(join, join->join_list, conds, TRUE);
@@ -6196,19 +6157,21 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
if (!conds)
{
*cond_value= Item::COND_TRUE;
- DBUG_RETURN(conds);
+ select->prep_where= 0;
+ }
+ else
+ {
+ DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
+ /* change field = field to field = const for each found field = const */
+ propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
+ /*
+ Remove all instances of item == item
+ Remove all and-levels where CONST item != CONST item
+ */
+ DBUG_EXECUTE("where",print_where(conds,"after const change"););
+ conds= remove_eq_conds(thd, conds, cond_value) ;
+ DBUG_EXECUTE("info",print_where(conds,"after remove"););
}
-
- DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
- /* change field = field to field = const for each found field = const */
- propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
- /*
- Remove all instances of item == item
- Remove all and-levels where CONST item != CONST item
- */
- DBUG_EXECUTE("where",print_where(conds,"after const change"););
- conds= remove_eq_conds(thd, conds, cond_value) ;
- DBUG_EXECUTE("info",print_where(conds,"after remove"););
DBUG_RETURN(conds);
}
@@ -6536,7 +6499,7 @@ static Field* create_tmp_field_from_item(THD *thd,
copy_func If set and item is a function, store copy of item
in this array
from_field if field will be created using other field as example,
- pointer example field will be written here
+ pointer example field will be written here
group 1 if we are going to do a relative group by on result
modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
@@ -6545,7 +6508,7 @@ static Field* create_tmp_field_from_item(THD *thd,
the record in the original table.
If modify_item is 0 then fill_record() will update
the temporary table
-
+
RETURN
0 on error
new_created field
@@ -6569,13 +6532,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
return new Field_double(item_sum->max_length,maybe_null,
item->name, table, item_sum->decimals);
case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
- case Item_sum::STD_FUNC:
+ case Item_sum::STD_FUNC:
if (group)
return new Field_string(sizeof(double)*2+sizeof(longlong),
0, item->name,table,&my_charset_bin);
else
return new Field_double(item_sum->max_length, maybe_null,
- item->name,table,item_sum->decimals);
+ item->name,table,item_sum->decimals);
case Item_sum::UNIQUE_USERS_FUNC:
return new Field_long(9,maybe_null,item->name,table,1);
default:
@@ -6683,7 +6646,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
else // if we run out of slots or we are not using tempool
sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
thd->thread_id, thd->tmp_table++);
-
+
if (lower_case_table_names)
my_casedn_str(files_charset_info, path);
@@ -6799,14 +6762,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
tmp_from_field++;
*(reg_field++)= new_field;
reclength+=new_field->pack_length();
- if (!(new_field->flags & NOT_NULL_FLAG))
- null_count++;
if (new_field->flags & BLOB_FLAG)
{
*blob_field++= new_field;
blob_count++;
}
((Item_sum*) item)->args[i]= new Item_field(new_field);
+ if (!(new_field->flags & NOT_NULL_FLAG))
+ {
+ null_count++;
+ /*
+ new_field->maybe_null() is still false, it will be
+ changed below. But we have to setup Item_field correctly
+ */
+ ((Item_sum*) item)->args[i]->maybe_null=1;
+ }
}
}
}
@@ -7339,6 +7309,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table.no_rows=1;
}
+#ifdef TO_BE_DONE_LATER_IN_4_1
+ /*
+ To use start_bulk_insert() (which is new in 4.1) we need to find
+ all places where a corresponding end_bulk_insert() should be put.
+ */
+ table->file->info(HA_STATUS_VARIABLE); /* update table->file->records */
+ new_table.file->start_bulk_insert(table->file->records);
+#else
+ /* HA_EXTRA_WRITE_CACHE can stay until close, no need to disable it */
+ new_table.file->extra(HA_EXTRA_WRITE_CACHE);
+#endif
+
/* copy all old rows */
while (!table->file->rnd_next(new_table.record[1]))
{
@@ -9275,9 +9257,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
keys.merge(table->used_keys);
/*
- We are adding here also the index speified in FORCE INDEX clause,
+ We are adding here also the index specified in FORCE INDEX clause,
if any.
- This is to allow users to use index in ORDER BY.
+ This is to allow users to use index in ORDER BY.
*/
if (table->force_index)
keys.merge(table->keys_in_use_for_query);
@@ -10054,7 +10036,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
Item *itemptr=*order->item;
if (itemptr->type() == Item::INT_ITEM)
{ /* Order by position */
- uint count= itemptr->val_int();
+ uint count= (uint) itemptr->val_int();
if (!count || count > fields.elements)
{
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
@@ -10067,13 +10049,18 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
return 0;
}
uint counter;
- Item **item= find_item_in_list(itemptr, fields, &counter, IGNORE_ERRORS);
- if (item)
+ Item **item= find_item_in_list(itemptr, fields, &counter,
+ REPORT_EXCEPT_NOT_FOUND);
+ if (!item)
+ return 1;
+
+ if (item != (Item **)not_found_item)
{
order->item= ref_pointer_array + counter;
order->in_field_list=1;
return 0;
}
+
order->in_field_list=0;
Item *it= *order->item;
/*
@@ -10536,7 +10523,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
{
if (!(pos= new Item_copy_string(pos)))
goto err;
- if (param->copy_funcs.push_back(pos))
+ /*
+ Item_copy_string::copy for function can call
+ Item_copy_string::val_int for blob via Item_ref.
+ But if Item_copy_string::copy for blob isn't called before,
+ it's value will be wrong
+ so let's insert Item_copy_string for blobs in the beginning of
+ copy_funcs
+ (to see full test case look at having.test, BUG #4358)
+ */
+ if (param->copy_funcs.push_front(pos))
goto err;
}
else
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 284e4315917..a1487693b79 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -506,4 +506,3 @@ bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
-COND *eliminate_not_funcs(THD *thd, COND *cond);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9e26a22cfa0..6322d99582d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -693,6 +693,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
TABLE *table;
handler *file;
char tmp[MAX_FIELD_WIDTH];
+ char tmp1[MAX_FIELD_WIDTH];
Item *item;
Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_fields");
@@ -779,9 +780,24 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
else if (field->unireg_check != Field::NEXT_NUMBER &&
!field->is_null())
{ // Not null by default
+ /*
+ Note: we have to convert the default value into
+ system_charset_info before sending.
+ This is necessary for "SET NAMES binary":
+ If the client character set is binary, we want to
+ send metadata in UTF8 rather than in the column's
+ character set.
+ This conversion also makes "SHOW COLUMNS" and
+ "SHOW CREATE TABLE" output consistent. Without
+ this conversion the default values were displayed
+ differently.
+ */
+ String def(tmp1,sizeof(tmp1), system_charset_info);
type.set(tmp, sizeof(tmp), field->charset());
field->val_str(&type);
- protocol->store(type.ptr(),type.length(),type.charset());
+ def.copy(type.ptr(), type.length(), type.charset(),
+ system_charset_info);
+ protocol->store(def.ptr(), def.length(), def.charset());
}
else if (field->unireg_check == Field::NEXT_NUMBER ||
field->maybe_null())
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 79365b7481b..ad32305e9b4 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -95,9 +95,18 @@ public:
Ptr[str_length]=0;
return Ptr;
}
+ inline char *c_ptr_safe()
+ {
+ if (Ptr && str_length < Alloced_length)
+ Ptr[str_length]=0;
+ else
+ (void) realloc(str_length);
+ return Ptr;
+ }
void set(String &str,uint32 offset,uint32 arg_length)
{
+ DBUG_ASSERT(&str != this);
free();
Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0;
if (str.Alloced_length)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 93fb7930da7..03c20be198e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1089,7 +1089,6 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
keys List of keys to create
tmp_table Set to 1 if this is an internal temporary table
(From ALTER TABLE)
- no_log Don't log the query to binary log.
DESCRIPTION
If one creates a temporary table, this is automaticly opened
@@ -1107,7 +1106,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
int mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
- List<Key> &keys,bool tmp_table,bool no_log,
+ List<Key> &keys,bool tmp_table,
uint select_field_count)
{
char path[FN_REFLEN];
@@ -1206,7 +1205,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
DBUG_RETURN(-1);
}
- if (wait_if_global_read_lock(thd, 0))
+ if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(error);
VOID(pthread_mutex_lock(&LOCK_open));
if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
@@ -1276,7 +1275,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
thd->tmp_table_used= 1;
}
- if (!tmp_table && !no_log && mysql_bin_log.is_open())
+ if (!tmp_table && mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -1346,6 +1345,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE *table;
tmp_table.table_name=0;
uint select_field_count= items->elements;
+ Disable_binlog disable_binlog(thd);
DBUG_ENTER("create_table_from_items");
/* Add selected items to field list */
@@ -1377,9 +1377,16 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
/* create and lock table */
/* QQ: This should be done atomic ! */
if (mysql_create_table(thd, create_table->db, create_table->real_name,
- create_info, *extra_fields, *keys, 0, 1,
- select_field_count)) // no logging
+ create_info, *extra_fields, *keys, 0,
+ select_field_count))
DBUG_RETURN(0);
+ /*
+ If this is a HEAP table, the automatic DELETE FROM which is written to the
+ binlog when a HEAP table is opened for the first time since startup, must
+ not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we
+ 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.
+ */
if (!(table= open_table(thd, create_table, 0, (bool*) 0)))
{
quick_rm_table(create_info->db_type, create_table->db,
@@ -1398,6 +1405,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
}
table->file->extra(HA_EXTRA_WRITE_CACHE);
DBUG_RETURN(table);
+ /* Note that leaving the function resets binlogging properties */
}
@@ -1567,7 +1575,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
reg_ext))
DBUG_RETURN(-1); // protect buffer overflow
- my_snprintf(dst_path, sizeof(dst_path), "%s/%s/%s",
+ my_snprintf(dst_path, sizeof(dst_path), "%s%s/%s",
mysql_real_data_home, db, table_name);
if (lock_and_wait_for_table_name(thd,table))
@@ -1814,7 +1822,6 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
dropping_tables--;
}
thd->exit_cond(old_message);
- pthread_mutex_unlock(&LOCK_open);
if (thd->killed)
goto err;
open_for_modify=0;
@@ -2688,7 +2695,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (do_send_ok)
send_ok(thd);
}
- else
+ else if (error > 0)
{
table->file->print_error(error, MYF(0));
error= -1;
@@ -3006,12 +3013,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
create_info->data_file_name=create_info->index_file_name=0;
-
- if ((error=mysql_create_table(thd, new_db, tmp_name,
- create_info,
- create_list,key_list,1,1,0))) // no logging
- DBUG_RETURN(error);
-
+ {
+ /* We don't log the statement, it will be logged later */
+ Disable_binlog disable_binlog(thd);
+ if ((error=mysql_create_table(thd, new_db, tmp_name,
+ create_info,
+ create_list,key_list,1,0)))
+ DBUG_RETURN(error);
+ }
if (table->tmp_table)
{
TABLE_LIST tbl;
@@ -3278,11 +3287,11 @@ copy_data_between_tables(TABLE *from,TABLE *to,
uint length;
SORT_FIELD *sortorder;
READ_RECORD info;
- Field *next_field;
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
ha_rows examined_rows;
+ bool auto_increment_field_copied= 0;
DBUG_ENTER("copy_data_between_tables");
if (!(copy= new Copy_field[to->fields]))
@@ -3299,7 +3308,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
{
def=it++;
if (def->field)
+ {
+ if (*ptr == to->next_number_field)
+ auto_increment_field_copied= TRUE;
(copy_end++)->set(*ptr,def->field,0);
+ }
+
}
found_count=delete_count=0;
@@ -3335,7 +3349,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
error= 1;
goto err;
}
-
+
/* Handler must be told explicitly to retrieve all columns, because
this function does not set field->query_id in the columns to the
current query id */
@@ -3344,7 +3358,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (handle_duplicates == DUP_IGNORE ||
handle_duplicates == DUP_REPLACE)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- next_field=to->next_number_field;
thd->row_count= 0;
while (!(error=info.read_record(&info)))
{
@@ -3355,10 +3368,17 @@ copy_data_between_tables(TABLE *from,TABLE *to,
break;
}
thd->row_count++;
- if (next_field)
- next_field->reset();
+ if (to->next_number_field)
+ {
+ if (auto_increment_field_copied)
+ to->auto_increment_field_not_null= TRUE;
+ else
+ to->next_number_field->reset();
+ }
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
+ {
copy_ptr->do_copy(copy_ptr);
+ }
if ((error=to->file->write_row((byte*) to->record[0])))
{
if ((handle_duplicates != DUP_IGNORE &&
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index d6b776571f2..827d75a9848 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -292,7 +292,9 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
Item_arena *arena= thd->current_arena;
Item_arena backup;
- if (arena)
+ if (!arena->is_stmt_prepare())
+ arena= 0
+ else
thd->set_n_backup_item_arena(arena, &backup);
Field **field;
for (field= table->field; *field; field++)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index ba3a36f2c34..19b6aa4b385 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -503,6 +503,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CASE_SYM
%token CONCAT
%token CONCAT_WS
+%token CONVERT_TZ_SYM
%token CURDATE
%token CURTIME
%token DATABASE
@@ -1116,7 +1117,10 @@ create:
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
- { Lex->create_info.default_table_charset=NULL; }
+ {
+ Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.used_fields= 0;
+ }
opt_create_database_options
{
LEX *lex=Lex;
@@ -2027,7 +2031,8 @@ sp_fetch_list:
YYABORT;
}
else
- { /* An SP local variable */
+ {
+ /* An SP local variable */
sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
i->add_to_varlist(spv);
@@ -2048,7 +2053,8 @@ sp_fetch_list:
YYABORT;
}
else
- { /* An SP local variable */
+ {
+ /* An SP local variable */
sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
i->add_to_varlist(spv);
@@ -2323,11 +2329,11 @@ create_select:
*/
lex->current_select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST;
+ lex->current_select->parsing_place= SELECT_LIST;
}
select_options select_item_list
{
- Select->parsing_place= SELECT_LEX_NODE::NO_MATTER;
+ Select->parsing_place= NO_MATTER;
}
opt_select_from
{
@@ -2352,11 +2358,8 @@ create_database_options:
| create_database_options create_database_option {};
create_database_option:
- opt_default COLLATE_SYM collation_name_or_default
- { Lex->create_info.default_table_charset=$3; }
- | opt_default charset charset_name_or_default
- { Lex->create_info.default_table_charset=$3; }
- ;
+ default_collation {}
+ | default_charset {};
opt_table_options:
/* empty */ { $$= 0; }
@@ -2418,21 +2421,46 @@ create_table_option:
table_list->next_local= 0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
- | opt_default charset opt_equal charset_name_or_default
- {
- Lex->create_info.default_table_charset= $4;
- Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- }
- | opt_default COLLATE_SYM opt_equal collation_name_or_default
- {
- Lex->create_info.default_table_charset= $4;
- Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
- }
+ | default_charset
+ | default_collation
| INSERT_METHOD opt_equal merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
| DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
{ Lex->create_info.data_file_name= $4.str; }
| INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; };
+default_charset:
+ opt_default charset opt_equal charset_name_or_default
+ {
+ HA_CREATE_INFO *cinfo= &Lex->create_info;
+ if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
+ cinfo->default_table_charset && $4 &&
+ !my_charset_same(cinfo->default_table_charset,$4))
+ {
+ net_printf(YYTHD, ER_CONFLICTING_DECLARATIONS,
+ "CHARACTER SET ", cinfo->default_table_charset->csname,
+ "CHARACTER SET ", $4->csname);
+ YYABORT;
+ }
+ Lex->create_info.default_table_charset= $4;
+ Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ };
+
+default_collation:
+ opt_default COLLATE_SYM opt_equal collation_name_or_default
+ {
+ HA_CREATE_INFO *cinfo= &Lex->create_info;
+ if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
+ cinfo->default_table_charset && $4 &&
+ !my_charset_same(cinfo->default_table_charset,$4))
+ {
+ net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
+ $4->name, cinfo->default_table_charset->csname);
+ YYABORT;
+ }
+ Lex->create_info.default_table_charset= $4;
+ Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+ };
+
storage_engines:
ident_or_text
{
@@ -3042,7 +3070,12 @@ alter:
}
alter_list
{}
- | ALTER DATABASE ident opt_create_database_options
+ | ALTER DATABASE ident
+ {
+ Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.used_fields= 0;
+ }
+ opt_create_database_options
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_ALTER_DB;
@@ -3193,6 +3226,12 @@ alter_list_item:
LEX *lex=Lex;
lex->select_lex.db=$3->db.str;
lex->name= $3->table.str;
+ if (check_table_name($3->table.str,$3->table.length) ||
+ $3->db.str && check_db_name($3->db.str))
+ {
+ net_printf(lex->thd,ER_WRONG_TABLE_NAME,$3->table.str);
+ YYABORT;
+ }
lex->alter_info.flags|= ALTER_RENAME;
}
| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
@@ -3631,11 +3670,11 @@ select_part2:
lex->lock_option= TL_READ;
if (sel->linkage != UNION_TYPE)
mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST;
+ lex->current_select->parsing_place= SELECT_LIST;
}
select_options select_item_list
{
- Select->parsing_place= SELECT_LEX_NODE::NO_MATTER;
+ Select->parsing_place= NO_MATTER;
}
select_into select_lock_type;
@@ -3986,8 +4025,14 @@ simple_expr:
| '+' expr %prec NEG { $$= $2; }
| '-' expr %prec NEG { $$= new Item_func_neg($2); }
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
- | NOT expr %prec NEG { $$= new Item_func_not($2); }
- | '!' expr %prec NEG { $$= new Item_func_not($2); }
+ | NOT expr %prec NEG
+ {
+ $$= negate_expression(YYTHD, $2);
+ }
+ | '!' expr %prec NEG
+ {
+ $$= negate_expression(YYTHD, $2);
+ }
| '(' expr ')' { $$= $2; }
| '(' expr ',' expr_list ')'
{
@@ -4009,8 +4054,7 @@ simple_expr:
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
| BINARY expr %prec NEG
{
- $$= new Item_func_set_collation($2,new Item_string(binary_keyword,
- 6, &my_charset_latin1));
+ $$= create_func_cast($2, ITEM_CAST_CHAR, -1, &my_charset_bin);
}
| CAST_SYM '(' expr AS cast_type ')'
{
@@ -4098,6 +4142,11 @@ simple_expr:
{ $$= new Item_func_concat(* $3); }
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
+ | CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')'
+ {
+ Lex->time_zone_tables_used= &fake_time_zone_tables_list;
+ $$= new Item_func_convert_tz($3, $5, $7);
+ }
| CURDATE optional_braces
{ $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; }
| CURTIME optional_braces
@@ -4833,11 +4882,11 @@ select_derived:
YYABORT;
mysql_init_select(lex);
lex->current_select->linkage= DERIVED_TABLE_TYPE;
- lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST;
+ lex->current_select->parsing_place= SELECT_LIST;
}
select_options select_item_list
{
- Select->parsing_place= SELECT_LEX_NODE::NO_MATTER;
+ Select->parsing_place= NO_MATTER;
}
opt_select_from union_opt
;
@@ -4934,12 +4983,15 @@ interval_time_st:
| MONTH_SYM { $$=INTERVAL_MONTH; }
| QUARTER_SYM { $$=INTERVAL_QUARTER; }
| SECOND_SYM { $$=INTERVAL_SECOND; }
- | YEAR_SYM { $$=INTERVAL_YEAR; };
+ | YEAR_SYM { $$=INTERVAL_YEAR; }
+ ;
date_time_type:
- DATE_SYM {$$=MYSQL_TIMESTAMP_DATE;}
- | TIME_SYM {$$=MYSQL_TIMESTAMP_TIME;}
- | DATETIME {$$=MYSQL_TIMESTAMP_DATETIME;};
+ DATE_SYM {$$=MYSQL_TIMESTAMP_DATE;}
+ | TIME_SYM {$$=MYSQL_TIMESTAMP_TIME;}
+ | DATETIME {$$=MYSQL_TIMESTAMP_DATETIME;}
+ | TIMESTAMP {$$=MYSQL_TIMESTAMP_DATETIME;}
+ ;
table_alias:
/* empty */
@@ -4958,11 +5010,17 @@ opt_all:
where_clause:
/* empty */ { Select->where= 0; }
- | WHERE expr
+ | WHERE
+ {
+ Select->parsing_place= IN_WHERE;
+ }
+ expr
{
- Select->where= $2;
- if ($2)
- $2->top_level_item();
+ SELECT_LEX *select= Select;
+ select->where= $3;
+ select->parsing_place= NO_MATTER;
+ if ($3)
+ $3->top_level_item();
}
;
@@ -4970,13 +5028,13 @@ having_clause:
/* empty */
| HAVING
{
- Select->parsing_place= SELECT_LEX_NODE::IN_HAVING;
+ Select->parsing_place= IN_HAVING;
}
expr
{
SELECT_LEX *sel= Select;
sel->having= $3;
- sel->parsing_place= SELECT_LEX_NODE::NO_MATTER;
+ sel->parsing_place= NO_MATTER;
if ($3)
$3->top_level_item();
}
@@ -5730,7 +5788,7 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
} opt_limit_clause_init
- | keys_or_index FROM table_ident opt_db
+ | keys_or_index from_or_in table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
if ($4)
@@ -6312,7 +6370,7 @@ simple_ident:
else
{
SELECT_LEX *sel=Select;
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,NullS,$1.str) :
(Item*) new Item_ref(0,0, NullS,NullS,$1.str);
@@ -6325,7 +6383,7 @@ simple_ident_nospvar:
ident
{
SELECT_LEX *sel=Select;
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,NullS,$1.str) :
(Item*) new Item_ref(0,0,NullS,NullS,$1.str);
@@ -6345,7 +6403,7 @@ simple_ident_q:
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $1.str, thd->where);
}
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,$1.str,$3.str) :
(Item*) new Item_ref(0,0,NullS,$1.str,$3.str);
@@ -6361,7 +6419,7 @@ simple_ident_q:
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $2.str, thd->where);
}
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,$2.str,$4.str) :
(Item*) new Item_ref(0,0,NullS,$2.str,$4.str);
@@ -6377,7 +6435,7 @@ simple_ident_q:
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $3.str, thd->where);
}
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ $$= (sel->parsing_place != IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
@@ -6791,7 +6849,8 @@ option_value:
&$1.base_name, $3));
}
else
- { /* An SP local variable */
+ {
+ /* An SP local variable */
sp_pcontext *ctx= lex->spcont;
sp_pvar_t *spv;
sp_instr_set *i;
@@ -6875,16 +6934,24 @@ internal_variable_name:
/* We have to lookup here since local vars can shadow sysvars */
if (!spc || !(spv = spc->find_pvar(&$1)))
- { /* Not an SP local variable */
+ {
+ /* Not an SP local variable */
sys_var *tmp=find_sys_var($1.str, $1.length);
if (!tmp)
YYABORT;
$$.var= tmp;
$$.base_name.str=0;
$$.base_name.length=0;
+ /*
+ If this is time_zone variable we should open time zone
+ describing tables
+ */
+ if (tmp == &sys_time_zone)
+ Lex->time_zone_tables_used= &fake_time_zone_tables_list;
}
else
- { /* An SP local variable */
+ {
+ /* An SP local variable */
$$.var= NULL;
$$.base_name= $1;
}
diff --git a/sql/table.cc b/sql/table.cc
index 1764df75a7e..5d0c60718d3 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1111,6 +1111,17 @@ void append_unescaped(String *res, const char *pos, uint length)
for (; pos != end ; pos++)
{
+#if defined(USE_MB) && MYSQL_VERSION_ID < 40100
+ uint mblen;
+ if (use_mb(default_charset_info) &&
+ (mblen= my_ismbchar(default_charset_info, pos, end)))
+ {
+ res->append(pos, mblen);
+ pos+= mblen;
+ continue;
+ }
+#endif
+
switch (*pos) {
case 0: /* Must be escaped for 'mysql' */
res->append('\\');
diff --git a/sql/time.cc b/sql/time.cc
index 132612e53c5..4421b6aa00f 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -20,166 +20,9 @@
#include "mysql_priv.h"
#include <m_ctype.h>
-static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */
-uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037";
-
-
-/*
- Offset of system time zone from UTC in seconds used to speed up
- work of my_system_gmt_sec() function.
-*/
-static long my_time_zone=0;
-
-
-/*
- Prepare offset of system time zone from UTC for my_system_gmt_sec() func.
-
- SYNOPSIS
- init_time()
-*/
-void init_time(void)
-{
- time_t seconds;
- struct tm *l_time,tm_tmp;;
- TIME my_time;
- bool not_used;
-
- seconds= (time_t) time((time_t*) 0);
- localtime_r(&seconds,&tm_tmp);
- l_time= &tm_tmp;
- my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */
- my_time.year= (uint) l_time->tm_year+1900;
- my_time.month= (uint) l_time->tm_mon+1;
- my_time.day= (uint) l_time->tm_mday;
- my_time.hour= (uint) l_time->tm_hour;
- my_time.minute= (uint) l_time->tm_min;
- my_time.second= (uint) l_time->tm_sec;
- my_system_gmt_sec(&my_time, &my_time_zone, &not_used); /* Init my_time_zone */
-}
-
-
-/*
- Convert time in TIME representation in system time zone to its
- my_time_t form (number of seconds in UTC since begginning of Unix Epoch).
-
- SYNOPSIS
- my_system_gmt_sec()
- t - time value to be converted
- my_timezone - pointer to long where offset of system time zone
- from UTC will be stored for caching
- in_dst_time_gap - set to true if time falls into spring time-gap
-
- NOTES
- The idea is to cache the time zone offset from UTC (including daylight
- saving time) for the next call to make things faster. But currently we
- just calculate this offset during startup (by calling init_time()
- function) and use it all the time.
- Time value provided should be legal time value (e.g. '2003-01-01 25:00:00'
- is not allowed).
-
- RETURN VALUE
- Time in UTC seconds since Unix Epoch representation.
-*/
-my_time_t
-my_system_gmt_sec(const TIME *t, long *my_timezone, bool *in_dst_time_gap)
-{
- uint loop;
- time_t tmp;
- struct tm *l_time,tm_tmp;
- long diff, current_timezone;
-
- /*
- Calculate the gmt time based on current time and timezone
- The -1 on the end is to ensure that if have a date that exists twice
- (like 2002-10-27 02:00:0 MET), we will find the initial date.
-
- By doing -3600 we will have to call localtime_r() several times, but
- I couldn't come up with a better way to get a repeatable result :(
-
- We can't use mktime() as it's buggy on many platforms and not thread safe.
- */
- tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
- (long) days_at_timestart)*86400L + (long) t->hour*3600L +
- (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
- 3600);
- current_timezone= my_time_zone;
-
- localtime_r(&tmp,&tm_tmp);
- l_time=&tm_tmp;
- for (loop=0;
- loop < 2 &&
- (t->hour != (uint) l_time->tm_hour ||
- t->minute != (uint) l_time->tm_min);
- loop++)
- { /* One check should be enough ? */
- /* Get difference in days */
- int days= t->day - l_time->tm_mday;
- if (days < -1)
- days= 1; // Month has wrapped
- else if (days > 1)
- days= -1;
- diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
- (long) (60*((int) t->minute - (int) l_time->tm_min)));
- current_timezone+= diff+3600; // Compensate for -3600 above
- tmp+= (time_t) diff;
- localtime_r(&tmp,&tm_tmp);
- l_time=&tm_tmp;
- }
- /*
- Fix that if we are in the not existing daylight saving time hour
- we move the start of the next real hour
- */
- if (loop == 2 && t->hour != (uint) l_time->tm_hour)
- {
- int days= t->day - l_time->tm_mday;
- if (days < -1)
- days=1; // Month has wrapped
- else if (days > 1)
- days= -1;
- diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+
- (long) (60*((int) t->minute - (int) l_time->tm_min)));
- if (diff == 3600)
- tmp+=3600 - t->minute*60 - t->second; // Move to next hour
- else if (diff == -3600)
- tmp-=t->minute*60 + t->second; // Move to previous hour
-
- *in_dst_time_gap= 1;
- }
- *my_timezone= current_timezone;
-
- return (my_time_t) tmp;
-} /* my_system_gmt_sec */
-
/* Some functions to calculate dates */
- /* Calculate nr of day since year 0 in new date-system (from 1615) */
-
-long calc_daynr(uint year,uint month,uint day)
-{
- long delsum;
- int temp;
- DBUG_ENTER("calc_daynr");
-
- if (year == 0 && month == 0 && day == 0)
- DBUG_RETURN(0); /* Skip errors */
- if (year < 200)
- {
- if ((year=year+1900) < 1900+YY_PART_YEAR)
- year+=100;
- }
- delsum= (long) (365L * year+ 31*(month-1) +day);
- if (month <= 2)
- year--;
- else
- delsum-= (long) (month*4+23)/10;
- temp=(int) ((year/100+1)*3)/4;
- DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld",
- year+(month <= 2),month,day,delsum+year/4-temp));
- DBUG_RETURN(delsum+(int) year/4-temp);
-} /* calc_daynr */
-
-
#ifndef TESTTIME
/* Calc weekday from daynr */
/* Returns 0 for monday, 1 for tuesday .... */
diff --git a/sql/tztime.cc b/sql/tztime.cc
index f2d20634ec5..af9af530fec 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -32,6 +32,7 @@
#include "mysql_priv.h"
#else
#include <my_global.h>
+#include <my_time.h>
#include "tztime.h"
#include <my_sys.h>
#endif
@@ -1358,6 +1359,13 @@ static bool tz_inited= 0;
static uint tz_leapcnt= 0;
static LS_INFO *tz_lsis= 0;
+/*
+ Shows whenever we have found time zone tables during start-up.
+ Used for avoiding of putting those tables to global table list
+ for queries that use time zone info.
+*/
+static bool time_zone_tables_exist= 1;
+
typedef struct st_tz_names_entry: public Sql_alloc
{
@@ -1387,6 +1395,68 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
/*
+ Prepare table list with time zone related tables from preallocated array.
+
+ SYNOPSIS
+ tz_init_table_list()
+ tz_tabs - pointer to preallocated array of 4 TABLE_LIST objects.
+
+ DESCRIPTION
+ This function prepares list of TABLE_LIST objects which can be used
+ for opening of time zone tables from preallocated array.
+*/
+
+void
+tz_init_table_list(TABLE_LIST *tz_tabs)
+{
+ bzero(tz_tabs, sizeof(TABLE_LIST) * 4);
+ tz_tabs[0].alias= tz_tabs[0].real_name= (char*)"time_zone_name";
+ tz_tabs[1].alias= tz_tabs[1].real_name= (char*)"time_zone";
+ tz_tabs[2].alias= tz_tabs[2].real_name= (char*)"time_zone_transition_type";
+ tz_tabs[3].alias= tz_tabs[3].real_name= (char*)"time_zone_transition";
+ tz_tabs[0].next= tz_tabs+1;
+ tz_tabs[1].next= tz_tabs+2;
+ tz_tabs[2].next= tz_tabs+3;
+ tz_tabs[0].lock_type= tz_tabs[1].lock_type= tz_tabs[2].lock_type=
+ tz_tabs[3].lock_type= TL_READ;
+ tz_tabs[0].db= tz_tabs[1].db= tz_tabs[2].db= tz_tabs[3].db= (char *)"mysql";
+}
+
+
+/*
+ Create table list with time zone related tables.
+
+ SYNOPSIS
+ my_tz_get_table_list()
+ thd - current thread object
+
+ DESCRIPTION
+ This function creates list of TABLE_LIST objects allocated in thd's
+ memroot, which can be used for opening of time zone tables.
+
+ 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 *tz_tabs;
+
+ if (!time_zone_tables_exist)
+ return 0;
+
+ if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) * 4)))
+ return &fake_time_zone_tables_list;
+
+ tz_init_table_list(tz_tabs);
+
+ return tz_tabs;
+}
+
+
+/*
Initialize time zone support infrastructure.
SYNOPSIS
@@ -1398,13 +1468,13 @@ extern "C" byte* my_offset_tzs_get_key(Time_zone_offset *entry, uint *length,
DESCRIPTION
This function will init memory structures needed for time zone support,
it will register mandatory SYSTEM time zone in them. It will try to open
- mysql.time_zone_leap_seconds table and and load information which further
- will be shared among all time zones loaded. It will also try to load
- information about default time zone. If system tables with time zone
- descriptions don't exist it won't fail (unless default_tzname is time zone
- from tables). If bootstrap parameter is true then this routine assumes that
- we are in bootstrap mode and won't load time zone descriptions unless someone
- specifies default time zone which is supposedly stored in those tables.
+ mysql.time_zone* tables and load information about default time zone and
+ information which further will be shared among all time zones loaded.
+ If system tables with time zone descriptions don't exist it won't fail
+ (unless default_tzname is time zone from tables). If bootstrap parameter
+ is true then this routine assumes that we are in bootstrap mode and won't
+ load time zone descriptions unless someone specifies default time zone
+ which is supposedly stored in those tables.
It'll also set default time zone if it is specified.
RETURN VALUES
@@ -1415,14 +1485,13 @@ my_bool
my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
THD *thd;
- TABLE_LIST tables;
+ TABLE_LIST *tables= 0;
+ TABLE_LIST tables_buff[5];
TABLE *table;
- TABLE *lock_ptr;
- MYSQL_LOCK *lock;
TZ_NAMES_ENTRY *tmp_tzname;
my_bool return_val= 1;
int res;
- uint not_used;
+ uint counter;
DBUG_ENTER("my_tz_init");
/*
@@ -1467,7 +1536,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
if (bootstrap)
{
/* If we are in bootstrap mode we should not load time zone tables */
- return_val= 0;
+ return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
@@ -1479,28 +1548,25 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
thd->db= my_strdup("mysql",MYF(0));
thd->db_length= 5; // Safety
- bzero((char*) &tables,sizeof(tables));
- tables.alias= tables.real_name= (char*)"time_zone_leap_second";
- tables.lock_type= TL_READ;
- tables.db= thd->db;
-
- if (open_tables(thd, &tables, &not_used))
+ bzero((char*) &tables_buff, sizeof(TABLE_LIST));
+ tables_buff[0].alias= tables_buff[0].real_name=
+ (char*)"time_zone_leap_second";
+ tables_buff[0].lock_type= TL_READ;
+ tables_buff[0].db= thd->db;
+ tables_buff[0].next= tables_buff + 1;
+ /* Fill TABLE_LIST for rest of the time zone describing tables */
+ tz_init_table_list(tables_buff + 1);
+
+ if (open_tables(thd, tables_buff, &counter) ||
+ lock_tables(thd, tables_buff, counter))
{
- sql_print_error("Warning: Can't open time zone table: %s "
- "trying to live without them", thd->net.last_error);
+ sql_print_warning("Can't open and lock time zone table: %s "
+ "trying to live without them", thd->net.last_error);
/* We will try emulate that everything is ok */
- return_val= 0;
+ return_val= time_zone_tables_exist= 0;
goto end_with_setting_default_tz;
}
-
- lock_ptr= tables.table;
- if (!(lock= mysql_lock_tables(thd, &lock_ptr, 1)))
- {
- sql_print_error("Fatal error: Can't lock time zone table: %s",
- thd->net.last_error);
- goto end_with_close;
- }
-
+ tables= tables_buff + 1;
/*
Now we are going to load leap seconds descriptions that are shared
@@ -1513,11 +1579,16 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
{
sql_print_error("Fatal error: Out of memory while loading "
"mysql.time_zone_leap_second table");
- goto end_with_unlock;
+ goto end_with_close;
}
- table= tables.table;
- table->file->ha_index_init(0);
+ table= tables_buff[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
+ for MyISAM.
+ */
+ (void)table->file->ha_index_init(0);
tz_leapcnt= 0;
res= table->file->index_first(table->record[0]);
@@ -1529,7 +1600,7 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
sql_print_error("Fatal error: While loading mysql.time_zone_leap_second"
" table: too much leaps");
table->file->ha_index_end();
- goto end_with_unlock;
+ goto end_with_close;
}
tz_lsis[tz_leapcnt].ls_trans= (my_time_t)table->field[0]->val_int();
@@ -1545,13 +1616,13 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
res= table->file->index_next(table->record[0]);
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
if (res != HA_ERR_END_OF_FILE)
{
sql_print_error("Fatal error: Error while loading "
"mysql.time_zone_leap_second table");
- goto end_with_unlock;
+ goto end_with_close;
}
/*
@@ -1561,19 +1632,12 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
return_val= 0;
-end_with_unlock:
- mysql_unlock_tables(thd, lock);
-
-end_with_close:
- close_thread_tables(thd);
- thd->version--; /* Force close to free memory */
-
end_with_setting_default_tz:
- /* If not an error and have default time zone try to load it */
- if (!return_val && default_tzname)
+ /* If we have default time zone try to load it */
+ if (default_tzname)
{
String tzname(default_tzname, &my_charset_latin1);
- if (!(global_system_variables.time_zone= my_tz_find(thd, &tzname)))
+ if (!(global_system_variables.time_zone= my_tz_find(&tzname, tables)))
{
sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
default_tzname);
@@ -1581,6 +1645,10 @@ end_with_setting_default_tz:
}
}
+end_with_close:
+ thd->version--; /* Force close to free memory */
+ close_thread_tables(thd);
+
end_with_cleanup:
/* if there were error free time zone describing structs */
@@ -1624,29 +1692,27 @@ void my_tz_free()
Load time zone description from system tables.
SYNOPSIS
- tz_load_from_db()
- thd - current thread object
- tz_name - name of time zone that should be loaded.
+ tz_load_from_open_tables()
+ tz_name - name of time zone that should be loaded.
+ tz_tables - list of tables from which time zone description
+ should be loaded
DESCRIPTION
- This function will try to open system tables describing time zones
- and to load information about time zone specified. It will also update
- information in hash used for time zones lookup.
+ This function will try to load information about time zone specified
+ from the list of the already opened and locked tables (first table in
+ tz_tables should be time_zone_name, next time_zone, then
+ time_zone_transition_type and time_zone_transition should be last).
+ It will also update information in hash used for time zones lookup.
RETURN VALUES
Returns pointer to newly created Time_zone object or 0 in case of error.
*/
+
static Time_zone*
-tz_load_from_db(THD *thd, const String *tz_name)
+tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
{
- TABLE_LIST tables[4];
TABLE *table= 0;
- TABLE *lock_ptr[4];
- MYSQL_LOCK *lock;
- char system_db_name[]= "mysql";
- char *db_save;
- uint db_length_save;
TIME_ZONE_INFO *tz_info;
TZ_NAMES_ENTRY *tmp_tzname;
Time_zone *return_val= 0;
@@ -1666,17 +1732,15 @@ tz_load_from_db(THD *thd, const String *tz_name)
#ifdef ABBR_ARE_USED
char chars[max(TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))];
#endif
- uint not_used;
- DBUG_ENTER("tz_load_from_db");
+ 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)))
{
- sql_print_error("Error: Out of memory while loading time zone "
- "description");
+ sql_print_error("Out of memory while loading time zone description");
return 0;
}
tz_info= (TIME_ZONE_INFO *)alloc_buff;
@@ -1689,76 +1753,45 @@ tz_load_from_db(THD *thd, const String *tz_name)
strmake(tz_name_buff, tz_name->ptr(), tz_name->length());
/*
- Open and lock time zone description tables
- */
- db_save= thd->db;
- db_length_save= thd->db_length;
- thd->db= system_db_name;
- thd->db_length= 5;
-
- bzero((char*) &tables,sizeof(tables));
- tables[0].alias= tables[0].real_name= (char*)"time_zone_name";
- tables[1].alias= tables[1].real_name= (char*)"time_zone";
- tables[2].alias= tables[2].real_name= (char*)"time_zone_transition";
- tables[3].alias= tables[3].real_name= (char*)"time_zone_transition_type";
- tables[0].next_local= tables[0].next_global= tables+1;
- tables[1].next_local= tables[1].next_global= tables+2;
- tables[2].next_local= tables[2].next_global= tables+3;
- tables[0].lock_type= tables[1].lock_type= tables[2].lock_type=
- tables[3].lock_type= TL_READ;
- tables[0].db= tables[1].db= tables[2].db= tables[3].db= thd->db;
- if (open_tables(thd, tables, &not_used))
- {
- sql_print_error("Error: Can't open time zone tables: %s",
- thd->net.last_error);
- goto end;
- }
-
- lock_ptr[0]= tables[0].table;
- lock_ptr[1]= tables[1].table;
- lock_ptr[2]= tables[2].table;
- lock_ptr[3]= tables[3].table;
- if (!(lock= mysql_lock_tables(thd, lock_ptr, 4)))
- {
- sql_print_error("Error: Can't lock time zone tables: %s",
- thd->net.last_error);
- goto end_with_close;
- }
-
- /*
Let us find out time zone id by its name (there is only one index
and it is specifically for this purpose).
*/
- table= tables[0].table;
-
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store(tz_name->ptr(), tz_name->length(), &my_charset_latin1);
- table->file->ha_index_init(0);
+ /*
+ 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
+ for MyISAM.
+ */
+ (void)table->file->ha_index_init(0);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
{
- sql_print_error("Error: Can't find description of time zone.");
- goto end_with_unlock;
+ sql_print_error("Can't find description of time zone.");
+ goto end;
}
tzid= (uint)table->field[1]->val_int();
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
Now we need to lookup record in mysql.time_zone table in order to
understand whenever this timezone uses leap seconds (again we are
using the only index in this table).
*/
- table= tables[1].table;
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
{
- sql_print_error("Error: Can't find description of time zone.");
- goto end_with_unlock;
+ sql_print_error("Can't find description of time zone.");
+ goto end;
}
/* If Uses_leap_seconds == 'Y' */
@@ -1768,7 +1801,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
tz_info->lsis= tz_lsis;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
Now we will iterate through records for out time zone in
@@ -1776,9 +1809,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
only for our time zone guess what are we doing?
Right - using special index.
*/
- table= tables[3].table;
+ table= tz_tables->table;
+ tz_tables= tz_tables->next;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
@@ -1792,7 +1826,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table: too big "
"transition type id");
- goto end_with_unlock;
+ goto end;
}
ttis[ttid].tt_gmtoff= (long)table->field[2]->val_int();
@@ -1806,7 +1840,7 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table: not enough "
"room for abbreviations");
- goto end_with_unlock;
+ goto end;
}
ttis[ttid].tt_abbrind= tz_info->charcnt;
memcpy(chars + tz_info->charcnt, abbr.ptr(), abbr.length());
@@ -1837,10 +1871,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition_type table");
- goto end_with_unlock;
+ goto end;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
/*
@@ -1848,9 +1882,9 @@ tz_load_from_db(THD *thd, const String *tz_name)
mysql.time_zone_transition table. Here we additionaly need records
in ascending order by index scan also satisfies us.
*/
- table= tables[2].table;
+ table= tz_tables->table;
table->field[0]->store((longlong)tzid);
- table->file->ha_index_init(0);
+ (void)table->file->ha_index_init(0);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
@@ -1865,14 +1899,14 @@ tz_load_from_db(THD *thd, const String *tz_name)
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table: "
"too much transitions");
- goto end_with_unlock;
+ goto end;
}
if (ttid + 1 > tz_info->typecnt)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table: "
"bad transition type id");
- goto end_with_unlock;
+ goto end;
}
ats[tz_info->timecnt]= ttime;
@@ -1895,10 +1929,10 @@ tz_load_from_db(THD *thd, const String *tz_name)
{
sql_print_error("Error while loading time zone description from "
"mysql.time_zone_transition table");
- goto end_with_unlock;
+ goto end;
}
- table->file->ha_index_end();
+ (void)table->file->ha_index_end();
table= 0;
/*
@@ -1913,9 +1947,8 @@ tz_load_from_db(THD *thd, const String *tz_name)
#endif
sizeof(TRAN_TYPE_INFO) * tz_info->typecnt)))
{
- sql_print_error("Error: Out of memory while loading time zone "
- "description");
- goto end_with_unlock;
+ sql_print_error("Out of memory while loading time zone description");
+ goto end;
}
@@ -1939,13 +1972,13 @@ tz_load_from_db(THD *thd, const String *tz_name)
*/
if (tz_info->typecnt < 1)
{
- sql_print_error("Error: loading time zone without transition types");
- goto end_with_unlock;
+ sql_print_error("loading time zone without transition types");
+ goto end;
}
if (prepare_tz_info(tz_info, &tz_storage))
{
- sql_print_error("Error: Unable to build mktime map for time zone");
- goto end_with_unlock;
+ sql_print_error("Unable to build mktime map for time zone");
+ goto end;
}
@@ -1956,8 +1989,8 @@ tz_load_from_db(THD *thd, const String *tz_name)
&my_charset_latin1),
my_hash_insert(&tz_names, (const byte *)tmp_tzname)))
{
- sql_print_error("Error: Out of memory while loading time zone");
- goto end_with_unlock;
+ sql_print_error("Out of memory while loading time zone");
+ goto end;
}
/*
@@ -1965,19 +1998,11 @@ tz_load_from_db(THD *thd, const String *tz_name)
*/
return_val= tmp_tzname->tz;
-end_with_unlock:
+end:
if (table)
- table->file->ha_index_end();
-
- mysql_unlock_tables(thd, lock);
+ (void)table->file->ha_index_end();
-end_with_close:
- close_thread_tables(thd);
-
-end:
- thd->db= db_save;
- thd->db_length= db_length_save;
DBUG_RETURN(return_val);
}
@@ -2067,8 +2092,8 @@ str_to_offset(const char *str, uint length, long *offset)
SYNOPSIS
my_tz_find()
- thd - current thread
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,
@@ -2090,7 +2115,11 @@ 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.
+ 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.
RETURN VALUE
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
@@ -2098,7 +2127,7 @@ str_to_offset(const char *str, uint length, long *offset)
*/
Time_zone *
-my_tz_find(THD *thd, const String * name)
+my_tz_find(const String * name, TABLE_LIST *tz_tables)
{
TZ_NAMES_ENTRY *tmp_tzname;
Time_zone *result_tz= 0;
@@ -2108,6 +2137,8 @@ my_tz_find(THD *thd, const String * name)
DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr() : "NULL"));
+ DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
+
if (!name)
DBUG_RETURN(0);
@@ -2125,18 +2156,21 @@ my_tz_find(THD *thd, const String * name)
if (!(result_tz= new (&tz_storage) Time_zone_offset(offset)) ||
my_hash_insert(&offset_tzs, (const byte *) result_tz))
{
+ result_tz= 0;
sql_print_error("Fatal error: Out of memory "
"while setting new time zone");
- result_tz= 0;
}
}
- } else {
+ }
+ else
+ {
+ result_tz= 0;
if ((tmp_tzname= (TZ_NAMES_ENTRY *)hash_search(&tz_names,
(const byte *)name->ptr(),
name->length())))
result_tz= tmp_tzname->tz;
- else
- result_tz= tz_load_from_db(thd, name);
+ else if (time_zone_tables_exist)
+ result_tz= tz_load_from_open_tables(name, tz_tables);
}
VOID(pthread_mutex_unlock(&tz_LOCK));
diff --git a/sql/tztime.h b/sql/tztime.h
index 334b14f4fc4..aabec260ec7 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -19,15 +19,8 @@
#pragma interface /* gcc class interface */
#endif
-/*
- Portable time_t replacement.
- Should be signed and hold seconds for 1902-2038 range.
-*/
-typedef long my_time_t;
-#define MY_TIME_T_MAX LONG_MAX
-#define MY_TIME_T_MIN LONG_MIN
-
#if !defined(TESTTIME) && !defined(TZINFO2SQL)
+
/*
This class represents abstract time zone and provides
basic interface for TIME <-> my_time_t conversion.
@@ -66,7 +59,8 @@ public:
extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM;
-extern Time_zone * my_tz_find(THD *thd, const String *name);
+extern TABLE_LIST * my_tz_get_table_list(THD *thd);
+extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();
diff --git a/sql/unireg.cc b/sql/unireg.cc
index b5f6c3546a4..c82fcc4abef 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -75,7 +75,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
- DBUG_ENTER("rea_create_table");
+ DBUG_ENTER("mysql_create_frm");
formnames.type_names=0;
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))