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
|
|
|
#ifndef INCLUDES_MYSQL_SQL_LIST_H
|
|
|
|
#define INCLUDES_MYSQL_SQL_LIST_H
|
2003-04-23 20:52:16 +02:00
|
|
|
/* Copyright (C) 2000-2003 MySQL AB
|
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 */
|
|
|
|
|
|
|
|
|
2005-05-04 15:05:56 +02:00
|
|
|
#ifdef USE_PRAGMA_INTERFACE
|
2000-07-31 21:29:14 +02:00
|
|
|
#pragma interface /* gcc class implementation */
|
|
|
|
#endif
|
|
|
|
|
2004-07-26 21:33:42 +02:00
|
|
|
/* mysql standard class memory allocator */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
class Sql_alloc
|
|
|
|
{
|
|
|
|
public:
|
2007-03-28 16:38:42 +02:00
|
|
|
static void *operator new(size_t size) throw ()
|
2002-12-08 02:19: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
|
|
|
return sql_alloc(size);
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
|
|
|
static void *operator new[](size_t size)
|
|
|
|
{
|
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 sql_alloc(size);
|
2002-12-08 02:19:03 +01:00
|
|
|
}
|
2007-03-29 08:35:28 +02:00
|
|
|
static void *operator new[](size_t size, MEM_ROOT *mem_root) throw ()
|
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 alloc_root(mem_root, size); }
|
2007-03-28 16:38:42 +02:00
|
|
|
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
|
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 alloc_root(mem_root, size); }
|
2004-01-30 08:09:42 +01:00
|
|
|
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
|
2005-02-15 01:55:44 +01:00
|
|
|
static void operator delete(void *ptr, MEM_ROOT *mem_root)
|
|
|
|
{ /* never called */ }
|
2007-02-24 03:22:34 +01:00
|
|
|
static void operator delete[](void *ptr, MEM_ROOT *mem_root)
|
|
|
|
{ /* never called */ }
|
2004-01-30 08:09:42 +01:00
|
|
|
static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); }
|
2001-08-10 16:05:54 +02:00
|
|
|
#ifdef HAVE_purify
|
|
|
|
bool dummy;
|
|
|
|
inline Sql_alloc() :dummy(0) {}
|
|
|
|
inline ~Sql_alloc() {}
|
|
|
|
#else
|
|
|
|
inline Sql_alloc() {}
|
|
|
|
inline ~Sql_alloc() {}
|
|
|
|
#endif
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
};
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2003-07-03 10:55:36 +02:00
|
|
|
Basic single linked list
|
|
|
|
Used for item and item_buffs.
|
|
|
|
All list ends with a pointer to the 'end_of_list' element, which
|
|
|
|
data pointer is a null pointer and the next pointer points to itself.
|
|
|
|
This makes it very fast to traverse lists as we don't have to
|
|
|
|
test for a specialend condition for list that can't contain a null
|
|
|
|
pointer.
|
2000-07-31 21:29:14 +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
|
|
|
|
|
|
|
/**
|
|
|
|
list_node - a node of a single-linked list.
|
|
|
|
@note We never call a destructor for instances of this class.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct list_node :public Sql_alloc
|
2001-08-02 05:29:50 +02:00
|
|
|
{
|
|
|
|
list_node *next;
|
|
|
|
void *info;
|
|
|
|
list_node(void *info_par,list_node *next_par)
|
|
|
|
:next(next_par),info(info_par)
|
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
|
|
|
{}
|
2001-08-02 05:29:50 +02:00
|
|
|
list_node() /* For end_of_list */
|
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
|
|
|
{
|
|
|
|
info= 0;
|
|
|
|
next= this;
|
|
|
|
}
|
2001-08-02 05:29:50 +02:00
|
|
|
};
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
|
2001-08-02 05:29:50 +02:00
|
|
|
extern list_node end_of_list;
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
class base_list :public Sql_alloc
|
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
protected:
|
|
|
|
list_node *first,**last;
|
|
|
|
|
|
|
|
public:
|
|
|
|
uint elements;
|
|
|
|
|
2001-08-02 05:29:50 +02:00
|
|
|
inline void empty() { elements=0; first= &end_of_list; last=&first;}
|
2000-07-31 21:29:14 +02:00
|
|
|
inline base_list() { empty(); }
|
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
|
|
|
/**
|
|
|
|
This is a shallow copy constructor that implicitly passes the ownership
|
|
|
|
from the source list to the new instance. The old instance is not
|
|
|
|
updated, so both objects end up sharing the same nodes. If one of
|
|
|
|
the instances then adds or removes a node, the other becomes out of
|
|
|
|
sync ('last' pointer), while still operational. Some old code uses and
|
|
|
|
relies on this behaviour. This logic is quite tricky: please do not use
|
|
|
|
it in any new code.
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
inline base_list(const base_list &tmp) :Sql_alloc()
|
|
|
|
{
|
2006-09-01 13:23:04 +02:00
|
|
|
elements= tmp.elements;
|
|
|
|
first= tmp.first;
|
|
|
|
last= elements ? tmp.last : &first;
|
2000-07-31 21:29:14 +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 a deep copy of the argument in memory root mem_root.
|
|
|
|
The elements themselves are copied by pointer. If you also
|
|
|
|
need to copy elements by value, you should employ
|
|
|
|
list_copy_and_replace_each_value after creating a copy.
|
|
|
|
*/
|
|
|
|
base_list(const base_list &rhs, MEM_ROOT *mem_root);
|
2002-06-13 02:20:16 +02:00
|
|
|
inline base_list(bool error) { }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool push_back(void *info)
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
if (((*last)=new list_node(info, &end_of_list)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
last= &(*last)->next;
|
|
|
|
elements++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2004-11-09 02:58:44 +01:00
|
|
|
inline bool push_back(void *info, MEM_ROOT *mem_root)
|
|
|
|
{
|
|
|
|
if (((*last)=new (mem_root) list_node(info, &end_of_list)))
|
|
|
|
{
|
|
|
|
last= &(*last)->next;
|
|
|
|
elements++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool push_front(void *info)
|
|
|
|
{
|
|
|
|
list_node *node=new list_node(info,first);
|
|
|
|
if (node)
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
if (last == &first)
|
2000-07-31 21:29:14 +02:00
|
|
|
last= &node->next;
|
|
|
|
first=node;
|
|
|
|
elements++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
void remove(list_node **prev)
|
|
|
|
{
|
|
|
|
list_node *node=(*prev)->next;
|
|
|
|
if (!--elements)
|
|
|
|
last= &first;
|
2003-11-27 02:23:52 +01:00
|
|
|
else if (last == &(*prev)->next)
|
|
|
|
last= prev;
|
|
|
|
delete *prev;
|
|
|
|
*prev=node;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-02-08 13:41:09 +01:00
|
|
|
inline void concat(base_list *list)
|
|
|
|
{
|
|
|
|
if (!list->is_empty())
|
|
|
|
{
|
|
|
|
*last= list->first;
|
|
|
|
last= list->last;
|
|
|
|
elements+= list->elements;
|
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
inline void *pop(void)
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
if (first == &end_of_list) return 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
list_node *tmp=first;
|
|
|
|
first=first->next;
|
|
|
|
if (!--elements)
|
|
|
|
last= &first;
|
|
|
|
return tmp->info;
|
|
|
|
}
|
2003-11-27 02:23:52 +01:00
|
|
|
inline void disjoin(base_list *list)
|
|
|
|
{
|
|
|
|
list_node **prev= &first;
|
|
|
|
list_node *node= first;
|
|
|
|
list_node *list_first= list->first;
|
|
|
|
elements=0;
|
|
|
|
while (node && node != list_first)
|
|
|
|
{
|
|
|
|
prev= &node->next;
|
|
|
|
node= node->next;
|
|
|
|
elements++;
|
|
|
|
}
|
|
|
|
*prev= *last;
|
|
|
|
last= prev;
|
|
|
|
}
|
2004-02-19 07:21:37 +01:00
|
|
|
inline void prepand(base_list *list)
|
|
|
|
{
|
|
|
|
if (!list->is_empty())
|
|
|
|
{
|
|
|
|
*list->last= first;
|
|
|
|
first= list->first;
|
|
|
|
elements+= list->elements;
|
|
|
|
}
|
2003-11-13 15:52:02 +01: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
|
|
|
/**
|
|
|
|
Swap two lists.
|
|
|
|
*/
|
|
|
|
inline void swap(base_list &rhs)
|
|
|
|
{
|
|
|
|
swap_variables(list_node *, first, rhs.first);
|
|
|
|
swap_variables(list_node **, last, rhs.last);
|
|
|
|
swap_variables(uint, elements, rhs.elements);
|
|
|
|
}
|
2002-06-12 23:13:12 +02:00
|
|
|
inline list_node* last_node() { return *last; }
|
|
|
|
inline list_node* first_node() { return first;}
|
2001-08-02 05:29:50 +02:00
|
|
|
inline void *head() { return first->info; }
|
|
|
|
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
|
|
|
|
inline bool is_empty() { return first == &end_of_list ; }
|
|
|
|
inline list_node *last_ref() { return &end_of_list; }
|
2000-07-31 21:29:14 +02:00
|
|
|
friend class base_list_iterator;
|
2002-06-12 23:13:12 +02:00
|
|
|
friend class error_list;
|
2002-06-13 02:20:16 +02:00
|
|
|
friend class error_list_iterator;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-05-15 22:56:45 +02:00
|
|
|
#ifdef LIST_EXTRA_DEBUG
|
|
|
|
/*
|
|
|
|
Check list invariants and print results into trace. Invariants are:
|
|
|
|
- (*last) points to end_of_list
|
|
|
|
- There are no NULLs in the list.
|
|
|
|
- base_list::elements is the number of elements in the list.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
check_list()
|
|
|
|
name Name to print to trace file
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
1 The list is Ok.
|
|
|
|
0 List invariants are not met.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool check_list(const char *name)
|
|
|
|
{
|
|
|
|
base_list *list= this;
|
|
|
|
list_node *node= first;
|
|
|
|
uint cnt= 0;
|
|
|
|
|
|
|
|
while (node->next != &end_of_list)
|
|
|
|
{
|
|
|
|
if (!node->info)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("list_invariants",("%s: error: NULL element in the list",
|
|
|
|
name));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
node= node->next;
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
if (last != &(node->next))
|
|
|
|
{
|
|
|
|
DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (cnt+1 != elements)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
DBUG_PRINT("list_invariants", ("%s: list is ok", name));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif // LIST_EXTRA_DEBUG
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
protected:
|
|
|
|
void after(void *info,list_node *node)
|
|
|
|
{
|
|
|
|
list_node *new_node=new list_node(info,node->next);
|
|
|
|
node->next=new_node;
|
|
|
|
elements++;
|
|
|
|
if (last == &(node->next))
|
|
|
|
last= &new_node->next;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class base_list_iterator
|
|
|
|
{
|
2003-01-25 01:25:52 +01:00
|
|
|
protected:
|
2000-07-31 21:29:14 +02:00
|
|
|
base_list *list;
|
2001-08-02 05:29:50 +02:00
|
|
|
list_node **el,**prev,*current;
|
2003-01-25 01:25:52 +01:00
|
|
|
void sublist(base_list &ls, uint elm)
|
|
|
|
{
|
|
|
|
ls.first= *el;
|
|
|
|
ls.last= list->last;
|
|
|
|
ls.elements= elm;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
public:
|
2005-11-28 20:57:50 +01:00
|
|
|
base_list_iterator()
|
|
|
|
:list(0), el(0), prev(0), current(0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{}
|
2003-01-25 01:25:52 +01:00
|
|
|
|
2005-11-28 20:57:50 +01:00
|
|
|
base_list_iterator(base_list &list_par)
|
|
|
|
{ init(list_par); }
|
|
|
|
|
|
|
|
inline void init(base_list &list_par)
|
|
|
|
{
|
|
|
|
list= &list_par;
|
|
|
|
el= &list_par.first;
|
|
|
|
prev= 0;
|
|
|
|
current= 0;
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
inline void *next(void)
|
|
|
|
{
|
|
|
|
prev=el;
|
2001-08-02 05:29:50 +02:00
|
|
|
current= *el;
|
2000-07-31 21:29:14 +02:00
|
|
|
el= ¤t->next;
|
|
|
|
return current->info;
|
|
|
|
}
|
2001-08-02 05:29:50 +02:00
|
|
|
inline void *next_fast(void)
|
|
|
|
{
|
|
|
|
list_node *tmp;
|
|
|
|
tmp= *el;
|
|
|
|
el= &tmp->next;
|
|
|
|
return tmp->info;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
inline void rewind(void)
|
|
|
|
{
|
|
|
|
el= &list->first;
|
|
|
|
}
|
2001-08-02 05:29:50 +02:00
|
|
|
inline void *replace(void *element)
|
2000-07-31 21:29:14 +02:00
|
|
|
{ // Return old element
|
|
|
|
void *tmp=current->info;
|
2003-06-04 17:28:51 +02:00
|
|
|
DBUG_ASSERT(current->info != 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
current->info=element;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
void *replace(base_list &new_list)
|
|
|
|
{
|
|
|
|
void *ret_value=current->info;
|
2001-08-02 05:29:50 +02:00
|
|
|
if (!new_list.is_empty())
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
*new_list.last=current->next;
|
|
|
|
current->info=new_list.first->info;
|
|
|
|
current->next=new_list.first->next;
|
2003-04-16 08:08:21 +02:00
|
|
|
if ((list->last == ¤t->next) && (new_list.elements > 1))
|
|
|
|
list->last= new_list.last;
|
2000-07-31 21:29:14 +02:00
|
|
|
list->elements+=new_list.elements-1;
|
|
|
|
}
|
|
|
|
return ret_value; // return old element
|
|
|
|
}
|
|
|
|
inline void remove(void) // Remove current
|
|
|
|
{
|
|
|
|
list->remove(prev);
|
|
|
|
el=prev;
|
|
|
|
current=0; // Safeguard
|
|
|
|
}
|
|
|
|
void after(void *element) // Insert element after current
|
|
|
|
{
|
|
|
|
list->after(element,current);
|
|
|
|
current=current->next;
|
|
|
|
el= ¤t->next;
|
|
|
|
}
|
|
|
|
inline void **ref(void) // Get reference pointer
|
|
|
|
{
|
|
|
|
return ¤t->info;
|
|
|
|
}
|
|
|
|
inline bool is_last(void)
|
|
|
|
{
|
2001-08-02 05:29:50 +02:00
|
|
|
return el == &list->last_ref()->next;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-06-12 23:13:12 +02:00
|
|
|
friend class error_list_iterator;
|
2000-07-31 21:29:14 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template <class T> class List :public base_list
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
inline List() :base_list() {}
|
|
|
|
inline List(const List<T> &tmp) :base_list(tmp) {}
|
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
|
|
|
inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
|
|
|
|
base_list(tmp, mem_root) {}
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool push_back(T *a) { return base_list::push_back(a); }
|
2004-11-09 02:58:44 +01:00
|
|
|
inline bool push_back(T *a, MEM_ROOT *mem_root)
|
|
|
|
{ return base_list::push_back(a, mem_root); }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool push_front(T *a) { return base_list::push_front(a); }
|
|
|
|
inline T* head() {return (T*) base_list::head(); }
|
|
|
|
inline T** head_ref() {return (T**) base_list::head_ref(); }
|
|
|
|
inline T* pop() {return (T*) base_list::pop(); }
|
2003-12-02 03:19:31 +01:00
|
|
|
inline void concat(List<T> *list) { base_list::concat(list); }
|
|
|
|
inline void disjoin(List<T> *list) { base_list::disjoin(list); }
|
2004-02-19 07:21:37 +01:00
|
|
|
inline void prepand(List<T> *list) { base_list::prepand(list); }
|
2000-07-31 21:29:14 +02:00
|
|
|
void delete_elements(void)
|
|
|
|
{
|
|
|
|
list_node *element,*next;
|
2001-08-02 05:29:50 +02:00
|
|
|
for (element=first; element != &end_of_list; element=next)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
next=element->next;
|
|
|
|
delete (T*) element->info;
|
|
|
|
}
|
|
|
|
empty();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <class T> class List_iterator :public base_list_iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
List_iterator(List<T> &a) : base_list_iterator(a) {}
|
2005-11-28 20:57:50 +01:00
|
|
|
List_iterator() : base_list_iterator() {}
|
|
|
|
inline void init(List<T> &a) { base_list_iterator::init(a); }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
|
|
|
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
|
|
|
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
2003-11-27 02:23:52 +01:00
|
|
|
inline void rewind(void) { base_list_iterator::rewind(); }
|
|
|
|
inline void remove() { base_list_iterator::remove(); }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline void after(T *a) { base_list_iterator::after(a); }
|
|
|
|
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
|
2001-08-02 05:29:50 +02:00
|
|
|
};
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
|
2001-08-02 05:29:50 +02:00
|
|
|
template <class T> class List_iterator_fast :public base_list_iterator
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
inline T *replace(T *a) { return (T*) 0; }
|
|
|
|
inline T *replace(List<T> &a) { return (T*) 0; }
|
|
|
|
inline void remove(void) { }
|
|
|
|
inline void after(T *a) { }
|
|
|
|
inline T** ref(void) { return (T**) 0; }
|
|
|
|
|
|
|
|
public:
|
2004-02-19 13:41:32 +01:00
|
|
|
inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
|
2005-11-28 20:57:50 +01:00
|
|
|
inline List_iterator_fast() : base_list_iterator() {}
|
|
|
|
inline void init(List<T> &a) { base_list_iterator::init(a); }
|
2001-08-02 05:29:50 +02:00
|
|
|
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
|
|
|
|
inline void rewind(void) { base_list_iterator::rewind(); }
|
2003-11-28 11:18:13 +01:00
|
|
|
void sublist(List<T> &list_arg, uint el_arg)
|
2003-01-25 01:25:52 +01:00
|
|
|
{
|
2003-11-28 11:18:13 +01:00
|
|
|
base_list_iterator::sublist(list_arg, el_arg);
|
2003-01-25 01:25:52 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2003-07-03 10:55:36 +02:00
|
|
|
A simple intrusive list which automaticly removes element from list
|
|
|
|
on delete (for THD element)
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
struct ilink
|
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
struct ilink **prev,*next;
|
2001-03-25 08:33:26 +02:00
|
|
|
static void *operator new(size_t size)
|
|
|
|
{
|
|
|
|
return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE));
|
|
|
|
}
|
|
|
|
static void operator delete(void* ptr_arg, size_t size)
|
|
|
|
{
|
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_arg, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
|
2001-03-25 08:33:26 +02:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
inline ilink()
|
|
|
|
{
|
|
|
|
prev=0; next=0;
|
|
|
|
}
|
|
|
|
inline void unlink()
|
|
|
|
{
|
|
|
|
/* Extra tests because element doesn't have to be linked */
|
|
|
|
if (prev) *prev= next;
|
|
|
|
if (next) next->prev=prev;
|
|
|
|
prev=0 ; next=0;
|
|
|
|
}
|
|
|
|
virtual ~ilink() { unlink(); } /*lint -e1740 */
|
|
|
|
};
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
|
2005-12-22 06:39:02 +01:00
|
|
|
/* Needed to be able to have an I_List of char* strings in mysqld.cc. */
|
|
|
|
|
|
|
|
class i_string: public ilink
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
const char* ptr;
|
|
|
|
i_string():ptr(0) { }
|
|
|
|
i_string(const char* s) : ptr(s) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* needed for linked list of two strings for replicate-rewrite-db */
|
|
|
|
class i_string_pair: public ilink
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
const char* key;
|
|
|
|
const char* val;
|
|
|
|
i_string_pair():key(0),val(0) { }
|
|
|
|
i_string_pair(const char* key_arg, const char* val_arg) :
|
|
|
|
key(key_arg),val(val_arg) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
template <class T> class I_List_iterator;
|
|
|
|
|
2005-08-22 17:23:01 +02:00
|
|
|
/*
|
|
|
|
WARNING: copy constructor of this class does not create a usable
|
|
|
|
copy, as its members may point at each other.
|
|
|
|
*/
|
|
|
|
|
2003-07-03 10:55:36 +02:00
|
|
|
class base_ilist
|
|
|
|
{
|
2005-08-22 17:23:01 +02:00
|
|
|
public:
|
2000-07-31 21:29:14 +02:00
|
|
|
struct ilink *first,last;
|
2003-05-19 10:09:24 +02:00
|
|
|
inline void empty() { first= &last; last.prev= &first; }
|
|
|
|
base_ilist() { empty(); }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool is_empty() { return first == &last; }
|
|
|
|
inline void append(ilink *a)
|
|
|
|
{
|
|
|
|
first->prev= &a->next;
|
|
|
|
a->next=first; a->prev= &first; first=a;
|
|
|
|
}
|
|
|
|
inline void push_back(ilink *a)
|
|
|
|
{
|
|
|
|
*last.prev= a;
|
|
|
|
a->next= &last;
|
|
|
|
a->prev= last.prev;
|
|
|
|
last.prev= &a->next;
|
|
|
|
}
|
|
|
|
inline struct ilink *get()
|
|
|
|
{
|
|
|
|
struct ilink *first_link=first;
|
|
|
|
if (first_link == &last)
|
|
|
|
return 0;
|
|
|
|
first_link->unlink(); // Unlink from list
|
|
|
|
return first_link;
|
|
|
|
}
|
2004-03-04 17:16:10 +01:00
|
|
|
inline struct ilink *head()
|
|
|
|
{
|
|
|
|
return (first != &last) ? first : 0;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
friend class base_list_iterator;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class base_ilist_iterator
|
|
|
|
{
|
|
|
|
base_ilist *list;
|
|
|
|
struct ilink **el,*current;
|
|
|
|
public:
|
|
|
|
base_ilist_iterator(base_ilist &list_par) :list(&list_par),
|
|
|
|
el(&list_par.first),current(0) {}
|
|
|
|
void *next(void)
|
|
|
|
{
|
|
|
|
/* This is coded to allow push_back() while iterating */
|
|
|
|
current= *el;
|
|
|
|
if (current == &list->last) return 0;
|
|
|
|
el= ¤t->next;
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <class T>
|
2003-07-03 10:55:36 +02:00
|
|
|
class I_List :private base_ilist
|
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
public:
|
|
|
|
I_List() :base_ilist() {}
|
2003-05-21 20:39:58 +02:00
|
|
|
inline void empty() { base_ilist::empty(); }
|
2000-07-31 21:29:14 +02:00
|
|
|
inline bool is_empty() { return base_ilist::is_empty(); }
|
|
|
|
inline void append(T* a) { base_ilist::append(a); }
|
|
|
|
inline void push_back(T* a) { base_ilist::push_back(a); }
|
|
|
|
inline T* get() { return (T*) base_ilist::get(); }
|
2004-03-04 17:16:10 +01:00
|
|
|
inline T* head() { return (T*) base_ilist::head(); }
|
2000-07-31 21:29:14 +02:00
|
|
|
#ifndef _lint
|
|
|
|
friend class I_List_iterator<T>;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <class T> class I_List_iterator :public base_ilist_iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
I_List_iterator(I_List<T> &a) : base_ilist_iterator(a) {}
|
|
|
|
inline T* operator++(int) { return (T*) base_ilist_iterator::next(); }
|
|
|
|
};
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
Make a deep copy of each list element.
|
|
|
|
|
|
|
|
@note A template function and not a template method of class List
|
|
|
|
is employed because of explicit template instantiation:
|
|
|
|
in server code there are explicit instantiations of List<T> and
|
|
|
|
an explicit instantiation of a template requires that any method
|
|
|
|
of the instantiated class used in the template can be resolved.
|
|
|
|
Evidently not all template arguments have clone() method with
|
|
|
|
the right signature.
|
|
|
|
|
|
|
|
@return You must query the error state in THD for out-of-memory
|
|
|
|
situation after calling this function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
list_copy_and_replace_each_value(List<T> &list, MEM_ROOT *mem_root)
|
|
|
|
{
|
|
|
|
/* Make a deep copy of each element */
|
|
|
|
List_iterator<T> it(list);
|
|
|
|
T *el;
|
|
|
|
while ((el= it++))
|
|
|
|
it.replace(el->clone(mem_root));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // INCLUDES_MYSQL_SQL_LIST_H
|