2009-09-10 11:18:29 +02:00
|
|
|
/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
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.
|
2001-12-06 13:10:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
**
|
|
|
|
** This file implements classes defined in sql_class.h
|
|
|
|
** Especially the classes to handle a result from a select
|
|
|
|
**
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-05-26 12:09:14 +02:00
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
2000-07-31 21:29:14 +02:00
|
|
|
#pragma implementation // gcc: Class implementation
|
|
|
|
#endif
|
|
|
|
|
2010-04-07 13:58:40 +02:00
|
|
|
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_priv.h"
|
|
|
|
#include "unireg.h" // REQUIRED: for other includes
|
|
|
|
#include "sql_class.h"
|
|
|
|
#include "lock.h" // unlock_global_read_lock, mysql_unlock_tables
|
|
|
|
#include "sql_cache.h" // query_cache_abort
|
|
|
|
#include "sql_base.h" // close_thread_tables
|
|
|
|
#include "sql_time.h" // date_time_format_copy
|
|
|
|
#include "sql_acl.h" // NO_ACCESS,
|
|
|
|
// acl_getroot_no_password
|
|
|
|
#include "sql_base.h" // close_temporary_tables
|
|
|
|
#include "sql_handler.h" // mysql_ha_cleanup
|
2007-04-12 08:58:04 +02:00
|
|
|
#include "rpl_rli.h"
|
2009-06-27 15:18:47 +02:00
|
|
|
#include "rpl_filter.h"
|
2007-04-13 14:55:28 +02:00
|
|
|
#include "rpl_record.h"
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
#include "slave.h"
|
2005-12-22 06:39:02 +01:00
|
|
|
#include <my_bitmap.h>
|
|
|
|
#include "log_event.h"
|
2009-12-15 20:52:47 +01:00
|
|
|
#include "sql_audit.h"
|
2000-07-31 21:29:14 +02:00
|
|
|
#include <m_ctype.h>
|
|
|
|
#include <sys/stat.h>
|
2001-03-14 07:07:12 +01:00
|
|
|
#include <thr_alarm.h>
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifdef __WIN__
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
2002-03-15 22:57:31 +01:00
|
|
|
#include <mysys_err.h>
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
#include <limits.h>
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-12-21 01:07:45 +01:00
|
|
|
#include "sp_rcontext.h"
|
|
|
|
#include "sp_cache.h"
|
2009-12-03 19:37:38 +01:00
|
|
|
#include "transaction.h"
|
2009-09-29 17:38:40 +02:00
|
|
|
#include "debug_sync.h"
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_parse.h" // is_update_query
|
2003-07-01 18:14:24 +02:00
|
|
|
|
2003-04-02 12:06:33 +02:00
|
|
|
/*
|
|
|
|
The following is used to initialise Table_ident with a internal
|
|
|
|
table name
|
|
|
|
*/
|
|
|
|
char internal_table_name[2]= "*";
|
2006-07-19 20:33:19 +02:00
|
|
|
char empty_c_string[1]= {0}; /* used for not defined db */
|
2003-04-02 12:06:33 +02:00
|
|
|
|
2005-10-25 11:02:48 +02:00
|
|
|
const char * const THD::DEFAULT_WHERE= "field list";
|
|
|
|
|
2002-10-24 22:33:24 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
** Instansiate templates
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2005-06-22 11:08:28 +02:00
|
|
|
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Used templates */
|
|
|
|
template class List<Key>;
|
|
|
|
template class List_iterator<Key>;
|
2007-06-10 12:43:57 +02:00
|
|
|
template class List<Key_part_spec>;
|
|
|
|
template class List_iterator<Key_part_spec>;
|
2000-07-31 21:29:14 +02:00
|
|
|
template class List<Alter_drop>;
|
|
|
|
template class List_iterator<Alter_drop>;
|
|
|
|
template class List<Alter_column>;
|
|
|
|
template class List_iterator<Alter_column>;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
** User variables
|
|
|
|
****************************************************************************/
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
extern "C" uchar *get_var_key(user_var_entry *entry, size_t *length,
|
|
|
|
my_bool not_used __attribute__((unused)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
*length= entry->name.length;
|
|
|
|
return (uchar*) entry->name.str;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-11-07 11:49:02 +01:00
|
|
|
extern "C" void free_user_var(user_var_entry *entry)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
|
|
|
|
if (entry->value && entry->value != pos)
|
|
|
|
my_free(entry->value, MYF(0));
|
|
|
|
my_free((char*) entry,MYF(0));
|
|
|
|
}
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
bool Key_part_spec::operator==(const Key_part_spec& other) const
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
return length == other.length &&
|
2009-10-09 17:18:52 +02:00
|
|
|
!my_strcasecmp(system_charset_info, field_name.str,
|
|
|
|
other.field_name.str);
|
2004-04-21 12:15:43 +02:00
|
|
|
}
|
|
|
|
|
5.1 version of a fix and test cases for bugs:
Bug#4968 ""Stored procedure crash if cursor opened on altered table"
Bug#6895 "Prepared Statements: ALTER TABLE DROP COLUMN does nothing"
Bug#19182 "CREATE TABLE bar (m INT) SELECT n FROM foo; doesn't work from
stored procedure."
Bug#19733 "Repeated alter, or repeated create/drop, fails"
Bug#22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server"
Bug#24879 "Prepared Statements: CREATE TABLE (UTF8 KEY) produces a
growing key length" (this bug is not fixed in 5.0)
Re-execution of CREATE DATABASE, CREATE TABLE and ALTER TABLE
statements in stored routines or as prepared statements caused
incorrect results (and crashes in versions prior to 5.0.25).
In 5.1 the problem occured only for CREATE DATABASE, CREATE TABLE
SELECT and CREATE TABLE with INDEX/DATA DIRECTOY options).
The problem of bugs 4968, 19733, 19282 and 6895 was that functions
mysql_prepare_table, mysql_create_table and mysql_alter_table are not
re-execution friendly: during their operation they modify contents
of LEX (members create_info, alter_info, key_list, create_list),
thus making the LEX unusable for the next execution.
In particular, these functions removed processed columns and keys from
create_list, key_list and drop_list. Search the code in sql_table.cc
for drop_it.remove() and similar patterns to find evidence.
The fix is to supply to these functions a usable copy of each of the
above structures at every re-execution of an SQL statement.
To simplify memory management, LEX::key_list and LEX::create_list
were added to LEX::alter_info, a fresh copy of which is created for
every execution.
The problem of crashing bug 22060 stemmed from the fact that the above
metnioned functions were not only modifying HA_CREATE_INFO structure
in LEX, but also were changing it to point to areas in volatile memory
of the execution memory root.
The patch solves this problem by creating and using an on-stack
copy of HA_CREATE_INFO in mysql_execute_command.
Additionally, this patch splits the part of mysql_alter_table
that analizes and rewrites information from the parser into
a separate function - mysql_prepare_alter_table, in analogy with
mysql_prepare_table, which is renamed to mysql_prepare_create_table.
2007-05-28 13:30:01 +02:00
|
|
|
/**
|
|
|
|
Construct an (almost) deep copy of this key. Only those
|
|
|
|
elements that are known to never change are not copied.
|
|
|
|
If out of memory, a partial copy is returned and an error is set
|
|
|
|
in THD.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Key::Key(const Key &rhs, MEM_ROOT *mem_root)
|
|
|
|
:type(rhs.type),
|
|
|
|
key_create_info(rhs.key_create_info),
|
|
|
|
columns(rhs.columns, mem_root),
|
|
|
|
name(rhs.name),
|
|
|
|
generated(rhs.generated)
|
|
|
|
{
|
|
|
|
list_copy_and_replace_each_value(columns, mem_root);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Construct an (almost) deep copy of this foreign key. Only those
|
|
|
|
elements that are known to never change are not copied.
|
|
|
|
If out of memory, a partial copy is returned and an error is set
|
|
|
|
in THD.
|
|
|
|
*/
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
|
5.1 version of a fix and test cases for bugs:
Bug#4968 ""Stored procedure crash if cursor opened on altered table"
Bug#6895 "Prepared Statements: ALTER TABLE DROP COLUMN does nothing"
Bug#19182 "CREATE TABLE bar (m INT) SELECT n FROM foo; doesn't work from
stored procedure."
Bug#19733 "Repeated alter, or repeated create/drop, fails"
Bug#22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server"
Bug#24879 "Prepared Statements: CREATE TABLE (UTF8 KEY) produces a
growing key length" (this bug is not fixed in 5.0)
Re-execution of CREATE DATABASE, CREATE TABLE and ALTER TABLE
statements in stored routines or as prepared statements caused
incorrect results (and crashes in versions prior to 5.0.25).
In 5.1 the problem occured only for CREATE DATABASE, CREATE TABLE
SELECT and CREATE TABLE with INDEX/DATA DIRECTOY options).
The problem of bugs 4968, 19733, 19282 and 6895 was that functions
mysql_prepare_table, mysql_create_table and mysql_alter_table are not
re-execution friendly: during their operation they modify contents
of LEX (members create_info, alter_info, key_list, create_list),
thus making the LEX unusable for the next execution.
In particular, these functions removed processed columns and keys from
create_list, key_list and drop_list. Search the code in sql_table.cc
for drop_it.remove() and similar patterns to find evidence.
The fix is to supply to these functions a usable copy of each of the
above structures at every re-execution of an SQL statement.
To simplify memory management, LEX::key_list and LEX::create_list
were added to LEX::alter_info, a fresh copy of which is created for
every execution.
The problem of crashing bug 22060 stemmed from the fact that the above
metnioned functions were not only modifying HA_CREATE_INFO structure
in LEX, but also were changing it to point to areas in volatile memory
of the execution memory root.
The patch solves this problem by creating and using an on-stack
copy of HA_CREATE_INFO in mysql_execute_command.
Additionally, this patch splits the part of mysql_alter_table
that analizes and rewrites information from the parser into
a separate function - mysql_prepare_alter_table, in analogy with
mysql_prepare_table, which is renamed to mysql_prepare_create_table.
2007-05-28 13:30:01 +02:00
|
|
|
:Key(rhs),
|
|
|
|
ref_table(rhs.ref_table),
|
|
|
|
ref_columns(rhs.ref_columns),
|
|
|
|
delete_opt(rhs.delete_opt),
|
|
|
|
update_opt(rhs.update_opt),
|
|
|
|
match_opt(rhs.match_opt)
|
|
|
|
{
|
|
|
|
list_copy_and_replace_each_value(ref_columns, mem_root);
|
|
|
|
}
|
2004-05-11 23:29:52 +02:00
|
|
|
|
|
|
|
/*
|
2004-05-15 10:57:40 +02:00
|
|
|
Test if a foreign key (= generated key) is a prefix of the given key
|
2004-05-11 23:29:52 +02:00
|
|
|
(ignoring key name, key type and order of columns)
|
|
|
|
|
|
|
|
NOTES:
|
|
|
|
This is only used to test if an index for a FOREIGN KEY exists
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
We only compare field names
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 Generated key is a prefix of other key
|
|
|
|
1 Not equal
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool foreign_key_prefix(Key *a, Key *b)
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2004-05-11 23:29:52 +02:00
|
|
|
/* Ensure that 'a' is the generated key */
|
|
|
|
if (a->generated)
|
|
|
|
{
|
|
|
|
if (b->generated && a->columns.elements > b->columns.elements)
|
2004-05-25 00:03:49 +02:00
|
|
|
swap_variables(Key*, a, b); // Put shorter key in 'a'
|
2004-05-11 23:29:52 +02:00
|
|
|
}
|
|
|
|
else
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2004-05-11 23:29:52 +02:00
|
|
|
if (!b->generated)
|
|
|
|
return TRUE; // No foreign key
|
2004-05-25 00:03:49 +02:00
|
|
|
swap_variables(Key*, a, b); // Put generated key in 'a'
|
2004-05-11 23:29:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Test if 'a' is a prefix of 'b' */
|
|
|
|
if (a->columns.elements > b->columns.elements)
|
|
|
|
return TRUE; // Can't be prefix
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Key_part_spec> col_it1(a->columns);
|
|
|
|
List_iterator<Key_part_spec> col_it2(b->columns);
|
|
|
|
const Key_part_spec *col1, *col2;
|
2004-05-11 23:29:52 +02:00
|
|
|
|
|
|
|
#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
|
|
|
|
while ((col1= col_it1++))
|
|
|
|
{
|
|
|
|
bool found= 0;
|
|
|
|
col_it2.rewind();
|
|
|
|
while ((col2= col_it2++))
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2004-05-11 23:29:52 +02:00
|
|
|
if (*col1 == *col2)
|
|
|
|
{
|
|
|
|
found= TRUE;
|
|
|
|
break;
|
|
|
|
}
|
2004-04-21 12:15:43 +02:00
|
|
|
}
|
2004-05-11 23:29:52 +02:00
|
|
|
if (!found)
|
|
|
|
return TRUE; // Error
|
|
|
|
}
|
|
|
|
return FALSE; // Is prefix
|
|
|
|
#else
|
|
|
|
while ((col1= col_it1++))
|
|
|
|
{
|
|
|
|
col2= col_it2++;
|
|
|
|
if (!(*col1 == *col2))
|
|
|
|
return TRUE;
|
2004-04-21 12:15:43 +02:00
|
|
|
}
|
2004-05-11 23:29:52 +02:00
|
|
|
return FALSE; // Is prefix
|
|
|
|
#endif
|
2004-04-21 12:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/****************************************************************************
|
|
|
|
** Thread specific functions
|
|
|
|
****************************************************************************/
|
2005-07-13 11:48:13 +02:00
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
/*
|
|
|
|
The following functions form part of the C plugin API
|
|
|
|
*/
|
|
|
|
|
2007-07-05 01:05:47 +02:00
|
|
|
extern "C" int mysql_tmpfile(const char *prefix)
|
|
|
|
{
|
|
|
|
char filename[FN_REFLEN];
|
|
|
|
File fd = create_temp_file(filename, mysql_tmpdir, prefix,
|
|
|
|
#ifdef __WIN__
|
|
|
|
O_BINARY | O_TRUNC | O_SEQUENTIAL |
|
|
|
|
O_SHORT_LIVED |
|
|
|
|
#endif /* __WIN__ */
|
|
|
|
O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
|
|
|
|
MYF(MY_WME));
|
|
|
|
if (fd >= 0) {
|
|
|
|
#ifndef __WIN__
|
|
|
|
/*
|
|
|
|
This can be removed once the following bug is fixed:
|
|
|
|
Bug #28903 create_temp_file() doesn't honor O_TEMPORARY option
|
|
|
|
(file not removed) (Unix)
|
|
|
|
*/
|
|
|
|
unlink(filename);
|
|
|
|
#endif /* !__WIN__ */
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2007-03-02 17:43:45 +01:00
|
|
|
int thd_in_lock_tables(const THD *thd)
|
2006-01-19 22:40:56 +01:00
|
|
|
{
|
2007-03-02 17:43:45 +01:00
|
|
|
return test(thd->in_lock_tables);
|
2006-01-19 22:40:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2007-03-02 17:43:45 +01:00
|
|
|
int thd_tablespace_op(const THD *thd)
|
2006-01-19 22:40:56 +01:00
|
|
|
{
|
2007-03-02 17:43:45 +01:00
|
|
|
return test(thd->tablespace_op);
|
2006-01-19 22:40:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2009-12-03 19:59:52 +01:00
|
|
|
const char *set_thd_proc_info(THD *thd, const char *info,
|
|
|
|
const char *calling_function,
|
|
|
|
const char *calling_file,
|
2007-05-02 20:13:33 +02:00
|
|
|
const unsigned int calling_line)
|
2006-01-19 22:40:56 +01:00
|
|
|
{
|
2009-12-03 19:59:52 +01:00
|
|
|
if (!thd)
|
|
|
|
thd= current_thd;
|
|
|
|
|
2006-01-19 22:40:56 +01:00
|
|
|
const char *old_info= thd->proc_info;
|
2009-12-03 19:59:52 +01:00
|
|
|
DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
|
2008-03-05 17:23:58 +01:00
|
|
|
(info != NULL) ? info : "(null)"));
|
2009-10-09 15:59:25 +02:00
|
|
|
#if defined(ENABLED_PROFILING)
|
2007-05-02 20:13:33 +02:00
|
|
|
thd->profiling.status_change(info, calling_function, calling_file, calling_line);
|
|
|
|
#endif
|
2006-01-19 22:40:56 +01:00
|
|
|
thd->proc_info= info;
|
|
|
|
return old_info;
|
|
|
|
}
|
|
|
|
|
2009-09-26 06:49:49 +02:00
|
|
|
extern "C"
|
2010-01-07 06:42:07 +01:00
|
|
|
const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
|
|
|
|
mysql_mutex_t *mutex, const char *msg)
|
2009-09-26 06:49:49 +02:00
|
|
|
{
|
|
|
|
if (!thd)
|
|
|
|
thd= current_thd;
|
|
|
|
|
2009-11-02 21:05:42 +01:00
|
|
|
return thd->enter_cond(cond, mutex, msg);
|
2009-09-26 06:49:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
void thd_exit_cond(MYSQL_THD thd, const char *old_msg)
|
|
|
|
{
|
|
|
|
if (!thd)
|
|
|
|
thd= current_thd;
|
|
|
|
|
2009-11-02 21:05:42 +01:00
|
|
|
thd->exit_cond(old_msg);
|
2009-09-26 06:49:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2006-05-27 07:05:39 +02:00
|
|
|
void **thd_ha_data(const THD *thd, const struct handlerton *hton)
|
|
|
|
{
|
2008-02-19 12:43:01 +01:00
|
|
|
return (void **) &thd->ha_data[hton->slot].ha_ptr;
|
2006-05-27 07:05:39 +02:00
|
|
|
}
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2007-03-02 17:43:45 +01:00
|
|
|
long long thd_test_options(const THD *thd, long long test_options)
|
|
|
|
{
|
2009-12-22 10:35:56 +01:00
|
|
|
return thd->variables.option_bits & test_options;
|
2007-03-02 17:43:45 +01:00
|
|
|
}
|
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2007-03-02 17:43:45 +01:00
|
|
|
int thd_sql_command(const THD *thd)
|
|
|
|
{
|
|
|
|
return (int) thd->lex->sql_command;
|
|
|
|
}
|
|
|
|
|
2007-04-15 15:47:27 +02:00
|
|
|
extern "C"
|
|
|
|
int thd_tx_isolation(const THD *thd)
|
|
|
|
{
|
|
|
|
return (int) thd->variables.tx_isolation;
|
|
|
|
}
|
|
|
|
|
2007-07-03 14:17:58 +02:00
|
|
|
extern "C"
|
|
|
|
void thd_inc_row_count(THD *thd)
|
|
|
|
{
|
2009-09-10 11:18:29 +02:00
|
|
|
thd->warning_info->inc_current_row_for_warning();
|
2007-07-03 14:17:58 +02:00
|
|
|
}
|
2007-03-02 17:43:45 +01:00
|
|
|
|
2008-11-07 13:12:56 +01:00
|
|
|
|
|
|
|
/**
|
2007-03-02 17:43:45 +01:00
|
|
|
Dumps a text description of a thread, its security context
|
|
|
|
(user, host) and the current query.
|
2007-04-15 15:47:27 +02:00
|
|
|
|
2008-11-17 15:17:21 +01:00
|
|
|
@param thd thread context
|
2008-11-07 13:12:56 +01:00
|
|
|
@param buffer pointer to preferred result buffer
|
|
|
|
@param length length of buffer
|
|
|
|
@param max_query_len how many chars of query to copy (0 for all)
|
|
|
|
|
|
|
|
@req LOCK_thread_count
|
|
|
|
|
|
|
|
@note LOCK_thread_count mutex is not necessary when the function is invoked on
|
|
|
|
the currently running thread (current_thd) or if the caller in some other
|
|
|
|
way guarantees that access to thd->query is serialized.
|
|
|
|
|
|
|
|
@return Pointer to string
|
2007-03-02 17:43:45 +01:00
|
|
|
*/
|
2008-11-07 13:12:56 +01:00
|
|
|
|
2007-03-23 18:14:46 +01:00
|
|
|
extern "C"
|
2007-04-13 19:23:02 +02:00
|
|
|
char *thd_security_context(THD *thd, char *buffer, unsigned int length,
|
|
|
|
unsigned int max_query_len)
|
2007-03-02 17:43:45 +01:00
|
|
|
{
|
|
|
|
String str(buffer, length, &my_charset_latin1);
|
|
|
|
const Security_context *sctx= &thd->main_security_ctx;
|
|
|
|
char header[64];
|
|
|
|
int len;
|
2008-11-07 13:12:56 +01:00
|
|
|
/*
|
|
|
|
The pointers thd->query and thd->proc_info might change since they are
|
|
|
|
being modified concurrently. This is acceptable for proc_info since its
|
|
|
|
values doesn't have to very accurate and the memory it points to is static,
|
|
|
|
but we need to attempt a snapshot on the pointer values to avoid using NULL
|
|
|
|
values. The pointer to thd->query however, doesn't point to static memory
|
|
|
|
and has to be protected by LOCK_thread_count or risk pointing to
|
|
|
|
uninitialized memory.
|
|
|
|
*/
|
|
|
|
const char *proc_info= thd->proc_info;
|
2007-04-15 15:47:27 +02:00
|
|
|
|
|
|
|
len= my_snprintf(header, sizeof(header),
|
2007-03-02 17:43:45 +01:00
|
|
|
"MySQL thread id %lu, query id %lu",
|
|
|
|
thd->thread_id, (ulong) thd->query_id);
|
|
|
|
str.length(0);
|
|
|
|
str.append(header, len);
|
2007-04-15 15:47:27 +02:00
|
|
|
|
2007-03-02 17:43:45 +01:00
|
|
|
if (sctx->host)
|
|
|
|
{
|
|
|
|
str.append(' ');
|
|
|
|
str.append(sctx->host);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sctx->ip)
|
|
|
|
{
|
|
|
|
str.append(' ');
|
|
|
|
str.append(sctx->ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sctx->user)
|
|
|
|
{
|
|
|
|
str.append(' ');
|
|
|
|
str.append(sctx->user);
|
|
|
|
}
|
|
|
|
|
2008-11-07 13:12:56 +01:00
|
|
|
if (proc_info)
|
2007-03-02 17:43:45 +01:00
|
|
|
{
|
|
|
|
str.append(' ');
|
2008-11-07 13:12:56 +01:00
|
|
|
str.append(proc_info);
|
2007-03-02 17:43:45 +01:00
|
|
|
}
|
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&thd->LOCK_thd_data);
|
2009-12-01 11:38:40 +01:00
|
|
|
|
2009-10-16 12:29:42 +02:00
|
|
|
if (thd->query())
|
2007-03-02 17:43:45 +01:00
|
|
|
{
|
|
|
|
if (max_query_len < 1)
|
2009-10-16 12:29:42 +02:00
|
|
|
len= thd->query_length();
|
2007-03-02 17:43:45 +01:00
|
|
|
else
|
2009-10-16 12:29:42 +02:00
|
|
|
len= min(thd->query_length(), max_query_len);
|
2007-03-02 17:43:45 +01:00
|
|
|
str.append('\n');
|
2009-10-16 12:29:42 +02:00
|
|
|
str.append(thd->query(), len);
|
2007-03-02 17:43:45 +01:00
|
|
|
}
|
2009-12-01 11:38:40 +01:00
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
2009-12-01 11:38:40 +01:00
|
|
|
|
2007-03-02 17:43:45 +01:00
|
|
|
if (str.c_ptr_safe() == buffer)
|
|
|
|
return buffer;
|
2008-11-17 15:17:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
We have to copy the new string to the destination buffer because the string
|
|
|
|
was reallocated to a larger buffer to be able to fit.
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(buffer != NULL);
|
|
|
|
length= min(str.length(), length-1);
|
|
|
|
memcpy(buffer, str.c_ptr_quick(), length);
|
|
|
|
/* Make sure that the new string is null terminated */
|
|
|
|
buffer[length]= '\0';
|
|
|
|
return buffer;
|
2007-03-02 17:43:45 +01:00
|
|
|
}
|
2005-07-13 11:48:13 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-09-10 10:49:49 +02:00
|
|
|
/**
|
2009-10-22 20:22:53 +02:00
|
|
|
Implementation of Drop_table_error_handler::handle_condition().
|
2009-09-10 10:49:49 +02:00
|
|
|
The reason in having this implementation is to silence technical low-level
|
|
|
|
warnings during DROP TABLE operation. Currently we don't want to expose
|
|
|
|
the following warnings during DROP TABLE:
|
|
|
|
- Some of table files are missed or invalid (the table is going to be
|
|
|
|
deleted anyway, so why bother that something was missed);
|
|
|
|
- A trigger associated with the table does not have DEFINER (One of the
|
|
|
|
MySQL specifics now is that triggers are loaded for the table being
|
|
|
|
dropped. So, we may have a warning that trigger does not have DEFINER
|
|
|
|
attribute during DROP TABLE operation).
|
|
|
|
|
|
|
|
@return TRUE if the condition is handled.
|
|
|
|
*/
|
2009-09-17 11:20:11 +02:00
|
|
|
bool Drop_table_error_handler::handle_condition(THD *thd,
|
|
|
|
uint sql_errno,
|
|
|
|
const char* sqlstate,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg,
|
|
|
|
MYSQL_ERROR ** cond_hdl)
|
|
|
|
{
|
|
|
|
*cond_hdl= NULL;
|
2009-09-10 10:49:49 +02:00
|
|
|
return ((sql_errno == EE_DELETE && my_errno == ENOENT) ||
|
|
|
|
sql_errno == ER_TRG_NO_DEFINER);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-24 17:00:45 +02:00
|
|
|
THD::THD()
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
:Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
|
|
|
|
/* statement id */ 0),
|
2009-12-03 12:12:53 +01:00
|
|
|
rli_fake(0),
|
2005-07-19 20:21:12 +02:00
|
|
|
lock_id(&main_lock_id),
|
2006-04-24 16:39:33 +02:00
|
|
|
user_time(0), in_sub_stmt(0),
|
2009-03-05 19:39:02 +01:00
|
|
|
sql_log_bin_toplevel(false),
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
binlog_unsafe_warning_flags(0), binlog_table_maps(0),
|
2008-08-07 03:33:01 +02:00
|
|
|
table_map_for_update(0),
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
arg_of_last_insert_id_function(FALSE),
|
|
|
|
first_successful_insert_id_in_prev_stmt(0),
|
|
|
|
first_successful_insert_id_in_prev_stmt_for_binlog(0),
|
|
|
|
first_successful_insert_id_in_cur_stmt(0),
|
|
|
|
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
|
2009-06-25 17:41:05 +02:00
|
|
|
examined_row_count(0),
|
2009-09-10 11:18:29 +02:00
|
|
|
warning_info(&main_warning_info),
|
|
|
|
stmt_da(&main_da),
|
2007-04-16 18:16:17 +02:00
|
|
|
is_fatal_error(0),
|
2007-08-02 02:59:41 +02:00
|
|
|
transaction_rollback_request(0),
|
|
|
|
is_fatal_sub_stmt_error(0),
|
2007-04-13 19:23:02 +02:00
|
|
|
rand_used(0),
|
|
|
|
time_zone_used(0),
|
|
|
|
in_lock_tables(0),
|
|
|
|
bootstrap(0),
|
|
|
|
derived_tables_processing(FALSE),
|
2007-06-14 16:35:59 +02:00
|
|
|
spcont(NULL),
|
2009-09-10 11:18:29 +02:00
|
|
|
m_parser_state(NULL),
|
2009-09-29 17:38:40 +02:00
|
|
|
#if defined(ENABLED_DEBUG_SYNC)
|
2009-10-14 10:25:39 +02:00
|
|
|
debug_sync_control(0),
|
2009-09-29 17:38:40 +02:00
|
|
|
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
2009-12-08 10:57:07 +01:00
|
|
|
main_warning_info(0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
ulong tmp;
|
|
|
|
|
2010-01-21 21:43:03 +01:00
|
|
|
mdl_context.init(this);
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
/*
|
|
|
|
Pass nominal parameters to init_alloc_root only to ensure that
|
|
|
|
the destructor works OK in case of an error. The main_mem_root
|
|
|
|
will be re-initialized in init_for_queries().
|
|
|
|
*/
|
|
|
|
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
2005-09-02 15:21:19 +02:00
|
|
|
stmt_arena= this;
|
2005-11-24 19:13:13 +01:00
|
|
|
thread_stack= 0;
|
This will be pushed only after I fix the testsuite.
This is the main commit for Worklog tasks:
* A more dynamic binlog format which allows small changes (1064)
* Log session variables in Query_log_event (1063)
Below 5.0 means 5.0.0.
MySQL 5.0 is able to replicate FOREIGN_KEY_CHECKS, UNIQUE_KEY_CHECKS (for speed),
SQL_AUTO_IS_NULL, SQL_MODE. Not charsets (WL#1062), not some vars (I can only think
of SQL_SELECT_LIMIT, which deserves a special treatment). Note that this
works for queries, except LOAD DATA INFILE (for this it would have to wait
for Dmitri's push of WL#874, which in turns waits for the present push, so...
the deadlock must be broken!). Note that when Dmitri pushes WL#874 in 5.0.1,
5.0.0 won't be able to replicate a LOAD DATA INFILE from 5.0.1.
Apart from that, the new binlog format is designed so that it can tolerate
a little variation in the events (so that a 5.0.0 slave could replicate a
5.0.1 master, except for LOAD DATA INFILE unfortunately); that is, when I
later add replication of charsets it should break nothing. And when I later
add a UID to every event, it should break nothing.
The main change brought by this patch is a new type of event, Format_description_log_event,
which describes some lengthes in other event types. This event is needed for
the master/slave/mysqlbinlog to understand a 5.0 log. Thanks to this event,
we can later add more bytes to the header of every event without breaking compatibility.
Inside Query_log_event, we have some additional dynamic format, as every Query_log_event
can have a different number of status variables, stored as pairs (code, value); that's
how SQL_MODE and session variables and catalog are stored. Like this, we can later
add count of affected rows, charsets... and we can have options --don't-log-count-affected-rows
if we want.
MySQL 5.0 is able to run on 4.x relay logs, 4.x binlogs.
Upgrading a 4.x master to 5.0 is ok (no need to delete binlogs),
upgrading a 4.x slave to 5.0 is ok (no need to delete relay logs);
so both can be "hot" upgrades.
Upgrading a 3.23 master to 5.0 requires as much as upgrading it to 4.0.
3.23 and 4.x can't be slaves of 5.0.
So downgrading from 5.0 to 4.x may be complicated.
Log_event::log_pos is now the position of the end of the event, which is
more useful than the position of the beginning. We take care about compatibility
with <5.0 (in which log_pos is the beginning).
I added a short test for replication of SQL_MODE and some other variables.
TODO:
- after committing this, merge the latest 5.0 into it
- fix all tests
- update the manual with upgrade notes.
2003-12-18 01:09:05 +01:00
|
|
|
catalog= (char*)"std"; // the only catalog we have for now
|
2005-09-15 21:29:07 +02:00
|
|
|
main_security_ctx.init();
|
|
|
|
security_ctx= &main_security_ctx;
|
A prerequisite patch for the fix for Bug#46224
"HANDLER statements within a transaction might lead to deadlocks".
Introduce a notion of a sentinel to MDL_context. A sentinel
is a ticket that separates all tickets in the context into two
groups: before and after it. Currently we can have (and need) only
one designated sentinel -- it separates all locks taken by LOCK
TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK
and all other locks, which must be released at COMMIT or ROLLBACK.
The tricky part is maintaining the sentinel up to date when
someone release its corresponding ticket. This can happen, e.g.
if someone issues DROP TABLE under LOCK TABLES (generally,
see all calls to release_all_locks_for_name()).
MDL_context::release_ticket() is modified to take care of it.
******
A fix and a test case for Bug#46224 "HANDLER statements within a
transaction might lead to deadlocks".
An attempt to mix HANDLER SQL statements, which are transaction-
agnostic, an open multi-statement transaction,
and DDL against the involved tables (in a concurrent connection)
could lead to a deadlock. The deadlock would occur when
HANDLER OPEN or HANDLER READ would have to wait on a conflicting
metadata lock. If the connection that issued HANDLER statement
also had other metadata locks (say, acquired in scope of a
transaction), a classical deadlock situation of mutual wait
could occur.
Incompatible change: entering LOCK TABLES mode automatically
closes all open HANDLERs in the current connection.
Incompatible change: previously an attempt to wait on a lock
in a connection that has an open HANDLER statement could wait
indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK
is produced.
The idea of the fix is to merge thd->handler_mdl_context
with the main mdl_context of the connection, used for transactional
locks. This makes deadlock detection possible, since all waits
with locks are "visible" and available to analysis in a single
MDL context of the connection.
Since HANDLER locks and transactional locks have a different life
cycle -- HANDLERs are explicitly open and closed, and so
are HANDLER locks, explicitly acquired and released, whereas
transactional locks "accumulate" till the end of a transaction
and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT,
a concept of "sentinel" was introduced to MDL_context.
All locks, HANDLER and others, reside in the same linked list.
However, a selected element of the list separates locks with
different life cycle. HANDLER locks always reside at the
end of the list, after the sentinel. Transactional locks are
prepended to the beginning of the list, before the sentinel.
Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only
release those locks that reside before the sentinel. HANDLER locks
must be released explicitly as part of HANDLER CLOSE statement,
or an implicit close.
The same approach with sentinel
is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES
statement has never worked together, the implementation is
made simple and only maintains one sentinel, which is used either
for HANDLER locks, or for LOCK TABLES locks.
2009-12-22 17:09:15 +01:00
|
|
|
no_errors=password= 0;
|
2003-11-25 15:41:12 +01:00
|
|
|
query_start_used= 0;
|
2003-10-11 22:26:39 +02:00
|
|
|
count_cuted_fields= CHECK_FIELD_IGNORE;
|
2003-03-31 10:39:46 +02:00
|
|
|
killed= NOT_KILLED;
|
2007-08-31 18:42:14 +02:00
|
|
|
col_access=0;
|
2007-10-19 23:20:38 +02:00
|
|
|
is_slave_error= thread_specific_used= FALSE;
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_clear(&handler_tables_hash);
|
2000-07-31 21:29:14 +02:00
|
|
|
tmp_table=0;
|
2000-10-03 13:18:03 +02:00
|
|
|
used_tables=0;
|
2009-09-10 11:18:29 +02:00
|
|
|
cuted_fields= 0L;
|
|
|
|
sent_row_count= 0L;
|
2004-10-27 11:51:17 +02:00
|
|
|
limit_found_rows= 0;
|
2007-08-01 20:40:04 +02:00
|
|
|
row_count_func= -1;
|
2003-11-27 18:51:53 +01:00
|
|
|
statement_id_counter= 0UL;
|
2003-11-02 13:00:25 +01:00
|
|
|
// Must be reset to handle error with THD's created for init of mysqld
|
2003-12-04 20:08:26 +01:00
|
|
|
lex->current_select= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
start_time=(time_t) 0;
|
2009-06-09 00:05:24 +02:00
|
|
|
start_utime= prior_thr_create_utime= 0L;
|
2007-07-30 10:33:50 +02:00
|
|
|
utime_after_lock= 0L;
|
2000-10-27 06:11:55 +02:00
|
|
|
current_linfo = 0;
|
2000-11-14 07:43:02 +01:00
|
|
|
slave_thread = 0;
|
2007-05-05 01:44:07 +02:00
|
|
|
bzero(&variables, sizeof(variables));
|
2007-07-14 14:58:39 +02:00
|
|
|
thread_id= 0;
|
2004-06-03 23:17:18 +02:00
|
|
|
one_shot_set= 0;
|
2001-07-21 00:22:54 +02:00
|
|
|
file_id = 0;
|
2005-03-23 21:39:20 +01:00
|
|
|
query_id= 0;
|
2009-03-25 17:48:10 +01:00
|
|
|
query_name_consts= 0;
|
2003-09-15 13:31:04 +02:00
|
|
|
db_charset= global_system_variables.collation_database;
|
2005-01-16 13:16:23 +01:00
|
|
|
bzero(ha_data, sizeof(ha_data));
|
2001-03-21 00:02:22 +01:00
|
|
|
mysys_var=0;
|
2005-08-25 15:34:34 +02:00
|
|
|
binlog_evt_union.do_union= FALSE;
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
enable_slow_log= 0;
|
2002-03-30 20:36:05 +01:00
|
|
|
#ifndef DBUG_OFF
|
|
|
|
dbug_sentry=THD_SENTRY_MAGIC;
|
2002-12-16 14:33:29 +01:00
|
|
|
#endif
|
2005-04-12 23:08:19 +02:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
2009-12-15 20:52:47 +01:00
|
|
|
mysql_audit_init_thd(this);
|
2001-03-21 00:02:22 +01:00
|
|
|
net.vio=0;
|
2002-12-16 14:33:29 +01:00
|
|
|
#endif
|
2005-10-14 15:34:52 +02:00
|
|
|
client_capabilities= 0; // minimalistic client
|
2001-03-21 00:02:22 +01:00
|
|
|
ull=0;
|
2006-05-22 20:46:13 +02:00
|
|
|
system_thread= NON_SYSTEM_THREAD;
|
|
|
|
cleanup_done= abort_on_warning= no_warnings_for_error= 0;
|
2003-04-26 19:43:28 +02:00
|
|
|
peer_port= 0; // For SHOW PROCESSLIST
|
2005-12-22 06:39:02 +01:00
|
|
|
transaction.m_pending_rows_event= 0;
|
2007-10-11 17:07:40 +02:00
|
|
|
transaction.on= 1;
|
2001-03-21 00:02:22 +01:00
|
|
|
#ifdef SIGNAL_WITH_VIO_CLOSE
|
|
|
|
active_vio = 0;
|
2005-04-12 23:08:19 +02:00
|
|
|
#endif
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
|
2001-03-21 00:02:22 +01:00
|
|
|
|
|
|
|
/* Variables with default values */
|
|
|
|
proc_info="login";
|
2005-10-25 11:02:48 +02:00
|
|
|
where= THD::DEFAULT_WHERE;
|
2001-03-21 00:02:22 +01:00
|
|
|
server_id = ::server_id;
|
2001-08-03 23:57:53 +02:00
|
|
|
slave_net = 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
command=COM_CONNECT;
|
2003-07-18 16:57:21 +02:00
|
|
|
*scramble= '\0';
|
2001-03-21 00:02:22 +01:00
|
|
|
|
2009-12-03 12:12:53 +01:00
|
|
|
/* Call to init() below requires fully initialized Open_tables_state. */
|
|
|
|
init_open_tables_state(this, refresh_version);
|
|
|
|
|
2002-11-16 19:19:10 +01:00
|
|
|
init();
|
2009-10-09 15:59:25 +02:00
|
|
|
#if defined(ENABLED_PROFILING)
|
2007-01-03 23:15:10 +01:00
|
|
|
profiling.set_thd(this);
|
2007-02-22 16:03:08 +01:00
|
|
|
#endif
|
2002-05-15 12:50:38 +02:00
|
|
|
user_connect=(USER_CONN *)0;
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
|
|
|
(my_hash_get_key) get_var_key,
|
|
|
|
(my_hash_free_key) free_user_var, 0);
|
2003-07-03 15:58:37 +02:00
|
|
|
|
2003-10-21 12:08:35 +02:00
|
|
|
sp_proc_cache= NULL;
|
|
|
|
sp_func_cache= NULL;
|
2002-10-02 12:33:08 +02:00
|
|
|
|
2003-01-30 18:39:54 +01:00
|
|
|
/* For user vars replication*/
|
|
|
|
if (opt_bin_log)
|
|
|
|
my_init_dynamic_array(&user_var_events,
|
2005-01-16 13:16:23 +01:00
|
|
|
sizeof(BINLOG_USER_VAR_EVENT *), 16, 16);
|
2003-01-30 18:39:54 +01:00
|
|
|
else
|
|
|
|
bzero((char*) &user_var_events, sizeof(user_var_events));
|
|
|
|
|
2002-12-11 08:17:51 +01:00
|
|
|
/* Protocol */
|
2007-01-30 22:48:05 +01:00
|
|
|
protocol= &protocol_text; // Default protocol
|
|
|
|
protocol_text.init(this);
|
|
|
|
protocol_binary.init(this);
|
2002-12-11 08:17:51 +01:00
|
|
|
|
2003-10-13 10:20:19 +02:00
|
|
|
tablespace_op=FALSE;
|
2006-12-14 23:51:37 +01:00
|
|
|
tmp= sql_rnd_with_mutex();
|
|
|
|
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
|
2006-07-10 15:27:03 +02:00
|
|
|
substitute_null_with_insert_id = FALSE;
|
2005-07-19 20:21:12 +02:00
|
|
|
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
|
|
|
|
thr_lock_owner_init(&main_lock_id, &lock_info);
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
|
|
|
|
m_internal_handler= NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void THD::push_internal_handler(Internal_error_handler *handler)
|
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
if (m_internal_handler)
|
|
|
|
{
|
|
|
|
handler->m_prev_internal_handler= m_internal_handler;
|
|
|
|
m_internal_handler= handler;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_internal_handler= handler;
|
|
|
|
}
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
}
|
|
|
|
|
2009-09-10 11:18:29 +02:00
|
|
|
bool THD::handle_condition(uint sql_errno,
|
|
|
|
const char* sqlstate,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg,
|
|
|
|
MYSQL_ERROR ** cond_hdl)
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
{
|
2009-05-29 15:37:54 +02:00
|
|
|
if (!m_internal_handler)
|
2009-09-10 11:18:29 +02:00
|
|
|
{
|
|
|
|
*cond_hdl= NULL;
|
2009-05-29 15:37:54 +02:00
|
|
|
return FALSE;
|
2009-09-10 11:18:29 +02:00
|
|
|
}
|
2009-05-29 15:37:54 +02:00
|
|
|
|
|
|
|
for (Internal_error_handler *error_handler= m_internal_handler;
|
|
|
|
error_handler;
|
2010-02-10 19:11:08 +01:00
|
|
|
error_handler= error_handler->m_prev_internal_handler)
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
{
|
2010-02-21 22:33:11 +01:00
|
|
|
if (error_handler->handle_condition(this, sql_errno, sqlstate, level, msg,
|
|
|
|
cond_hdl))
|
2009-09-10 11:18:29 +02:00
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
}
|
|
|
|
|
2009-05-29 15:37:54 +02:00
|
|
|
return FALSE;
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-10 15:37:34 +01:00
|
|
|
Internal_error_handler *THD::pop_internal_handler()
|
Bug#8407 (Stored functions/triggers ignore exception handler)
Bug 18914 (Calling certain SPs from triggers fail)
Bug 20713 (Functions will not not continue for SQLSTATE VALUE '42S02')
Bug 21825 (Incorrect message error deleting records in a table with a
trigger for inserting)
Bug 22580 (DROP TABLE in nested stored procedure causes strange dependency
error)
Bug 25345 (Cursors from Functions)
This fix resolves a long standing issue originally reported with bug 8407,
which affect the behavior of Stored Procedures, Stored Functions and Trigger
in many different ways, causing symptoms reported by all the bugs listed.
In all cases, the root cause of the problem traces back to 8407 and how the
server locks tables involved with sub statements.
Prior to this fix, the implementation of stored routines would:
- compute the transitive closure of all the tables referenced by a top level
statement
- open and lock all the tables involved
- execute the top level statement
"transitive closure of tables" means collecting:
- all the tables,
- all the stored functions,
- all the views,
- all the table triggers
- all the stored procedures
involved, and recursively inspect these objects definition to find more
references to more objects, until the list of every object referenced does
not grow any more.
This mechanism is known as "pre-locking" tables before execution.
The motivation for locking all the tables (possibly) used at once is to
prevent dead locks.
One problem with this approach is that, if the execution path the code
really takes during runtime does not use a given table, and if the table is
missing, the server would not execute the statement.
This in particular has a major impact on triggers, since a missing table
referenced by an update/delete trigger would prevent an insert trigger to run.
Another problem is that stored routines might define SQL exception handlers
to deal with missing tables, but the server implementation would never give
user code a chance to execute this logic, since the routine is never
executed when a missing table cause the pre-locking code to fail.
With this fix, the internal implementation of the pre-locking code has been
relaxed of some constraints, so that failure to open a table does not
necessarily prevent execution of a stored routine.
In particular, the pre-locking mechanism is now behaving as follows:
1) the first step, to compute the transitive closure of all the tables
possibly referenced by a statement, is unchanged.
2) the next step, which is to open all the tables involved, only attempts
to open the tables added by the pre-locking code, but silently fails without
reporting any error or invoking any exception handler is the table is not
present. This is achieved by trapping internal errors with
Prelock_error_handler
3) the locking step only locks tables that were successfully opened.
4) when executing sub statements, the list of tables used by each statements
is evaluated as before. The tables needed by the sub statement are expected
to be already opened and locked. Statement referencing tables that were not
opened in step 2) will fail to find the table in the open list, and only at
this point will execution of the user code fail.
5) when a runtime exception is raised at 4), the instruction continuation
destination (the next instruction to execute in case of SQL continue
handlers) is evaluated.
This is achieved with sp_instr::exec_open_and_lock_tables()
6) if a user exception handler is present in the stored routine, that
handler is invoked as usual, so that ER_NO_SUCH_TABLE exceptions can be
trapped by stored routines. If no handler exists, then the runtime execution
will fail as expected.
With all these changes, a side effect is that view security is impacted, in
two different ways.
First, a view defined as "select stored_function()", where the stored
function references a table that may not exist, is considered valid.
The rationale is that, because the stored function might trap exceptions
during execution and still return a valid result, there is no way to decide
when the view is created if a missing table really cause the view to be invalid.
Secondly, testing for existence of tables is now done later during
execution. View security, which consist of trapping errors and return a
generic ER_VIEW_INVALID (to prevent disclosing information) was only
implemented at very specific phases covering *opening* tables, but not
covering the runtime execution. Because of this existing limitation,
errors that were previously trapped and converted into ER_VIEW_INVALID are
not trapped, causing table names to be reported to the user.
This change is exposing an existing problem, which is independent and will
be resolved separately.
2007-03-06 03:42:07 +01:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(m_internal_handler != NULL);
|
2010-02-10 15:37:34 +01:00
|
|
|
Internal_error_handler *popped_handler= m_internal_handler;
|
2009-05-29 15:37:54 +02:00
|
|
|
m_internal_handler= m_internal_handler->m_prev_internal_handler;
|
2010-02-10 15:37:34 +01:00
|
|
|
return popped_handler;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2009-09-10 11:18:29 +02:00
|
|
|
|
|
|
|
void THD::raise_error(uint sql_errno)
|
|
|
|
{
|
|
|
|
const char* msg= ER(sql_errno);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_ERROR,
|
|
|
|
msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void THD::raise_error_printf(uint sql_errno, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char ebuff[MYSQL_ERRMSG_SIZE];
|
|
|
|
DBUG_ENTER("THD::raise_error_printf");
|
|
|
|
DBUG_PRINT("my", ("nr: %d errno: %d", sql_errno, errno));
|
|
|
|
const char* format= ER(sql_errno);
|
|
|
|
va_start(args, sql_errno);
|
|
|
|
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
|
|
|
|
va_end(args);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_ERROR,
|
|
|
|
ebuff);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
void THD::raise_warning(uint sql_errno)
|
|
|
|
{
|
|
|
|
const char* msg= ER(sql_errno);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void THD::raise_warning_printf(uint sql_errno, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char ebuff[MYSQL_ERRMSG_SIZE];
|
|
|
|
DBUG_ENTER("THD::raise_warning_printf");
|
|
|
|
DBUG_PRINT("enter", ("warning: %u", sql_errno));
|
|
|
|
const char* format= ER(sql_errno);
|
|
|
|
va_start(args, sql_errno);
|
|
|
|
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
|
|
|
|
va_end(args);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ebuff);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
void THD::raise_note(uint sql_errno)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("THD::raise_note");
|
|
|
|
DBUG_PRINT("enter", ("code: %d", sql_errno));
|
2009-12-22 10:35:56 +01:00
|
|
|
if (!(variables.option_bits & OPTION_SQL_NOTES))
|
2009-09-10 11:18:29 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
const char* msg= ER(sql_errno);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
msg);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
void THD::raise_note_printf(uint sql_errno, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char ebuff[MYSQL_ERRMSG_SIZE];
|
|
|
|
DBUG_ENTER("THD::raise_note_printf");
|
|
|
|
DBUG_PRINT("enter",("code: %u", sql_errno));
|
2009-12-22 10:35:56 +01:00
|
|
|
if (!(variables.option_bits & OPTION_SQL_NOTES))
|
2009-09-10 11:18:29 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
const char* format= ER(sql_errno);
|
|
|
|
va_start(args, sql_errno);
|
|
|
|
my_vsnprintf(ebuff, sizeof(ebuff), format, args);
|
|
|
|
va_end(args);
|
|
|
|
(void) raise_condition(sql_errno,
|
|
|
|
NULL,
|
|
|
|
MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ebuff);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
MYSQL_ERROR* THD::raise_condition(uint sql_errno,
|
|
|
|
const char* sqlstate,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg)
|
|
|
|
{
|
|
|
|
MYSQL_ERROR *cond= NULL;
|
|
|
|
DBUG_ENTER("THD::raise_condition");
|
|
|
|
|
2009-12-22 10:35:56 +01:00
|
|
|
if (!(variables.option_bits & OPTION_SQL_NOTES) &&
|
2009-09-10 11:18:29 +02:00
|
|
|
(level == MYSQL_ERROR::WARN_LEVEL_NOTE))
|
|
|
|
DBUG_RETURN(NULL);
|
|
|
|
|
|
|
|
warning_info->opt_clear_warning_info(query_id);
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO: replace by DBUG_ASSERT(sql_errno != 0) once all bugs similar to
|
|
|
|
Bug#36768 are fixed: a SQL condition must have a real (!=0) error number
|
|
|
|
so that it can be caught by handlers.
|
|
|
|
*/
|
|
|
|
if (sql_errno == 0)
|
|
|
|
sql_errno= ER_UNKNOWN_ERROR;
|
|
|
|
if (msg == NULL)
|
|
|
|
msg= ER(sql_errno);
|
|
|
|
if (sqlstate == NULL)
|
|
|
|
sqlstate= mysql_errno_to_sqlstate(sql_errno);
|
|
|
|
|
|
|
|
if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
|
|
|
|
really_abort_on_warning())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
FIXME:
|
|
|
|
push_warning and strict SQL_MODE case.
|
|
|
|
*/
|
|
|
|
level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
|
|
|
killed= THD::KILL_BAD_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (level)
|
|
|
|
{
|
|
|
|
case MYSQL_ERROR::WARN_LEVEL_NOTE:
|
|
|
|
case MYSQL_ERROR::WARN_LEVEL_WARN:
|
|
|
|
got_warning= 1;
|
|
|
|
break;
|
|
|
|
case MYSQL_ERROR::WARN_LEVEL_ERROR:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handle_condition(sql_errno, sqlstate, level, msg, &cond))
|
|
|
|
DBUG_RETURN(cond);
|
|
|
|
|
|
|
|
if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
|
|
|
{
|
|
|
|
is_slave_error= 1; // needed to catch query errors during replication
|
|
|
|
|
|
|
|
/*
|
|
|
|
thd->lex->current_select == 0 if lex structure is not inited
|
|
|
|
(not query command (COM_QUERY))
|
|
|
|
*/
|
|
|
|
if (lex->current_select &&
|
|
|
|
lex->current_select->no_error && !is_fatal_error)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("error",
|
|
|
|
("Error converted to warning: current_select: no_error %d "
|
|
|
|
"fatal_error: %d",
|
|
|
|
(lex->current_select ?
|
|
|
|
lex->current_select->no_error : 0),
|
|
|
|
(int) is_fatal_error));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (! stmt_da->is_error())
|
|
|
|
stmt_da->set_error_status(this, sql_errno, msg, sqlstate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If a continue handler is found, the error message will be cleared
|
|
|
|
by the stored procedures code.
|
|
|
|
*/
|
|
|
|
if (!is_fatal_error && spcont &&
|
|
|
|
spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Do not push any warnings, a handled error must be completely
|
|
|
|
silenced.
|
|
|
|
*/
|
|
|
|
DBUG_RETURN(cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Un-handled conditions */
|
|
|
|
|
|
|
|
cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg);
|
|
|
|
DBUG_RETURN(cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
MYSQL_ERROR*
|
|
|
|
THD::raise_condition_no_handler(uint sql_errno,
|
|
|
|
const char* sqlstate,
|
|
|
|
MYSQL_ERROR::enum_warning_level level,
|
|
|
|
const char* msg)
|
|
|
|
{
|
|
|
|
MYSQL_ERROR *cond= NULL;
|
|
|
|
DBUG_ENTER("THD::raise_condition_no_handler");
|
|
|
|
|
2009-10-13 20:18:48 +02:00
|
|
|
query_cache_abort(&query_cache_tls);
|
2009-09-10 11:18:29 +02:00
|
|
|
|
|
|
|
/* FIXME: broken special case */
|
|
|
|
if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
|
|
|
|
DBUG_RETURN(NULL);
|
|
|
|
|
|
|
|
cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg);
|
|
|
|
DBUG_RETURN(cond);
|
|
|
|
}
|
2007-07-05 01:05:47 +02:00
|
|
|
extern "C"
|
|
|
|
void *thd_alloc(MYSQL_THD thd, unsigned int size)
|
|
|
|
{
|
|
|
|
return thd->alloc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
void *thd_calloc(MYSQL_THD thd, unsigned int size)
|
|
|
|
{
|
|
|
|
return thd->calloc(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
char *thd_strdup(MYSQL_THD thd, const char *str)
|
|
|
|
{
|
|
|
|
return thd->strdup(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size)
|
|
|
|
{
|
|
|
|
return thd->strmake(str, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
LEX_STRING *thd_make_lex_string(THD *thd, LEX_STRING *lex_str,
|
|
|
|
const char *str, unsigned int size,
|
|
|
|
int allocate_lex_string)
|
|
|
|
{
|
|
|
|
return thd->make_lex_string(lex_str, str, size,
|
|
|
|
(bool) allocate_lex_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size)
|
|
|
|
{
|
|
|
|
return thd->memdup(str, size);
|
|
|
|
}
|
|
|
|
|
2008-02-19 17:44:09 +01:00
|
|
|
extern "C"
|
2007-07-05 01:05:47 +02:00
|
|
|
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
|
|
|
|
{
|
|
|
|
*xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
|
|
|
|
}
|
2002-11-16 19:19:10 +01:00
|
|
|
|
2009-06-10 10:59:49 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
extern "C" THD *_current_thd_noinline(void)
|
|
|
|
{
|
|
|
|
return my_pthread_getspecific_ptr(THD*,THR_THD);
|
|
|
|
}
|
|
|
|
#endif
|
2002-11-16 19:19:10 +01:00
|
|
|
/*
|
|
|
|
Init common variables that has to be reset on start and on change_user
|
|
|
|
*/
|
|
|
|
|
|
|
|
void THD::init(void)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_global_system_variables);
|
2007-04-02 20:38:58 +02:00
|
|
|
plugin_thdvar_init(this);
|
2007-07-14 14:58:39 +02:00
|
|
|
/*
|
|
|
|
variables= global_system_variables above has reset
|
|
|
|
variables.pseudo_thread_id to 0. We need to correct it here to
|
|
|
|
avoid temporary tables replication failure.
|
|
|
|
*/
|
|
|
|
variables.pseudo_thread_id= thread_id;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_global_system_variables);
|
2002-11-16 19:19:10 +01:00
|
|
|
server_status= SERVER_STATUS_AUTOCOMMIT;
|
2005-06-24 03:29:56 +02:00
|
|
|
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
|
|
|
|
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
|
2007-10-10 15:57:01 +02:00
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
transaction.all.modified_non_trans_table=
|
|
|
|
transaction.stmt.modified_non_trans_table= FALSE;
|
2002-11-16 19:19:10 +01:00
|
|
|
open_options=ha_open_options;
|
2002-12-02 16:52:22 +01:00
|
|
|
update_lock_default= (variables.low_priority_updates ?
|
|
|
|
TL_WRITE_LOW_PRIORITY :
|
|
|
|
TL_WRITE);
|
2002-11-16 19:19:10 +01:00
|
|
|
session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
|
2003-08-19 15:00:12 +02:00
|
|
|
update_charset();
|
2009-09-30 18:00:22 +02:00
|
|
|
reset_current_stmt_binlog_format_row();
|
2004-09-13 15:48:01 +02:00
|
|
|
bzero((char *) &status_var, sizeof(status_var));
|
2009-12-22 10:35:56 +01:00
|
|
|
sql_log_bin_toplevel= variables.option_bits & OPTION_BIN_LOG;
|
2009-09-29 17:38:40 +02:00
|
|
|
|
|
|
|
#if defined(ENABLED_DEBUG_SYNC)
|
|
|
|
/* Initialize the Debug Sync Facility. See debug_sync.cc. */
|
|
|
|
debug_sync_init_thread(this);
|
|
|
|
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
2002-11-16 19:19:10 +01:00
|
|
|
}
|
|
|
|
|
2003-03-19 20:23:13 +01:00
|
|
|
|
2003-12-21 20:26:45 +01:00
|
|
|
/*
|
|
|
|
Init THD for query processing.
|
|
|
|
This has to be called once before we call mysql_parse.
|
|
|
|
See also comments in sql_class.h.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void THD::init_for_queries()
|
|
|
|
{
|
2007-02-19 14:57:54 +01:00
|
|
|
set_time();
|
2004-09-03 17:11:09 +02:00
|
|
|
ha_enable_transaction(this,TRUE);
|
2004-09-23 11:48:17 +02:00
|
|
|
|
2004-11-08 00:13:54 +01:00
|
|
|
reset_root_defaults(mem_root, variables.query_alloc_block_size,
|
2004-09-23 11:48:17 +02:00
|
|
|
variables.query_prealloc_size);
|
|
|
|
reset_root_defaults(&transaction.mem_root,
|
|
|
|
variables.trans_alloc_block_size,
|
|
|
|
variables.trans_prealloc_size);
|
2005-08-12 21:15:01 +02:00
|
|
|
transaction.xid_state.xid.null();
|
|
|
|
transaction.xid_state.in_thd=1;
|
2003-12-21 20:26:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-11-16 19:19:10 +01:00
|
|
|
/*
|
|
|
|
Do what's needed when one invokes change user
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
change_user()
|
|
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
Reset all resources that are connection specific
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void THD::change_user(void)
|
|
|
|
{
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_lock(&LOCK_status);
|
2008-02-12 18:59:09 +01:00
|
|
|
add_to_status(&global_status_var, &status_var);
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_status);
|
2008-02-12 18:59:09 +01:00
|
|
|
|
2002-11-16 19:19:10 +01:00
|
|
|
cleanup();
|
2007-04-13 00:56:22 +02:00
|
|
|
killed= NOT_KILLED;
|
2002-11-21 21:25:53 +01:00
|
|
|
cleanup_done= 0;
|
2002-11-16 19:19:10 +01:00
|
|
|
init();
|
2004-09-22 13:50:07 +02:00
|
|
|
stmt_map.reset();
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
|
|
|
(my_hash_get_key) get_var_key,
|
|
|
|
(my_hash_free_key) free_user_var, 0);
|
2003-10-21 12:08:35 +02:00
|
|
|
sp_cache_clear(&sp_proc_cache);
|
|
|
|
sp_cache_clear(&sp_func_cache);
|
2002-11-16 19:19:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-08-21 19:06:00 +02:00
|
|
|
/* Do operations that may take a long time */
|
|
|
|
|
|
|
|
void THD::cleanup(void)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-08-21 19:06:00 +02:00
|
|
|
DBUG_ENTER("THD::cleanup");
|
2007-02-23 12:13:55 +01:00
|
|
|
DBUG_ASSERT(cleanup_done == 0);
|
|
|
|
|
2007-04-05 21:34:33 +02:00
|
|
|
killed= KILL_CONNECTION;
|
2005-04-06 18:43:35 +02:00
|
|
|
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
|
2005-08-12 21:15:01 +02:00
|
|
|
if (transaction.xid_state.xa_state == XA_PREPARED)
|
|
|
|
{
|
|
|
|
#error xid_state in the cache should be replaced by the allocated value
|
|
|
|
}
|
2005-04-06 18:43:35 +02:00
|
|
|
#endif
|
2005-08-12 21:15:01 +02:00
|
|
|
{
|
2009-12-03 19:37:38 +01:00
|
|
|
transaction.xid_state.xa_state= XA_NOTR;
|
|
|
|
trans_rollback(this);
|
2005-08-12 21:15:01 +02:00
|
|
|
xid_cache_delete(&transaction.xid_state);
|
|
|
|
}
|
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5,
2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1
- initial changeset that introduced the fix for
Bug#989 and follow up fixes for all test suite failures
introduced in the initial changeset.
------------------------------------------------------------
revno: 2617.31.1
committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
branch nick: 4284-6.0
timestamp: Fri 2009-03-06 19:17:00 -0300
message:
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking
Currently the MySQL server does not keep metadata locks on
schema objects for the duration of a transaction, thus failing
to guarantee the integrity of the schema objects being used
during the transaction and to protect then from concurrent
DDL operations. This also poses a problem for replication as
a DDL operation might be replicated even thought there are
active transactions using the object being modified.
The solution is to defer the release of metadata locks until
a active transaction is either committed or rolled back. This
prevents other statements from modifying the table for the
entire duration of the transaction. This provides commitment
ordering for guaranteeing serializability across multiple
transactions.
- Incompatible change:
If MySQL's metadata locking system encounters a lock conflict,
the usual schema is to use the try and back-off technique to
avoid deadlocks -- this schema consists in releasing all locks
and trying to acquire them all in one go.
But in a transactional context this algorithm can't be utilized
as its not possible to release locks acquired during the course
of the transaction without breaking the transaction commitments.
To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
returned if a lock conflict is encountered during a transaction.
Let's consider an example:
A transaction has two statements that modify table t1, then table
t2, and then commits. The first statement of the transaction will
acquire a shared metadata lock on table t1, and it will be kept
utill COMMIT to ensure serializability.
At the moment when the second statement attempts to acquire a
shared metadata lock on t2, a concurrent ALTER or DROP statement
might have locked t2 exclusively. The prescription of the current
locking protocol is that the acquirer of the shared lock backs off
-- gives up all his current locks and retries. This implies that
the entire multi-statement transaction has to be rolled back.
- Incompatible change:
FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
LOCK won't cause locked tables to be implicitly unlocked anymore.
2009-12-05 00:02:48 +01:00
|
|
|
|
2009-12-02 16:22:15 +01:00
|
|
|
locked_tables_list.unlock_locked_tables(this);
|
A prerequisite patch for the fix for Bug#46224
"HANDLER statements within a transaction might lead to deadlocks".
Introduce a notion of a sentinel to MDL_context. A sentinel
is a ticket that separates all tickets in the context into two
groups: before and after it. Currently we can have (and need) only
one designated sentinel -- it separates all locks taken by LOCK
TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK
and all other locks, which must be released at COMMIT or ROLLBACK.
The tricky part is maintaining the sentinel up to date when
someone release its corresponding ticket. This can happen, e.g.
if someone issues DROP TABLE under LOCK TABLES (generally,
see all calls to release_all_locks_for_name()).
MDL_context::release_ticket() is modified to take care of it.
******
A fix and a test case for Bug#46224 "HANDLER statements within a
transaction might lead to deadlocks".
An attempt to mix HANDLER SQL statements, which are transaction-
agnostic, an open multi-statement transaction,
and DDL against the involved tables (in a concurrent connection)
could lead to a deadlock. The deadlock would occur when
HANDLER OPEN or HANDLER READ would have to wait on a conflicting
metadata lock. If the connection that issued HANDLER statement
also had other metadata locks (say, acquired in scope of a
transaction), a classical deadlock situation of mutual wait
could occur.
Incompatible change: entering LOCK TABLES mode automatically
closes all open HANDLERs in the current connection.
Incompatible change: previously an attempt to wait on a lock
in a connection that has an open HANDLER statement could wait
indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK
is produced.
The idea of the fix is to merge thd->handler_mdl_context
with the main mdl_context of the connection, used for transactional
locks. This makes deadlock detection possible, since all waits
with locks are "visible" and available to analysis in a single
MDL context of the connection.
Since HANDLER locks and transactional locks have a different life
cycle -- HANDLERs are explicitly open and closed, and so
are HANDLER locks, explicitly acquired and released, whereas
transactional locks "accumulate" till the end of a transaction
and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT,
a concept of "sentinel" was introduced to MDL_context.
All locks, HANDLER and others, reside in the same linked list.
However, a selected element of the list separates locks with
different life cycle. HANDLER locks always reside at the
end of the list, after the sentinel. Transactional locks are
prepended to the beginning of the list, before the sentinel.
Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only
release those locks that reside before the sentinel. HANDLER locks
must be released explicitly as part of HANDLER CLOSE statement,
or an implicit close.
The same approach with sentinel
is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES
statement has never worked together, the implementation is
made simple and only maintains one sentinel, which is used either
for HANDLER locks, or for LOCK TABLES locks.
2009-12-22 17:09:15 +01:00
|
|
|
mysql_ha_cleanup(this);
|
2009-09-29 17:38:40 +02:00
|
|
|
|
Implement new type-of-operation-aware metadata locks.
Add a wait-for graph based deadlock detector to the
MDL subsystem.
Fixes bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock" and
bug #37346 "innodb does not detect deadlock between update and
alter table".
The first bug manifested itself as an unwarranted abort of a
transaction with ER_LOCK_DEADLOCK error by a concurrent ALTER
statement, when this transaction tried to repeat use of a
table, which it has already used in a similar fashion before
ALTER started.
The second bug showed up as a deadlock between table-level
locks and InnoDB row locks, which was "detected" only after
innodb_lock_wait_timeout timeout.
A transaction would start using the table and modify a few
rows.
Then ALTER TABLE would come in, and start copying rows
into a temporary table. Eventually it would stumble on
the modified records and get blocked on a row lock.
The first transaction would try to do more updates, and get
blocked on thr_lock.c lock.
This situation of circular wait would only get resolved
by a timeout.
Both these bugs stemmed from inadequate solutions to the
problem of deadlocks occurring between different
locking subsystems.
In the first case we tried to avoid deadlocks between metadata
locking and table-level locking subsystems, when upgrading shared
metadata lock to exclusive one.
Transactions holding the shared lock on the table and waiting for
some table-level lock used to be aborted too aggressively.
We also allowed ALTER TABLE to start in presence of transactions
that modify the subject table. ALTER TABLE acquires
TL_WRITE_ALLOW_READ lock at start, and that block all writes
against the table (naturally, we don't want any writes to be lost
when switching the old and the new table). TL_WRITE_ALLOW_READ
lock, in turn, would block the started transaction on thr_lock.c
lock, should they do more updates. This, again, lead to the need
to abort such transactions.
The second bug occurred simply because we didn't have any
mechanism to detect deadlocks between the table-level locks
in thr_lock.c and row-level locks in InnoDB, other than
innodb_lock_wait_timeout.
This patch solves both these problems by moving lock conflicts
which are causing these deadlocks into the metadata locking
subsystem, thus making it possible to avoid or detect such
deadlocks inside MDL.
To do this we introduce new type-of-operation-aware metadata
locks, which allow MDL subsystem to know not only the fact that
transaction has used or is going to use some object but also what
kind of operation it has carried out or going to carry out on the
object.
This, along with the addition of a special kind of upgradable
metadata lock, allows ALTER TABLE to wait until all
transactions which has updated the table to go away.
This solves the second issue.
Another special type of upgradable metadata lock is acquired
by LOCK TABLE WRITE. This second lock type allows to solve the
first issue, since abortion of table-level locks in event of
DDL under LOCK TABLES becomes also unnecessary.
Below follows the list of incompatible changes introduced by
this patch:
- From now on, ALTER TABLE and CREATE/DROP TRIGGER SQL (i.e. those
statements that acquire TL_WRITE_ALLOW_READ lock)
wait for all transactions which has *updated* the table to
complete.
- From now on, LOCK TABLES ... WRITE, REPAIR/OPTIMIZE TABLE
(i.e. all statements which acquire TL_WRITE table-level lock) wait
for all transaction which *updated or read* from the table
to complete.
As a consequence, innodb_table_locks=0 option no longer applies
to LOCK TABLES ... WRITE.
- DROP DATABASE, DROP TABLE, RENAME TABLE no longer abort
statements or transactions which use tables being dropped or
renamed, and instead wait for these transactions to complete.
- Since LOCK TABLES WRITE now takes a special metadata lock,
not compatible with with reads or writes against the subject table
and transaction-wide, thr_lock.c deadlock avoidance algorithm
that used to ensure absence of deadlocks between LOCK TABLES
WRITE and other statements is no longer sufficient, even for
MyISAM. The wait-for graph based deadlock detector of MDL
subsystem may sometimes be necessary and is involved. This may
lead to ER_LOCK_DEADLOCK error produced for multi-statement
transactions even if these only use MyISAM:
session 1: session 2:
begin;
update t1 ... lock table t2 write, t1 write;
-- gets a lock on t2, blocks on t1
update t2 ...
(ER_LOCK_DEADLOCK)
- Finally, support of LOW_PRIORITY option for LOCK TABLES ... WRITE
was abandoned.
LOCK TABLE ... LOW_PRIORITY WRITE from now on has the same
priority as the usual LOCK TABLE ... WRITE.
SELECT HIGH PRIORITY no longer trumps LOCK TABLE ... WRITE in
the wait queue.
- We do not take upgradable metadata locks on implicitly
locked tables. So if one has, say, a view v1 that uses
table t1, and issues:
LOCK TABLE v1 WRITE;
FLUSH TABLE t1; -- (or just 'FLUSH TABLES'),
an error is produced.
In order to be able to perform DDL on a table under LOCK TABLES,
the table must be locked explicitly in the LOCK TABLES list.
2010-02-01 12:43:06 +01:00
|
|
|
DBUG_ASSERT(open_tables == NULL);
|
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5,
2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1
- initial changeset that introduced the fix for
Bug#989 and follow up fixes for all test suite failures
introduced in the initial changeset.
------------------------------------------------------------
revno: 2617.31.1
committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
branch nick: 4284-6.0
timestamp: Fri 2009-03-06 19:17:00 -0300
message:
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking
Currently the MySQL server does not keep metadata locks on
schema objects for the duration of a transaction, thus failing
to guarantee the integrity of the schema objects being used
during the transaction and to protect then from concurrent
DDL operations. This also poses a problem for replication as
a DDL operation might be replicated even thought there are
active transactions using the object being modified.
The solution is to defer the release of metadata locks until
a active transaction is either committed or rolled back. This
prevents other statements from modifying the table for the
entire duration of the transaction. This provides commitment
ordering for guaranteeing serializability across multiple
transactions.
- Incompatible change:
If MySQL's metadata locking system encounters a lock conflict,
the usual schema is to use the try and back-off technique to
avoid deadlocks -- this schema consists in releasing all locks
and trying to acquire them all in one go.
But in a transactional context this algorithm can't be utilized
as its not possible to release locks acquired during the course
of the transaction without breaking the transaction commitments.
To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
returned if a lock conflict is encountered during a transaction.
Let's consider an example:
A transaction has two statements that modify table t1, then table
t2, and then commits. The first statement of the transaction will
acquire a shared metadata lock on table t1, and it will be kept
utill COMMIT to ensure serializability.
At the moment when the second statement attempts to acquire a
shared metadata lock on t2, a concurrent ALTER or DROP statement
might have locked t2 exclusively. The prescription of the current
locking protocol is that the acquirer of the shared lock backs off
-- gives up all his current locks and retries. This implies that
the entire multi-statement transaction has to be rolled back.
- Incompatible change:
FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
LOCK won't cause locked tables to be implicitly unlocked anymore.
2009-12-05 00:02:48 +01:00
|
|
|
/*
|
|
|
|
If the thread was in the middle of an ongoing transaction (rolled
|
|
|
|
back a few lines above) or under LOCK TABLES (unlocked the tables
|
|
|
|
and left the mode a few lines above), there will be outstanding
|
|
|
|
metadata locks. Release them.
|
|
|
|
*/
|
A prerequisite patch for the fix for Bug#46224
"HANDLER statements within a transaction might lead to deadlocks".
Introduce a notion of a sentinel to MDL_context. A sentinel
is a ticket that separates all tickets in the context into two
groups: before and after it. Currently we can have (and need) only
one designated sentinel -- it separates all locks taken by LOCK
TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK
and all other locks, which must be released at COMMIT or ROLLBACK.
The tricky part is maintaining the sentinel up to date when
someone release its corresponding ticket. This can happen, e.g.
if someone issues DROP TABLE under LOCK TABLES (generally,
see all calls to release_all_locks_for_name()).
MDL_context::release_ticket() is modified to take care of it.
******
A fix and a test case for Bug#46224 "HANDLER statements within a
transaction might lead to deadlocks".
An attempt to mix HANDLER SQL statements, which are transaction-
agnostic, an open multi-statement transaction,
and DDL against the involved tables (in a concurrent connection)
could lead to a deadlock. The deadlock would occur when
HANDLER OPEN or HANDLER READ would have to wait on a conflicting
metadata lock. If the connection that issued HANDLER statement
also had other metadata locks (say, acquired in scope of a
transaction), a classical deadlock situation of mutual wait
could occur.
Incompatible change: entering LOCK TABLES mode automatically
closes all open HANDLERs in the current connection.
Incompatible change: previously an attempt to wait on a lock
in a connection that has an open HANDLER statement could wait
indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK
is produced.
The idea of the fix is to merge thd->handler_mdl_context
with the main mdl_context of the connection, used for transactional
locks. This makes deadlock detection possible, since all waits
with locks are "visible" and available to analysis in a single
MDL context of the connection.
Since HANDLER locks and transactional locks have a different life
cycle -- HANDLERs are explicitly open and closed, and so
are HANDLER locks, explicitly acquired and released, whereas
transactional locks "accumulate" till the end of a transaction
and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT,
a concept of "sentinel" was introduced to MDL_context.
All locks, HANDLER and others, reside in the same linked list.
However, a selected element of the list separates locks with
different life cycle. HANDLER locks always reside at the
end of the list, after the sentinel. Transactional locks are
prepended to the beginning of the list, before the sentinel.
Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only
release those locks that reside before the sentinel. HANDLER locks
must be released explicitly as part of HANDLER CLOSE statement,
or an implicit close.
The same approach with sentinel
is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES
statement has never worked together, the implementation is
made simple and only maintains one sentinel, which is used either
for HANDLER locks, or for LOCK TABLES locks.
2009-12-22 17:09:15 +01:00
|
|
|
mdl_context.release_transactional_locks();
|
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5,
2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1
- initial changeset that introduced the fix for
Bug#989 and follow up fixes for all test suite failures
introduced in the initial changeset.
------------------------------------------------------------
revno: 2617.31.1
committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
branch nick: 4284-6.0
timestamp: Fri 2009-03-06 19:17:00 -0300
message:
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking
Currently the MySQL server does not keep metadata locks on
schema objects for the duration of a transaction, thus failing
to guarantee the integrity of the schema objects being used
during the transaction and to protect then from concurrent
DDL operations. This also poses a problem for replication as
a DDL operation might be replicated even thought there are
active transactions using the object being modified.
The solution is to defer the release of metadata locks until
a active transaction is either committed or rolled back. This
prevents other statements from modifying the table for the
entire duration of the transaction. This provides commitment
ordering for guaranteeing serializability across multiple
transactions.
- Incompatible change:
If MySQL's metadata locking system encounters a lock conflict,
the usual schema is to use the try and back-off technique to
avoid deadlocks -- this schema consists in releasing all locks
and trying to acquire them all in one go.
But in a transactional context this algorithm can't be utilized
as its not possible to release locks acquired during the course
of the transaction without breaking the transaction commitments.
To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
returned if a lock conflict is encountered during a transaction.
Let's consider an example:
A transaction has two statements that modify table t1, then table
t2, and then commits. The first statement of the transaction will
acquire a shared metadata lock on table t1, and it will be kept
utill COMMIT to ensure serializability.
At the moment when the second statement attempts to acquire a
shared metadata lock on t2, a concurrent ALTER or DROP statement
might have locked t2 exclusively. The prescription of the current
locking protocol is that the acquirer of the shared lock backs off
-- gives up all his current locks and retries. This implies that
the entire multi-statement transaction has to be rolled back.
- Incompatible change:
FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
LOCK won't cause locked tables to be implicitly unlocked anymore.
2009-12-05 00:02:48 +01:00
|
|
|
|
Implement new type-of-operation-aware metadata locks.
Add a wait-for graph based deadlock detector to the
MDL subsystem.
Fixes bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock" and
bug #37346 "innodb does not detect deadlock between update and
alter table".
The first bug manifested itself as an unwarranted abort of a
transaction with ER_LOCK_DEADLOCK error by a concurrent ALTER
statement, when this transaction tried to repeat use of a
table, which it has already used in a similar fashion before
ALTER started.
The second bug showed up as a deadlock between table-level
locks and InnoDB row locks, which was "detected" only after
innodb_lock_wait_timeout timeout.
A transaction would start using the table and modify a few
rows.
Then ALTER TABLE would come in, and start copying rows
into a temporary table. Eventually it would stumble on
the modified records and get blocked on a row lock.
The first transaction would try to do more updates, and get
blocked on thr_lock.c lock.
This situation of circular wait would only get resolved
by a timeout.
Both these bugs stemmed from inadequate solutions to the
problem of deadlocks occurring between different
locking subsystems.
In the first case we tried to avoid deadlocks between metadata
locking and table-level locking subsystems, when upgrading shared
metadata lock to exclusive one.
Transactions holding the shared lock on the table and waiting for
some table-level lock used to be aborted too aggressively.
We also allowed ALTER TABLE to start in presence of transactions
that modify the subject table. ALTER TABLE acquires
TL_WRITE_ALLOW_READ lock at start, and that block all writes
against the table (naturally, we don't want any writes to be lost
when switching the old and the new table). TL_WRITE_ALLOW_READ
lock, in turn, would block the started transaction on thr_lock.c
lock, should they do more updates. This, again, lead to the need
to abort such transactions.
The second bug occurred simply because we didn't have any
mechanism to detect deadlocks between the table-level locks
in thr_lock.c and row-level locks in InnoDB, other than
innodb_lock_wait_timeout.
This patch solves both these problems by moving lock conflicts
which are causing these deadlocks into the metadata locking
subsystem, thus making it possible to avoid or detect such
deadlocks inside MDL.
To do this we introduce new type-of-operation-aware metadata
locks, which allow MDL subsystem to know not only the fact that
transaction has used or is going to use some object but also what
kind of operation it has carried out or going to carry out on the
object.
This, along with the addition of a special kind of upgradable
metadata lock, allows ALTER TABLE to wait until all
transactions which has updated the table to go away.
This solves the second issue.
Another special type of upgradable metadata lock is acquired
by LOCK TABLE WRITE. This second lock type allows to solve the
first issue, since abortion of table-level locks in event of
DDL under LOCK TABLES becomes also unnecessary.
Below follows the list of incompatible changes introduced by
this patch:
- From now on, ALTER TABLE and CREATE/DROP TRIGGER SQL (i.e. those
statements that acquire TL_WRITE_ALLOW_READ lock)
wait for all transactions which has *updated* the table to
complete.
- From now on, LOCK TABLES ... WRITE, REPAIR/OPTIMIZE TABLE
(i.e. all statements which acquire TL_WRITE table-level lock) wait
for all transaction which *updated or read* from the table
to complete.
As a consequence, innodb_table_locks=0 option no longer applies
to LOCK TABLES ... WRITE.
- DROP DATABASE, DROP TABLE, RENAME TABLE no longer abort
statements or transactions which use tables being dropped or
renamed, and instead wait for these transactions to complete.
- Since LOCK TABLES WRITE now takes a special metadata lock,
not compatible with with reads or writes against the subject table
and transaction-wide, thr_lock.c deadlock avoidance algorithm
that used to ensure absence of deadlocks between LOCK TABLES
WRITE and other statements is no longer sufficient, even for
MyISAM. The wait-for graph based deadlock detector of MDL
subsystem may sometimes be necessary and is involved. This may
lead to ER_LOCK_DEADLOCK error produced for multi-statement
transactions even if these only use MyISAM:
session 1: session 2:
begin;
update t1 ... lock table t2 write, t1 write;
-- gets a lock on t2, blocks on t1
update t2 ...
(ER_LOCK_DEADLOCK)
- Finally, support of LOW_PRIORITY option for LOCK TABLES ... WRITE
was abandoned.
LOCK TABLE ... LOW_PRIORITY WRITE from now on has the same
priority as the usual LOCK TABLE ... WRITE.
SELECT HIGH PRIORITY no longer trumps LOCK TABLE ... WRITE in
the wait queue.
- We do not take upgradable metadata locks on implicitly
locked tables. So if one has, say, a view v1 that uses
table t1, and issues:
LOCK TABLE v1 WRITE;
FLUSH TABLE t1; -- (or just 'FLUSH TABLES'),
an error is produced.
In order to be able to perform DDL on a table under LOCK TABLES,
the table must be locked explicitly in the LOCK TABLES list.
2010-02-01 12:43:06 +01:00
|
|
|
/* Release the global read lock, if acquired. */
|
|
|
|
if (global_read_lock.is_acquired())
|
|
|
|
global_read_lock.unlock_global_read_lock(this);
|
|
|
|
|
|
|
|
/* All metadata locks must have been released by now. */
|
|
|
|
DBUG_ASSERT(!mdl_context.has_locks());
|
|
|
|
|
2009-09-29 17:38:40 +02:00
|
|
|
#if defined(ENABLED_DEBUG_SYNC)
|
|
|
|
/* End the Debug Sync Facility. See debug_sync.cc. */
|
|
|
|
debug_sync_end_thread(this);
|
|
|
|
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
|
|
|
|
2005-08-30 15:22:19 +02:00
|
|
|
delete_dynamic(&user_var_events);
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&user_vars);
|
2000-07-31 21:29:14 +02:00
|
|
|
close_temporary_tables(this);
|
2003-10-21 12:08:35 +02:00
|
|
|
sp_cache_clear(&sp_proc_cache);
|
2005-09-09 09:43:26 +02:00
|
|
|
sp_cache_clear(&sp_func_cache);
|
|
|
|
|
2002-11-16 19:19:10 +01:00
|
|
|
if (ull)
|
2001-03-06 14:24:08 +01:00
|
|
|
{
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_lock(&LOCK_user_locks);
|
2002-11-16 19:19:10 +01:00
|
|
|
item_user_lock_release(ull);
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_user_locks);
|
2007-10-11 15:11:12 +02:00
|
|
|
ull= NULL;
|
2001-03-06 14:24:08 +01:00
|
|
|
}
|
2003-04-02 20:42:28 +02:00
|
|
|
|
2001-08-21 19:06:00 +02:00
|
|
|
cleanup_done=1;
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
2002-11-16 19:19:10 +01:00
|
|
|
|
2001-08-21 19:06:00 +02:00
|
|
|
THD::~THD()
|
|
|
|
{
|
2002-03-30 20:36:05 +01:00
|
|
|
THD_CHECK_SENTRY(this);
|
2001-08-21 19:06:00 +02:00
|
|
|
DBUG_ENTER("~THD()");
|
2002-08-22 15:50:58 +02:00
|
|
|
/* Ensure that no one is using THD */
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_thd_data);
|
|
|
|
mysql_mutex_unlock(&LOCK_thd_data);
|
2004-09-13 15:48:01 +02:00
|
|
|
add_to_status(&global_status_var, &status_var);
|
2002-08-22 15:50:58 +02:00
|
|
|
|
2001-08-21 19:06:00 +02:00
|
|
|
/* Close connection */
|
2005-04-04 00:50:05 +02:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
2001-08-21 19:06:00 +02:00
|
|
|
if (net.vio)
|
|
|
|
{
|
|
|
|
vio_delete(net.vio);
|
2005-04-04 00:50:05 +02:00
|
|
|
net_end(&net);
|
2001-08-21 19:06:00 +02:00
|
|
|
}
|
2002-12-16 14:33:29 +01:00
|
|
|
#endif
|
2006-04-12 23:46:44 +02:00
|
|
|
stmt_map.reset(); /* close all prepared statements */
|
2005-07-19 20:21:12 +02:00
|
|
|
DBUG_ASSERT(lock_info.n_cursors == 0);
|
2001-08-21 19:06:00 +02:00
|
|
|
if (!cleanup_done)
|
|
|
|
cleanup();
|
2005-01-16 13:16:23 +01:00
|
|
|
|
2009-12-04 00:52:05 +01:00
|
|
|
mdl_context.destroy();
|
2005-04-04 00:50:05 +02:00
|
|
|
ha_close_connection(this);
|
2009-12-15 20:52:47 +01:00
|
|
|
mysql_audit_release(this);
|
2007-03-02 17:43:45 +01:00
|
|
|
plugin_thdvar_cleanup(this);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
DBUG_PRINT("info", ("freeing security context"));
|
|
|
|
main_security_ctx.destroy();
|
2004-01-07 18:30:15 +01:00
|
|
|
safeFree(db);
|
2002-03-15 22:57:31 +01:00
|
|
|
free_root(&transaction.mem_root,MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
mysys_var=0; // Safety (shouldn't be needed)
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_destroy(&LOCK_thd_data);
|
2002-03-30 20:36:05 +01:00
|
|
|
#ifndef DBUG_OFF
|
2003-12-04 20:08:26 +01:00
|
|
|
dbug_sentry= THD_SENTRY_GONE;
|
2001-03-13 04:17:32 +01:00
|
|
|
#endif
|
2005-12-22 06:39:02 +01:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
|
|
|
if (rli_fake)
|
2008-02-12 18:21:17 +01:00
|
|
|
{
|
2005-12-22 06:39:02 +01:00
|
|
|
delete rli_fake;
|
2008-02-12 18:21:17 +01:00
|
|
|
rli_fake= NULL;
|
|
|
|
}
|
2009-12-15 20:52:47 +01:00
|
|
|
|
|
|
|
mysql_audit_free_thd(this);
|
2005-12-22 06:39:02 +01:00
|
|
|
#endif
|
|
|
|
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
free_root(&main_mem_root, MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
2002-08-22 15:50:58 +02:00
|
|
|
|
2004-09-13 15:48:01 +02:00
|
|
|
/*
|
2006-01-10 17:56:23 +01:00
|
|
|
Add all status variables to another status variable array
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
add_to_status()
|
|
|
|
to_var add to this array
|
|
|
|
from_var from this array
|
2004-09-13 15:48:01 +02:00
|
|
|
|
|
|
|
NOTES
|
|
|
|
This function assumes that all variables are long/ulong.
|
|
|
|
If this assumption will change, then we have to explictely add
|
|
|
|
the other variables after the while loop
|
|
|
|
*/
|
|
|
|
|
|
|
|
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
ulong *end= (ulong*) ((uchar*) to_var +
|
2006-10-30 13:35:57 +01:00
|
|
|
offsetof(STATUS_VAR, last_system_status_var) +
|
2004-09-13 15:48:01 +02:00
|
|
|
sizeof(ulong));
|
|
|
|
ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
|
|
|
|
|
|
|
|
while (to != end)
|
|
|
|
*(to++)+= *(from++);
|
|
|
|
}
|
|
|
|
|
2006-06-20 12:20:32 +02:00
|
|
|
/*
|
|
|
|
Add the difference between two status variable arrays to another one.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
add_diff_to_status
|
|
|
|
to_var add to this array
|
|
|
|
from_var from this array
|
|
|
|
dec_var minus this array
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
This function assumes that all variables are long/ulong.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
|
|
|
|
STATUS_VAR *dec_var)
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
ulong *end= (ulong*) ((uchar*) to_var + offsetof(STATUS_VAR,
|
2006-06-20 12:20:32 +02:00
|
|
|
last_system_status_var) +
|
|
|
|
sizeof(ulong));
|
|
|
|
ulong *to= (ulong*) to_var, *from= (ulong*) from_var, *dec= (ulong*) dec_var;
|
|
|
|
|
|
|
|
while (to != end)
|
|
|
|
*(to++)+= *(from++) - *(dec++);
|
|
|
|
}
|
|
|
|
|
2004-09-13 15:48:01 +02:00
|
|
|
|
2003-03-31 10:39:46 +02:00
|
|
|
void THD::awake(THD::killed_state state_to_set)
|
2001-03-14 07:07:12 +01:00
|
|
|
{
|
2006-05-22 20:46:13 +02:00
|
|
|
DBUG_ENTER("THD::awake");
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
|
2002-03-30 20:36:05 +01:00
|
|
|
THD_CHECK_SENTRY(this);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_assert_owner(&LOCK_thd_data);
|
2002-08-22 15:50:58 +02:00
|
|
|
|
2003-03-31 10:39:46 +02:00
|
|
|
killed= state_to_set;
|
|
|
|
if (state_to_set != THD::KILL_QUERY)
|
2005-12-14 18:42:08 +01:00
|
|
|
{
|
2007-02-23 12:13:55 +01:00
|
|
|
thr_alarm_kill(thread_id);
|
|
|
|
if (!slave_thread)
|
|
|
|
thread_scheduler.post_kill_notification(this);
|
2001-03-14 07:07:12 +01:00
|
|
|
#ifdef SIGNAL_WITH_VIO_CLOSE
|
2007-11-15 13:35:35 +01:00
|
|
|
if (this != current_thd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
In addition to a signal, let's close the socket of the thread that
|
|
|
|
is being killed. This is to make sure it does not block if the
|
|
|
|
signal is lost. This needs to be done only on platforms where
|
|
|
|
signals are not a reliable interruption mechanism.
|
|
|
|
|
|
|
|
If we're killing ourselves, we know that we're not blocked, so this
|
|
|
|
hack is not used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
close_active_vio();
|
|
|
|
}
|
2001-03-14 07:07:12 +01:00
|
|
|
#endif
|
2005-12-14 18:42:08 +01:00
|
|
|
}
|
2001-03-14 07:07:12 +01:00
|
|
|
if (mysys_var)
|
2002-06-12 14:04:18 +02:00
|
|
|
{
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_lock(&mysys_var->mutex);
|
2002-06-12 14:04:18 +02:00
|
|
|
if (!system_thread) // Don't abort locks
|
|
|
|
mysys_var->abort=1;
|
|
|
|
/*
|
|
|
|
This broadcast could be up in the air if the victim thread
|
|
|
|
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.
|
2004-07-30 00:53:25 +02:00
|
|
|
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.
|
2004-08-24 17:00:45 +02:00
|
|
|
|
2004-07-30 00:53:25 +02:00
|
|
|
Note that there is a small chance we fail to kill. If victim has locked
|
2004-08-24 17:00:45 +02:00
|
|
|
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
|
2004-07-30 00:53:25 +02:00
|
|
|
see it immediately and so may have time to reach the cond_wait().
|
2002-06-12 14:04:18 +02:00
|
|
|
*/
|
2004-07-30 00:53:25 +02:00
|
|
|
if (mysys_var->current_cond && mysys_var->current_mutex)
|
2001-03-14 07:07:12 +01:00
|
|
|
{
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_lock(mysys_var->current_mutex);
|
|
|
|
mysql_cond_broadcast(mysys_var->current_cond);
|
|
|
|
mysql_mutex_unlock(mysys_var->current_mutex);
|
2001-03-14 07:07:12 +01:00
|
|
|
}
|
2009-12-10 04:19:51 +01:00
|
|
|
mysql_mutex_unlock(&mysys_var->mutex);
|
2002-06-12 14:04:18 +02:00
|
|
|
}
|
2006-05-22 20:46:13 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2001-03-14 07:07:12 +01:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
/*
|
|
|
|
Remember the location of thread info, the structure needed for
|
|
|
|
sql_alloc() and the structure for the net buffer
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
bool THD::store_globals()
|
|
|
|
{
|
2005-11-23 19:18:10 +01:00
|
|
|
/*
|
|
|
|
Assert that thread_stack is initialized: it's necessary to be able
|
|
|
|
to track stack overrun.
|
|
|
|
*/
|
2007-02-23 12:13:55 +01:00
|
|
|
DBUG_ASSERT(thread_stack);
|
2005-11-23 19:18:10 +01:00
|
|
|
|
2002-09-05 15:17:08 +02:00
|
|
|
if (my_pthread_setspecific_ptr(THR_THD, this) ||
|
2002-10-02 16:55:12 +02:00
|
|
|
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
|
2002-09-05 15:17:08 +02:00
|
|
|
return 1;
|
|
|
|
mysys_var=my_thread_var;
|
2003-10-31 23:20:23 +01:00
|
|
|
/*
|
2007-02-23 12:13:55 +01:00
|
|
|
Let mysqld define the thread id (not mysys)
|
|
|
|
This allows us to move THD to different threads if needed.
|
2003-10-31 23:20:23 +01:00
|
|
|
*/
|
2007-02-23 12:13:55 +01:00
|
|
|
mysys_var->id= thread_id;
|
|
|
|
real_id= pthread_self(); // For debugging
|
|
|
|
|
2005-07-31 11:49:55 +02:00
|
|
|
/*
|
|
|
|
We have to call thr_lock_info_init() again here as THD may have been
|
|
|
|
created in another thread
|
|
|
|
*/
|
2005-07-19 20:21:12 +02:00
|
|
|
thr_lock_info_init(&lock_info);
|
2002-09-05 15:17:08 +02:00
|
|
|
return 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-12 14:04:18 +02:00
|
|
|
|
2006-10-02 12:28:23 +02:00
|
|
|
/*
|
|
|
|
Cleanup after query.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
THD::cleanup_after_query()
|
2004-09-15 21:10:31 +02:00
|
|
|
|
2006-10-02 12:28:23 +02:00
|
|
|
DESCRIPTION
|
2006-10-03 15:07:30 +02:00
|
|
|
This function is used to reset thread data to its default state.
|
2006-10-02 12:28:23 +02:00
|
|
|
|
|
|
|
NOTE
|
|
|
|
This function is not suitable for setting thread data to some
|
|
|
|
non-default values, as there is only one replication thread, so
|
|
|
|
different master threads may overwrite data of each other on
|
|
|
|
slave.
|
|
|
|
*/
|
2006-10-03 15:07:30 +02:00
|
|
|
|
2004-09-15 21:10:31 +02:00
|
|
|
void THD::cleanup_after_query()
|
|
|
|
{
|
2007-03-09 18:18:28 +01:00
|
|
|
/*
|
|
|
|
Reset rand_used so that detection of calls to rand() will save random
|
|
|
|
seeds if needed by the slave.
|
|
|
|
|
|
|
|
Do not reset rand_used if inside a stored function or trigger because
|
|
|
|
only the call to these operations is logged. Thus only the calling
|
|
|
|
statement needs to detect rand() calls made by its substatements. These
|
|
|
|
substatements must not set rand_used to 0 because it would remove the
|
|
|
|
detection of rand() by the calling statement.
|
|
|
|
*/
|
2006-09-12 15:42:13 +02:00
|
|
|
if (!in_sub_stmt) /* stored functions and triggers are a special case */
|
|
|
|
{
|
|
|
|
/* Forget those values, for next binlogger: */
|
|
|
|
stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
|
|
|
|
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
|
2007-03-09 18:18:28 +01:00
|
|
|
rand_used= 0;
|
2006-09-12 15:42:13 +02:00
|
|
|
}
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
if (first_successful_insert_id_in_cur_stmt > 0)
|
2004-09-15 21:10:31 +02:00
|
|
|
{
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
/* set what LAST_INSERT_ID() will return */
|
|
|
|
first_successful_insert_id_in_prev_stmt=
|
|
|
|
first_successful_insert_id_in_cur_stmt;
|
|
|
|
first_successful_insert_id_in_cur_stmt= 0;
|
2006-08-01 06:49:43 +02:00
|
|
|
substitute_null_with_insert_id= TRUE;
|
2004-09-15 21:10:31 +02:00
|
|
|
}
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
arg_of_last_insert_id_function= 0;
|
2004-09-15 21:10:31 +02:00
|
|
|
/* Free Items that were created during this execution */
|
2005-06-23 18:22:08 +02:00
|
|
|
free_items();
|
2005-10-25 11:02:48 +02:00
|
|
|
/* Reset where. */
|
|
|
|
where= THD::DEFAULT_WHERE;
|
2008-07-31 08:24:27 +02:00
|
|
|
/* reset table map for multi-table update */
|
|
|
|
table_map_for_update= 0;
|
2004-09-15 21:10:31 +02:00
|
|
|
}
|
|
|
|
|
2006-10-03 15:07:30 +02:00
|
|
|
|
2007-07-05 01:05:47 +02:00
|
|
|
/**
|
2007-10-16 21:37:31 +02:00
|
|
|
Create a LEX_STRING in this connection.
|
2007-07-05 01:05:47 +02:00
|
|
|
|
|
|
|
@param lex_str pointer to LEX_STRING object to be initialized
|
|
|
|
@param str initializer to be copied into lex_str
|
|
|
|
@param length length of str, in bytes
|
|
|
|
@param allocate_lex_string if TRUE, allocate new LEX_STRING object,
|
|
|
|
instead of using lex_str value
|
|
|
|
@return NULL on failure, or pointer to the LEX_STRING object
|
|
|
|
*/
|
|
|
|
LEX_STRING *THD::make_lex_string(LEX_STRING *lex_str,
|
|
|
|
const char* str, uint length,
|
|
|
|
bool allocate_lex_string)
|
|
|
|
{
|
|
|
|
if (allocate_lex_string)
|
|
|
|
if (!(lex_str= (LEX_STRING *)alloc(sizeof(LEX_STRING))))
|
|
|
|
return 0;
|
|
|
|
if (!(lex_str->str= strmake_root(mem_root, str, length)))
|
|
|
|
return 0;
|
|
|
|
lex_str->length= length;
|
|
|
|
return lex_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-18 23:08:08 +02:00
|
|
|
/*
|
|
|
|
Convert a string to another character set
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
convert_string()
|
|
|
|
to Store new allocated string here
|
|
|
|
to_cs New character set for allocated string
|
|
|
|
from String to convert
|
|
|
|
from_length Length of string to convert
|
|
|
|
from_cs Original character set
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
to will be 0-terminated to make it easy to pass to system funcs
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 End of memory.
|
|
|
|
In this case to->str will point to 0 and to->length will be 0.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
|
|
|
|
const char *from, uint from_length,
|
|
|
|
CHARSET_INFO *from_cs)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("convert_string");
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t new_length= to_cs->mbmaxlen * from_length;
|
2004-10-29 14:00:39 +02:00
|
|
|
uint dummy_errors;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (!(to->str= (char*) alloc(new_length+1)))
|
2003-08-18 23:08:08 +02:00
|
|
|
{
|
|
|
|
to->length= 0; // Safety fix
|
|
|
|
DBUG_RETURN(1); // EOM
|
|
|
|
}
|
|
|
|
to->length= copy_and_convert((char*) to->str, new_length, to_cs,
|
2004-10-29 14:00:39 +02:00
|
|
|
from, from_length, from_cs, &dummy_errors);
|
2003-08-18 23:08:08 +02:00
|
|
|
to->str[to->length]=0; // Safety
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-25 00:03:49 +02:00
|
|
|
/*
|
|
|
|
Convert string from source character set to target character set inplace.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
THD::convert_string
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Convert string using convert_buffer - buffer for character set
|
|
|
|
conversion shared between all protocols.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
!0 out of memory
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
|
|
|
|
{
|
2004-10-29 14:00:39 +02:00
|
|
|
uint dummy_errors;
|
|
|
|
if (convert_buffer.copy(s->ptr(), s->length(), from_cs, to_cs, &dummy_errors))
|
2004-05-25 00:03:49 +02:00
|
|
|
return TRUE;
|
|
|
|
/* If convert_buffer >> s copying is more efficient long term */
|
|
|
|
if (convert_buffer.alloced_length() >= convert_buffer.length() * 2 ||
|
|
|
|
!s->is_alloced())
|
|
|
|
{
|
|
|
|
return s->copy(convert_buffer);
|
|
|
|
}
|
|
|
|
s->swap(convert_buffer);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-06 14:15:43 +02:00
|
|
|
|
2003-08-18 23:08:08 +02:00
|
|
|
/*
|
|
|
|
Update some cache variables when character set changes
|
|
|
|
*/
|
|
|
|
|
|
|
|
void THD::update_charset()
|
|
|
|
{
|
2004-07-06 14:15:43 +02:00
|
|
|
uint32 not_used;
|
2009-12-22 10:35:56 +01:00
|
|
|
charset_is_system_charset=
|
|
|
|
!String::needs_conversion(0,
|
|
|
|
variables.character_set_client,
|
|
|
|
system_charset_info,
|
|
|
|
¬_used);
|
2004-07-06 14:15:43 +02:00
|
|
|
charset_is_collation_connection=
|
2009-12-22 10:35:56 +01:00
|
|
|
!String::needs_conversion(0,
|
|
|
|
variables.character_set_client,
|
|
|
|
variables.collation_connection,
|
2004-07-06 14:15:43 +02:00
|
|
|
¬_used);
|
2006-01-18 09:55:38 +01:00
|
|
|
charset_is_character_set_filesystem=
|
2009-12-22 10:35:56 +01:00
|
|
|
!String::needs_conversion(0,
|
|
|
|
variables.character_set_client,
|
|
|
|
variables.character_set_filesystem,
|
|
|
|
¬_used);
|
2003-08-18 23:08:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-15 22:57:31 +01:00
|
|
|
/* routings to adding tables to list of changed in transaction tables */
|
|
|
|
|
|
|
|
inline static void list_include(CHANGED_TABLE_LIST** prev,
|
|
|
|
CHANGED_TABLE_LIST* curr,
|
|
|
|
CHANGED_TABLE_LIST* new_table)
|
|
|
|
{
|
|
|
|
if (new_table)
|
|
|
|
{
|
|
|
|
*prev = new_table;
|
|
|
|
(*prev)->next = curr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add table to list of changed in transaction tables */
|
2002-06-11 10:20:31 +02:00
|
|
|
|
2002-03-15 22:57:31 +01:00
|
|
|
void THD::add_changed_table(TABLE *table)
|
|
|
|
{
|
2002-06-11 10:20:31 +02:00
|
|
|
DBUG_ENTER("THD::add_changed_table(table)");
|
2002-03-15 22:57:31 +01:00
|
|
|
|
2009-12-03 23:46:14 +01:00
|
|
|
DBUG_ASSERT(in_multi_stmt_transaction() && table->file->has_transactions());
|
2005-11-23 21:45:02 +01:00
|
|
|
add_changed_table(table->s->table_cache_key.str,
|
2007-05-31 16:45:22 +02:00
|
|
|
(long) table->s->table_cache_key.length);
|
2002-09-19 19:10:06 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2002-09-19 09:36:19 +02:00
|
|
|
}
|
2002-03-15 22:57:31 +01:00
|
|
|
|
2002-11-07 02:54:00 +01:00
|
|
|
|
2002-09-19 09:36:19 +02:00
|
|
|
void THD::add_changed_table(const char *key, long key_length)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("THD::add_changed_table(key)");
|
2002-11-07 02:54:00 +01:00
|
|
|
CHANGED_TABLE_LIST **prev_changed = &transaction.changed_tables;
|
|
|
|
CHANGED_TABLE_LIST *curr = transaction.changed_tables;
|
2002-03-15 22:57:31 +01:00
|
|
|
|
2002-11-07 02:54:00 +01:00
|
|
|
for (; curr; prev_changed = &(curr->next), curr = curr->next)
|
2002-03-15 22:57:31 +01:00
|
|
|
{
|
2002-09-19 09:36:19 +02:00
|
|
|
int cmp = (long)curr->key_length - (long)key_length;
|
2002-03-15 22:57:31 +01:00
|
|
|
if (cmp < 0)
|
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
list_include(prev_changed, curr, changed_table_dup(key, key_length));
|
2002-03-15 22:57:31 +01:00
|
|
|
DBUG_PRINT("info",
|
2007-03-22 19:32:07 +01:00
|
|
|
("key_length: %ld %u", key_length,
|
|
|
|
(*prev_changed)->key_length));
|
2002-03-15 22:57:31 +01:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
else if (cmp == 0)
|
|
|
|
{
|
2002-09-19 09:36:19 +02:00
|
|
|
cmp = memcmp(curr->key, key, curr->key_length);
|
2002-03-15 22:57:31 +01:00
|
|
|
if (cmp < 0)
|
|
|
|
{
|
2002-11-07 02:54:00 +01:00
|
|
|
list_include(prev_changed, curr, changed_table_dup(key, key_length));
|
2002-03-15 22:57:31 +01:00
|
|
|
DBUG_PRINT("info",
|
2007-03-28 19:46:42 +02:00
|
|
|
("key_length: %ld %u", key_length,
|
2002-11-07 02:54:00 +01:00
|
|
|
(*prev_changed)->key_length));
|
2002-03-15 22:57:31 +01:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
else if (cmp == 0)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("info", ("already in list"));
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-11-07 02:54:00 +01:00
|
|
|
*prev_changed = changed_table_dup(key, key_length);
|
2007-03-22 19:32:07 +01:00
|
|
|
DBUG_PRINT("info", ("key_length: %ld %u", key_length,
|
2002-11-07 02:54:00 +01:00
|
|
|
(*prev_changed)->key_length));
|
2002-03-15 22:57:31 +01:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
2002-06-11 10:20:31 +02:00
|
|
|
|
2002-09-19 09:36:19 +02:00
|
|
|
CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
|
2002-03-15 22:57:31 +01:00
|
|
|
{
|
|
|
|
CHANGED_TABLE_LIST* new_table =
|
|
|
|
(CHANGED_TABLE_LIST*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST))+
|
2002-09-19 09:36:19 +02:00
|
|
|
key_length + 1);
|
2002-03-15 22:57:31 +01:00
|
|
|
if (!new_table)
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
|
|
|
|
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
|
2003-03-31 10:39:46 +02:00
|
|
|
killed= KILL_CONNECTION;
|
2002-03-15 22:57:31 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
new_table->key= ((char*)new_table)+ ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST));
|
2002-03-15 22:57:31 +01:00
|
|
|
new_table->next = 0;
|
2002-09-19 09:36:19 +02:00
|
|
|
new_table->key_length = key_length;
|
|
|
|
::memcpy(new_table->key, key, key_length);
|
2002-03-15 22:57:31 +01:00
|
|
|
return new_table;
|
|
|
|
}
|
|
|
|
|
2004-09-16 11:47:39 +02:00
|
|
|
|
2002-09-26 22:08:22 +02:00
|
|
|
int THD::send_explain_fields(select_result *result)
|
|
|
|
{
|
|
|
|
List<Item> field_list;
|
|
|
|
Item *item;
|
2004-09-16 11:47:39 +02:00
|
|
|
CHARSET_INFO *cs= system_charset_info;
|
2002-12-11 08:17:51 +01:00
|
|
|
field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG));
|
2004-09-16 11:47:39 +02:00
|
|
|
field_list.push_back(new Item_empty_string("select_type", 19, cs));
|
2007-04-03 13:13:27 +02:00
|
|
|
field_list.push_back(item= new Item_empty_string("table", NAME_CHAR_LEN, cs));
|
2005-06-07 15:34:13 +02:00
|
|
|
item->maybe_null= 1;
|
2005-12-22 10:29:00 +01:00
|
|
|
if (lex->describe & DESCRIBE_PARTITIONS)
|
|
|
|
{
|
2005-12-27 13:04:35 +01:00
|
|
|
/* Maximum length of string that make_used_partitions_str() can produce */
|
|
|
|
item= new Item_empty_string("partitions", MAX_PARTITIONS * (1 + FN_LEN),
|
|
|
|
cs);
|
|
|
|
field_list.push_back(item);
|
2005-12-22 10:29:00 +01:00
|
|
|
item->maybe_null= 1;
|
|
|
|
}
|
2005-06-07 15:34:13 +02:00
|
|
|
field_list.push_back(item= new Item_empty_string("type", 10, cs));
|
|
|
|
item->maybe_null= 1;
|
2002-09-26 22:08:22 +02:00
|
|
|
field_list.push_back(item=new Item_empty_string("possible_keys",
|
2007-04-03 13:13:27 +02:00
|
|
|
NAME_CHAR_LEN*MAX_KEY, cs));
|
2002-09-26 22:08:22 +02:00
|
|
|
item->maybe_null=1;
|
2007-04-03 13:13:27 +02:00
|
|
|
field_list.push_back(item=new Item_empty_string("key", NAME_CHAR_LEN, cs));
|
2002-09-26 22:08:22 +02:00
|
|
|
item->maybe_null=1;
|
2003-11-13 15:52:02 +01:00
|
|
|
field_list.push_back(item=new Item_empty_string("key_len",
|
2007-04-03 13:13:27 +02:00
|
|
|
NAME_CHAR_LEN*MAX_KEY));
|
2002-09-26 22:08:22 +02:00
|
|
|
item->maybe_null=1;
|
|
|
|
field_list.push_back(item=new Item_empty_string("ref",
|
2007-04-03 13:13:27 +02:00
|
|
|
NAME_CHAR_LEN*MAX_REF_PARTS,
|
|
|
|
cs));
|
2002-09-26 22:08:22 +02:00
|
|
|
item->maybe_null=1;
|
2005-06-07 15:34:13 +02:00
|
|
|
field_list.push_back(item= new Item_return_int("rows", 10,
|
|
|
|
MYSQL_TYPE_LONGLONG));
|
2006-07-28 19:27:01 +02:00
|
|
|
if (lex->describe & DESCRIBE_EXTENDED)
|
|
|
|
{
|
|
|
|
field_list.push_back(item= new Item_float("filtered", 0.1234, 2, 4));
|
|
|
|
item->maybe_null=1;
|
|
|
|
}
|
2005-06-07 15:34:13 +02:00
|
|
|
item->maybe_null= 1;
|
2004-09-16 11:47:39 +02:00
|
|
|
field_list.push_back(new Item_empty_string("Extra", 255, cs));
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
return (result->send_result_set_metadata(field_list,
|
|
|
|
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
|
2002-09-26 22:08:22 +02:00
|
|
|
}
|
2002-03-15 22:57:31 +01:00
|
|
|
|
2002-09-03 14:44:25 +02:00
|
|
|
#ifdef SIGNAL_WITH_VIO_CLOSE
|
|
|
|
void THD::close_active_vio()
|
|
|
|
{
|
2003-03-12 00:40:06 +01:00
|
|
|
DBUG_ENTER("close_active_vio");
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_assert_owner(&LOCK_thd_data);
|
2003-01-28 18:03:05 +01:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
2002-09-03 14:44:25 +02:00
|
|
|
if (active_vio)
|
|
|
|
{
|
|
|
|
vio_close(active_vio);
|
|
|
|
active_vio = 0;
|
|
|
|
}
|
2003-01-28 18:03:05 +01:00
|
|
|
#endif
|
2003-03-13 13:52:15 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2002-09-03 14:44:25 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-11-14 08:43:24 +01:00
|
|
|
|
2004-10-08 00:21:19 +02:00
|
|
|
struct Item_change_record: public ilink
|
|
|
|
{
|
|
|
|
Item **place;
|
|
|
|
Item *old_value;
|
|
|
|
/* Placement new was hidden by `new' in ilink (TODO: check): */
|
2004-10-08 15:00:36 +02:00
|
|
|
static void *operator new(size_t size, void *mem) { return mem; }
|
2005-02-15 01:55:44 +01:00
|
|
|
static void operator delete(void *ptr, size_t size) {}
|
|
|
|
static void operator delete(void *ptr, void *mem) { /* never called */ }
|
2004-10-08 00:21:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Register an item tree tree transformation, performed by the query
|
|
|
|
optimizer. We need a pointer to runtime_memroot because it may be !=
|
2005-09-02 15:21:19 +02:00
|
|
|
thd->mem_root (due to possible set_n_backup_active_arena called for thd).
|
2004-10-08 00:21:19 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
|
|
|
|
MEM_ROOT *runtime_memroot)
|
|
|
|
{
|
|
|
|
Item_change_record *change;
|
|
|
|
/*
|
|
|
|
Now we use one node per change, which adds some memory overhead,
|
|
|
|
but still is rather fast as we use alloc_root for allocations.
|
|
|
|
A list of item tree changes of an average query should be short.
|
|
|
|
*/
|
|
|
|
void *change_mem= alloc_root(runtime_memroot, sizeof(*change));
|
|
|
|
if (change_mem == 0)
|
|
|
|
{
|
2005-07-01 13:47:45 +02:00
|
|
|
/*
|
|
|
|
OOM, thd->fatal_error() is called by the error handler of the
|
|
|
|
memroot. Just return.
|
|
|
|
*/
|
2004-10-08 00:21:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
change= new (change_mem) Item_change_record;
|
|
|
|
change->place= place;
|
|
|
|
change->old_value= old_value;
|
A fix and test case for Bug#5987 "subselect in bool function
crashes server (prepared statements)": the bug was that all boolean
items always recovered its original arguments at statement cleanup
stage.
This collided with Item_subselect::select_transformer, which tries to
permanently change the item tree to use a transformed subselect instead of
original one.
So we had this call sequence for prepare:
mysql_stmt_prepare -> JOIN::prepare ->
Item_subselect::fix_fields -> the item tree gets transformed ->
Item_bool_rowready_func2::cleanup, item tree is recovered to original
state, while it shouldn't have been;
mysql_stmt_execute -> attempts to execute a broken tree -> crash.
Now instead of bluntly recovering all arguments of bool functions in
Item_bool_rowready_func2::cleanup, we recover only those
which were changed, and do it in one place.
There still would exist a possibility for a collision with subselect
tranformation, if permanent and temporary changes were performed at the
same stage.
But fortunately subselect transformation is always done first, so it
doesn't conflict with the optimization done by propogate_cond_constants.
Now we have:
mysql_stmt_prepare -> JOIN::prepare -> subselect transformation
permanently changes the tree -> cleanup doesn't recover anything,
because nothing was registered for recovery.
mysql_stmt_execute -> JOIN::prepare (the tree is already transformed,
so it doesn't change), JOIN::optimize ->
propogate_cond_constants -> temporary changes the item tree
with constants -> JOIN::execute -> cleanup ->
the changes done by propogate_cond_constants are recovered, as
they were registered for recovery.
2004-10-10 00:39:22 +02:00
|
|
|
change_list.append(change);
|
2004-10-08 00:21:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void THD::rollback_item_tree_changes()
|
|
|
|
{
|
|
|
|
I_List_iterator<Item_change_record> it(change_list);
|
|
|
|
Item_change_record *change;
|
2004-11-03 11:39:38 +01:00
|
|
|
DBUG_ENTER("rollback_item_tree_changes");
|
|
|
|
|
2004-10-08 00:21:19 +02:00
|
|
|
while ((change= it++))
|
|
|
|
*change->place= change->old_value;
|
|
|
|
/* We can forget about changes memory: it's allocated in runtime memroot */
|
|
|
|
change_list.empty();
|
2004-11-03 11:39:38 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2004-10-08 00:21:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
** Functions to provide a interface to select results
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
select_result::select_result()
|
|
|
|
{
|
|
|
|
thd=current_thd;
|
|
|
|
}
|
|
|
|
|
2003-10-08 17:53:31 +02:00
|
|
|
void select_result::send_error(uint errcode,const char *err)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
my_message(errcode, err, MYF(0));
|
2003-10-08 17:53:31 +02:00
|
|
|
}
|
|
|
|
|
2004-08-24 18:17:11 +02:00
|
|
|
|
|
|
|
void select_result::cleanup()
|
|
|
|
{
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
|
2006-12-01 11:25:06 +01:00
|
|
|
bool select_result::check_simple_select() const
|
|
|
|
{
|
|
|
|
my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-08 17:53:31 +02:00
|
|
|
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);
|
2009-10-12 08:22:53 +02:00
|
|
|
static String default_xml_row_term("<row>", default_charset_info);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-10-12 08:22:53 +02:00
|
|
|
sql_exchange::sql_exchange(char *name, bool flag,
|
|
|
|
enum enum_filetype filetype_arg)
|
2000-07-31 21:29:14 +02:00
|
|
|
:file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
|
|
|
|
{
|
2009-10-12 08:22:53 +02:00
|
|
|
filetype= filetype_arg;
|
2000-07-31 21:29:14 +02:00
|
|
|
field_term= &default_field_term;
|
2003-09-18 15:58:02 +02:00
|
|
|
enclosed= line_start= &my_empty_string;
|
2009-10-12 08:22:53 +02:00
|
|
|
line_term= filetype == FILETYPE_CSV ?
|
|
|
|
&default_line_term : &default_xml_row_term;
|
2000-07-31 21:29:14 +02:00
|
|
|
escaped= &default_escaped;
|
2007-02-28 14:06:57 +01:00
|
|
|
cs= NULL;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2008-09-17 08:34:00 +02:00
|
|
|
bool sql_exchange::escaped_given(void)
|
|
|
|
{
|
|
|
|
return escaped != &default_escaped;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
bool select_send::send_result_set_metadata(List<Item> &list, uint flags)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-09-13 15:32:42 +02:00
|
|
|
bool res;
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
if (!(res= thd->protocol->send_result_set_metadata(&list, flags)))
|
2007-10-31 16:33:13 +01:00
|
|
|
is_result_set_started= 1;
|
2005-09-13 15:32:42 +02:00
|
|
|
return res;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2005-09-13 15:32:42 +02:00
|
|
|
void select_send::abort()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("select_send::abort");
|
2009-09-10 11:18:29 +02:00
|
|
|
|
|
|
|
if (is_result_set_started && thd->spcont)
|
2005-09-13 15:32:42 +02:00
|
|
|
{
|
|
|
|
/*
|
2007-10-31 16:33:13 +01:00
|
|
|
We're executing a stored procedure, have an open result
|
2009-09-10 11:18:29 +02:00
|
|
|
set and an SQL exception condition. In this situation we
|
|
|
|
must abort the current statement, silence the error and
|
|
|
|
start executing the continue/exit handler if one is found.
|
2007-10-31 16:33:13 +01:00
|
|
|
Before aborting the statement, let's end the open result set, as
|
|
|
|
otherwise the client will hang due to the violation of the
|
|
|
|
client/server protocol.
|
2005-09-13 15:32:42 +02:00
|
|
|
*/
|
2009-09-10 11:18:29 +02:00
|
|
|
thd->spcont->end_partial_result_set= TRUE;
|
2005-09-13 15:32:42 +02:00
|
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-31 16:33:13 +01:00
|
|
|
/**
|
|
|
|
Cleanup an instance of this class for re-use
|
|
|
|
at next execution of a prepared statement/
|
|
|
|
stored procedure statement.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void select_send::cleanup()
|
|
|
|
{
|
|
|
|
is_result_set_started= FALSE;
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Send data to client. Returns 0 if ok */
|
|
|
|
|
|
|
|
bool select_send::send_data(List<Item> &items)
|
|
|
|
{
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
Protocol *protocol= thd->protocol;
|
|
|
|
DBUG_ENTER("select_send::send_data");
|
|
|
|
|
2002-05-08 22:14:40 +02:00
|
|
|
if (unit->offset_limit_cnt)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // using limit offset,count
|
2002-05-08 22:14:40 +02:00
|
|
|
unit->offset_limit_cnt--;
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-12-11 08:17:51 +01:00
|
|
|
|
2003-03-16 18:17:54 +01:00
|
|
|
/*
|
|
|
|
We may be passing the control from mysqld to the client: release the
|
|
|
|
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
|
|
|
|
by thd
|
|
|
|
*/
|
2006-03-23 14:51:31 +01:00
|
|
|
ha_release_temporary_latches(thd);
|
2003-03-03 18:31:01 +01:00
|
|
|
|
2002-12-11 08:17:51 +01:00
|
|
|
protocol->prepare_for_resend();
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
if (protocol->send_result_set_row(&items))
|
2007-12-12 16:21:01 +01:00
|
|
|
{
|
|
|
|
protocol->remove_last_row();
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2007-12-12 16:21:01 +01:00
|
|
|
}
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
|
|
|
|
thd->sent_row_count++;
|
|
|
|
|
2007-12-12 16:21:01 +01:00
|
|
|
if (thd->vio_ok())
|
2002-12-11 08:17:51 +01:00
|
|
|
DBUG_RETURN(protocol->write());
|
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1,
2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29,
2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and
some other minor revisions.
This patch implements:
WL#4264 "Backup: Stabilize Service Interface" -- all the
server prerequisites except si_objects.{h,cc} themselves (they can
be just copied over, when needed).
WL#4435: Support OUT-parameters in prepared statements.
(and all issues in the initial patches for these two
tasks, that were discovered in pushbuild and during testing).
Bug#39519: mysql_stmt_close() should flush all data
associated with the statement.
After execution of a prepared statement, send OUT parameters of the invoked
stored procedure, if any, to the client.
When using the binary protocol, send the parameters in an additional result
set over the wire. When using the text protocol, assign out parameters to
the user variables from the CALL(@var1, @var2, ...) specification.
The following refactoring has been made:
- Protocol::send_fields() was renamed to Protocol::send_result_set_metadata();
- A new Protocol::send_result_set_row() was introduced to incapsulate
common functionality for sending row data.
- Signature of Protocol::prepare_for_send() was changed: this operation
does not need a list of items, the number of items is fully sufficient.
The following backward incompatible changes have been made:
- CLIENT_MULTI_RESULTS is now enabled by default in the client;
- CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
2009-10-21 22:02:06 +02:00
|
|
|
|
2007-12-12 16:21:01 +01:00
|
|
|
DBUG_RETURN(0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool select_send::send_eof()
|
|
|
|
{
|
2006-03-23 14:51:31 +01:00
|
|
|
/*
|
|
|
|
We may be passing the control from mysqld to the client: release the
|
|
|
|
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
|
|
|
|
by thd
|
|
|
|
*/
|
|
|
|
ha_release_temporary_latches(thd);
|
2003-03-03 18:31:01 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Unlock tables before sending packet to gain some speed */
|
2009-12-01 15:39:03 +01:00
|
|
|
if (thd->lock && ! thd->locked_tables_mode)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-10-26 18:30:01 +02:00
|
|
|
mysql_unlock_tables(thd, thd->lock);
|
|
|
|
thd->lock=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2008-08-19 15:15:29 +02:00
|
|
|
/*
|
|
|
|
Don't send EOF if we're in error condition (which implies we've already
|
|
|
|
sent or are sending an error)
|
|
|
|
*/
|
|
|
|
if (thd->is_error())
|
|
|
|
return TRUE;
|
2008-02-19 13:58:08 +01:00
|
|
|
::my_eof(thd);
|
2007-12-12 16:21:01 +01:00
|
|
|
is_result_set_started= 0;
|
|
|
|
return FALSE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
/************************************************************************
|
|
|
|
Handling writing to file
|
|
|
|
************************************************************************/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
void select_to_file::send_error(uint errcode,const char *err)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
my_message(errcode, err, MYF(0));
|
2004-02-05 10:22:08 +01:00
|
|
|
if (file > 0)
|
|
|
|
{
|
|
|
|
(void) end_io_cache(&cache);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_close(file, MYF(0));
|
|
|
|
/* Delete file on error */
|
|
|
|
mysql_file_delete(key_select_to_file, path, MYF(0));
|
2004-02-05 10:22:08 +01:00
|
|
|
file= -1;
|
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
|
2004-08-24 18:17:11 +02:00
|
|
|
bool select_to_file::send_eof()
|
|
|
|
{
|
|
|
|
int error= test(end_io_cache(&cache));
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_close(file, MYF(MY_WME)))
|
2004-08-24 18:17:11 +02:00
|
|
|
error= 1;
|
|
|
|
if (!error)
|
2007-10-15 14:42:41 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
In order to remember the value of affected rows for ROW_COUNT()
|
|
|
|
function, SELECT INTO has to have an own SQLCOM.
|
|
|
|
TODO: split from SQLCOM_SELECT
|
|
|
|
*/
|
2008-02-19 13:45:21 +01:00
|
|
|
::my_ok(thd,row_count);
|
2007-10-15 14:42:41 +02:00
|
|
|
}
|
2004-08-24 18:17:11 +02:00
|
|
|
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);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_close(file, MYF(0));
|
2004-08-24 18:17:11 +02:00
|
|
|
file= -1;
|
|
|
|
}
|
|
|
|
path[0]= '\0';
|
|
|
|
row_count= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
select_to_file::~select_to_file()
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (file >= 0)
|
|
|
|
{ // This only happens in case of error
|
|
|
|
(void) end_io_cache(&cache);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_close(file, MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
file= -1;
|
|
|
|
}
|
2004-02-05 10:22:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
** Export of select to textfile
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
select_export::~select_export()
|
|
|
|
{
|
2000-09-16 03:27:21 +02:00
|
|
|
thd->sent_row_count=row_count;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
/*
|
|
|
|
Create file with IO cache
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
create_file()
|
|
|
|
thd Thread handle
|
|
|
|
path File name
|
|
|
|
exchange Excange class
|
|
|
|
cache IO cache
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
>= 0 File handle
|
|
|
|
-1 Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static File create_file(THD *thd, char *path, sql_exchange *exchange,
|
|
|
|
IO_CACHE *cache)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-02-05 10:22:08 +01:00
|
|
|
File file;
|
2007-02-14 14:44:34 +01:00
|
|
|
uint option= MY_UNPACK_FILENAME | MY_RELATIVE_PATH;
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
|
2004-02-05 10:22:08 +01:00
|
|
|
option|= MY_REPLACE_DIR; // Force use of db directory
|
2000-07-31 21:29:14 +02:00
|
|
|
#endif
|
2004-08-24 19:45:32 +02:00
|
|
|
|
2004-09-13 18:49:41 +02:00
|
|
|
if (!dirname_length(exchange->file_name))
|
2004-09-07 08:55:34 +02:00
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
strxnmov(path, FN_REFLEN-1, mysql_real_data_home, thd->db ? thd->db : "",
|
|
|
|
NullS);
|
2004-09-07 08:55:34 +02:00
|
|
|
(void) fn_format(path, exchange->file_name, path, "", option);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
(void) fn_format(path, exchange->file_name, mysql_real_data_home, "", option);
|
2007-02-14 14:44:34 +01:00
|
|
|
|
|
|
|
if (opt_secure_file_priv &&
|
|
|
|
strncmp(opt_secure_file_priv, path, strlen(opt_secure_file_priv)))
|
|
|
|
{
|
|
|
|
/* Write only allowed to dir or subdir specified by secure_file_priv */
|
|
|
|
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
if (!access(path, F_OK))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
|
2004-02-09 12:31:03 +01:00
|
|
|
return -1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
/* Create the file world readable */
|
2010-01-07 06:42:07 +01:00
|
|
|
if ((file= mysql_file_create(key_select_to_file,
|
|
|
|
path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
|
2004-02-05 10:22:08 +01:00
|
|
|
return file;
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifdef HAVE_FCHMOD
|
2004-02-05 10:22:08 +01:00
|
|
|
(void) fchmod(file, 0666); // Because of umask()
|
2000-07-31 21:29:14 +02:00
|
|
|
#else
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
(void) chmod(path, 0666);
|
2000-07-31 21:29:14 +02:00
|
|
|
#endif
|
2004-02-05 10:22:08 +01:00
|
|
|
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_close(file, MYF(0));
|
|
|
|
/* Delete file on error, it was just created */
|
|
|
|
mysql_file_delete(key_select_to_file, path, MYF(0));
|
2004-02-05 10:22:08 +01:00
|
|
|
return -1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-02-05 10:22:08 +01:00
|
|
|
return file;
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
|
|
|
{
|
|
|
|
bool blob_flag=0;
|
2007-10-23 13:16:59 +02:00
|
|
|
bool string_results= FALSE, non_string_results= FALSE;
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
unit= u;
|
|
|
|
if ((uint) strlen(exchange->file_name) + NAME_LEN >= FN_REFLEN)
|
|
|
|
strmake(path,exchange->file_name,FN_REFLEN-1);
|
|
|
|
|
2009-07-31 19:14:52 +02:00
|
|
|
write_cs= exchange->cs ? exchange->cs : &my_charset_bin;
|
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
if ((file= create_file(thd, path, exchange, &cache)) < 0)
|
Fixed Bug#2123, mysqld segmentation faulted when it tried to
open a file that already existed. The problem was that end_io_cache()
was called even if init_io_cache() was not. This affected both
OUTFILE and DUMPFILE (both fixed). Sometimes wrongly aligned pointer was freed,
sometimes mysqld core dumped.
Other problem was that select_dump::send_error removed the dumpfile,
even if it was created by an earlier run, or by some other program, if
the file permissions just permitted it. Fixed it so that the file will
only be deleted, if an error occurred, but the file was created by mysqld
just a moment ago, in that thread.
On the other hand, select_export did not handle the corresponding garbage
file at all. Both fixed.
After these fixes, a big part of the select_export::prepare and select_dump::prepare
code became identical. Merged the code into a new function called create_file(),
which is now called by the two latter functions.
Regards,
Jani
2004-01-15 05:48:31 +01:00
|
|
|
return 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Check if there is any blobs in data */
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(list);
|
2000-07-31 21:29:14 +02:00
|
|
|
Item *item;
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
if (item->max_length >= MAX_BLOB_WIDTH)
|
|
|
|
{
|
|
|
|
blob_flag=1;
|
|
|
|
break;
|
|
|
|
}
|
2007-10-23 13:16:59 +02:00
|
|
|
if (item->result_type() == STRING_RESULT)
|
|
|
|
string_results= TRUE;
|
|
|
|
else
|
|
|
|
non_string_results= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2009-07-31 19:14:52 +02:00
|
|
|
if (exchange->escaped->numchars() > 1 || exchange->enclosed->numchars() > 1)
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_FIELD_TERMINATORS, MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (exchange->escaped->length() > 1 || exchange->enclosed->length() > 1 ||
|
|
|
|
!my_isascii(exchange->escaped->ptr()[0]) ||
|
|
|
|
!my_isascii(exchange->enclosed->ptr()[0]) ||
|
|
|
|
!exchange->field_term->is_ascii() || !exchange->line_term->is_ascii() ||
|
|
|
|
!exchange->line_start->is_ascii())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Current LOAD DATA INFILE recognizes field/line separators "as is" without
|
|
|
|
converting from client charset to data file charset. So, it is supposed,
|
|
|
|
that input file of LOAD DATA INFILE consists of data in one charset and
|
|
|
|
separators in other charset. For the compatibility with that [buggy]
|
|
|
|
behaviour SELECT INTO OUTFILE implementation has been saved "as is" too,
|
|
|
|
but the new warning message has been added:
|
|
|
|
|
|
|
|
Non-ASCII separator arguments are not fully supported
|
|
|
|
*/
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED,
|
|
|
|
ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED));
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
field_term_length=exchange->field_term->length();
|
2007-11-20 17:15:20 +01:00
|
|
|
field_term_char= field_term_length ?
|
|
|
|
(int) (uchar) (*exchange->field_term)[0] : INT_MAX;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!exchange->line_term->length())
|
|
|
|
exchange->line_term=exchange->field_term; // Use this if it exists
|
2007-11-20 17:15:20 +01:00
|
|
|
field_sep_char= (exchange->enclosed->length() ?
|
|
|
|
(int) (uchar) (*exchange->enclosed)[0] : field_term_char);
|
2008-09-17 08:34:00 +02:00
|
|
|
if (exchange->escaped->length() && (exchange->escaped_given() ||
|
|
|
|
!(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)))
|
|
|
|
escape_char= (int) (uchar) (*exchange->escaped)[0];
|
|
|
|
else
|
|
|
|
escape_char= -1;
|
2007-07-03 18:05:17 +02:00
|
|
|
is_ambiguous_field_sep= test(strchr(ESCAPE_CHARS, field_sep_char));
|
2007-07-06 00:43:23 +02:00
|
|
|
is_unsafe_field_sep= test(strchr(NUMERIC_CHARS, field_sep_char));
|
2000-07-31 21:29:14 +02:00
|
|
|
line_sep_char= (exchange->line_term->length() ?
|
2007-11-20 17:15:20 +01:00
|
|
|
(int) (uchar) (*exchange->line_term)[0] : INT_MAX);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!field_term_length)
|
|
|
|
exchange->opt_enclosed=0;
|
|
|
|
if (!exchange->enclosed->length())
|
|
|
|
exchange->opt_enclosed=1; // A little quicker loop
|
|
|
|
fixed_row_size= (!field_term_length && !exchange->enclosed->length() &&
|
|
|
|
!blob_flag);
|
2007-10-23 13:16:59 +02:00
|
|
|
if ((is_ambiguous_field_sep && exchange->enclosed->is_empty() &&
|
|
|
|
(string_results || is_unsafe_field_sep)) ||
|
|
|
|
(exchange->opt_enclosed && non_string_results &&
|
|
|
|
field_term_length && strchr(NUMERIC_CHARS, field_term_char)))
|
|
|
|
{
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_AMBIGUOUS_FIELD_TERM, ER(ER_AMBIGUOUS_FIELD_TERM));
|
|
|
|
is_ambiguous_field_term= TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
is_ambiguous_field_term= FALSE;
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-07 10:16:49 +02:00
|
|
|
#define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \
|
2007-10-23 13:16:59 +02:00
|
|
|
(enclosed ? (int) (uchar) (x) == field_sep_char \
|
|
|
|
: (int) (uchar) (x) == field_term_char) || \
|
2007-06-07 10:16:49 +02:00
|
|
|
(int) (uchar) (x) == line_sep_char || \
|
|
|
|
!(x))
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
bool select_export::send_data(List<Item> &items)
|
|
|
|
{
|
|
|
|
|
2006-06-28 18:55:30 +02:00
|
|
|
DBUG_ENTER("select_export::send_data");
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
|
2009-07-31 19:14:52 +02:00
|
|
|
char cvt_buff[MAX_FIELD_WIDTH];
|
|
|
|
String cvt_str(cvt_buff, sizeof(cvt_buff), write_cs);
|
2000-07-31 21:29:14 +02:00
|
|
|
bool space_inited=0;
|
2003-01-29 14:31:20 +01:00
|
|
|
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
|
2000-07-31 21:29:14 +02:00
|
|
|
tmp.length(0);
|
|
|
|
|
2002-05-08 22:14:40 +02:00
|
|
|
if (unit->offset_limit_cnt)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // using limit offset,count
|
2002-05-08 22:14:40 +02:00
|
|
|
unit->offset_limit_cnt--;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
row_count++;
|
|
|
|
Item *item;
|
|
|
|
uint used_length=0,items_left=items.elements;
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(items);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) exchange->line_start->ptr(),
|
2000-07-31 21:29:14 +02:00
|
|
|
exchange->line_start->length()))
|
|
|
|
goto err;
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
Item_result result_type=item->result_type();
|
2007-10-23 13:16:59 +02:00
|
|
|
bool enclosed = (exchange->enclosed->length() &&
|
|
|
|
(!exchange->opt_enclosed || result_type == STRING_RESULT));
|
2000-07-31 21:29:14 +02:00
|
|
|
res=item->str_result(&tmp);
|
2009-07-31 19:14:52 +02:00
|
|
|
if (res && !my_charset_same(write_cs, res->charset()) &&
|
|
|
|
!my_charset_same(write_cs, &my_charset_bin))
|
|
|
|
{
|
|
|
|
const char *well_formed_error_pos;
|
|
|
|
const char *cannot_convert_error_pos;
|
|
|
|
const char *from_end_pos;
|
|
|
|
const char *error_pos;
|
|
|
|
uint32 bytes;
|
|
|
|
bytes= well_formed_copy_nchars(write_cs, cvt_buff, sizeof(cvt_buff),
|
|
|
|
res->charset(), res->ptr(), res->length(),
|
|
|
|
sizeof(cvt_buff),
|
|
|
|
&well_formed_error_pos,
|
|
|
|
&cannot_convert_error_pos,
|
|
|
|
&from_end_pos);
|
|
|
|
error_pos= well_formed_error_pos ? well_formed_error_pos
|
|
|
|
: cannot_convert_error_pos;
|
|
|
|
if (error_pos)
|
|
|
|
{
|
|
|
|
char printable_buff[32];
|
|
|
|
convert_to_printable(printable_buff, sizeof(printable_buff),
|
|
|
|
error_pos, res->ptr() + res->length() - error_pos,
|
|
|
|
res->charset(), 6);
|
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
|
|
|
|
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
|
|
|
|
"string", printable_buff,
|
|
|
|
item->name, row_count);
|
|
|
|
}
|
|
|
|
cvt_str.length(bytes);
|
|
|
|
res= &cvt_str;
|
|
|
|
}
|
2007-10-23 13:16:59 +02:00
|
|
|
if (res && enclosed)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) exchange->enclosed->ptr(),
|
2000-07-31 21:29:14 +02:00
|
|
|
exchange->enclosed->length()))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (!res)
|
|
|
|
{ // NULL
|
|
|
|
if (!fixed_row_size)
|
|
|
|
{
|
|
|
|
if (escape_char != -1) // Use \N syntax
|
|
|
|
{
|
|
|
|
null_buff[0]=escape_char;
|
|
|
|
null_buff[1]='N';
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) null_buff,2))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
else if (my_b_write(&cache,(uchar*) "NULL",4))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
used_length=0; // Fill with space
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fixed_row_size)
|
|
|
|
used_length=min(res->length(),item->max_length);
|
|
|
|
else
|
|
|
|
used_length=res->length();
|
2007-07-06 00:43:23 +02:00
|
|
|
if ((result_type == STRING_RESULT || is_unsafe_field_sep) &&
|
|
|
|
escape_char != -1)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-06-07 10:16:49 +02:00
|
|
|
char *pos, *start, *end;
|
|
|
|
CHARSET_INFO *res_charset= res->charset();
|
|
|
|
CHARSET_INFO *character_set_client= thd->variables.
|
|
|
|
character_set_client;
|
|
|
|
bool check_second_byte= (res_charset == &my_charset_bin) &&
|
|
|
|
character_set_client->
|
|
|
|
escape_with_backslash_is_dangerous;
|
|
|
|
DBUG_ASSERT(character_set_client->mbmaxlen == 2 ||
|
|
|
|
!character_set_client->escape_with_backslash_is_dangerous);
|
2000-07-31 21:29:14 +02:00
|
|
|
for (start=pos=(char*) res->ptr(),end=pos+used_length ;
|
|
|
|
pos != end ;
|
|
|
|
pos++)
|
|
|
|
{
|
|
|
|
#ifdef USE_MB
|
2002-12-20 14:57:24 +01:00
|
|
|
if (use_mb(res_charset))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
int l;
|
2002-12-20 14:57:24 +01:00
|
|
|
if ((l=my_ismbchar(res_charset, pos, end)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
pos += l-1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2007-06-07 10:16:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Special case when dumping BINARY/VARBINARY/BLOB values
|
|
|
|
for the clients with character sets big5, cp932, gbk and sjis,
|
|
|
|
which can have the escape character (0x5C "\" by default)
|
|
|
|
as the second byte of a multi-byte sequence.
|
|
|
|
|
|
|
|
If
|
|
|
|
- pos[0] is a valid multi-byte head (e.g 0xEE) and
|
|
|
|
- pos[1] is 0x00, which will be escaped as "\0",
|
|
|
|
|
|
|
|
then we'll get "0xEE + 0x5C + 0x30" in the output file.
|
|
|
|
|
|
|
|
If this file is later loaded using this sequence of commands:
|
|
|
|
|
|
|
|
mysql> create table t1 (a varchar(128)) character set big5;
|
|
|
|
mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1;
|
|
|
|
|
|
|
|
then 0x5C will be misinterpreted as the second byte
|
|
|
|
of a multi-byte character "0xEE + 0x5C", instead of
|
|
|
|
escape character for 0x00.
|
|
|
|
|
|
|
|
To avoid this confusion, we'll escape the multi-byte
|
|
|
|
head character too, so the sequence "0xEE + 0x00" will be
|
|
|
|
dumped as "0x5C + 0xEE + 0x5C + 0x30".
|
|
|
|
|
|
|
|
Note, in the condition below we only check if
|
|
|
|
mbcharlen is equal to 2, because there are no
|
|
|
|
character sets with mbmaxlen longer than 2
|
|
|
|
and with escape_with_backslash_is_dangerous set.
|
|
|
|
DBUG_ASSERT before the loop makes that sure.
|
|
|
|
*/
|
|
|
|
|
2007-10-23 13:16:59 +02:00
|
|
|
if ((NEED_ESCAPING(*pos) ||
|
|
|
|
(check_second_byte &&
|
|
|
|
my_mbcharlen(character_set_client, (uchar) *pos) == 2 &&
|
|
|
|
pos + 1 < end &&
|
|
|
|
NEED_ESCAPING(pos[1]))) &&
|
|
|
|
/*
|
|
|
|
Don't escape field_term_char by doubling - doubling is only
|
|
|
|
valid for ENCLOSED BY characters:
|
|
|
|
*/
|
2007-11-20 17:15:20 +01:00
|
|
|
(enclosed || !is_ambiguous_field_term ||
|
|
|
|
(int) (uchar) *pos != field_term_char))
|
2007-06-07 10:16:49 +02:00
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
char tmp_buff[2];
|
2007-11-20 17:15:20 +01:00
|
|
|
tmp_buff[0]= ((int) (uchar) *pos == field_sep_char &&
|
Fixed bug #29294.
The `SELECT 'r' INTO OUTFILE ... FIELDS ENCLOSED BY 'r' ' statement
encoded the 'r' string to a 4 byte string of value x'725c7272'
(sequence of 4 characters: r\rr).
The LOAD DATA statement decoded this string to a 1 byte string of
value x'0d' (ASCII Carriage Return character) instead of the original
'r' character.
The same error also happened with the FIELDS ENCLOSED BY clause
followed by special characters: 'n', 't', 'r', 'b', '0', 'Z' and 'N'.
NOTE 1: This is a result of the undocumented feature: the LOAD DATA INFILE
recognises 2-byte input sequences like \n, \t, \r and \Z in addition
to documented 2-byte sequences: \0 and \N. This feature should be
documented (here backspace character is a default ESCAPED BY character,
in the real-life example it may be any ESCAPED BY character).
NOTE 2, changed behaviour:
Now the `SELECT INTO OUTFILE' statement with the `FIELDS ENCLOSED BY'
clause followed by one of: 'n', 't', 'r', 'b', '0', 'Z' or 'N' characters
encodes this special character itself by doubling it ('r' --> 'rr'),
not by prepending it with an escape character.
2007-07-03 16:37:46 +02:00
|
|
|
is_ambiguous_field_sep) ?
|
|
|
|
field_sep_char : escape_char;
|
2000-07-31 21:29:14 +02:00
|
|
|
tmp_buff[1]= *pos ? *pos : '0';
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)) ||
|
|
|
|
my_b_write(&cache,(uchar*) tmp_buff,2))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
start=pos+1;
|
|
|
|
}
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) start,(uint) (pos-start)))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
else if (my_b_write(&cache,(uchar*) res->ptr(),used_length))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (fixed_row_size)
|
|
|
|
{ // Fill with space
|
|
|
|
if (item->max_length > used_length)
|
|
|
|
{
|
|
|
|
/* QQ: Fix by adding a my_b_fill() function */
|
|
|
|
if (!space_inited)
|
|
|
|
{
|
|
|
|
space_inited=1;
|
|
|
|
bfill(space,sizeof(space),' ');
|
|
|
|
}
|
|
|
|
uint length=item->max_length-used_length;
|
2002-06-11 10:20:31 +02:00
|
|
|
for (; length > sizeof(space) ; length-=sizeof(space))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) space,sizeof(space)))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) space,length))
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2007-10-23 13:16:59 +02:00
|
|
|
if (res && enclosed)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache, (uchar*) exchange->enclosed->ptr(),
|
2007-03-20 19:09:28 +01:00
|
|
|
exchange->enclosed->length()))
|
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
if (--items_left)
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache, (uchar*) exchange->field_term->ptr(),
|
2007-03-20 19:09:28 +01:00
|
|
|
field_term_length))
|
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) exchange->line_term->ptr(),
|
2000-07-31 21:29:14 +02:00
|
|
|
exchange->line_term->length()))
|
|
|
|
goto err;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
** Dump of select to a binary file
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2002-05-08 22:14:40 +02:00
|
|
|
select_dump::prepare(List<Item> &list __attribute__((unused)),
|
|
|
|
SELECT_LEX_UNIT *u)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-05-08 22:14:40 +02:00
|
|
|
unit= u;
|
2004-02-05 10:22:08 +01:00
|
|
|
return (int) ((file= create_file(thd, path, exchange, &cache)) < 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool select_dump::send_data(List<Item> &items)
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
List_iterator_fast<Item> li(items);
|
2000-07-31 21:29:14 +02:00
|
|
|
char buff[MAX_FIELD_WIDTH];
|
2003-01-29 14:31:20 +01:00
|
|
|
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
|
2000-07-31 21:29:14 +02:00
|
|
|
tmp.length(0);
|
|
|
|
Item *item;
|
2006-06-28 18:55:30 +02:00
|
|
|
DBUG_ENTER("select_dump::send_data");
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2002-05-08 22:14:40 +02:00
|
|
|
if (unit->offset_limit_cnt)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // using limit offset,count
|
2002-05-08 22:14:40 +02:00
|
|
|
unit->offset_limit_cnt--;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
if (row_count++ > 1)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
while ((item=li++))
|
|
|
|
{
|
|
|
|
res=item->str_result(&tmp);
|
2000-09-28 23:58:16 +02:00
|
|
|
if (!res) // If NULL
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_b_write(&cache,(uchar*) "",1))
|
2000-09-28 23:58:16 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
else if (my_b_write(&cache,(uchar*) res->ptr(),res->length()))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno);
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
err:
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-28 11:18:13 +01:00
|
|
|
select_subselect::select_subselect(Item_subselect *item_arg)
|
2002-05-12 22:46:42 +02:00
|
|
|
{
|
2003-11-28 11:18:13 +01:00
|
|
|
item= item_arg;
|
2002-05-12 22:46:42 +02:00
|
|
|
}
|
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
|
2002-12-19 20:15:09 +01:00
|
|
|
bool select_singlerow_subselect::send_data(List<Item> &items)
|
2002-05-12 22:46:42 +02:00
|
|
|
{
|
2002-12-19 20:15:09 +01:00
|
|
|
DBUG_ENTER("select_singlerow_subselect::send_data");
|
|
|
|
Item_singlerow_subselect *it= (Item_singlerow_subselect *)item;
|
2002-11-18 21:41:57 +01:00
|
|
|
if (it->assigned())
|
|
|
|
{
|
2004-01-02 23:12:07 +01:00
|
|
|
my_message(ER_SUBQUERY_NO_1_ROW, ER(ER_SUBQUERY_NO_1_ROW), MYF(0));
|
2002-05-28 21:38:17 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
|
|
|
if (unit->offset_limit_cnt)
|
2002-06-01 22:35:36 +02:00
|
|
|
{ // Using limit offset,count
|
2002-05-28 21:38:17 +02:00
|
|
|
unit->offset_limit_cnt--;
|
|
|
|
DBUG_RETURN(0);
|
2002-05-12 22:46:42 +02:00
|
|
|
}
|
2002-06-01 22:35:36 +02:00
|
|
|
List_iterator_fast<Item> li(items);
|
2002-12-19 06:38:33 +01:00
|
|
|
Item *val_item;
|
|
|
|
for (uint i= 0; (val_item= li++); i++)
|
|
|
|
it->store(i, val_item);
|
2002-09-03 08:50:36 +02:00
|
|
|
it->assigned(1);
|
2002-05-28 21:38:17 +02:00
|
|
|
DBUG_RETURN(0);
|
2002-05-12 22:46:42 +02:00
|
|
|
}
|
2002-06-19 16:52:44 +02:00
|
|
|
|
2004-02-05 10:22:08 +01:00
|
|
|
|
2005-01-26 14:27:45 +01:00
|
|
|
void select_max_min_finder_subselect::cleanup()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("select_max_min_finder_subselect::cleanup");
|
|
|
|
cache= 0;
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-12 11:38:03 +02:00
|
|
|
bool select_max_min_finder_subselect::send_data(List<Item> &items)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("select_max_min_finder_subselect::send_data");
|
2004-11-18 17:10:07 +01:00
|
|
|
Item_maxmin_subselect *it= (Item_maxmin_subselect *)item;
|
2003-08-12 11:38:03 +02:00
|
|
|
List_iterator_fast<Item> li(items);
|
|
|
|
Item *val_item= li++;
|
2004-11-18 17:10:07 +01:00
|
|
|
it->register_value();
|
2003-08-12 11:38:03 +02:00
|
|
|
if (it->assigned())
|
|
|
|
{
|
|
|
|
cache->store(val_item);
|
|
|
|
if ((this->*op)())
|
|
|
|
it->store(0, cache);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!cache)
|
|
|
|
{
|
2007-11-10 20:44:48 +01:00
|
|
|
cache= Item_cache::get_cache(val_item);
|
2003-08-12 11:38:03 +02:00
|
|
|
switch (val_item->result_type())
|
|
|
|
{
|
|
|
|
case REAL_RESULT:
|
|
|
|
op= &select_max_min_finder_subselect::cmp_real;
|
|
|
|
break;
|
|
|
|
case INT_RESULT:
|
|
|
|
op= &select_max_min_finder_subselect::cmp_int;
|
|
|
|
break;
|
|
|
|
case STRING_RESULT:
|
|
|
|
op= &select_max_min_finder_subselect::cmp_str;
|
|
|
|
break;
|
2005-02-08 23:50:45 +01:00
|
|
|
case DECIMAL_RESULT:
|
|
|
|
op= &select_max_min_finder_subselect::cmp_decimal;
|
|
|
|
break;
|
2003-08-12 11:38:03 +02:00
|
|
|
case ROW_RESULT:
|
|
|
|
// This case should never be choosen
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
op= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cache->store(val_item);
|
|
|
|
it->store(0, cache);
|
|
|
|
}
|
|
|
|
it->assigned(1);
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool select_max_min_finder_subselect::cmp_real()
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
|
2004-11-11 19:39:35 +01:00
|
|
|
double val1= cache->val_real(), val2= maxmin->val_real();
|
2003-08-12 11:38:03 +02:00
|
|
|
if (fmax)
|
|
|
|
return (cache->null_value && !maxmin->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
val1 > val2);
|
2005-02-19 17:58:27 +01:00
|
|
|
return (maxmin->null_value && !cache->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
val1 < val2);
|
2003-08-12 11:38:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool select_max_min_finder_subselect::cmp_int()
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
|
2003-08-12 11:38:03 +02:00
|
|
|
longlong val1= cache->val_int(), val2= maxmin->val_int();
|
|
|
|
if (fmax)
|
|
|
|
return (cache->null_value && !maxmin->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
val1 > val2);
|
2005-02-19 17:58:27 +01:00
|
|
|
return (maxmin->null_value && !cache->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
val1 < val2);
|
2003-08-12 11:38:03 +02:00
|
|
|
}
|
|
|
|
|
2005-02-08 23:50:45 +01:00
|
|
|
bool select_max_min_finder_subselect::cmp_decimal()
|
|
|
|
{
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
|
2005-02-08 23:50:45 +01:00
|
|
|
my_decimal cval, *cvalue= cache->val_decimal(&cval);
|
|
|
|
my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
|
|
|
|
if (fmax)
|
|
|
|
return (cache->null_value && !maxmin->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
my_decimal_cmp(cvalue, mvalue) > 0) ;
|
2005-02-19 17:58:27 +01:00
|
|
|
return (maxmin->null_value && !cache->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
my_decimal_cmp(cvalue,mvalue) < 0);
|
2005-02-08 23:50:45 +01:00
|
|
|
}
|
|
|
|
|
2003-08-12 11:38:03 +02:00
|
|
|
bool select_max_min_finder_subselect::cmp_str()
|
|
|
|
{
|
|
|
|
String *val1, *val2, buf1, buf2;
|
2006-12-14 23:51:37 +01:00
|
|
|
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
|
2003-08-12 11:38:03 +02:00
|
|
|
/*
|
|
|
|
as far as both operand is Item_cache buf1 & buf2 will not be used,
|
|
|
|
but added for safety
|
|
|
|
*/
|
|
|
|
val1= cache->val_str(&buf1);
|
|
|
|
val2= maxmin->val_str(&buf1);
|
|
|
|
if (fmax)
|
|
|
|
return (cache->null_value && !maxmin->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
sortcmp(val1, val2, cache->collation.collation) > 0) ;
|
2005-02-19 17:58:27 +01:00
|
|
|
return (maxmin->null_value && !cache->null_value) ||
|
|
|
|
(!cache->null_value && !maxmin->null_value &&
|
|
|
|
sortcmp(val1, val2, cache->collation.collation) < 0);
|
2003-08-12 11:38:03 +02:00
|
|
|
}
|
|
|
|
|
2002-06-19 16:52:44 +02:00
|
|
|
bool select_exists_subselect::send_data(List<Item> &items)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("select_exists_subselect::send_data");
|
|
|
|
Item_exists_subselect *it= (Item_exists_subselect *)item;
|
|
|
|
if (unit->offset_limit_cnt)
|
|
|
|
{ // Using limit offset,count
|
|
|
|
unit->offset_limit_cnt--;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
it->value= 1;
|
2002-09-03 08:50:36 +02:00
|
|
|
it->assigned(1);
|
2002-06-19 16:52:44 +02:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2002-10-11 20:49:10 +02:00
|
|
|
|
|
|
|
/***************************************************************************
|
2004-02-05 10:22:08 +01:00
|
|
|
Dump of select to variables
|
2002-10-11 20:49:10 +02:00
|
|
|
***************************************************************************/
|
2004-02-05 10:22:08 +01:00
|
|
|
|
2002-10-16 15:55:08 +02:00
|
|
|
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
2002-10-11 20:49:10 +02:00
|
|
|
{
|
2003-10-01 16:15:24 +02:00
|
|
|
unit= u;
|
2006-11-28 23:21:39 +01:00
|
|
|
|
2002-10-16 15:55:08 +02:00
|
|
|
if (var_list.elements != list.elements)
|
2002-10-11 20:49:10 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
|
|
|
|
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
|
2002-10-16 15:55:08 +02:00
|
|
|
return 1;
|
2006-11-29 18:15:15 +01:00
|
|
|
}
|
2002-10-16 15:55:08 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2003-03-06 19:16:46 +01:00
|
|
|
|
2003-10-01 16:15:24 +02:00
|
|
|
|
2006-12-01 11:25:06 +01:00
|
|
|
bool select_dumpvar::check_simple_select() const
|
|
|
|
{
|
|
|
|
my_error(ER_SP_BAD_CURSOR_SELECT, MYF(0));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-24 18:17:11 +02:00
|
|
|
void select_dumpvar::cleanup()
|
|
|
|
{
|
2006-11-28 23:21:39 +01:00
|
|
|
row_count= 0;
|
2004-08-24 18:17:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-15 19:58:35 +02:00
|
|
|
Query_arena::Type Query_arena::type() const
|
2004-08-21 00:02:46 +02:00
|
|
|
{
|
2004-09-06 14:14:10 +02:00
|
|
|
DBUG_ASSERT(0); /* Should never be called */
|
2004-08-21 00:02:46 +02:00
|
|
|
return STATEMENT;
|
2004-05-20 01:02:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-23 18:22:08 +02:00
|
|
|
void Query_arena::free_items()
|
|
|
|
{
|
|
|
|
Item *next;
|
|
|
|
DBUG_ENTER("Query_arena::free_items");
|
|
|
|
/* This works because items are allocated with sql_alloc() */
|
|
|
|
for (; free_list; free_list= next)
|
|
|
|
{
|
|
|
|
next= free_list->next;
|
|
|
|
free_list->delete_self();
|
|
|
|
}
|
|
|
|
/* Postcondition: free_list is 0 */
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-22 00:11:21 +02:00
|
|
|
void Query_arena::set_query_arena(Query_arena *set)
|
|
|
|
{
|
|
|
|
mem_root= set->mem_root;
|
|
|
|
free_list= set->free_list;
|
|
|
|
state= set->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Query_arena::cleanup_stmt()
|
|
|
|
{
|
2009-03-19 21:20:15 +01:00
|
|
|
DBUG_ASSERT(! "Query_arena::cleanup_stmt() not implemented");
|
2005-09-22 00:11:21 +02:00
|
|
|
}
|
|
|
|
|
2003-12-20 00:16:10 +01:00
|
|
|
/*
|
2007-04-13 19:23:02 +02:00
|
|
|
Statement functions
|
2003-12-20 00:16:10 +01:00
|
|
|
*/
|
|
|
|
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
|
|
|
|
enum enum_state state_arg, ulong id_arg)
|
|
|
|
:Query_arena(mem_root_arg, state_arg),
|
2005-06-22 21:12:25 +02:00
|
|
|
id(id_arg),
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
mark_used_columns(MARK_COLUMNS_READ),
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
lex(lex_arg),
|
2007-08-31 18:42:14 +02:00
|
|
|
cursor(0),
|
|
|
|
db(NULL),
|
|
|
|
db_length(0)
|
2003-12-20 00:16:10 +01:00
|
|
|
{
|
2009-10-16 12:29:42 +02:00
|
|
|
query_string.length= 0;
|
|
|
|
query_string.str= NULL;
|
2004-04-12 23:58:48 +02:00
|
|
|
name.str= NULL;
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-06-15 19:58:35 +02:00
|
|
|
Query_arena::Type Statement::type() const
|
2003-12-20 00:16:10 +01:00
|
|
|
{
|
|
|
|
return STATEMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Statement::set_statement(Statement *stmt)
|
|
|
|
{
|
|
|
|
id= stmt->id;
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
mark_used_columns= stmt->mark_used_columns;
|
2003-12-20 00:16:10 +01:00
|
|
|
lex= stmt->lex;
|
2009-10-16 12:29:42 +02:00
|
|
|
query_string= stmt->query_string;
|
2004-08-03 12:32:21 +02:00
|
|
|
cursor= stmt->cursor;
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-21 00:02:46 +02:00
|
|
|
void
|
|
|
|
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
|
|
|
|
{
|
2005-07-01 06:05:42 +02:00
|
|
|
DBUG_ENTER("Statement::set_n_backup_statement");
|
2004-08-21 00:02:46 +02:00
|
|
|
backup->set_statement(this);
|
|
|
|
set_statement(stmt);
|
2005-07-01 06:05:42 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2004-08-21 00:02:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
|
|
|
|
{
|
2005-07-01 06:05:42 +02:00
|
|
|
DBUG_ENTER("Statement::restore_backup_statement");
|
2004-08-21 00:02:46 +02:00
|
|
|
stmt->set_statement(this);
|
|
|
|
set_statement(backup);
|
2005-07-01 06:05:42 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2004-08-21 00:02:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-16 12:29:42 +02:00
|
|
|
/** Assign a new value to thd->query. */
|
|
|
|
|
|
|
|
void Statement::set_query_inner(char *query_arg, uint32 query_length_arg)
|
|
|
|
{
|
|
|
|
query_string.str= query_arg;
|
|
|
|
query_string.length= query_length_arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-14 00:53:59 +02:00
|
|
|
void THD::end_statement()
|
2004-08-24 18:17:11 +02:00
|
|
|
{
|
A fix for Bug#26750 "valgrind leak in sp_head" (and post-review
fixes).
The legend: on a replication slave, in case a trigger creation
was filtered out because of application of replicate-do-table/
replicate-ignore-table rule, the parsed definition of a trigger was not
cleaned up properly. LEX::sphead member was left around and leaked
memory. Until the actual implementation of support of
replicate-ignore-table rules for triggers by the patch for Bug 24478 it
was never the case that "case SQLCOM_CREATE_TRIGGER"
was not executed once a trigger was parsed,
so the deletion of lex->sphead there worked and the memory did not leak.
The fix:
The real cause of the bug is that there is no 1 or 2 places where
we can clean up the main LEX after parse. And the reason we
can not have just one or two places where we clean up the LEX is
asymmetric behaviour of MYSQLparse in case of success or error.
One of the root causes of this behaviour is the code in Item::Item()
constructor. There, a newly created item adds itself to THD::free_list
- a single-linked list of Items used in a statement. Yuck. This code
is unaware that we may have more than one statement active at a time,
and always assumes that the free_list of the current statement is
located in THD::free_list. One day we need to be able to explicitly
allocate an item in a given Query_arena.
Thus, when parsing a definition of a stored procedure, like
CREATE PROCEDURE p1() BEGIN SELECT a FROM t1; SELECT b FROM t1; END;
we actually need to reset THD::mem_root, THD::free_list and THD::lex
to parse the nested procedure statement (SELECT *).
The actual reset and restore is implemented in semantic actions
attached to sp_proc_stmt grammar rule.
The problem is that in case of a parsing error inside a nested statement
Bison generated parser would abort immediately, without executing the
restore part of the semantic action. This would leave THD in an
in-the-middle-of-parsing state.
This is why we couldn't have had a single place where we clean up the LEX
after MYSQLparse - in case of an error we needed to do a clean up
immediately, in case of success a clean up could have been delayed.
This left the door open for a memory leak.
One of the following possibilities were considered when working on a fix:
- patch the replication logic to do the clean up. Rejected
as breaks module borders, replication code should not need to know the
gory details of clean up procedure after CREATE TRIGGER.
- wrap MYSQLparse with a function that would do a clean up.
Rejected as ideally we should fix the problem when it happens, not
adjust for it outside of the problematic code.
- make sure MYSQLparse cleans up after itself by invoking the clean up
functionality in the appropriate places before return. Implemented in
this patch.
- use %destructor rule for sp_proc_stmt to restore THD - cleaner
than the prevoius approach, but rejected
because needs a careful analysis of the side effects, and this patch is
for 5.0, and long term we need to use the next alternative anyway
- make sure that sp_proc_stmt doesn't juggle with THD - this is a
large work that will affect many modules.
Cleanup: move main_lex and main_mem_root from Statement to its
only two descendants Prepared_statement and THD. This ensures that
when a Statement instance was created for purposes of statement backup,
we do not involve LEX constructor/destructor, which is fairly expensive.
In order to track that the transformation produces equivalent
functionality please check the respective constructors and destructors
of Statement, Prepared_statement and THD - these members were
used only there.
This cleanup is unrelated to the patch.
2007-03-07 10:24:46 +01:00
|
|
|
/* Cleanup SQL processing state to reuse this statement in next query. */
|
2004-08-24 18:17:11 +02:00
|
|
|
lex_end(lex);
|
|
|
|
delete lex->result;
|
|
|
|
lex->result= 0;
|
2004-09-15 21:10:31 +02:00
|
|
|
/* Note that free_list is freed in cleanup_after_query() */
|
|
|
|
|
2004-08-24 18:17:11 +02:00
|
|
|
/*
|
|
|
|
Don't free mem_root, as mem_root is freed in the end of dispatch_command
|
|
|
|
(once for any command).
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 15:21:19 +02:00
|
|
|
void THD::set_n_backup_active_arena(Query_arena *set, Query_arena *backup)
|
2004-02-08 19:14:13 +01:00
|
|
|
{
|
2005-09-02 15:21:19 +02:00
|
|
|
DBUG_ENTER("THD::set_n_backup_active_arena");
|
2005-06-23 18:22:08 +02:00
|
|
|
DBUG_ASSERT(backup->is_backup_arena == FALSE);
|
2005-07-01 06:05:42 +02:00
|
|
|
|
2005-09-02 15:21:19 +02:00
|
|
|
backup->set_query_arena(this);
|
|
|
|
set_query_arena(set);
|
2004-11-03 11:39:38 +01:00
|
|
|
#ifndef DBUG_OFF
|
2005-06-23 18:22:08 +02:00
|
|
|
backup->is_backup_arena= TRUE;
|
2004-11-03 11:39:38 +01:00
|
|
|
#endif
|
2004-09-09 05:59:26 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2004-02-08 19:14:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-02 15:21:19 +02:00
|
|
|
void THD::restore_active_arena(Query_arena *set, Query_arena *backup)
|
2004-02-12 02:10:26 +01:00
|
|
|
{
|
2005-09-02 15:21:19 +02:00
|
|
|
DBUG_ENTER("THD::restore_active_arena");
|
2005-06-23 18:22:08 +02:00
|
|
|
DBUG_ASSERT(backup->is_backup_arena);
|
2005-09-02 15:21:19 +02:00
|
|
|
set->set_query_arena(this);
|
|
|
|
set_query_arena(backup);
|
2004-11-03 11:39:38 +01:00
|
|
|
#ifndef DBUG_OFF
|
2005-06-23 18:22:08 +02:00
|
|
|
backup->is_backup_arena= FALSE;
|
2004-09-23 11:48:17 +02:00
|
|
|
#endif
|
2004-11-03 11:39:38 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2004-02-12 02:10:26 +01:00
|
|
|
}
|
|
|
|
|
2003-12-20 00:16:10 +01:00
|
|
|
Statement::~Statement()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
C_MODE_START
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar *
|
|
|
|
get_statement_id_as_hash_key(const uchar *record, size_t *key_length,
|
2003-12-20 00:16:10 +01:00
|
|
|
my_bool not_used __attribute__((unused)))
|
|
|
|
{
|
|
|
|
const Statement *statement= (const Statement *) record;
|
|
|
|
*key_length= sizeof(statement->id);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
return (uchar *) &((const Statement *) statement)->id;
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void delete_statement_as_hash_key(void *key)
|
|
|
|
{
|
|
|
|
delete (Statement *) key;
|
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
static uchar *get_stmt_name_hash_key(Statement *entry, size_t *length,
|
2004-04-30 18:08:38 +02:00
|
|
|
my_bool not_used __attribute__((unused)))
|
2004-04-12 23:58:48 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
*length= entry->name.length;
|
|
|
|
return (uchar*) entry->name.str;
|
2004-04-12 23:58:48 +02:00
|
|
|
}
|
|
|
|
|
2003-12-20 00:16:10 +01:00
|
|
|
C_MODE_END
|
|
|
|
|
|
|
|
Statement_map::Statement_map() :
|
|
|
|
last_found_statement(0)
|
|
|
|
{
|
2004-04-12 23:58:48 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
START_STMT_HASH_SIZE = 16,
|
|
|
|
START_NAME_HASH_SIZE = 16
|
|
|
|
};
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_init(&st_hash, &my_charset_bin, START_STMT_HASH_SIZE, 0, 0,
|
|
|
|
get_statement_id_as_hash_key,
|
|
|
|
delete_statement_as_hash_key, MYF(0));
|
|
|
|
my_hash_init(&names_hash, system_charset_info, START_NAME_HASH_SIZE, 0, 0,
|
|
|
|
(my_hash_get_key) get_stmt_name_hash_key,
|
|
|
|
NULL,MYF(0));
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
Implement WL#2661 "Prepared Statements: Dynamic SQL in Stored Procedures".
The idea of the patch is to separate statement processing logic,
such as parsing, validation of the parsed tree, execution and cleanup,
from global query processing logic, such as logging, resetting
priorities of a thread, resetting stored procedure cache, resetting
thread count of errors and warnings.
This makes PREPARE and EXECUTE behave similarly to the rest of SQL
statements and allows their use in stored procedures.
This patch contains a change in behaviour:
until recently for each SQL prepared statement command, 2 queries
were written to the general log, e.g.
[Query] prepare stmt from @stmt_text;
[Prepare] select * from t1 <-- contents of @stmt_text
The chagne was necessary to prevent [Prepare] commands from being written
to the general log when executing a stored procedure with Dynamic SQL.
We should consider whether the old behavior is preferrable and probably
restore it.
This patch refixes Bug#7115, Bug#10975 (partially), Bug#10605 (various bugs
in Dynamic SQL reported before it was disabled).
2005-09-03 01:13:18 +02:00
|
|
|
|
2006-04-07 21:37:06 +02:00
|
|
|
/*
|
|
|
|
Insert a new statement to the thread-local statement map.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
If there was an old statement with the same name, replace it with the
|
|
|
|
new one. Otherwise, check if max_prepared_stmt_count is not reached yet,
|
|
|
|
increase prepared_stmt_count, and insert the new statement. It's okay
|
|
|
|
to delete an old statement and fail to insert the new one.
|
|
|
|
|
|
|
|
POSTCONDITIONS
|
|
|
|
All named prepared statements are also present in names_hash.
|
|
|
|
Statement names in names_hash are unique.
|
|
|
|
The statement is added only if prepared_stmt_count < max_prepard_stmt_count
|
|
|
|
last_found_statement always points to a valid statement or is 0
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
0 success
|
|
|
|
1 error: out of resources or max_prepared_stmt_count limit has been
|
|
|
|
reached. An error is sent to the client, the statement is deleted.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int Statement_map::insert(THD *thd, Statement *statement)
|
2004-04-12 23:58:48 +02:00
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (my_hash_insert(&st_hash, (uchar*) statement))
|
2004-04-12 23:58:48 +02:00
|
|
|
{
|
2006-04-07 21:37:06 +02:00
|
|
|
/*
|
|
|
|
Delete is needed only in case of an insert failure. In all other
|
|
|
|
cases hash_delete will also delete the statement.
|
|
|
|
*/
|
|
|
|
delete statement;
|
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
goto err_st_hash;
|
|
|
|
}
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
if (statement->name.str && my_hash_insert(&names_hash, (uchar*) statement))
|
2004-04-12 23:58:48 +02:00
|
|
|
{
|
2006-04-12 23:46:44 +02:00
|
|
|
my_error(ER_OUT_OF_RESOURCES, MYF(0));
|
|
|
|
goto err_names_hash;
|
2004-04-12 23:58:48 +02:00
|
|
|
}
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
/*
|
|
|
|
We don't check that prepared_stmt_count is <= max_prepared_stmt_count
|
|
|
|
because we would like to allow to lower the total limit
|
|
|
|
of prepared statements below the current count. In that case
|
|
|
|
no new statements can be added until prepared_stmt_count drops below
|
|
|
|
the limit.
|
|
|
|
*/
|
|
|
|
if (prepared_stmt_count >= max_prepared_stmt_count)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
|
2006-04-12 23:46:44 +02:00
|
|
|
my_error(ER_MAX_PREPARED_STMT_COUNT_REACHED, MYF(0),
|
|
|
|
max_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
goto err_max;
|
|
|
|
}
|
|
|
|
prepared_stmt_count++;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
|
2005-10-06 16:54:43 +02:00
|
|
|
last_found_statement= statement;
|
2006-04-07 21:37:06 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_max:
|
|
|
|
if (statement->name.str)
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&names_hash, (uchar*) statement);
|
2006-04-07 21:37:06 +02:00
|
|
|
err_names_hash:
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&st_hash, (uchar*) statement);
|
2006-04-07 21:37:06 +02:00
|
|
|
err_st_hash:
|
|
|
|
return 1;
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
2004-04-12 23:58:48 +02:00
|
|
|
|
2005-07-19 20:21:12 +02:00
|
|
|
void Statement_map::close_transient_cursors()
|
|
|
|
{
|
2005-09-22 00:11:21 +02:00
|
|
|
#ifdef TO_BE_IMPLEMENTED
|
2005-07-19 20:21:12 +02:00
|
|
|
Statement *stmt;
|
|
|
|
while ((stmt= transient_cursor_list.head()))
|
|
|
|
stmt->close_cursor(); /* deletes itself from the list */
|
2005-09-22 00:11:21 +02:00
|
|
|
#endif
|
2005-07-19 20:21:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-07 21:37:06 +02:00
|
|
|
void Statement_map::erase(Statement *statement)
|
|
|
|
{
|
|
|
|
if (statement == last_found_statement)
|
|
|
|
last_found_statement= 0;
|
|
|
|
if (statement->name.str)
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&names_hash, (uchar *) statement);
|
2006-04-12 23:46:44 +02:00
|
|
|
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&st_hash, (uchar *) statement);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
DBUG_ASSERT(prepared_stmt_count > 0);
|
|
|
|
prepared_stmt_count--;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Statement_map::reset()
|
|
|
|
{
|
|
|
|
/* Must be first, hash_free will reset st_hash.records */
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
|
|
|
|
prepared_stmt_count-= st_hash.records;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
|
|
|
|
my_hash_reset(&names_hash);
|
|
|
|
my_hash_reset(&st_hash);
|
|
|
|
last_found_statement= 0;
|
2003-12-20 00:16:10 +01:00
|
|
|
}
|
|
|
|
|
2004-04-12 23:58:48 +02:00
|
|
|
|
2006-04-07 21:37:06 +02:00
|
|
|
Statement_map::~Statement_map()
|
|
|
|
{
|
|
|
|
/* Must go first, hash_free will reset st_hash.records */
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
|
|
|
|
prepared_stmt_count-= st_hash.records;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
|
2006-04-07 21:37:06 +02:00
|
|
|
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&names_hash);
|
|
|
|
my_hash_free(&st_hash);
|
2006-04-07 21:37:06 +02:00
|
|
|
}
|
|
|
|
|
2002-10-16 15:55:08 +02:00
|
|
|
bool select_dumpvar::send_data(List<Item> &items)
|
|
|
|
{
|
2006-11-29 18:15:15 +01:00
|
|
|
List_iterator_fast<my_var> var_li(var_list);
|
2005-05-09 00:59:10 +02:00
|
|
|
List_iterator<Item> it(items);
|
2006-11-28 23:21:39 +01:00
|
|
|
Item *item;
|
2006-11-29 18:15:15 +01:00
|
|
|
my_var *mv;
|
2006-06-21 00:21:10 +02:00
|
|
|
DBUG_ENTER("select_dumpvar::send_data");
|
2002-10-16 15:55:08 +02:00
|
|
|
|
2003-01-18 15:23:37 +01:00
|
|
|
if (unit->offset_limit_cnt)
|
2006-06-21 00:21:10 +02:00
|
|
|
{ // using limit offset,count
|
2003-01-18 15:23:37 +01:00
|
|
|
unit->offset_limit_cnt--;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2002-10-16 15:55:08 +02:00
|
|
|
if (row_count++)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
|
2002-10-16 15:55:08 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
2006-11-29 18:15:15 +01:00
|
|
|
while ((mv= var_li++) && (item= it++))
|
2003-10-24 20:14:26 +02:00
|
|
|
{
|
2006-11-29 18:15:15 +01:00
|
|
|
if (mv->local)
|
2003-01-18 17:21:13 +01:00
|
|
|
{
|
2006-11-30 19:09:48 +01:00
|
|
|
if (thd->spcont->set_variable(thd, mv->offset, &item))
|
|
|
|
DBUG_RETURN(1);
|
2003-01-18 17:21:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-11-30 19:09:48 +01:00
|
|
|
Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
|
2009-10-30 14:15:43 +01:00
|
|
|
if (suv->fix_fields(thd, 0))
|
|
|
|
DBUG_RETURN (1);
|
2009-02-24 15:47:12 +01:00
|
|
|
suv->save_item_result(item);
|
2009-10-30 14:15:43 +01:00
|
|
|
if (suv->update())
|
|
|
|
DBUG_RETURN (1);
|
2003-01-18 17:21:13 +01:00
|
|
|
}
|
2003-10-24 20:14:26 +02:00
|
|
|
}
|
2008-02-19 12:43:01 +01:00
|
|
|
DBUG_RETURN(thd->is_error());
|
2002-10-11 20:49:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool select_dumpvar::send_eof()
|
|
|
|
{
|
2003-11-19 11:26:18 +01:00
|
|
|
if (! row_count)
|
2004-11-24 17:22:29 +01:00
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
|
2007-10-15 14:42:41 +02:00
|
|
|
/*
|
|
|
|
In order to remember the value of affected rows for ROW_COUNT()
|
|
|
|
function, SELECT INTO has to have an own SQLCOM.
|
|
|
|
TODO: split from SQLCOM_SELECT
|
|
|
|
*/
|
2008-02-19 13:45:21 +01:00
|
|
|
::my_ok(thd,row_count);
|
2003-11-19 11:26:18 +01:00
|
|
|
return 0;
|
2002-10-11 20:49:10 +02:00
|
|
|
}
|
2003-11-28 11:18:13 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
TMP_TABLE_PARAM
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void TMP_TABLE_PARAM::init()
|
|
|
|
{
|
2006-01-18 12:48:57 +01:00
|
|
|
DBUG_ENTER("TMP_TABLE_PARAM::init");
|
|
|
|
DBUG_PRINT("enter", ("this: 0x%lx", (ulong)this));
|
2003-11-28 11:18:13 +01:00
|
|
|
field_count= sum_func_count= func_count= hidden_field_count= 0;
|
|
|
|
group_parts= group_length= group_null_parts= 0;
|
|
|
|
quick_group= 1;
|
2004-11-18 10:16:06 +01:00
|
|
|
table_charset= 0;
|
2005-11-30 11:52:12 +01:00
|
|
|
precomputed_group_by= 0;
|
2006-01-18 12:48:57 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2003-11-28 11:18:13 +01:00
|
|
|
}
|
2004-09-13 15:48:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
void thd_increment_bytes_sent(ulong length)
|
|
|
|
{
|
2005-03-09 19:22:30 +01:00
|
|
|
THD *thd=current_thd;
|
2005-03-09 20:49:44 +01:00
|
|
|
if (likely(thd != 0))
|
2005-03-09 19:22:30 +01:00
|
|
|
{ /* current_thd==0 when close_connection() calls net_send_error() */
|
|
|
|
thd->status_var.bytes_sent+= length;
|
|
|
|
}
|
2004-09-13 15:48:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void thd_increment_bytes_received(ulong length)
|
|
|
|
{
|
|
|
|
current_thd->status_var.bytes_received+= length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void thd_increment_net_big_packet_count(ulong length)
|
|
|
|
{
|
|
|
|
current_thd->status_var.net_big_packet_count+= length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void THD::set_status_var_init()
|
|
|
|
{
|
|
|
|
bzero((char*) &status_var, sizeof(status_var));
|
|
|
|
}
|
2005-07-13 11:48:13 +02:00
|
|
|
|
2005-09-15 21:29:07 +02:00
|
|
|
|
2005-09-20 20:20:38 +02:00
|
|
|
void Security_context::init()
|
2005-09-15 21:29:07 +02:00
|
|
|
{
|
|
|
|
host= user= priv_user= ip= 0;
|
|
|
|
host_or_ip= "connecting host";
|
2006-07-04 21:46:15 +02:00
|
|
|
priv_host[0]= '\0';
|
2007-10-19 17:57:08 +02:00
|
|
|
master_access= 0;
|
2005-09-15 21:29:07 +02:00
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
|
|
db_access= NO_ACCESS;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-20 20:20:38 +02:00
|
|
|
void Security_context::destroy()
|
2005-09-15 21:29:07 +02:00
|
|
|
{
|
|
|
|
// If not pointer to constant
|
|
|
|
if (host != my_localhost)
|
|
|
|
safeFree(host);
|
|
|
|
if (user != delayed_user)
|
|
|
|
safeFree(user);
|
|
|
|
safeFree(ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-20 20:20:38 +02:00
|
|
|
void Security_context::skip_grants()
|
2005-09-15 21:29:07 +02:00
|
|
|
{
|
|
|
|
/* privileges for the user are unknown everything is allowed */
|
|
|
|
host_or_ip= (char *)"";
|
|
|
|
master_access= ~NO_ACCESS;
|
|
|
|
priv_user= (char *)"";
|
|
|
|
*priv_host= '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-22 20:46:13 +02:00
|
|
|
bool Security_context::set_user(char *user_arg)
|
|
|
|
{
|
|
|
|
safeFree(user);
|
|
|
|
user= my_strdup(user_arg, MYF(0));
|
|
|
|
return user == 0;
|
|
|
|
}
|
|
|
|
|
2007-04-13 22:35:56 +02:00
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
|
|
/**
|
|
|
|
Initialize this security context from the passed in credentials
|
|
|
|
and activate it in the current thread.
|
|
|
|
|
2007-08-16 16:07:48 +02:00
|
|
|
@param thd
|
|
|
|
@param definer_user
|
|
|
|
@param definer_host
|
|
|
|
@param db
|
2007-04-13 22:35:56 +02:00
|
|
|
@param[out] backup Save a pointer to the current security context
|
|
|
|
in the thread. In case of success it points to the
|
|
|
|
saved old context, otherwise it points to NULL.
|
|
|
|
|
|
|
|
|
|
|
|
During execution of a statement, multiple security contexts may
|
|
|
|
be needed:
|
|
|
|
- the security context of the authenticated user, used as the
|
|
|
|
default security context for all top-level statements
|
|
|
|
- in case of a view or a stored program, possibly the security
|
|
|
|
context of the definer of the routine, if the object is
|
|
|
|
defined with SQL SECURITY DEFINER option.
|
|
|
|
|
|
|
|
The currently "active" security context is parameterized in THD
|
|
|
|
member security_ctx. By default, after a connection is
|
|
|
|
established, this member points at the "main" security context
|
|
|
|
- the credentials of the authenticated user.
|
|
|
|
|
|
|
|
Later, if we would like to execute some sub-statement or a part
|
|
|
|
of a statement under credentials of a different user, e.g.
|
|
|
|
definer of a procedure, we authenticate this user in a local
|
|
|
|
instance of Security_context by means of this method (and
|
|
|
|
ultimately by means of acl_getroot_no_password), and make the
|
|
|
|
local instance active in the thread by re-setting
|
|
|
|
thd->security_ctx pointer.
|
|
|
|
|
|
|
|
Note, that the life cycle and memory management of the "main" and
|
|
|
|
temporary security contexts are different.
|
|
|
|
For the main security context, the memory for user/host/ip is
|
|
|
|
allocated on system heap, and the THD class frees this memory in
|
|
|
|
its destructor. The only case when contents of the main security
|
|
|
|
context may change during its life time is when someone issued
|
|
|
|
CHANGE USER command.
|
|
|
|
Memory management of a "temporary" security context is
|
|
|
|
responsibility of the module that creates it.
|
|
|
|
|
|
|
|
@retval TRUE there is no user with the given credentials. The erro
|
|
|
|
is reported in the thread.
|
|
|
|
@retval FALSE success
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
Security_context::
|
|
|
|
change_security_context(THD *thd,
|
|
|
|
LEX_STRING *definer_user,
|
|
|
|
LEX_STRING *definer_host,
|
|
|
|
LEX_STRING *db,
|
|
|
|
Security_context **backup)
|
|
|
|
{
|
|
|
|
bool needs_change;
|
|
|
|
|
|
|
|
DBUG_ENTER("Security_context::change_security_context");
|
|
|
|
|
|
|
|
DBUG_ASSERT(definer_user->str && definer_host->str);
|
|
|
|
|
|
|
|
*backup= NULL;
|
|
|
|
/*
|
|
|
|
The current security context may have NULL members
|
|
|
|
if we have just started the thread and not authenticated
|
|
|
|
any user. This use case is currently in events worker thread.
|
|
|
|
*/
|
|
|
|
needs_change= (thd->security_ctx->priv_user == NULL ||
|
|
|
|
strcmp(definer_user->str, thd->security_ctx->priv_user) ||
|
|
|
|
thd->security_ctx->priv_host == NULL ||
|
|
|
|
my_strcasecmp(system_charset_info, definer_host->str,
|
|
|
|
thd->security_ctx->priv_host));
|
|
|
|
if (needs_change)
|
|
|
|
{
|
|
|
|
if (acl_getroot_no_password(this, definer_user->str, definer_host->str,
|
|
|
|
definer_host->str, db->str))
|
|
|
|
{
|
|
|
|
my_error(ER_NO_SUCH_USER, MYF(0), definer_user->str,
|
|
|
|
definer_host->str);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
*backup= thd->security_ctx;
|
|
|
|
thd->security_ctx= this;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Security_context::restore_security_context(THD *thd,
|
|
|
|
Security_context *backup)
|
|
|
|
{
|
|
|
|
if (backup)
|
|
|
|
thd->security_ctx= backup;
|
|
|
|
}
|
|
|
|
#endif
|
2006-06-28 01:28:03 +02:00
|
|
|
|
2009-03-25 17:42:34 +01:00
|
|
|
|
2009-03-25 17:10:27 +01:00
|
|
|
bool Security_context::user_matches(Security_context *them)
|
|
|
|
{
|
|
|
|
return ((user != NULL) && (them->user != NULL) &&
|
|
|
|
!strcmp(user, them->user));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-13 11:48:13 +02:00
|
|
|
/****************************************************************************
|
|
|
|
Handling of open and locked tables states.
|
|
|
|
|
|
|
|
This is used when we want to open/lock (and then close) some tables when
|
|
|
|
we already have a set of tables open and locked. We use these methods for
|
|
|
|
access to mysql.proc table to find definitions of stored routines.
|
|
|
|
****************************************************************************/
|
|
|
|
|
2010-01-21 21:43:03 +01:00
|
|
|
void THD::reset_n_backup_open_tables_state(Open_tables_backup *backup)
|
2005-07-13 11:48:13 +02:00
|
|
|
{
|
2005-08-08 15:46:06 +02:00
|
|
|
DBUG_ENTER("reset_n_backup_open_tables_state");
|
|
|
|
backup->set_open_tables_state(this);
|
2010-01-21 21:43:03 +01:00
|
|
|
backup->mdl_system_tables_svp= mdl_context.mdl_savepoint();
|
2009-11-30 16:55:03 +01:00
|
|
|
reset_open_tables_state(this);
|
2006-02-16 08:30:53 +01:00
|
|
|
state_flags|= Open_tables_state::BACKUPS_AVAIL;
|
2005-08-08 15:46:06 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2005-07-13 11:48:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-21 21:43:03 +01:00
|
|
|
void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
|
2005-08-08 15:46:06 +02:00
|
|
|
{
|
|
|
|
DBUG_ENTER("restore_backup_open_tables_state");
|
2010-01-21 21:43:03 +01:00
|
|
|
mdl_context.rollback_to_savepoint(backup->mdl_system_tables_svp);
|
2005-08-08 15:46:06 +02:00
|
|
|
/*
|
|
|
|
Before we will throw away current open tables state we want
|
|
|
|
to be sure that it was properly cleaned up.
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
|
A prerequisite patch for the fix for Bug#46224
"HANDLER statements within a transaction might lead to deadlocks".
Introduce a notion of a sentinel to MDL_context. A sentinel
is a ticket that separates all tickets in the context into two
groups: before and after it. Currently we can have (and need) only
one designated sentinel -- it separates all locks taken by LOCK
TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK
and all other locks, which must be released at COMMIT or ROLLBACK.
The tricky part is maintaining the sentinel up to date when
someone release its corresponding ticket. This can happen, e.g.
if someone issues DROP TABLE under LOCK TABLES (generally,
see all calls to release_all_locks_for_name()).
MDL_context::release_ticket() is modified to take care of it.
******
A fix and a test case for Bug#46224 "HANDLER statements within a
transaction might lead to deadlocks".
An attempt to mix HANDLER SQL statements, which are transaction-
agnostic, an open multi-statement transaction,
and DDL against the involved tables (in a concurrent connection)
could lead to a deadlock. The deadlock would occur when
HANDLER OPEN or HANDLER READ would have to wait on a conflicting
metadata lock. If the connection that issued HANDLER statement
also had other metadata locks (say, acquired in scope of a
transaction), a classical deadlock situation of mutual wait
could occur.
Incompatible change: entering LOCK TABLES mode automatically
closes all open HANDLERs in the current connection.
Incompatible change: previously an attempt to wait on a lock
in a connection that has an open HANDLER statement could wait
indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK
is produced.
The idea of the fix is to merge thd->handler_mdl_context
with the main mdl_context of the connection, used for transactional
locks. This makes deadlock detection possible, since all waits
with locks are "visible" and available to analysis in a single
MDL context of the connection.
Since HANDLER locks and transactional locks have a different life
cycle -- HANDLERs are explicitly open and closed, and so
are HANDLER locks, explicitly acquired and released, whereas
transactional locks "accumulate" till the end of a transaction
and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT,
a concept of "sentinel" was introduced to MDL_context.
All locks, HANDLER and others, reside in the same linked list.
However, a selected element of the list separates locks with
different life cycle. HANDLER locks always reside at the
end of the list, after the sentinel. Transactional locks are
prepended to the beginning of the list, before the sentinel.
Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only
release those locks that reside before the sentinel. HANDLER locks
must be released explicitly as part of HANDLER CLOSE statement,
or an implicit close.
The same approach with sentinel
is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES
statement has never worked together, the implementation is
made simple and only maintains one sentinel, which is used either
for HANDLER locks, or for LOCK TABLES locks.
2009-12-22 17:09:15 +01:00
|
|
|
derived_tables == 0 &&
|
2009-12-01 15:39:03 +01:00
|
|
|
lock == 0 &&
|
|
|
|
locked_tables_mode == LTM_NONE &&
|
2008-05-20 09:29:16 +02:00
|
|
|
m_reprepare_observer == NULL);
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2005-08-08 15:46:06 +02:00
|
|
|
set_open_tables_state(backup);
|
2005-07-13 11:48:13 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
2005-08-15 17:15:12 +02:00
|
|
|
|
2007-07-05 01:05:47 +02:00
|
|
|
/**
|
|
|
|
Check the killed state of a user thread
|
|
|
|
@param thd user thread
|
|
|
|
@retval 0 the user thread is active
|
|
|
|
@retval 1 the user thread has been killed
|
|
|
|
*/
|
|
|
|
extern "C" int thd_killed(const MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return(thd->killed);
|
|
|
|
}
|
2005-08-15 17:15:12 +02:00
|
|
|
|
2008-02-19 17:44:09 +01:00
|
|
|
/**
|
|
|
|
Return the thread id of a user thread
|
|
|
|
@param thd user thread
|
|
|
|
@return thread id
|
|
|
|
*/
|
|
|
|
extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return((unsigned long)thd->thread_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-05 01:05:47 +02:00
|
|
|
#ifdef INNODB_COMPATIBILITY_HOOKS
|
|
|
|
extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return(thd->charset());
|
|
|
|
}
|
|
|
|
|
2009-10-16 12:29:42 +02:00
|
|
|
/**
|
|
|
|
OBSOLETE : there's no way to ensure the string is null terminated.
|
|
|
|
Use thd_query_string instead()
|
|
|
|
*/
|
2007-07-05 01:05:47 +02:00
|
|
|
extern "C" char **thd_query(MYSQL_THD thd)
|
|
|
|
{
|
2009-10-16 12:29:42 +02:00
|
|
|
return(&thd->query_string.str);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Get the current query string for the thread.
|
|
|
|
|
|
|
|
@param The MySQL internal thread pointer
|
|
|
|
@return query string and length. May be non-null-terminated.
|
|
|
|
*/
|
|
|
|
extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return(&thd->query_string);
|
2007-07-05 01:05:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int thd_slave_thread(const MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return(thd->slave_thread);
|
|
|
|
}
|
2005-08-15 17:15:12 +02:00
|
|
|
|
2007-07-05 01:05:47 +02:00
|
|
|
extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
|
|
|
|
{
|
2007-07-31 13:58:04 +02:00
|
|
|
return(thd->transaction.all.modified_non_trans_table);
|
2007-07-05 01:05:47 +02:00
|
|
|
}
|
|
|
|
|
2007-07-10 13:37:43 +02:00
|
|
|
extern "C" int thd_binlog_format(const MYSQL_THD thd)
|
2007-07-05 01:05:47 +02:00
|
|
|
{
|
2009-12-22 10:35:56 +01:00
|
|
|
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
|
2008-11-03 12:14:48 +01:00
|
|
|
return (int) thd->variables.binlog_format;
|
|
|
|
else
|
|
|
|
return BINLOG_FORMAT_UNSPEC;
|
2007-07-05 01:05:47 +02:00
|
|
|
}
|
2007-08-02 10:22:31 +02:00
|
|
|
|
|
|
|
extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)
|
|
|
|
{
|
|
|
|
mark_transaction_to_rollback(thd, all);
|
|
|
|
}
|
2009-09-24 16:52:52 +02:00
|
|
|
|
|
|
|
extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd)
|
|
|
|
{
|
|
|
|
return binlog_filter->db_ok(thd->db);
|
|
|
|
}
|
2007-07-05 01:05:47 +02:00
|
|
|
#endif // INNODB_COMPATIBILITY_HOOKS */
|
2005-08-15 17:35:48 +02:00
|
|
|
|
2005-08-15 17:15:12 +02:00
|
|
|
/****************************************************************************
|
|
|
|
Handling of statement states in functions and triggers.
|
|
|
|
|
|
|
|
This is used to ensure that the function/trigger gets a clean state
|
|
|
|
to work with and does not cause any side effects of the calling statement.
|
|
|
|
|
|
|
|
It also allows most stored functions and triggers to replicate even
|
|
|
|
if they are used items that would normally be stored in the binary
|
|
|
|
replication (like last_insert_id() etc...)
|
|
|
|
|
|
|
|
The following things is done
|
|
|
|
- Disable binary logging for the duration of the statement
|
|
|
|
- Disable multi-result-sets for the duration of the statement
|
2006-04-21 16:55:04 +02:00
|
|
|
- Value of last_insert_id() is saved and restored
|
2005-08-15 17:15:12 +02:00
|
|
|
- Value set by 'SET INSERT_ID=#' is reset and restored
|
|
|
|
- Value for found_rows() is reset and restored
|
|
|
|
- examined_row_count is added to the total
|
|
|
|
- cuted_fields is added to the total
|
2005-11-19 13:09:23 +01:00
|
|
|
- new savepoint level is created and destroyed
|
2005-08-15 17:15:12 +02:00
|
|
|
|
|
|
|
NOTES:
|
|
|
|
Seed for random() is saved for the first! usage of RAND()
|
|
|
|
We reset examined_row_count and cuted_fields and add these to the
|
|
|
|
result to ensure that if we have a bug that would reset these within
|
|
|
|
a function, we are not loosing any rows from the main statement.
|
2006-04-21 16:55:04 +02:00
|
|
|
|
|
|
|
We do not reset value of last_insert_id().
|
2005-08-15 17:15:12 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
void THD::reset_sub_statement_state(Sub_statement_state *backup,
|
|
|
|
uint new_state)
|
|
|
|
{
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
|
|
|
/* BUG#33029, if we are replicating from a buggy master, reset
|
|
|
|
auto_inc_intervals_forced to prevent substatement
|
|
|
|
(triggers/functions) from using erroneous INSERT_ID value
|
|
|
|
*/
|
|
|
|
if (rpl_master_erroneous_autoinc(this))
|
|
|
|
{
|
2008-06-19 20:47:59 +02:00
|
|
|
DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0);
|
|
|
|
auto_inc_intervals_forced.swap(&backup->auto_inc_intervals_forced);
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-12-22 10:35:56 +01:00
|
|
|
backup->option_bits= variables.option_bits;
|
2005-08-15 17:15:12 +02:00
|
|
|
backup->in_sub_stmt= in_sub_stmt;
|
|
|
|
backup->enable_slow_log= enable_slow_log;
|
|
|
|
backup->limit_found_rows= limit_found_rows;
|
|
|
|
backup->examined_row_count= examined_row_count;
|
|
|
|
backup->sent_row_count= sent_row_count;
|
|
|
|
backup->cuted_fields= cuted_fields;
|
|
|
|
backup->client_capabilities= client_capabilities;
|
2005-11-19 13:09:23 +01:00
|
|
|
backup->savepoints= transaction.savepoints;
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
backup->first_successful_insert_id_in_prev_stmt=
|
|
|
|
first_successful_insert_id_in_prev_stmt;
|
|
|
|
backup->first_successful_insert_id_in_cur_stmt=
|
|
|
|
first_successful_insert_id_in_cur_stmt;
|
2005-08-15 17:15:12 +02:00
|
|
|
|
2005-12-22 06:39:02 +01:00
|
|
|
if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
!is_current_stmt_binlog_format_row())
|
2006-05-16 11:16:23 +02:00
|
|
|
{
|
2009-12-22 10:35:56 +01:00
|
|
|
variables.option_bits&= ~OPTION_BIN_LOG;
|
2007-02-27 19:20:47 +01:00
|
|
|
}
|
2007-02-26 20:06:10 +01:00
|
|
|
|
2010-01-12 13:07:09 +01:00
|
|
|
if ((backup->option_bits & OPTION_BIN_LOG) &&
|
|
|
|
is_update_query(lex->sql_command) &&
|
|
|
|
!is_current_stmt_binlog_format_row())
|
2007-02-26 20:06:10 +01:00
|
|
|
mysql_bin_log.start_union_events(this, this->query_id);
|
|
|
|
|
2005-08-15 17:15:12 +02:00
|
|
|
/* Disable result sets */
|
|
|
|
client_capabilities &= ~CLIENT_MULTI_RESULTS;
|
|
|
|
in_sub_stmt|= new_state;
|
|
|
|
examined_row_count= 0;
|
|
|
|
sent_row_count= 0;
|
|
|
|
cuted_fields= 0;
|
2005-11-19 13:09:23 +01:00
|
|
|
transaction.savepoints= 0;
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
first_successful_insert_id_in_cur_stmt= 0;
|
2005-08-15 17:15:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void THD::restore_sub_statement_state(Sub_statement_state *backup)
|
|
|
|
{
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
#ifndef EMBEDDED_LIBRARY
|
|
|
|
/* BUG#33029, if we are replicating from a buggy master, restore
|
|
|
|
auto_inc_intervals_forced so that the top statement can use the
|
|
|
|
INSERT_ID value set before this statement.
|
|
|
|
*/
|
|
|
|
if (rpl_master_erroneous_autoinc(this))
|
|
|
|
{
|
2008-06-19 20:47:59 +02:00
|
|
|
backup->auto_inc_intervals_forced.swap(&auto_inc_intervals_forced);
|
|
|
|
DBUG_ASSERT(backup->auto_inc_intervals_forced.nb_elements() == 0);
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-11-19 13:09:23 +01:00
|
|
|
/*
|
|
|
|
To save resources we want to release savepoints which were created
|
|
|
|
during execution of function or trigger before leaving their savepoint
|
|
|
|
level. It is enough to release first savepoint set on this level since
|
|
|
|
all later savepoints will be released automatically.
|
|
|
|
*/
|
|
|
|
if (transaction.savepoints)
|
|
|
|
{
|
|
|
|
SAVEPOINT *sv;
|
|
|
|
for (sv= transaction.savepoints; sv->prev; sv= sv->prev)
|
|
|
|
{}
|
|
|
|
/* ha_release_savepoint() never returns error. */
|
|
|
|
(void)ha_release_savepoint(this, sv);
|
|
|
|
}
|
|
|
|
transaction.savepoints= backup->savepoints;
|
2009-12-22 10:35:56 +01:00
|
|
|
variables.option_bits= backup->option_bits;
|
2005-08-15 17:15:12 +02:00
|
|
|
in_sub_stmt= backup->in_sub_stmt;
|
|
|
|
enable_slow_log= backup->enable_slow_log;
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
first_successful_insert_id_in_prev_stmt=
|
|
|
|
backup->first_successful_insert_id_in_prev_stmt;
|
|
|
|
first_successful_insert_id_in_cur_stmt=
|
|
|
|
backup->first_successful_insert_id_in_cur_stmt;
|
2005-08-15 17:15:12 +02:00
|
|
|
limit_found_rows= backup->limit_found_rows;
|
|
|
|
sent_row_count= backup->sent_row_count;
|
|
|
|
client_capabilities= backup->client_capabilities;
|
2007-07-30 15:14:34 +02:00
|
|
|
/*
|
|
|
|
If we've left sub-statement mode, reset the fatal error flag.
|
|
|
|
Otherwise keep the current value, to propagate it up the sub-statement
|
|
|
|
stack.
|
|
|
|
*/
|
|
|
|
if (!in_sub_stmt)
|
|
|
|
is_fatal_sub_stmt_error= FALSE;
|
2005-08-15 17:15:12 +02:00
|
|
|
|
2009-12-22 10:35:56 +01:00
|
|
|
if ((variables.option_bits & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
|
2010-01-12 13:07:09 +01:00
|
|
|
!is_current_stmt_binlog_format_row())
|
2007-02-26 20:06:10 +01:00
|
|
|
mysql_bin_log.stop_union_events(this);
|
2007-02-23 18:58:56 +01:00
|
|
|
|
2005-08-15 17:15:12 +02:00
|
|
|
/*
|
|
|
|
The following is added to the old values as we are interested in the
|
|
|
|
total complexity of the query
|
|
|
|
*/
|
|
|
|
examined_row_count+= backup->examined_row_count;
|
|
|
|
cuted_fields+= backup->cuted_fields;
|
|
|
|
}
|
2005-08-15 17:35:48 +02:00
|
|
|
|
|
|
|
|
2009-07-24 17:58:58 +02:00
|
|
|
void THD::set_statement(Statement *stmt)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_thd_data);
|
2009-07-24 17:58:58 +02:00
|
|
|
Statement::set_statement(stmt);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_thd_data);
|
2009-07-24 17:58:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Assign a new value to thd->query. */
|
|
|
|
|
|
|
|
void THD::set_query(char *query_arg, uint32 query_length_arg)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_thd_data);
|
2009-10-16 12:29:42 +02:00
|
|
|
set_query_inner(query_arg, query_length_arg);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_thd_data);
|
2009-07-24 17:58:58 +02:00
|
|
|
}
|
|
|
|
|
2009-11-24 14:28:38 +01:00
|
|
|
/** Assign a new value to thd->query and thd->query_id. */
|
|
|
|
|
|
|
|
void THD::set_query_and_id(char *query_arg, uint32 query_length_arg,
|
|
|
|
query_id_t new_query_id)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_thd_data);
|
2009-11-24 14:28:38 +01:00
|
|
|
set_query_inner(query_arg, query_length_arg);
|
|
|
|
query_id= new_query_id;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_thd_data);
|
2009-11-24 14:28:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Assign a new value to thd->query_id. */
|
|
|
|
|
|
|
|
void THD::set_query_id(query_id_t new_query_id)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_thd_data);
|
2009-11-24 14:28:38 +01:00
|
|
|
query_id= new_query_id;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_thd_data);
|
2009-11-24 14:28:38 +01:00
|
|
|
}
|
|
|
|
|
2009-07-24 17:58:58 +02:00
|
|
|
|
2010-02-12 08:05:43 +01:00
|
|
|
/**
|
|
|
|
Leave explicit LOCK TABLES or prelocked mode and restore value of
|
|
|
|
transaction sentinel in MDL subsystem.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void THD::leave_locked_tables_mode()
|
|
|
|
{
|
|
|
|
locked_tables_mode= LTM_NONE;
|
|
|
|
/* Make sure we don't release the global read lock when leaving LTM. */
|
|
|
|
mdl_context.reset_trans_sentinel(global_read_lock.global_shared_lock());
|
|
|
|
/* Also ensure that we don't release metadata locks for open HANDLERs. */
|
|
|
|
if (handler_tables_hash.records)
|
|
|
|
mysql_ha_move_tickets_after_trans_sentinel(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-30 15:14:34 +02:00
|
|
|
/**
|
|
|
|
Mark transaction to rollback and mark error as fatal to a sub-statement.
|
|
|
|
|
|
|
|
@param thd Thread handle
|
|
|
|
@param all TRUE <=> rollback main transaction.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mark_transaction_to_rollback(THD *thd, bool all)
|
|
|
|
{
|
2007-10-10 22:00:57 +02:00
|
|
|
if (thd)
|
|
|
|
{
|
|
|
|
thd->is_fatal_sub_stmt_error= TRUE;
|
|
|
|
thd->transaction_rollback_request= all;
|
2009-10-28 15:49:56 +01:00
|
|
|
/*
|
|
|
|
Aborted transactions can not be IGNOREd.
|
|
|
|
Switch off the IGNORE flag for the current
|
|
|
|
SELECT_LEX. This should allow my_error()
|
|
|
|
to report the error and abort the execution
|
|
|
|
flow, even in presence
|
|
|
|
of IGNORE clause.
|
|
|
|
*/
|
|
|
|
if (thd->lex->current_select)
|
|
|
|
thd->lex->current_select->no_error= FALSE;
|
2007-10-10 22:00:57 +02:00
|
|
|
}
|
2007-07-30 15:14:34 +02:00
|
|
|
}
|
2005-08-15 17:35:48 +02:00
|
|
|
/***************************************************************************
|
|
|
|
Handling of XA id cacheing
|
|
|
|
***************************************************************************/
|
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_t LOCK_xid_cache;
|
2005-08-12 21:15:01 +02:00
|
|
|
HASH xid_cache;
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
extern "C" uchar *xid_get_hash_key(const uchar *, size_t *, my_bool);
|
|
|
|
extern "C" void xid_free_hash(void *);
|
|
|
|
|
|
|
|
uchar *xid_get_hash_key(const uchar *ptr, size_t *length,
|
2005-08-12 21:15:01 +02:00
|
|
|
my_bool not_used __attribute__((unused)))
|
|
|
|
{
|
2005-10-05 16:38:53 +02:00
|
|
|
*length=((XID_STATE*)ptr)->xid.key_length();
|
|
|
|
return ((XID_STATE*)ptr)->xid.key();
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
|
|
|
|
2007-08-13 15:11:25 +02:00
|
|
|
void xid_free_hash(void *ptr)
|
2005-08-12 21:15:01 +02:00
|
|
|
{
|
|
|
|
if (!((XID_STATE*)ptr)->in_thd)
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
my_free((uchar*)ptr, MYF(0));
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
#ifdef HAVE_PSI_INTERFACE
|
|
|
|
static PSI_mutex_key key_LOCK_xid_cache;
|
|
|
|
|
|
|
|
static PSI_mutex_info all_xid_mutexes[]=
|
|
|
|
{
|
|
|
|
{ &key_LOCK_xid_cache, "LOCK_xid_cache", PSI_FLAG_GLOBAL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static void init_xid_psi_keys(void)
|
|
|
|
{
|
|
|
|
const char* category= "sql";
|
|
|
|
int count;
|
|
|
|
|
|
|
|
if (PSI_server == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
count= array_elements(all_xid_mutexes);
|
|
|
|
PSI_server->register_mutex(category, all_xid_mutexes, count);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_PSI_INTERFACE */
|
|
|
|
|
2005-08-12 21:15:01 +02:00
|
|
|
bool xid_cache_init()
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
#ifdef HAVE_PSI_INTERFACE
|
|
|
|
init_xid_psi_keys();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mysql_mutex_init(key_LOCK_xid_cache, &LOCK_xid_cache, MY_MUTEX_INIT_FAST);
|
2009-10-14 18:37:38 +02:00
|
|
|
return my_hash_init(&xid_cache, &my_charset_bin, 100, 0, 0,
|
|
|
|
xid_get_hash_key, xid_free_hash, 0) != 0;
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void xid_cache_free()
|
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
if (my_hash_inited(&xid_cache))
|
2005-08-12 21:15:01 +02:00
|
|
|
{
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_free(&xid_cache);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_destroy(&LOCK_xid_cache);
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
XID_STATE *xid_cache_search(XID *xid)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_xid_cache);
|
2009-10-14 18:37:38 +02:00
|
|
|
XID_STATE *res=(XID_STATE *)my_hash_search(&xid_cache, xid->key(),
|
|
|
|
xid->key_length());
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_xid_cache);
|
2005-08-12 21:15:01 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-08-15 17:35:48 +02:00
|
|
|
|
2005-08-12 21:15:01 +02:00
|
|
|
bool xid_cache_insert(XID *xid, enum xa_states xa_state)
|
|
|
|
{
|
|
|
|
XID_STATE *xs;
|
|
|
|
my_bool res;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_xid_cache);
|
2009-10-14 18:37:38 +02:00
|
|
|
if (my_hash_search(&xid_cache, xid->key(), xid->key_length()))
|
2005-08-12 21:15:01 +02:00
|
|
|
res=0;
|
|
|
|
else if (!(xs=(XID_STATE *)my_malloc(sizeof(*xs), MYF(MY_WME))))
|
|
|
|
res=1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xs->xa_state=xa_state;
|
|
|
|
xs->xid.set(xid);
|
|
|
|
xs->in_thd=0;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
res=my_hash_insert(&xid_cache, (uchar*)xs);
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_xid_cache);
|
2005-08-12 21:15:01 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-08-15 17:35:48 +02:00
|
|
|
|
2005-08-12 21:15:01 +02:00
|
|
|
bool xid_cache_insert(XID_STATE *xid_state)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_xid_cache);
|
2009-10-14 18:37:38 +02:00
|
|
|
DBUG_ASSERT(my_hash_search(&xid_cache, xid_state->xid.key(),
|
|
|
|
xid_state->xid.key_length())==0);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
my_bool res=my_hash_insert(&xid_cache, (uchar*)xid_state);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_xid_cache);
|
2005-08-12 21:15:01 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-08-15 17:35:48 +02:00
|
|
|
|
2005-08-12 21:15:01 +02:00
|
|
|
void xid_cache_delete(XID_STATE *xid_state)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_xid_cache);
|
2009-10-14 18:37:38 +02:00
|
|
|
my_hash_delete(&xid_cache, (uchar *)xid_state);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_xid_cache);
|
2005-08-12 21:15:01 +02:00
|
|
|
}
|
|
|
|
|
2009-07-22 18:29:26 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Decide on logging format to use for the statement and issue errors
|
|
|
|
or warnings as needed. The decision depends on the following
|
|
|
|
parameters:
|
|
|
|
|
|
|
|
- The logging mode, i.e., the value of binlog_format. Can be
|
|
|
|
statement, mixed, or row.
|
|
|
|
|
|
|
|
- The type of statement. There are three types of statements:
|
|
|
|
"normal" safe statements; unsafe statements; and row injections.
|
|
|
|
An unsafe statement is one that, if logged in statement format,
|
|
|
|
might produce different results when replayed on the slave (e.g.,
|
|
|
|
INSERT DELAYED). A row injection is either a BINLOG statement, or
|
|
|
|
a row event executed by the slave's SQL thread.
|
|
|
|
|
|
|
|
- The capabilities of tables modified by the statement. The
|
|
|
|
*capabilities vector* for a table is a set of flags associated
|
|
|
|
with the table. Currently, it only includes two flags: *row
|
|
|
|
capability flag* and *statement capability flag*.
|
|
|
|
|
|
|
|
The row capability flag is set if and only if the engine can
|
|
|
|
handle row-based logging. The statement capability flag is set if
|
|
|
|
and only if the table can handle statement-based logging.
|
|
|
|
|
|
|
|
Decision table for logging format
|
|
|
|
---------------------------------
|
|
|
|
|
|
|
|
The following table summarizes how the format and generated
|
|
|
|
warning/error depends on the tables' capabilities, the statement
|
|
|
|
type, and the current binlog_format.
|
|
|
|
|
|
|
|
Row capable N NNNNNNNNN YYYYYYYYY YYYYYYYYY
|
|
|
|
Statement capable N YYYYYYYYY NNNNNNNNN YYYYYYYYY
|
|
|
|
|
|
|
|
Statement type * SSSUUUIII SSSUUUIII SSSUUUIII
|
|
|
|
|
|
|
|
binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR
|
|
|
|
|
2009-10-14 18:32:08 +02:00
|
|
|
Logged format - SS-S----- -RR-RR-RR SRRSRR-RR
|
|
|
|
Warning/Error 1 --2732444 5--5--6-- ---7--6--
|
2009-07-22 18:29:26 +02:00
|
|
|
|
|
|
|
Legend
|
|
|
|
------
|
|
|
|
|
|
|
|
Row capable: N - Some table not row-capable, Y - All tables row-capable
|
|
|
|
Stmt capable: N - Some table not stmt-capable, Y - All tables stmt-capable
|
|
|
|
Statement type: (S)afe, (U)nsafe, or Row (I)njection
|
|
|
|
binlog_format: (S)TATEMENT, (M)IXED, or (R)OW
|
|
|
|
Logged format: (S)tatement or (R)ow
|
|
|
|
Warning/Error: Warnings and error messages are as follows:
|
|
|
|
|
|
|
|
1. Error: Cannot execute statement: binlogging impossible since both
|
|
|
|
row-incapable engines and statement-incapable engines are
|
|
|
|
involved.
|
|
|
|
|
|
|
|
2. Error: Cannot execute statement: binlogging impossible since
|
|
|
|
BINLOG_FORMAT = ROW and at least one table uses a storage engine
|
|
|
|
limited to statement-logging.
|
|
|
|
|
2009-10-14 18:32:08 +02:00
|
|
|
3. Error: Cannot execute statement: binlogging of unsafe statement
|
|
|
|
is impossible when storage engine is limited to statement-logging
|
|
|
|
and BINLOG_FORMAT = MIXED.
|
2009-07-22 18:29:26 +02:00
|
|
|
|
|
|
|
4. Error: Cannot execute row injection: binlogging impossible since
|
|
|
|
at least one table uses a storage engine limited to
|
|
|
|
statement-logging.
|
|
|
|
|
|
|
|
5. Error: Cannot execute statement: binlogging impossible since
|
|
|
|
BINLOG_FORMAT = STATEMENT and at least one table uses a storage
|
|
|
|
engine limited to row-logging.
|
|
|
|
|
|
|
|
6. Error: Cannot execute row injection: binlogging impossible since
|
|
|
|
BINLOG_FORMAT = STATEMENT.
|
|
|
|
|
|
|
|
7. Warning: Unsafe statement binlogged in statement format since
|
|
|
|
BINLOG_FORMAT = STATEMENT.
|
|
|
|
|
|
|
|
In addition, we can produce the following error (not depending on
|
|
|
|
the variables of the decision diagram):
|
|
|
|
|
|
|
|
8. Error: Cannot execute statement: binlogging impossible since more
|
|
|
|
than one engine is involved and at least one engine is
|
|
|
|
self-logging.
|
|
|
|
|
|
|
|
For each error case above, the statement is prevented from being
|
|
|
|
logged, we report an error, and roll back the statement. For
|
|
|
|
warnings, we set the thd->binlog_flags variable: the warning will be
|
|
|
|
printed only if the statement is successfully logged.
|
|
|
|
|
|
|
|
@see THD::binlog_query
|
|
|
|
|
|
|
|
@param[in] thd Client thread
|
|
|
|
@param[in] tables Tables involved in the query
|
|
|
|
|
|
|
|
@retval 0 No error; statement can be logged.
|
|
|
|
@retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
|
|
|
|
*/
|
|
|
|
|
|
|
|
int THD::decide_logging_format(TABLE_LIST *tables)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("THD::decide_logging_format");
|
2009-11-30 19:20:26 +01:00
|
|
|
DBUG_PRINT("info", ("query: %s", query()));
|
2010-01-25 22:34:34 +01:00
|
|
|
DBUG_PRINT("info", ("variables.binlog_format: %u",
|
2009-07-22 18:29:26 +02:00
|
|
|
variables.binlog_format));
|
|
|
|
DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
|
|
|
|
lex->get_stmt_unsafe_flags()));
|
2009-07-22 22:14:20 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
We should not decide logging format if the binlog is closed or
|
|
|
|
binlogging is off, or if the statement is filtered out from the
|
|
|
|
binlog by filtering rules.
|
|
|
|
*/
|
2010-01-12 13:07:09 +01:00
|
|
|
if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
|
2009-07-22 22:14:20 +02:00
|
|
|
!(variables.binlog_format == BINLOG_FORMAT_STMT &&
|
|
|
|
!binlog_filter->db_ok(db)))
|
2009-07-22 18:29:26 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Compute one bit field with the union of all the engine
|
|
|
|
capabilities, and one with the intersection of all the engine
|
|
|
|
capabilities.
|
|
|
|
*/
|
2010-02-22 04:25:33 +01:00
|
|
|
handler::Table_flags flags_write_some_set= 0;
|
2009-07-22 18:29:26 +02:00
|
|
|
handler::Table_flags flags_some_set= 0;
|
2010-02-22 04:25:33 +01:00
|
|
|
handler::Table_flags flags_write_all_set=
|
2009-07-22 18:29:26 +02:00
|
|
|
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
|
|
|
|
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
/*
|
|
|
|
If different types of engines are about to be updated.
|
|
|
|
For example: Innodb and Falcon; Innodb and MyIsam.
|
|
|
|
*/
|
2010-02-22 04:25:33 +01:00
|
|
|
my_bool multi_write_engine= FALSE;
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
/*
|
|
|
|
If different types of engines are about to be accessed
|
|
|
|
and any of them is about to be updated. For example:
|
|
|
|
Innodb and Falcon; Innodb and MyIsam.
|
|
|
|
*/
|
|
|
|
my_bool multi_access_engine= FALSE;
|
|
|
|
/*
|
|
|
|
If non-transactional and transactional engines are about
|
|
|
|
to be accessed and any of them is about to be updated.
|
|
|
|
For example: Innodb and MyIsam.
|
|
|
|
*/
|
|
|
|
my_bool trans_non_trans_access_engines= FALSE;
|
|
|
|
/*
|
|
|
|
If all engines that are about to be updated are
|
|
|
|
transactional.
|
|
|
|
*/
|
|
|
|
my_bool all_trans_write_engines= TRUE;
|
2009-11-03 20:02:56 +01:00
|
|
|
TABLE* prev_write_table= NULL;
|
|
|
|
TABLE* prev_access_table= NULL;
|
2009-07-22 18:29:26 +02:00
|
|
|
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
{
|
|
|
|
static const char *prelocked_mode_name[] = {
|
|
|
|
"NON_PRELOCKED",
|
|
|
|
"PRELOCKED",
|
|
|
|
"PRELOCKED_UNDER_LOCK_TABLES",
|
|
|
|
};
|
|
|
|
DBUG_PRINT("debug", ("prelocked_mode: %s",
|
2010-02-04 23:08:08 +01:00
|
|
|
prelocked_mode_name[locked_tables_mode]));
|
2009-07-22 18:29:26 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get the capabilities vector for all involved storage engines and
|
|
|
|
mask out the flags for the binary log.
|
|
|
|
*/
|
|
|
|
for (TABLE_LIST *table= tables; table; table= table->next_global)
|
|
|
|
{
|
|
|
|
if (table->placeholder())
|
|
|
|
continue;
|
|
|
|
if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
|
|
|
|
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
|
2010-02-22 04:25:33 +01:00
|
|
|
handler::Table_flags const flags= table->table->file->ha_table_flags();
|
|
|
|
DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
|
|
|
|
table->table_name, flags));
|
2009-07-22 18:29:26 +02:00
|
|
|
if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
|
|
|
|
{
|
2009-11-03 20:02:56 +01:00
|
|
|
if (prev_write_table && prev_write_table->file->ht !=
|
|
|
|
table->table->file->ht)
|
2010-02-22 04:25:33 +01:00
|
|
|
multi_write_engine= TRUE;
|
2010-04-20 11:10:43 +02:00
|
|
|
/*
|
|
|
|
Every temporary table must be always written to the binary
|
|
|
|
log in transaction boundaries and as such we artificially
|
|
|
|
classify them as transactional.
|
|
|
|
|
|
|
|
Indirectly, this avoids classifying a temporary table created
|
|
|
|
on a non-transactional engine as unsafe when it is modified
|
|
|
|
after any transactional table:
|
|
|
|
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO innodb_t VALUES (1);
|
|
|
|
INSERT INTO myisam_t_temp VALUES (1);
|
|
|
|
COMMIT;
|
|
|
|
|
|
|
|
BINARY LOG:
|
|
|
|
|
|
|
|
BEGIN;
|
|
|
|
INSERT INTO innodb_t VALUES (1);
|
|
|
|
INSERT INTO myisam_t_temp VALUES (1);
|
|
|
|
COMMIT;
|
|
|
|
*/
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
all_trans_write_engines= all_trans_write_engines &&
|
2010-04-20 11:10:43 +02:00
|
|
|
(table->table->file->has_transactions() ||
|
|
|
|
table->table->s->tmp_table);
|
2009-11-03 20:02:56 +01:00
|
|
|
prev_write_table= table->table;
|
2010-02-22 04:25:33 +01:00
|
|
|
flags_write_all_set &= flags;
|
|
|
|
flags_write_some_set |= flags;
|
2009-07-22 18:29:26 +02:00
|
|
|
}
|
2010-02-22 04:25:33 +01:00
|
|
|
flags_some_set |= flags;
|
2010-04-20 11:10:43 +02:00
|
|
|
/*
|
|
|
|
The mixture of non-transactional and transactional tables must
|
|
|
|
identified and classified as unsafe. However, a temporary table
|
|
|
|
must be always handled as a transactional table. Based on that,
|
|
|
|
we have the following statements classified as mixed and by
|
|
|
|
consequence as unsafe:
|
|
|
|
|
|
|
|
1: INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
|
|
|
|
2: INSERT INTO innodb_t SELECT * FROM myisam_t;
|
|
|
|
|
|
|
|
3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
|
|
|
|
|
|
|
|
4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
|
|
|
|
|
|
|
|
5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
|
|
|
|
|
|
|
|
The following statements are not considered mixed and as such
|
|
|
|
are safe:
|
|
|
|
|
|
|
|
1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
|
|
|
|
|
|
|
|
2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
|
|
|
|
*/
|
|
|
|
if (!trans_non_trans_access_engines && prev_access_table &&
|
|
|
|
(lex->sql_command != SQLCOM_CREATE_TABLE ||
|
|
|
|
(lex->sql_command == SQLCOM_CREATE_TABLE &&
|
|
|
|
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
|
2010-02-22 04:25:33 +01:00
|
|
|
{
|
2010-04-20 11:10:43 +02:00
|
|
|
my_bool prev_trans;
|
|
|
|
my_bool act_trans;
|
|
|
|
if (prev_access_table->s->tmp_table || table->table->s->tmp_table)
|
|
|
|
{
|
|
|
|
prev_trans= prev_access_table->s->tmp_table ? TRUE :
|
|
|
|
prev_access_table->file->has_transactions();
|
|
|
|
act_trans= table->table->s->tmp_table ? TRUE :
|
|
|
|
table->table->file->has_transactions();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prev_trans= prev_access_table->file->has_transactions();
|
|
|
|
act_trans= table->table->file->has_transactions();
|
|
|
|
}
|
|
|
|
trans_non_trans_access_engines= (prev_trans != act_trans);
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
multi_access_engine= TRUE;
|
2010-02-22 04:25:33 +01:00
|
|
|
}
|
2009-11-03 20:02:56 +01:00
|
|
|
prev_access_table= table->table;
|
2009-07-22 18:29:26 +02:00
|
|
|
}
|
|
|
|
|
2010-02-22 04:25:33 +01:00
|
|
|
DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
|
|
|
|
DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
|
|
|
|
DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
|
|
|
|
DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
|
|
|
|
DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
|
|
|
|
trans_non_trans_access_engines));
|
2010-02-22 04:25:33 +01:00
|
|
|
|
|
|
|
int error= 0;
|
|
|
|
int unsafe_flags;
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
/*
|
|
|
|
Set the statement as unsafe if:
|
|
|
|
|
|
|
|
. it is a mixed statement, i.e. access transactional and non-transactional
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
tables, and update any of them;
|
|
|
|
|
|
|
|
or:
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
. an early statement updated a transactional table;
|
|
|
|
. and, the current statement updates a non-transactional table.
|
|
|
|
|
|
|
|
Any mixed statement is classified as unsafe to ensure that mixed mode is
|
|
|
|
completely safe. Consider the following example to understand why we
|
|
|
|
decided to do this:
|
|
|
|
|
|
|
|
Note that mixed statements such as
|
|
|
|
|
|
|
|
1: INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
|
|
|
|
2: INSERT INTO innodb_t SELECT * FROM myisam_t;
|
|
|
|
|
2010-04-20 11:10:43 +02:00
|
|
|
3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
|
|
|
|
|
|
|
|
4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
|
|
|
|
|
|
|
|
5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
are classified as unsafe to ensure that in mixed mode the execution is
|
|
|
|
completely safe and equivalent to the row mode. Consider the following
|
|
|
|
statements and sessions (connections) to understand the reason:
|
|
|
|
|
|
|
|
con1: INSERT INTO innodb_t VALUES (1);
|
|
|
|
con1: INSERT INTO innodb_t VALUES (100);
|
|
|
|
|
|
|
|
con1: BEGIN
|
|
|
|
con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
con1: INSERT INTO innodb_t VALUES (200);
|
|
|
|
con1: COMMIT;
|
|
|
|
|
|
|
|
The point is that the concurrent statements may be written into the binary log
|
|
|
|
in a way different from the execution. For example,
|
|
|
|
|
|
|
|
BINARY LOG:
|
|
|
|
|
|
|
|
con2: BEGIN;
|
|
|
|
con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
con2: COMMIT;
|
|
|
|
con1: BEGIN
|
|
|
|
con1: INSERT INTO innodb_t VALUES (200);
|
|
|
|
con1: COMMIT;
|
|
|
|
|
|
|
|
....
|
|
|
|
|
|
|
|
or
|
|
|
|
|
|
|
|
BINARY LOG:
|
|
|
|
|
|
|
|
con1: BEGIN
|
|
|
|
con1: INSERT INTO innodb_t VALUES (200);
|
|
|
|
con1: COMMIT;
|
|
|
|
con2: BEGIN;
|
|
|
|
con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
con2: COMMIT;
|
|
|
|
|
|
|
|
Clearly, this may become a problem in STMT mode and setting the statement
|
|
|
|
as unsafe will make rows to be written into the binary log in MIXED mode
|
|
|
|
and as such the problem will not stand.
|
|
|
|
|
|
|
|
In STMT mode, although such statement is classified as unsafe, i.e.
|
|
|
|
|
|
|
|
INSERT INTO myisam_t SELECT * FROM innodb_t;
|
|
|
|
|
|
|
|
there is no enough information to avoid writing it outside the boundaries
|
|
|
|
of a transaction. This is not a problem if we are considering snapshot
|
|
|
|
isolation level but if we have pure repeatable read or serializable the
|
|
|
|
lock history on the slave will be different from the master.
|
|
|
|
*/
|
2010-04-01 01:16:22 +02:00
|
|
|
if (trans_non_trans_access_engines)
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
|
|
|
|
else if (trans_has_updated_trans_table(this) && !all_trans_write_engines)
|
2009-11-03 20:02:56 +01:00
|
|
|
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
|
|
|
|
|
2009-07-22 18:29:26 +02:00
|
|
|
/*
|
|
|
|
If more than one engine is involved in the statement and at
|
|
|
|
least one is doing it's own logging (is *self-logging*), the
|
|
|
|
statement cannot be logged atomically, so we generate an error
|
|
|
|
rather than allowing the binlog to become corrupt.
|
|
|
|
*/
|
2010-02-22 04:25:33 +01:00
|
|
|
if (multi_write_engine &&
|
|
|
|
(flags_write_some_set & HA_HAS_OWN_BINLOGGING))
|
2009-07-22 18:29:26 +02:00
|
|
|
my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
|
|
|
|
MYF(0));
|
BUG#51291 Unfortunate effect around variable binlog_direct_non_transactional_updates
BUG#46364 introduced the flag binlog_direct_non_transactional_updates which
would make N-changes to be written to the binary log upon committing the
statement when "ON". On the other hand, when "OFF" the option was supposed
to mimic the behavior in 5.1. However, the implementation was not mimicking
the behavior correctly and the following bugs popped up:
Case #1: N-changes executed within a transaction would go into
the S-cache. When later in the same transaction a
T-change occurs, N-changes following it were written
to the T-cache instead of the S-cache. In some cases,
this raises problems. For example, a
Table_map_log_event being written initially into the
S-cache, together with the initial N-changes, would be
absent from the T-cache. This would log N-changes
orphaned from a Table_map_log_event (thence discarded
at the slave). (MIXED and ROW)
Case #2: When rolling back a transaction, the N-changes that
might be in the T-cache were disregarded and
truncated along with the T-changes. (MIXED and ROW)
Case #3: When a MIXED statement (TN) is ahead of any other
T-changes in the transaction and it fails, it is kept
in the T-cache until the transaction ends. This is
not the case in 5.1 or Betony (5.5.2). In these, the
failed TN statement would be written to the binlog at
the same instant it had failed and not deferred until
transaction end. (SBR)
To fix these problems, we have decided to do what follows:
For Case #1 and #2, we circumvent them:
1. by not letting binlog_direct_non_transactional_updates
affect MIXED and RBR. These modes will keep the behavior
provided by WL#2687. Although this will make Celosia to
behave differently from 5.1, an execution will be always
safe under such modes in the sense that slaves will never
go out sync. In 5.1, using either MIXED or ROW while
mixing N-statements and T-statements was not safe.
For Case #3, we don't actually fix it. We:
1. keep it and make all MIXED statements whether they end
up failing or not or whether they are up front in the
transaction or after some transactional change to always
be stored in the T-cache. This means that it is written
to the binary log on transaction commit/rollback only.
2. We make the warning message even more specific about the
MIXED statement and SBR.
2010-03-31 15:22:47 +02:00
|
|
|
else if (multi_access_engine && flags_some_set & HA_HAS_OWN_BINLOGGING)
|
2010-02-22 04:25:33 +01:00
|
|
|
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
|
2009-07-22 18:29:26 +02:00
|
|
|
|
|
|
|
/* both statement-only and row-only engines involved */
|
2010-02-22 04:25:33 +01:00
|
|
|
if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0)
|
2009-07-22 18:29:26 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
1. Error: Binary logging impossible since both row-incapable
|
|
|
|
engines and statement-incapable engines are involved
|
|
|
|
*/
|
|
|
|
my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
|
|
|
|
}
|
|
|
|
/* statement-only engines involved */
|
2010-02-22 04:25:33 +01:00
|
|
|
else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
|
2009-07-22 18:29:26 +02:00
|
|
|
{
|
|
|
|
if (lex->is_stmt_row_injection())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
4. Error: Cannot execute row injection since table uses
|
|
|
|
storage engine limited to statement-logging
|
|
|
|
*/
|
|
|
|
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
|
|
|
|
}
|
|
|
|
else if (variables.binlog_format == BINLOG_FORMAT_ROW)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
2. Error: Cannot modify table that uses a storage engine
|
|
|
|
limited to statement-logging when BINLOG_FORMAT = ROW
|
|
|
|
*/
|
|
|
|
my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
|
|
|
|
}
|
|
|
|
else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
|
|
|
|
{
|
|
|
|
/*
|
2009-10-14 18:32:08 +02:00
|
|
|
3. Error: Cannot execute statement: binlogging of unsafe
|
|
|
|
statement is impossible when storage engine is limited to
|
|
|
|
statement-logging and BINLOG_FORMAT = MIXED.
|
2009-07-22 18:29:26 +02:00
|
|
|
*/
|
2009-10-14 18:32:08 +02:00
|
|
|
for (int unsafe_type= 0;
|
|
|
|
unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
|
|
|
|
unsafe_type++)
|
|
|
|
if (unsafe_flags & (1 << unsafe_type))
|
|
|
|
my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
|
|
|
|
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
|
2009-07-22 18:29:26 +02:00
|
|
|
}
|
|
|
|
/* log in statement format! */
|
|
|
|
}
|
|
|
|
/* no statement-only engines */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* binlog_format = STATEMENT */
|
|
|
|
if (variables.binlog_format == BINLOG_FORMAT_STMT)
|
|
|
|
{
|
|
|
|
if (lex->is_stmt_row_injection())
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
6. Error: Cannot execute row injection since
|
|
|
|
BINLOG_FORMAT = STATEMENT
|
|
|
|
*/
|
|
|
|
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
|
|
|
|
}
|
2010-02-22 04:25:33 +01:00
|
|
|
else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
|
2009-07-22 18:29:26 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
5. Error: Cannot modify table that uses a storage engine
|
|
|
|
limited to row-logging when binlog_format = STATEMENT
|
|
|
|
*/
|
|
|
|
my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
|
|
|
|
}
|
|
|
|
else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
7. Warning: Unsafe statement logged as statement due to
|
|
|
|
binlog_format = STATEMENT
|
|
|
|
*/
|
2009-10-14 18:32:08 +02:00
|
|
|
binlog_unsafe_warning_flags|= unsafe_flags;
|
2009-07-22 18:29:26 +02:00
|
|
|
DBUG_PRINT("info", ("Scheduling warning to be issued by "
|
|
|
|
"binlog_query: '%s'",
|
|
|
|
ER(ER_BINLOG_UNSAFE_STATEMENT)));
|
2009-10-14 18:32:08 +02:00
|
|
|
DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
|
2009-07-22 18:29:26 +02:00
|
|
|
binlog_unsafe_warning_flags));
|
|
|
|
}
|
|
|
|
/* log in statement format! */
|
|
|
|
}
|
|
|
|
/* No statement-only engines and binlog_format != STATEMENT.
|
|
|
|
I.e., nothing prevents us from row logging if needed. */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
|
2010-02-22 04:25:33 +01:00
|
|
|
|| (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
|
2009-07-22 18:29:26 +02:00
|
|
|
{
|
|
|
|
/* log in row format! */
|
2009-09-30 18:00:22 +02:00
|
|
|
set_current_stmt_binlog_format_row_if_mixed();
|
2009-07-22 18:29:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
DBUG_PRINT("info", ("decision: no logging since an error was generated"));
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("decision: logging in %s format",
|
|
|
|
is_current_stmt_binlog_format_row() ?
|
|
|
|
"ROW" : "STATEMENT"));
|
|
|
|
}
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
else
|
|
|
|
DBUG_PRINT("info", ("decision: no logging since "
|
|
|
|
"mysql_bin_log.is_open() = %d "
|
2009-07-22 22:14:20 +02:00
|
|
|
"and (options & OPTION_BIN_LOG) = 0x%llx "
|
2010-01-25 22:34:34 +01:00
|
|
|
"and binlog_format = %u "
|
2009-07-22 22:14:20 +02:00
|
|
|
"and binlog_filter->db_ok(db) = %d",
|
|
|
|
mysql_bin_log.is_open(),
|
2010-01-12 13:07:09 +01:00
|
|
|
(variables.option_bits & OPTION_BIN_LOG),
|
2009-07-22 22:14:20 +02:00
|
|
|
variables.binlog_format,
|
|
|
|
binlog_filter->db_ok(db)));
|
2009-07-22 18:29:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-22 06:39:02 +01:00
|
|
|
/*
|
|
|
|
Implementation of interface to write rows to the binary log through the
|
|
|
|
thread. The thread is responsible for writing the rows it has
|
|
|
|
inserted/updated/deleted.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MYSQL_CLIENT
|
|
|
|
|
|
|
|
/*
|
|
|
|
Template member function for ensuring that there is an rows log
|
|
|
|
event of the apropriate type before proceeding.
|
|
|
|
|
|
|
|
PRE CONDITION:
|
|
|
|
- Events of type 'RowEventT' have the type code 'type_code'.
|
|
|
|
|
|
|
|
POST CONDITION:
|
|
|
|
If a non-NULL pointer is returned, the pending event for thread 'thd' will
|
|
|
|
be an event of type 'RowEventT' (which have the type code 'type_code')
|
|
|
|
will either empty or have enough space to hold 'needed' bytes. In
|
|
|
|
addition, the columns bitmap will be correct for the row, meaning that
|
|
|
|
the pending event will be flushed if the columns in the event differ from
|
|
|
|
the columns suppled to the function.
|
|
|
|
|
|
|
|
RETURNS
|
|
|
|
If no error, a non-NULL pending event (either one which already existed or
|
|
|
|
the newly created one).
|
|
|
|
If error, NULL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
template <class RowsEventT> Rows_log_event*
|
|
|
|
THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
|
|
|
|
MY_BITMAP const* cols,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t colcnt,
|
|
|
|
size_t needed,
|
2006-01-09 15:59:39 +01:00
|
|
|
bool is_transactional,
|
|
|
|
RowsEventT *hint __attribute__((unused)))
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_ENTER("binlog_prepare_pending_rows_event");
|
2005-12-22 06:39:02 +01:00
|
|
|
/* Pre-conditions */
|
2006-03-09 03:56:14 +01:00
|
|
|
DBUG_ASSERT(table->s->table_map_id != ~0UL);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
/* Fetch the type code for the RowsEventT template parameter */
|
|
|
|
int const type_code= RowsEventT::TYPE_CODE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
There is no good place to set up the transactional data, so we
|
|
|
|
have to do it here.
|
|
|
|
*/
|
|
|
|
if (binlog_setup_trx_data())
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(NULL);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
if (unlikely(pending && !pending->is_valid()))
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(NULL);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check if the current event is non-NULL and a write-rows
|
|
|
|
event. Also check if the table provided is mapped: if it is not,
|
|
|
|
then we have switched to writing to a new table.
|
|
|
|
If there is no pending event, we need to create one. If there is a pending
|
|
|
|
event, but it's not about the same table id, or not of the same type
|
|
|
|
(between Write, Update and Delete), or not the same affected columns, or
|
|
|
|
going to be too big, flush this event to disk and create a new pending
|
|
|
|
event.
|
|
|
|
*/
|
|
|
|
if (!pending ||
|
|
|
|
pending->server_id != serv_id ||
|
|
|
|
pending->get_table_id() != table->s->table_map_id ||
|
|
|
|
pending->get_type_code() != type_code ||
|
|
|
|
pending->get_data_size() + needed > opt_binlog_rows_event_max_size ||
|
|
|
|
pending->get_width() != colcnt ||
|
|
|
|
!bitmap_cmp(pending->get_cols(), cols))
|
|
|
|
{
|
|
|
|
/* Create a new RowsEventT... */
|
|
|
|
Rows_log_event* const
|
|
|
|
ev= new RowsEventT(this, table, table->s->table_map_id, cols,
|
|
|
|
is_transactional);
|
|
|
|
if (unlikely(!ev))
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(NULL);
|
2005-12-22 06:39:02 +01:00
|
|
|
ev->server_id= serv_id; // I don't like this, it's too easy to forget.
|
|
|
|
/*
|
|
|
|
flush the pending event and replace it with the newly created
|
|
|
|
event...
|
|
|
|
*/
|
2009-11-03 20:02:56 +01:00
|
|
|
if (unlikely(
|
|
|
|
mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
|
|
|
|
is_transactional)))
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
delete ev;
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(NULL);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(ev); /* This is the new pending event */
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
2006-02-16 08:30:53 +01:00
|
|
|
DBUG_RETURN(pending); /* This is the current pending event */
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
|
2006-02-02 15:22:31 +01:00
|
|
|
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
2005-12-22 06:39:02 +01:00
|
|
|
/*
|
2006-02-16 08:30:53 +01:00
|
|
|
Instantiate the versions we need, we have -fno-implicit-template as
|
2005-12-22 06:39:02 +01:00
|
|
|
compiling option.
|
|
|
|
*/
|
|
|
|
template Rows_log_event*
|
2006-01-09 15:59:39 +01:00
|
|
|
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t, size_t, bool,
|
2006-01-09 15:59:39 +01:00
|
|
|
Write_rows_log_event*);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
template Rows_log_event*
|
2006-01-09 15:59:39 +01:00
|
|
|
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t colcnt, size_t, bool,
|
2006-01-09 15:59:39 +01:00
|
|
|
Delete_rows_log_event *);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
template Rows_log_event*
|
2006-01-09 15:59:39 +01:00
|
|
|
THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t colcnt, size_t, bool,
|
2006-01-09 15:59:39 +01:00
|
|
|
Update_rows_log_event *);
|
2006-02-02 15:22:31 +01:00
|
|
|
#endif
|
2007-01-29 00:47:35 +01:00
|
|
|
|
|
|
|
#ifdef NOT_USED
|
2005-12-22 06:39:02 +01:00
|
|
|
static char const*
|
|
|
|
field_type_name(enum_field_types type)
|
|
|
|
{
|
2007-01-29 00:47:35 +01:00
|
|
|
switch (type) {
|
2005-12-22 06:39:02 +01:00
|
|
|
case MYSQL_TYPE_DECIMAL:
|
|
|
|
return "MYSQL_TYPE_DECIMAL";
|
|
|
|
case MYSQL_TYPE_TINY:
|
|
|
|
return "MYSQL_TYPE_TINY";
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
|
|
return "MYSQL_TYPE_SHORT";
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
|
|
return "MYSQL_TYPE_LONG";
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
|
|
return "MYSQL_TYPE_FLOAT";
|
|
|
|
case MYSQL_TYPE_DOUBLE:
|
|
|
|
return "MYSQL_TYPE_DOUBLE";
|
|
|
|
case MYSQL_TYPE_NULL:
|
|
|
|
return "MYSQL_TYPE_NULL";
|
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
|
|
return "MYSQL_TYPE_TIMESTAMP";
|
|
|
|
case MYSQL_TYPE_LONGLONG:
|
|
|
|
return "MYSQL_TYPE_LONGLONG";
|
|
|
|
case MYSQL_TYPE_INT24:
|
|
|
|
return "MYSQL_TYPE_INT24";
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
|
|
return "MYSQL_TYPE_DATE";
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
|
|
return "MYSQL_TYPE_TIME";
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
|
|
return "MYSQL_TYPE_DATETIME";
|
|
|
|
case MYSQL_TYPE_YEAR:
|
|
|
|
return "MYSQL_TYPE_YEAR";
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
return "MYSQL_TYPE_NEWDATE";
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
return "MYSQL_TYPE_VARCHAR";
|
|
|
|
case MYSQL_TYPE_BIT:
|
|
|
|
return "MYSQL_TYPE_BIT";
|
|
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
|
|
return "MYSQL_TYPE_NEWDECIMAL";
|
|
|
|
case MYSQL_TYPE_ENUM:
|
|
|
|
return "MYSQL_TYPE_ENUM";
|
|
|
|
case MYSQL_TYPE_SET:
|
|
|
|
return "MYSQL_TYPE_SET";
|
|
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
|
|
return "MYSQL_TYPE_TINY_BLOB";
|
|
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
|
|
return "MYSQL_TYPE_MEDIUM_BLOB";
|
|
|
|
case MYSQL_TYPE_LONG_BLOB:
|
|
|
|
return "MYSQL_TYPE_LONG_BLOB";
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
return "MYSQL_TYPE_BLOB";
|
|
|
|
case MYSQL_TYPE_VAR_STRING:
|
|
|
|
return "MYSQL_TYPE_VAR_STRING";
|
|
|
|
case MYSQL_TYPE_STRING:
|
|
|
|
return "MYSQL_TYPE_STRING";
|
|
|
|
case MYSQL_TYPE_GEOMETRY:
|
|
|
|
return "MYSQL_TYPE_GEOMETRY";
|
|
|
|
}
|
|
|
|
return "Unknown";
|
|
|
|
}
|
2007-01-29 00:47:35 +01:00
|
|
|
#endif
|
2005-12-22 06:39:02 +01:00
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
namespace {
|
|
|
|
/**
|
|
|
|
Class to handle temporary allocation of memory for row data.
|
|
|
|
|
|
|
|
The responsibilities of the class is to provide memory for
|
|
|
|
packing one or two rows of packed data (depending on what
|
|
|
|
constructor is called).
|
|
|
|
|
|
|
|
In order to make the allocation more efficient for "simple" rows,
|
|
|
|
i.e., rows that do not contain any blobs, a pointer to the
|
|
|
|
allocated memory is of memory is stored in the table structure
|
|
|
|
for simple rows. If memory for a table containing a blob field
|
|
|
|
is requested, only memory for that is allocated, and subsequently
|
|
|
|
released when the object is destroyed.
|
|
|
|
|
|
|
|
*/
|
|
|
|
class Row_data_memory {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
Build an object to keep track of a block-local piece of memory
|
|
|
|
for storing a row of data.
|
|
|
|
|
|
|
|
@param table
|
|
|
|
Table where the pre-allocated memory is stored.
|
|
|
|
|
|
|
|
@param length
|
|
|
|
Length of data that is needed, if the record contain blobs.
|
|
|
|
*/
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
Row_data_memory(TABLE *table, size_t const len1)
|
2006-11-15 16:49:03 +01:00
|
|
|
: m_memory(0)
|
|
|
|
{
|
|
|
|
#ifndef DBUG_OFF
|
2007-02-23 21:48:15 +01:00
|
|
|
m_alloc_checked= FALSE;
|
2006-11-15 16:49:03 +01:00
|
|
|
#endif
|
|
|
|
allocate_memory(table, len1);
|
|
|
|
m_ptr[0]= has_memory() ? m_memory : 0;
|
|
|
|
m_ptr[1]= 0;
|
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
|
2006-11-15 16:49:03 +01:00
|
|
|
: m_memory(0)
|
|
|
|
{
|
|
|
|
#ifndef DBUG_OFF
|
2007-02-23 21:48:15 +01:00
|
|
|
m_alloc_checked= FALSE;
|
2006-11-15 16:49:03 +01:00
|
|
|
#endif
|
|
|
|
allocate_memory(table, len1 + len2);
|
|
|
|
m_ptr[0]= has_memory() ? m_memory : 0;
|
|
|
|
m_ptr[1]= has_memory() ? m_memory + len1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Row_data_memory()
|
|
|
|
{
|
|
|
|
if (m_memory != 0 && m_release_memory_on_destruction)
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
my_free((uchar*) m_memory, MYF(MY_WME));
|
2006-11-15 16:49:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Is there memory allocated?
|
|
|
|
|
|
|
|
@retval true There is memory allocated
|
|
|
|
@retval false Memory allocation failed
|
|
|
|
*/
|
|
|
|
bool has_memory() const {
|
|
|
|
#ifndef DBUG_OFF
|
2007-02-23 21:48:15 +01:00
|
|
|
m_alloc_checked= TRUE;
|
2006-11-15 16:49:03 +01:00
|
|
|
#endif
|
|
|
|
return m_memory != 0;
|
|
|
|
}
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *slot(uint s)
|
2006-11-15 16:49:03 +01:00
|
|
|
{
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
|
2006-11-15 16:49:03 +01:00
|
|
|
DBUG_ASSERT(m_ptr[s] != 0);
|
2007-02-23 21:48:15 +01:00
|
|
|
DBUG_ASSERT(m_alloc_checked == TRUE);
|
2006-11-15 16:49:03 +01:00
|
|
|
return m_ptr[s];
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
void allocate_memory(TABLE *const table, size_t const total_length)
|
2006-11-15 16:49:03 +01:00
|
|
|
{
|
|
|
|
if (table->s->blob_fields == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
The maximum length of a packed record is less than this
|
|
|
|
length. We use this value instead of the supplied length
|
|
|
|
when allocating memory for records, since we don't know how
|
|
|
|
the memory will be used in future allocations.
|
|
|
|
|
|
|
|
Since table->s->reclength is for unpacked records, we have
|
|
|
|
to add two bytes for each field, which can potentially be
|
|
|
|
added to hold the length of a packed field.
|
|
|
|
*/
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const maxlen= table->s->reclength + 2 * table->s->fields;
|
2006-11-15 16:49:03 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Allocate memory for two records if memory hasn't been
|
|
|
|
allocated. We allocate memory for two records so that it can
|
|
|
|
be used when processing update rows as well.
|
|
|
|
*/
|
|
|
|
if (table->write_row_record == 0)
|
|
|
|
table->write_row_record=
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
(uchar *) alloc_root(&table->mem_root, 2 * maxlen);
|
2006-11-15 16:49:03 +01:00
|
|
|
m_memory= table->write_row_record;
|
2007-02-23 21:48:15 +01:00
|
|
|
m_release_memory_on_destruction= FALSE;
|
2006-11-15 16:49:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
|
2007-02-23 21:48:15 +01:00
|
|
|
m_release_memory_on_destruction= TRUE;
|
2006-11-15 16:49:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
mutable bool m_alloc_checked;
|
|
|
|
#endif
|
|
|
|
bool m_release_memory_on_destruction;
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *m_memory;
|
|
|
|
uchar *m_ptr[2];
|
2006-11-15 16:49:03 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-22 06:39:02 +01:00
|
|
|
int THD::binlog_write_row(TABLE* table, bool is_trans,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
MY_BITMAP const* cols, size_t colcnt,
|
|
|
|
uchar const *record)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
|
2005-12-22 06:39:02 +01:00
|
|
|
|
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes
Changes that requires code changes in other code of other storage engines.
(Note that all changes are very straightforward and one should find all issues
by compiling a --debug build and fixing all compiler errors and all
asserts in field.cc while running the test suite),
- New optional handler function introduced: reset()
This is called after every DML statement to make it easy for a handler to
statement specific cleanups.
(The only case it's not called is if force the file to be closed)
- handler::extra(HA_EXTRA_RESET) is removed. Code that was there before
should be moved to handler::reset()
- table->read_set contains a bitmap over all columns that are needed
in the query. read_row() and similar functions only needs to read these
columns
- table->write_set contains a bitmap over all columns that will be updated
in the query. write_row() and update_row() only needs to update these
columns.
The above bitmaps should now be up to date in all context
(including ALTER TABLE, filesort()).
The handler is informed of any changes to the bitmap after
fix_fields() by calling the virtual function
handler::column_bitmaps_signal(). If the handler does caching of
these bitmaps (instead of using table->read_set, table->write_set),
it should redo the caching in this code. as the signal() may be sent
several times, it's probably best to set a variable in the signal
and redo the caching on read_row() / write_row() if the variable was
set.
- Removed the read_set and write_set bitmap objects from the handler class
- Removed all column bit handling functions from the handler class.
(Now one instead uses the normal bitmap functions in my_bitmap.c instead
of handler dedicated bitmap functions)
- field->query_id is removed. One should instead instead check
table->read_set and table->write_set if a field is used in the query.
- handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and
handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now
instead use table->read_set to check for which columns to retrieve.
- If a handler needs to call Field->val() or Field->store() on columns
that are not used in the query, one should install a temporary
all-columns-used map while doing so. For this, we provide the following
functions:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
field->val();
dbug_tmp_restore_column_map(table->read_set, old_map);
and similar for the write map:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
field->val();
dbug_tmp_restore_column_map(table->write_set, old_map);
If this is not done, you will sooner or later hit a DBUG_ASSERT
in the field store() / val() functions.
(For not DBUG binaries, the dbug_tmp_restore_column_map() and
dbug_tmp_restore_column_map() are inline dummy functions and should
be optimized away be the compiler).
- If one needs to temporary set the column map for all binaries (and not
just to avoid the DBUG_ASSERT() in the Field::store() / Field::val()
methods) one should use the functions tmp_use_all_columns() and
tmp_restore_column_map() instead of the above dbug_ variants.
- All 'status' fields in the handler base class (like records,
data_file_length etc) are now stored in a 'stats' struct. This makes
it easier to know what status variables are provided by the base
handler. This requires some trivial variable names in the extra()
function.
- New virtual function handler::records(). This is called to optimize
COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true.
(stats.records is not supposed to be an exact value. It's only has to
be 'reasonable enough' for the optimizer to be able to choose a good
optimization path).
- Non virtual handler::init() function added for caching of virtual
constants from engine.
- Removed has_transactions() virtual method. Now one should instead return
HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support
transactions.
- The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument
that is to be used with 'new handler_name()' to allocate the handler
in the right area. The xxxx_create_handler() function is also
responsible for any initialization of the object before returning.
For example, one should change:
static handler *myisam_create_handler(TABLE_SHARE *table)
{
return new ha_myisam(table);
}
->
static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root)
{
return new (mem_root) ha_myisam(table);
}
- New optional virtual function: use_hidden_primary_key().
This is called in case of an update/delete when
(table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
but we don't have a primary key. This allows the handler to take precisions
in remembering any hidden primary key to able to update/delete any
found row. The default handler marks all columns to be read.
- handler::table_flags() now returns a ulonglong (to allow for more flags).
- New/changed table_flags()
- HA_HAS_RECORDS Set if ::records() is supported
- HA_NO_TRANSACTIONS Set if engine doesn't support transactions
- HA_PRIMARY_KEY_REQUIRED_FOR_DELETE
Set if we should mark all primary key columns for
read when reading rows as part of a DELETE
statement. If there is no primary key,
all columns are marked for read.
- HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some
cases (based on table->read_set)
- HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS
Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION.
- HA_DUPP_POS Renamed to HA_DUPLICATE_POS
- HA_REQUIRES_KEY_COLUMNS_FOR_DELETE
Set this if we should mark ALL key columns for
read when when reading rows as part of a DELETE
statement. In case of an update we will mark
all keys for read for which key part changed
value.
- HA_STATS_RECORDS_IS_EXACT
Set this if stats.records is exact.
(This saves us some extra records() calls
when optimizing COUNT(*))
- Removed table_flags()
- HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if
handler::records() gives an exact count() and
HA_STATS_RECORDS_IS_EXACT if stats.records is exact.
- HA_READ_RND_SAME Removed (no one supported this one)
- Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk()
- Renamed handler::dupp_pos to handler::dup_pos
- Removed not used variable handler::sortkey
Upper level handler changes:
- ha_reset() now does some overall checks and calls ::reset()
- ha_table_flags() added. This is a cached version of table_flags(). The
cache is updated on engine creation time and updated on open.
MySQL level changes (not obvious from the above):
- DBUG_ASSERT() added to check that column usage matches what is set
in the column usage bit maps. (This found a LOT of bugs in current
column marking code).
- In 5.1 before, all used columns was marked in read_set and only updated
columns was marked in write_set. Now we only mark columns for which we
need a value in read_set.
- Column bitmaps are created in open_binary_frm() and open_table_from_share().
(Before this was in table.cc)
- handler::table_flags() calls are replaced with handler::ha_table_flags()
- For calling field->val() you must have the corresponding bit set in
table->read_set. For calling field->store() you must have the
corresponding bit set in table->write_set. (There are asserts in
all store()/val() functions to catch wrong usage)
- thd->set_query_id is renamed to thd->mark_used_columns and instead
of setting this to an integer value, this has now the values:
MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE
Changed also all variables named 'set_query_id' to mark_used_columns.
- In filesort() we now inform the handler of exactly which columns are needed
doing the sort and choosing the rows.
- The TABLE_SHARE object has a 'all_set' column bitmap one can use
when one needs a column bitmap with all columns set.
(This is used for table->use_all_columns() and other places)
- The TABLE object has 3 column bitmaps:
- def_read_set Default bitmap for columns to be read
- def_write_set Default bitmap for columns to be written
- tmp_set Can be used as a temporary bitmap when needed.
The table object has also two pointer to bitmaps read_set and write_set
that the handler should use to find out which columns are used in which way.
- count() optimization now calls handler::records() instead of using
handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true).
- Added extra argument to Item::walk() to indicate if we should also
traverse sub queries.
- Added TABLE parameter to cp_buffer_from_ref()
- Don't close tables created with CREATE ... SELECT but keep them in
the table cache. (Faster usage of newly created tables).
New interfaces:
- table->clear_column_bitmaps() to initialize the bitmaps for tables
at start of new statements.
- table->column_bitmaps_set() to set up new column bitmaps and signal
the handler about this.
- table->column_bitmaps_set_no_signal() for some few cases where we need
to setup new column bitmaps but don't signal the handler (as the handler
has already been signaled about these before). Used for the momement
only in opt_range.cc when doing ROR scans.
- table->use_all_columns() to install a bitmap where all columns are marked
as use in the read and the write set.
- table->default_column_bitmaps() to install the normal read and write
column bitmaps, but not signaling the handler about this.
This is mainly used when creating TABLE instances.
- table->mark_columns_needed_for_delete(),
table->mark_columns_needed_for_delete() and
table->mark_columns_needed_for_insert() to allow us to put additional
columns in column usage maps if handler so requires.
(The handler indicates what it neads in handler->table_flags())
- table->prepare_for_position() to allow us to tell handler that it
needs to read primary key parts to be able to store them in
future table->position() calls.
(This replaces the table->file->ha_retrieve_all_pk function)
- table->mark_auto_increment_column() to tell handler are going to update
columns part of any auto_increment key.
- table->mark_columns_used_by_index() to mark all columns that is part of
an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow
it to quickly know that it only needs to read colums that are part
of the key. (The handler can also use the column map for detecting this,
but simpler/faster handler can just monitor the extra() call).
- table->mark_columns_used_by_index_no_reset() to in addition to other columns,
also mark all columns that is used by the given key.
- table->restore_column_maps_after_mark_index() to restore to default
column maps after a call to table->mark_columns_used_by_index().
- New item function register_field_in_read_map(), for marking used columns
in table->read_map. Used by filesort() to mark all used columns
- Maintain in TABLE->merge_keys set of all keys that are used in query.
(Simplices some optimization loops)
- Maintain Field->part_of_key_not_clustered which is like Field->part_of_key
but the field in the clustered key is not assumed to be part of all index.
(used in opt_range.cc for faster loops)
- dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map()
tmp_use_all_columns() and tmp_restore_column_map() functions to temporally
mark all columns as usable. The 'dbug_' version is primarily intended
inside a handler when it wants to just call Field:store() & Field::val()
functions, but don't need the column maps set for any other usage.
(ie:: bitmap_is_set() is never called)
- We can't use compare_records() to skip updates for handlers that returns
a partial column set and the read_set doesn't cover all columns in the
write set. The reason for this is that if we have a column marked only for
write we can't in the MySQL level know if the value changed or not.
The reason this worked before was that MySQL marked all to be written
columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden
bug'.
- open_table_from_share() does not anymore setup temporary MEM_ROOT
object as a thread specific variable for the handler. Instead we
send the to-be-used MEMROOT to get_new_handler().
(Simpler, faster code)
Bugs fixed:
- Column marking was not done correctly in a lot of cases.
(ALTER TABLE, when using triggers, auto_increment fields etc)
(Could potentially result in wrong values inserted in table handlers
relying on that the old column maps or field->set_query_id was correct)
Especially when it comes to triggers, there may be cases where the
old code would cause lost/wrong values for NDB and/or InnoDB tables.
- Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags:
OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG.
This allowed me to remove some wrong warnings about:
"Some non-transactional changed tables couldn't be rolled back"
- Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset
(thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose
some warnings about
"Some non-transactional changed tables couldn't be rolled back")
- Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table()
which could cause delete_table to report random failures.
- Fixed core dumps for some tests when running with --debug
- Added missing FN_LIBCHAR in mysql_rm_tmp_tables()
(This has probably caused us to not properly remove temporary files after
crash)
- slow_logs was not properly initialized, which could maybe cause
extra/lost entries in slow log.
- If we get an duplicate row on insert, change column map to read and
write all columns while retrying the operation. This is required by
the definition of REPLACE and also ensures that fields that are only
part of UPDATE are properly handled. This fixed a bug in NDB and
REPLACE where REPLACE wrongly copied some column values from the replaced
row.
- For table handler that doesn't support NULL in keys, we would give an error
when creating a primary key with NULL fields, even after the fields has been
automaticly converted to NOT NULL.
- Creating a primary key on a SPATIAL key, would fail if field was not
declared as NOT NULL.
Cleanups:
- Removed not used condition argument to setup_tables
- Removed not needed item function reset_query_id_processor().
- Field->add_index is removed. Now this is instead maintained in
(field->flags & FIELD_IN_ADD_INDEX)
- Field->fieldnr is removed (use field->field_index instead)
- New argument to filesort() to indicate that it should return a set of
row pointers (not used columns). This allowed me to remove some references
to sql_command in filesort and should also enable us to return column
results in some cases where we couldn't before.
- Changed column bitmap handling in opt_range.cc to be aligned with TABLE
bitmap, which allowed me to use bitmap functions instead of looping over
all fields to create some needed bitmaps. (Faster and smaller code)
- Broke up found too long lines
- Moved some variable declaration at start of function for better code
readability.
- Removed some not used arguments from functions.
(setup_fields(), mysql_prepare_insert_check_table())
- setup_fields() now takes an enum instead of an int for marking columns
usage.
- For internal temporary tables, use handler::write_row(),
handler::delete_row() and handler::update_row() instead of
handler::ha_xxxx() for faster execution.
- Changed some constants to enum's and define's.
- Using separate column read and write sets allows for easier checking
of timestamp field was set by statement.
- Remove calls to free_io_cache() as this is now done automaticly in ha_reset()
- Don't build table->normalized_path as this is now identical to table->path
(after bar's fixes to convert filenames)
- Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to
do comparision with the 'convert-dbug-for-diff' tool.
Things left to do in 5.1:
- We wrongly log failed CREATE TABLE ... SELECT in some cases when using
row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result)
Mats has promised to look into this.
- Test that my fix for CREATE TABLE ... SELECT is indeed correct.
(I added several test cases for this, but in this case it's better that
someone else also tests this throughly).
Lars has promosed to do this.
2006-06-04 17:52:22 +02:00
|
|
|
/*
|
|
|
|
Pack records into format for transfer. We are allocating more
|
|
|
|
memory than needed, but that doesn't matter.
|
2005-12-22 06:39:02 +01:00
|
|
|
*/
|
2006-11-15 16:49:03 +01:00
|
|
|
Row_data_memory memory(table, max_row_length(table, record));
|
|
|
|
if (!memory.has_memory())
|
|
|
|
return HA_ERR_OUT_OF_MEM;
|
2005-12-22 06:39:02 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *row_data= memory.slot(0);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const len= pack_row(table, cols, row_data, record);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
Rows_log_event* const ev=
|
|
|
|
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
|
|
|
|
len, is_trans,
|
|
|
|
static_cast<Write_rows_log_event*>(0));
|
|
|
|
|
|
|
|
if (unlikely(ev == 0))
|
|
|
|
return HA_ERR_OUT_OF_MEM;
|
|
|
|
|
|
|
|
return ev->add_row_data(row_data, len);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int THD::binlog_update_row(TABLE* table, bool is_trans,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
MY_BITMAP const* cols, size_t colcnt,
|
|
|
|
const uchar *before_record,
|
|
|
|
const uchar *after_record)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
|
2005-12-22 06:39:02 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const before_maxlen = max_row_length(table, before_record);
|
|
|
|
size_t const after_maxlen = max_row_length(table, after_record);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
Row_data_memory row_data(table, before_maxlen, after_maxlen);
|
|
|
|
if (!row_data.has_memory())
|
|
|
|
return HA_ERR_OUT_OF_MEM;
|
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *before_row= row_data.slot(0);
|
|
|
|
uchar *after_row= row_data.slot(1);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const before_size= pack_row(table, cols, before_row,
|
2005-12-22 06:39:02 +01:00
|
|
|
before_record);
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const after_size= pack_row(table, cols, after_row,
|
2005-12-22 06:39:02 +01:00
|
|
|
after_record);
|
2006-11-21 13:57:52 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Don't print debug messages when running valgrind since they can
|
|
|
|
trigger false warnings.
|
|
|
|
*/
|
|
|
|
#ifndef HAVE_purify
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
DBUG_DUMP("before_record", before_record, table->s->reclength);
|
|
|
|
DBUG_DUMP("after_record", after_record, table->s->reclength);
|
|
|
|
DBUG_DUMP("before_row", before_row, before_size);
|
|
|
|
DBUG_DUMP("after_row", after_row, after_size);
|
2006-11-21 13:57:52 +01:00
|
|
|
#endif
|
2006-09-21 18:05:02 +02:00
|
|
|
|
2006-01-09 15:59:39 +01:00
|
|
|
Rows_log_event* const ev=
|
|
|
|
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
|
|
|
|
before_size + after_size, is_trans,
|
|
|
|
static_cast<Update_rows_log_event*>(0));
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
if (unlikely(ev == 0))
|
|
|
|
return HA_ERR_OUT_OF_MEM;
|
|
|
|
|
|
|
|
return
|
2006-09-21 18:05:02 +02:00
|
|
|
ev->add_row_data(before_row, before_size) ||
|
2005-12-22 06:39:02 +01:00
|
|
|
ev->add_row_data(after_row, after_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
int THD::binlog_delete_row(TABLE* table, bool is_trans,
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
MY_BITMAP const* cols, size_t colcnt,
|
|
|
|
uchar const *record)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Pack records into format for transfer. We are allocating more
|
|
|
|
memory than needed, but that doesn't matter.
|
|
|
|
*/
|
2006-11-15 16:49:03 +01:00
|
|
|
Row_data_memory memory(table, max_row_length(table, record));
|
|
|
|
if (unlikely(!memory.has_memory()))
|
2005-12-22 06:39:02 +01:00
|
|
|
return HA_ERR_OUT_OF_MEM;
|
2006-11-15 16:49:03 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
uchar *row_data= memory.slot(0);
|
2006-11-15 16:49:03 +01:00
|
|
|
|
WL#3817: Simplify string / memory area types and make things more consistent (first part)
The following type conversions was done:
- Changed byte to uchar
- Changed gptr to uchar*
- Change my_string to char *
- Change my_size_t to size_t
- Change size_s to size_t
Removed declaration of byte, gptr, my_string, my_size_t and size_s.
Following function parameter changes was done:
- All string functions in mysys/strings was changed to use size_t
instead of uint for string lengths.
- All read()/write() functions changed to use size_t (including vio).
- All protocoll functions changed to use size_t instead of uint
- Functions that used a pointer to a string length was changed to use size_t*
- Changed malloc(), free() and related functions from using gptr to use void *
as this requires fewer casts in the code and is more in line with how the
standard functions work.
- Added extra length argument to dirname_part() to return the length of the
created string.
- Changed (at least) following functions to take uchar* as argument:
- db_dump()
- my_net_write()
- net_write_command()
- net_store_data()
- DBUG_DUMP()
- decimal2bin() & bin2decimal()
- Changed my_compress() and my_uncompress() to use size_t. Changed one
argument to my_uncompress() from a pointer to a value as we only return
one value (makes function easier to use).
- Changed type of 'pack_data' argument to packfrm() to avoid casts.
- Changed in readfrm() and writefrom(), ha_discover and handler::discover()
the type for argument 'frmdata' to uchar** to avoid casts.
- Changed most Field functions to use uchar* instead of char* (reduced a lot of
casts).
- Changed field->val_xxx(xxx, new_ptr) to take const pointers.
Other changes:
- Removed a lot of not needed casts
- Added a few new cast required by other changes
- Added some cast to my_multi_malloc() arguments for safety (as string lengths
needs to be uint, not size_t).
- Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done
explicitely as this conflict was often hided by casting the function to
hash_get_key).
- Changed some buffers to memory regions to uchar* to avoid casts.
- Changed some string lengths from uint to size_t.
- Changed field->ptr to be uchar* instead of char*. This allowed us to
get rid of a lot of casts.
- Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar
- Include zlib.h in some files as we needed declaration of crc32()
- Changed MY_FILE_ERROR to be (size_t) -1.
- Changed many variables to hold the result of my_read() / my_write() to be
size_t. This was needed to properly detect errors (which are
returned as (size_t) -1).
- Removed some very old VMS code
- Changed packfrm()/unpackfrm() to not be depending on uint size
(portability fix)
- Removed windows specific code to restore cursor position as this
causes slowdown on windows and we should not mix read() and pread()
calls anyway as this is not thread safe. Updated function comment to
reflect this. Changed function that depended on original behavior of
my_pwrite() to itself restore the cursor position (one such case).
- Added some missing checking of return value of malloc().
- Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow.
- Changed type of table_def::m_size from my_size_t to ulong to reflect that
m_size is the number of elements in the array, not a string/memory
length.
- Moved THD::max_row_length() to table.cc (as it's not depending on THD).
Inlined max_row_length_blob() into this function.
- More function comments
- Fixed some compiler warnings when compiled without partitions.
- Removed setting of LEX_STRING() arguments in declaration (portability fix).
- Some trivial indentation/variable name changes.
- Some trivial code simplifications:
- Replaced some calls to alloc_root + memcpy to use
strmake_root()/strdup_root().
- Changed some calls from memdup() to strmake() (Safety fix)
- Simpler loops in client-simple.c
2007-05-10 11:59:39 +02:00
|
|
|
size_t const len= pack_row(table, cols, row_data, record);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-01-09 15:59:39 +01:00
|
|
|
Rows_log_event* const ev=
|
|
|
|
binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
|
|
|
|
len, is_trans,
|
|
|
|
static_cast<Delete_rows_log_event*>(0));
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
if (unlikely(ev == 0))
|
|
|
|
return HA_ERR_OUT_OF_MEM;
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2006-11-15 16:49:03 +01:00
|
|
|
return ev->add_row_data(row_data, len);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
int THD::binlog_remove_pending_rows_event(bool clear_maps,
|
|
|
|
bool is_transactional)
|
2008-09-03 22:04:07 +02:00
|
|
|
{
|
2008-10-21 14:18:38 +02:00
|
|
|
DBUG_ENTER("THD::binlog_remove_pending_rows_event");
|
2008-09-03 22:04:07 +02:00
|
|
|
|
|
|
|
if (!mysql_bin_log.is_open())
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
mysql_bin_log.remove_pending_rows_event(this, is_transactional);
|
2008-09-03 22:04:07 +02:00
|
|
|
|
|
|
|
if (clear_maps)
|
|
|
|
binlog_table_maps= 0;
|
|
|
|
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
DBUG_ENTER("THD::binlog_flush_pending_rows_event");
|
2006-08-16 14:55:57 +02:00
|
|
|
/*
|
|
|
|
We shall flush the pending event even if we are not in row-based
|
|
|
|
mode: it might be the case that we left row-based mode before
|
|
|
|
flushing anything (e.g., if we have explicitly locked tables).
|
|
|
|
*/
|
|
|
|
if (!mysql_bin_log.is_open())
|
2005-12-22 06:39:02 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Mark the event as the last event of a statement if the stmt_end
|
|
|
|
flag is set.
|
|
|
|
*/
|
|
|
|
int error= 0;
|
2009-11-03 20:02:56 +01:00
|
|
|
if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
if (stmt_end)
|
|
|
|
{
|
|
|
|
pending->set_flags(Rows_log_event::STMT_END_F);
|
|
|
|
pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
|
2006-02-16 08:30:53 +01:00
|
|
|
binlog_table_maps= 0;
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
|
2009-11-03 20:02:56 +01:00
|
|
|
error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
|
|
|
|
is_transactional);
|
2006-02-16 08:30:53 +01:00
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-08 17:25:24 +02:00
|
|
|
#if !defined(DBUG_OFF) && !defined(_lint)
|
2008-08-19 13:18:59 +02:00
|
|
|
static const char *
|
|
|
|
show_query_type(THD::enum_binlog_query_type qtype)
|
|
|
|
{
|
|
|
|
switch (qtype) {
|
|
|
|
case THD::ROW_QUERY_TYPE:
|
|
|
|
return "ROW";
|
|
|
|
case THD::STMT_QUERY_TYPE:
|
|
|
|
return "STMT";
|
2008-10-08 17:25:24 +02:00
|
|
|
case THD::QUERY_TYPE_COUNT:
|
2008-08-22 12:40:21 +02:00
|
|
|
default:
|
2008-10-08 17:25:24 +02:00
|
|
|
DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
|
2008-08-19 13:18:59 +02:00
|
|
|
}
|
2008-10-08 11:15:00 +02:00
|
|
|
static char buf[64];
|
|
|
|
sprintf(buf, "UNKNOWN#%d", qtype);
|
|
|
|
return buf;
|
2008-08-19 13:18:59 +02:00
|
|
|
}
|
2008-08-22 12:40:21 +02:00
|
|
|
#endif
|
2008-08-19 13:18:59 +02:00
|
|
|
|
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
/**
|
|
|
|
Auxiliary method used by @c binlog_query() to raise warnings.
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2009-08-19 13:38:30 +02:00
|
|
|
The type of warning and the type of unsafeness is stored in
|
|
|
|
THD::binlog_unsafe_warning_flags.
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
*/
|
|
|
|
void THD::issue_unsafe_warnings()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("issue_unsafe_warnings");
|
|
|
|
/*
|
|
|
|
Ensure that binlog_unsafe_warning_flags is big enough to hold all
|
|
|
|
bits. This is actually a constant expression.
|
|
|
|
*/
|
2009-10-14 18:32:08 +02:00
|
|
|
DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2009-10-14 18:32:08 +02:00
|
|
|
uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
|
2006-02-16 08:30:53 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
/*
|
2009-08-19 13:38:30 +02:00
|
|
|
Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
warnings that have been printed already.
|
|
|
|
*/
|
|
|
|
unsafe_type_flags &= (LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS ^
|
|
|
|
(unsafe_type_flags >> LEX::BINLOG_STMT_UNSAFE_COUNT));
|
|
|
|
/* If all warnings have been printed already, return. */
|
|
|
|
if (unsafe_type_flags == 0)
|
|
|
|
DBUG_VOID_RETURN;
|
2006-02-16 08:30:53 +01:00
|
|
|
|
2009-10-14 18:32:08 +02:00
|
|
|
DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
|
2006-02-16 08:30:53 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
/*
|
|
|
|
For each unsafe_type, check if the statement is unsafe in this way
|
|
|
|
and issue a warning.
|
|
|
|
*/
|
|
|
|
for (int unsafe_type=0;
|
|
|
|
unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
|
|
|
|
unsafe_type++)
|
|
|
|
{
|
|
|
|
if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
|
|
|
|
{
|
2009-10-14 18:32:08 +02:00
|
|
|
push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_BINLOG_UNSAFE_STATEMENT,
|
|
|
|
ER(ER_BINLOG_UNSAFE_STATEMENT),
|
|
|
|
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
|
2009-09-30 18:00:22 +02:00
|
|
|
if (global_system_variables.log_warnings)
|
2009-10-14 18:32:08 +02:00
|
|
|
{
|
|
|
|
char buf[MYSQL_ERRMSG_SIZE * 2];
|
|
|
|
sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
|
|
|
|
ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
|
2009-11-30 19:20:26 +01:00
|
|
|
sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
|
2009-10-14 18:32:08 +02:00
|
|
|
}
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
Mark these unsafe types as already printed, to avoid printing
|
|
|
|
warnings for them again.
|
|
|
|
*/
|
2009-10-14 18:32:08 +02:00
|
|
|
binlog_unsafe_warning_flags|=
|
|
|
|
unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
/**
|
|
|
|
Log the current query.
|
2005-12-22 06:39:02 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
The query will be logged in either row format or statement format
|
2009-09-30 18:00:22 +02:00
|
|
|
depending on the value of @c current_stmt_binlog_format_row field and
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
the value of the @c qtype parameter.
|
2005-12-22 06:39:02 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
This function must be called:
|
2006-02-16 08:30:53 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
- After the all calls to ha_*_row() functions have been issued.
|
2006-02-16 08:30:53 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
- After any writes to system tables. Rationale: if system tables
|
|
|
|
were written after a call to this function, and the master crashes
|
|
|
|
after the call to this function and before writing the system
|
|
|
|
tables, then the master and slave get out of sync.
|
|
|
|
|
|
|
|
- Before tables are unlocked and closed.
|
|
|
|
|
|
|
|
@see decide_logging_format
|
|
|
|
|
|
|
|
@retval 0 Success
|
|
|
|
|
|
|
|
@retval nonzero If there is a failure when writing the query (e.g.,
|
|
|
|
write failure), then the error code is returned.
|
2005-12-22 06:39:02 +01:00
|
|
|
*/
|
2007-08-13 15:11:25 +02:00
|
|
|
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
|
2009-11-03 20:02:56 +01:00
|
|
|
ulong query_len, bool is_trans, bool direct,
|
|
|
|
bool suppress_use, int errcode)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
DBUG_ENTER("THD::binlog_query");
|
2008-08-19 13:18:59 +02:00
|
|
|
DBUG_PRINT("enter", ("qtype: %s query: '%s'",
|
|
|
|
show_query_type(qtype), query_arg));
|
2007-08-13 15:11:25 +02:00
|
|
|
DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
|
2006-02-16 08:30:53 +01:00
|
|
|
|
2006-08-16 14:55:57 +02:00
|
|
|
/*
|
|
|
|
If we are not in prelocked mode, mysql_unlock_tables() will be
|
|
|
|
called after this binlog_query(), so we have to flush the pending
|
|
|
|
rows event with the STMT_END_F set to unlock all tables at the
|
|
|
|
slave side as well.
|
|
|
|
|
|
|
|
If we are in prelocked mode, the flushing will be done inside the
|
|
|
|
top-most close_thread_tables().
|
|
|
|
*/
|
2009-12-01 15:39:03 +01:00
|
|
|
if (this->locked_tables_mode <= LTM_LOCK_TABLES)
|
2009-11-03 20:02:56 +01:00
|
|
|
if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
|
2006-08-16 14:55:57 +02:00
|
|
|
DBUG_RETURN(error);
|
|
|
|
|
2007-05-27 22:20:01 +02:00
|
|
|
/*
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
Warnings for unsafe statements logged in statement format are
|
|
|
|
printed here instead of in decide_logging_format(). This is
|
|
|
|
because the warnings should be printed only if the statement is
|
|
|
|
actually logged. When executing decide_logging_format(), we cannot
|
|
|
|
know for sure if the statement will be logged.
|
2007-05-27 22:20:01 +02:00
|
|
|
*/
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
if (sql_log_bin_toplevel)
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
issue_unsafe_warnings();
|
2007-05-27 22:20:01 +02:00
|
|
|
|
2006-05-05 19:08:40 +02:00
|
|
|
switch (qtype) {
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
/*
|
|
|
|
ROW_QUERY_TYPE means that the statement may be logged either in
|
|
|
|
row format or in statement format. If
|
2009-09-30 18:00:22 +02:00
|
|
|
current_stmt_binlog_format is row, it means that the
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
statement has already been logged in row format and hence shall
|
|
|
|
not be logged again.
|
|
|
|
*/
|
2006-11-01 09:49:03 +01:00
|
|
|
case THD::ROW_QUERY_TYPE:
|
2008-08-19 13:18:59 +02:00
|
|
|
DBUG_PRINT("debug",
|
2009-09-30 18:00:22 +02:00
|
|
|
("is_current_stmt_binlog_format_row: %d",
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
is_current_stmt_binlog_format_row()));
|
|
|
|
if (is_current_stmt_binlog_format_row())
|
2006-11-01 09:49:03 +01:00
|
|
|
DBUG_RETURN(0);
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
/* Fall through */
|
2005-12-22 06:39:02 +01:00
|
|
|
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
/*
|
|
|
|
STMT_QUERY_TYPE means that the query must be logged in statement
|
|
|
|
format; it cannot be logged in row format. This is typically
|
|
|
|
used by DDL statements. It is an error to use this query type
|
2009-09-30 18:00:22 +02:00
|
|
|
if current_stmt_binlog_format_row is row.
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
|
|
|
|
@todo Currently there are places that call this method with
|
2009-09-30 18:00:22 +02:00
|
|
|
STMT_QUERY_TYPE and current_stmt_binlog_format is row. Fix those
|
BUG#39934: Slave stops for engine that only support row-based logging
This is a post-push fix addressing review requests and
problems with extra warnings.
Problem 1: The sub-statement where an unsafe warning was detected was
printed as part of the warning. This was ok for statements that
were unsafe due to, e.g., calls to UUID(), but did not make
sense for statements that were unsafe because there was more than
one autoincrement column (unsafeness in this case comes from the
combination of several sub-statements).
Fix 1: Instead of printing the sub-statement, print an explanation
of why the statement is unsafe.
Problem 2:
When a recursive construct (i.e., stored proceure, stored
function, trigger, view, prepared statement) contained several
sub-statements, and at least one of them was unsafe, there would be
one unsafeness warning per sub-statement - even for safe
sub-statements.
Fix 2:
Ensure that each type of warning is printed at most once, by
remembering throughout the execution of the statement which types
of warnings have been printed.
2009-07-22 18:16:17 +02:00
|
|
|
places and add assert to ensure correct behavior. /Sven
|
2005-12-22 06:39:02 +01:00
|
|
|
*/
|
|
|
|
case THD::STMT_QUERY_TYPE:
|
|
|
|
/*
|
2006-02-16 08:30:53 +01:00
|
|
|
The MYSQL_LOG::write() function will set the STMT_END_F flag and
|
|
|
|
flush the pending rows event if necessary.
|
BUG#39934: Slave stops for engine that only support row-based logging
General overview:
The logic for switching to row format when binlog_format=MIXED had
numerous flaws. The underlying problem was the lack of a consistent
architecture.
General purpose of this changeset:
This changeset introduces an architecture for switching to row format
when binlog_format=MIXED. It enforces the architecture where it has
to. It leaves some bugs to be fixed later. It adds extensive tests to
verify that unsafe statements work as expected and that appropriate
errors are produced by problems with the selection of binlog format.
It was not practical to split this into smaller pieces of work.
Problem 1:
To determine the logging mode, the code has to take several parameters
into account (namely: (1) the value of binlog_format; (2) the
capabilities of the engines; (3) the type of the current statement:
normal, unsafe, or row injection). These parameters may conflict in
several ways, namely:
- binlog_format=STATEMENT for a row injection
- binlog_format=STATEMENT for an unsafe statement
- binlog_format=STATEMENT for an engine only supporting row logging
- binlog_format=ROW for an engine only supporting statement logging
- statement is unsafe and engine does not support row logging
- row injection in a table that does not support statement logging
- statement modifies one table that does not support row logging and
one that does not support statement logging
Several of these conflicts were not detected, or were detected with
an inappropriate error message. The problem of BUG#39934 was that no
appropriate error message was written for the case when an engine
only supporting row logging executed a row injection with
binlog_format=ROW. However, all above cases must be handled.
Fix 1:
Introduce new error codes (sql/share/errmsg.txt). Ensure that all
conditions are detected and handled in decide_logging_format()
Problem 2:
The binlog format shall be determined once per statement, in
decide_logging_format(). It shall not be changed before or after that.
Before decide_logging_format() is called, all information necessary to
determine the logging format must be available. This principle ensures
that all unsafe statements are handled in a consistent way.
However, this principle is not followed:
thd->set_current_stmt_binlog_row_based_if_mixed() is called in several
places, including from code executing UPDATE..LIMIT,
INSERT..SELECT..LIMIT, DELETE..LIMIT, INSERT DELAYED, and
SET @@binlog_format. After Problem 1 was fixed, that caused
inconsistencies where these unsafe statements would not print the
appropriate warnings or errors for some of the conflicts.
Fix 2:
Remove calls to THD::set_current_stmt_binlog_row_based_if_mixed() from
code executed after decide_logging_format(). Compensate by calling the
set_current_stmt_unsafe() at parse time. This way, all unsafe statements
are detected by decide_logging_format().
Problem 3:
INSERT DELAYED is not unsafe: it is logged in statement format even if
binlog_format=MIXED, and no warning is printed even if
binlog_format=STATEMENT. This is BUG#45825.
Fix 3:
Made INSERT DELAYED set itself to unsafe at parse time. This allows
decide_logging_format() to detect that a warning should be printed or
the binlog_format changed.
Problem 4:
LIMIT clause were not marked as unsafe when executed inside stored
functions/triggers/views/prepared statements. This is
BUG#45785.
Fix 4:
Make statements containing the LIMIT clause marked as unsafe at
parse time, instead of at execution time. This allows propagating
unsafe-ness to the view.
2009-07-14 21:31:19 +02:00
|
|
|
*/
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
2009-11-03 20:02:56 +01:00
|
|
|
Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
|
|
|
|
suppress_use, errcode);
|
2005-12-22 06:39:02 +01:00
|
|
|
qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
|
2006-02-16 08:30:53 +01:00
|
|
|
/*
|
|
|
|
Binlog table maps will be irrelevant after a Query_log_event
|
|
|
|
(they are just removed on the slave side) so after the query
|
|
|
|
log event is written to the binary log, we pretend that no
|
|
|
|
table maps were written.
|
|
|
|
*/
|
|
|
|
int error= mysql_bin_log.write(&qinfo);
|
|
|
|
binlog_table_maps= 0;
|
|
|
|
DBUG_RETURN(error);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case THD::QUERY_TYPE_COUNT:
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
|
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
|
|
|
|
ulonglong incr)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Discrete_intervals_list::append");
|
|
|
|
/* first, see if this can be merged with previous */
|
|
|
|
if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
|
|
|
|
{
|
|
|
|
/* it cannot, so need to add a new interval */
|
|
|
|
Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
DBUG_RETURN(append(new_interval));
|
WL#3146 "less locking in auto_increment":
this is a cleanup patch for our current auto_increment handling:
new names for auto_increment variables in THD, new methods to manipulate them
(see sql_class.h), some move into handler::, causing less backup/restore
work when executing substatements.
This makes the logic hopefully clearer, less work is is needed in
mysql_insert().
By cleaning up, using different variables for different purposes (instead
of one for 3 things...), we fix those bugs, which someone may want to fix
in 5.0 too:
BUG#20339 "stored procedure using LAST_INSERT_ID() does not replicate
statement-based"
BUG#20341 "stored function inserting into one auto_increment puts bad
data in slave"
BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY UPDATE"
(now if a row is updated, LAST_INSERT_ID() will return its id)
and re-fixes:
BUG#6880 "LAST_INSERT_ID() value changes during multi-row INSERT"
(already fixed differently by Ramil in 4.1)
Test of documented behaviour of mysql_insert_id() (there was no test).
The behaviour changes introduced are:
- LAST_INSERT_ID() now returns "the first autogenerated auto_increment value
successfully inserted", instead of "the first autogenerated auto_increment
value if any row was successfully inserted", see auto_increment.test.
Same for mysql_insert_id(), see mysql_client_test.c.
- LAST_INSERT_ID() returns the id of the updated row if ON DUPLICATE KEY
UPDATE, see auto_increment.test. Same for mysql_insert_id(), see
mysql_client_test.c.
- LAST_INSERT_ID() does not change if no autogenerated value was successfully
inserted (it used to then be 0), see auto_increment.test.
- if in INSERT SELECT no autogenerated value was successfully inserted,
mysql_insert_id() now returns the id of the last inserted row (it already
did this for INSERT VALUES), see mysql_client_test.c.
- if INSERT SELECT uses LAST_INSERT_ID(X), mysql_insert_id() now returns X
(it already did this for INSERT VALUES), see mysql_client_test.c.
- NDB now behaves like other engines wrt SET INSERT_ID: with INSERT IGNORE,
the id passed in SET INSERT_ID is re-used until a row succeeds; SET INSERT_ID
influences not only the first row now.
Additionally, when unlocking a table we check that the thread is not keeping
a next_insert_id (as the table is unlocked that id is potentially out-of-date);
forgetting about this next_insert_id is done in a new
handler::ha_release_auto_increment().
Finally we prepare for engines capable of reserving finite-length intervals
of auto_increment values: we store such intervals in THD. The next step
(to be done by the replication team in 5.1) is to read those intervals from
THD and actually store them in the statement-based binary log. NDB
will be a good engine to test that.
2006-07-09 17:52:19 +02:00
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
BUG#33029 5.0 to 5.1 replication fails on dup key when inserting
using a trig in SP
For all 5.0 and up to 5.1.12 exclusive, when a stored routine or
trigger caused an INSERT into an AUTO_INCREMENT column, the
generated AUTO_INCREMENT value should not be written into the
binary log, which means if a statement does not generate
AUTO_INCREMENT value itself, there will be no Intvar event (SET
INSERT_ID) associated with it even if one of the stored routine
or trigger caused generation of such a value. And meanwhile, when
executing a stored routine or trigger, it would ignore the
INSERT_ID value even if there is a INSERT_ID value available set
by a SET INSERT_ID statement.
Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is
written into the binary log, and the value will be used if
available when executing the stored routine or trigger.
Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12
(referenced as the buggy versions in the text below), when a
statement that generates AUTO_INCREMENT value by the top
statement was executed in the body of a SP, all statements in the
SP after this statement would be treated as if they had generated
AUTO_INCREMENT by the top statement. When a statement that did
not generate AUTO_INCREMENT value by the top statement but by a
function/trigger called by it, an erroneous Intvar event would be
associated with the statement, this erroneous INSERT_ID value
wouldn't cause problem when replicating between masters and
slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID
value was not used when executing functions/triggers. But when
replicating from buggy versions to 5.1.12 or newer, which will
use the INSERT_ID value in functions/triggers, the erroneous
value will be used, which would cause duplicate entry error and
cause the slave to stop.
The patch for 5.1 fixed it to ignore the SET INSERT_ID value when
executing functions/triggers if it is replicating from a master
of buggy versions, another patch for 5.0 fixed it not to generate
the erroneous Intvar event.
2008-03-14 04:35:41 +01:00
|
|
|
bool Discrete_intervals_list::append(Discrete_interval *new_interval)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Discrete_intervals_list::append");
|
|
|
|
if (unlikely(new_interval == NULL))
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
DBUG_PRINT("info",("adding new auto_increment interval"));
|
|
|
|
if (head == NULL)
|
|
|
|
head= current= new_interval;
|
|
|
|
else
|
|
|
|
tail->next= new_interval;
|
|
|
|
tail= new_interval;
|
|
|
|
elements++;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2005-12-22 06:39:02 +01:00
|
|
|
#endif /* !defined(MYSQL_CLIENT) */
|