2011-07-04 01:25:49 +02:00
|
|
|
/*
|
|
|
|
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
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.
|
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.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2011-07-04 01:25:49 +02:00
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/* drop and alter of tables */
|
|
|
|
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_priv.h"
|
|
|
|
#include "unireg.h"
|
2009-12-08 10:57:07 +01:00
|
|
|
#include "debug_sync.h"
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_table.h"
|
|
|
|
#include "sql_rename.h" // do_rename
|
|
|
|
#include "sql_parse.h" // test_if_data_home_dir
|
|
|
|
#include "sql_cache.h" // query_cache_*
|
2010-08-31 12:03:36 +02:00
|
|
|
#include "sql_base.h" // open_table_uncached, lock_table_names
|
2010-11-11 18:11:05 +01:00
|
|
|
#include "lock.h" // mysql_unlock_tables
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "strfunc.h" // find_type2, find_set
|
2010-05-25 22:01:38 +02:00
|
|
|
#include "sql_view.h" // view_checksum
|
|
|
|
#include "sql_truncate.h" // regenerate_locked_table
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_partition.h" // mem_alloc_error,
|
|
|
|
// generate_partition_syntax,
|
|
|
|
// partition_info
|
2010-07-01 15:53:46 +02:00
|
|
|
#include "sql_db.h" // load_db_opt_by_name
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_time.h" // make_truncated_value_warning
|
|
|
|
#include "records.h" // init_read_record, end_read_record
|
|
|
|
#include "filesort.h" // filesort_free_buffers
|
|
|
|
#include "sql_select.h" // setup_order,
|
|
|
|
// make_unireg_sortorder
|
|
|
|
#include "sql_handler.h" // mysql_ha_rm_tables
|
|
|
|
#include "discover.h" // readfrm
|
|
|
|
#include "my_pthread.h" // pthread_mutex_t
|
|
|
|
#include "log_event.h" // Query_log_event
|
2002-09-19 16:49:41 +02:00
|
|
|
#include <hash.h>
|
2000-07-31 21:29:14 +02:00
|
|
|
#include <myisam.h>
|
2003-04-27 21:12:08 +02:00
|
|
|
#include <my_dir.h>
|
2005-07-19 18:06:49 +02:00
|
|
|
#include "sp_head.h"
|
2009-12-29 13:19:05 +01:00
|
|
|
#include "sp.h"
|
2005-07-19 18:06:49 +02:00
|
|
|
#include "sql_trigger.h"
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_parse.h"
|
2005-12-22 06:39:02 +01:00
|
|
|
#include "sql_show.h"
|
2009-12-03 19:37:38 +01:00
|
|
|
#include "transaction.h"
|
2010-05-25 22:01:38 +02:00
|
|
|
#include "datadict.h" // dd_frm_type()
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
#ifdef __WIN__
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
|
2004-09-07 16:56:31 +02:00
|
|
|
const char *primary_key_name="PRIMARY";
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
|
|
|
|
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
|
|
|
|
static int copy_data_between_tables(TABLE *from,TABLE *to,
|
2007-06-10 12:43:57 +02:00
|
|
|
List<Create_field> &create, bool ignore,
|
2004-04-08 16:56:45 +02:00
|
|
|
uint order_num, ORDER *order,
|
2006-12-01 11:37:33 +01:00
|
|
|
ha_rows *copied,ha_rows *deleted,
|
2007-05-23 11:46:10 +02:00
|
|
|
enum enum_enable_or_disable keys_onoff,
|
|
|
|
bool error_if_not_empty);
|
2006-12-01 11:37:33 +01:00
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
|
2007-04-16 18:16:17 +02:00
|
|
|
static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
|
2008-03-23 13:29:35 +01:00
|
|
|
static int
|
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
|
|
|
mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
|
|
|
Alter_info *alter_info,
|
|
|
|
bool tmp_table,
|
|
|
|
uint *db_options,
|
|
|
|
handler *file, KEY **key_info_buffer,
|
|
|
|
uint *key_count, int select_field_count);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
|
2009-06-02 11:07:17 +02:00
|
|
|
/**
|
|
|
|
@brief Helper function for explain_filename
|
2009-09-25 11:26:49 +02:00
|
|
|
@param thd Thread handle
|
|
|
|
@param to_p Explained name in system_charset_info
|
|
|
|
@param end_p End of the to_p buffer
|
|
|
|
@param name Name to be converted
|
|
|
|
@param name_len Length of the name, in bytes
|
2009-06-02 11:07:17 +02:00
|
|
|
*/
|
2009-09-25 11:26:49 +02:00
|
|
|
static char* add_identifier(THD* thd, char *to_p, const char * end_p,
|
|
|
|
const char* name, uint name_len)
|
2009-06-02 11:07:17 +02:00
|
|
|
{
|
|
|
|
uint res;
|
|
|
|
uint errors;
|
|
|
|
const char *conv_name;
|
|
|
|
char tmp_name[FN_REFLEN];
|
|
|
|
char conv_string[FN_REFLEN];
|
2009-09-25 11:26:49 +02:00
|
|
|
int quote;
|
2009-06-02 11:07:17 +02:00
|
|
|
|
|
|
|
DBUG_ENTER("add_identifier");
|
|
|
|
if (!name[name_len])
|
|
|
|
conv_name= name;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strnmov(tmp_name, name, name_len);
|
|
|
|
tmp_name[name_len]= 0;
|
|
|
|
conv_name= tmp_name;
|
|
|
|
}
|
|
|
|
res= strconvert(&my_charset_filename, conv_name, system_charset_info,
|
|
|
|
conv_string, FN_REFLEN, &errors);
|
|
|
|
if (!res || errors)
|
2009-08-07 15:08:32 +02:00
|
|
|
{
|
|
|
|
DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors));
|
2009-06-02 11:07:17 +02:00
|
|
|
conv_name= name;
|
2009-08-07 15:08:32 +02:00
|
|
|
}
|
2009-06-02 11:07:17 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
|
|
|
|
conv_name= conv_string;
|
|
|
|
}
|
|
|
|
|
2009-09-25 11:26:49 +02:00
|
|
|
quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"';
|
|
|
|
|
|
|
|
if (quote != EOF && (end_p - to_p > 2))
|
2009-08-07 15:08:32 +02:00
|
|
|
{
|
2009-09-25 11:26:49 +02:00
|
|
|
*(to_p++)= (char) quote;
|
2009-08-07 15:08:32 +02:00
|
|
|
while (*conv_name && (end_p - to_p - 1) > 0)
|
|
|
|
{
|
|
|
|
uint length= my_mbcharlen(system_charset_info, *conv_name);
|
|
|
|
if (!length)
|
|
|
|
length= 1;
|
2009-09-25 11:26:49 +02:00
|
|
|
if (length == 1 && *conv_name == (char) quote)
|
2009-08-07 15:08:32 +02:00
|
|
|
{
|
|
|
|
if ((end_p - to_p) < 3)
|
|
|
|
break;
|
2009-09-25 11:26:49 +02:00
|
|
|
*(to_p++)= (char) quote;
|
2009-08-07 15:08:32 +02:00
|
|
|
*(to_p++)= *(conv_name++);
|
|
|
|
}
|
2009-09-02 12:22:47 +02:00
|
|
|
else if (((long) length) < (end_p - to_p))
|
2009-08-07 15:08:32 +02:00
|
|
|
{
|
|
|
|
to_p= strnmov(to_p, conv_name, length);
|
|
|
|
conv_name+= length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break; /* string already filled */
|
|
|
|
}
|
2009-09-25 11:26:49 +02:00
|
|
|
if (end_p > to_p) {
|
|
|
|
*(to_p++)= (char) quote;
|
|
|
|
if (end_p > to_p)
|
|
|
|
*to_p= 0; /* terminate by NUL, but do not include it in the count */
|
|
|
|
}
|
2009-08-07 15:08:32 +02:00
|
|
|
}
|
2009-06-02 11:07:17 +02:00
|
|
|
else
|
2009-08-07 15:08:32 +02:00
|
|
|
to_p= strnmov(to_p, conv_name, end_p - to_p);
|
|
|
|
DBUG_RETURN(to_p);
|
2009-06-02 11:07:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Explain a path name by split it to database, table etc.
|
|
|
|
|
|
|
|
@details Break down the path name to its logic parts
|
|
|
|
(database, table, partition, subpartition).
|
|
|
|
filename_to_tablename cannot be used on partitions, due to the #P# part.
|
|
|
|
There can be up to 6 '#', #P# for partition, #SP# for subpartition
|
|
|
|
and #TMP# or #REN# for temporary or renamed partitions.
|
|
|
|
This should be used when something should be presented to a user in a
|
|
|
|
diagnostic, error etc. when it would be useful to know what a particular
|
|
|
|
file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc.
|
|
|
|
|
2009-09-25 11:26:49 +02:00
|
|
|
@param thd Thread handle
|
2009-06-02 11:07:17 +02:00
|
|
|
@param from Path name in my_charset_filename
|
|
|
|
Null terminated in my_charset_filename, normalized
|
|
|
|
to use '/' as directory separation character.
|
|
|
|
@param to Explained name in system_charset_info
|
|
|
|
@param to_length Size of to buffer
|
|
|
|
@param explain_mode Requested output format.
|
|
|
|
EXPLAIN_ALL_VERBOSE ->
|
|
|
|
[Database `db`, ]Table `tbl`[,[ Temporary| Renamed]
|
|
|
|
Partition `p` [, Subpartition `sp`]]
|
|
|
|
EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl`
|
|
|
|
[[ Temporary| Renamed] Partition `p`
|
|
|
|
[, Subpartition `sp`]]
|
|
|
|
EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |*
|
|
|
|
[,[ Temporary| Renamed] Partition `p`
|
|
|
|
[, Subpartition `sp`]] *|
|
|
|
|
(| is really a /, and it is all in one line)
|
|
|
|
|
|
|
|
@retval Length of returned string
|
|
|
|
*/
|
|
|
|
|
2009-09-25 11:26:49 +02:00
|
|
|
uint explain_filename(THD* thd,
|
|
|
|
const char *from,
|
2009-06-02 11:07:17 +02:00
|
|
|
char *to,
|
|
|
|
uint to_length,
|
|
|
|
enum_explain_filename_mode explain_mode)
|
|
|
|
{
|
|
|
|
uint res= 0;
|
|
|
|
char *to_p= to;
|
|
|
|
char *end_p= to_p + to_length;
|
|
|
|
const char *db_name= NULL;
|
|
|
|
int db_name_len= 0;
|
|
|
|
const char *table_name;
|
|
|
|
int table_name_len= 0;
|
|
|
|
const char *part_name= NULL;
|
|
|
|
int part_name_len= 0;
|
|
|
|
const char *subpart_name= NULL;
|
|
|
|
int subpart_name_len= 0;
|
|
|
|
enum enum_file_name_type {NORMAL, TEMP, RENAMED} name_type= NORMAL;
|
|
|
|
const char *tmp_p;
|
|
|
|
DBUG_ENTER("explain_filename");
|
|
|
|
DBUG_PRINT("enter", ("from '%s'", from));
|
|
|
|
tmp_p= from;
|
|
|
|
table_name= from;
|
|
|
|
/*
|
|
|
|
If '/' then take last directory part as database.
|
|
|
|
'/' is the directory separator, not FN_LIB_CHAR
|
|
|
|
*/
|
|
|
|
while ((tmp_p= strchr(tmp_p, '/')))
|
|
|
|
{
|
|
|
|
db_name= table_name;
|
|
|
|
/* calculate the length */
|
|
|
|
db_name_len= tmp_p - db_name;
|
|
|
|
tmp_p++;
|
|
|
|
table_name= tmp_p;
|
|
|
|
}
|
|
|
|
tmp_p= table_name;
|
|
|
|
while (!res && (tmp_p= strchr(tmp_p, '#')))
|
|
|
|
{
|
|
|
|
tmp_p++;
|
|
|
|
switch (tmp_p[0]) {
|
|
|
|
case 'P':
|
|
|
|
case 'p':
|
|
|
|
if (tmp_p[1] == '#')
|
|
|
|
part_name= tmp_p + 2;
|
|
|
|
else
|
|
|
|
res= 1;
|
|
|
|
tmp_p+= 2;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
case 's':
|
|
|
|
if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#')
|
|
|
|
{
|
|
|
|
part_name_len= tmp_p - part_name - 1;
|
|
|
|
subpart_name= tmp_p + 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
res= 2;
|
|
|
|
tmp_p+= 3;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
case 't':
|
|
|
|
if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
|
|
|
|
(tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
|
|
|
|
tmp_p[3] == '#' && !tmp_p[4])
|
|
|
|
name_type= TEMP;
|
|
|
|
else
|
|
|
|
res= 3;
|
|
|
|
tmp_p+= 4;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
case 'r':
|
|
|
|
if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
|
|
|
|
(tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
|
|
|
|
tmp_p[3] == '#' && !tmp_p[4])
|
|
|
|
name_type= RENAMED;
|
|
|
|
else
|
|
|
|
res= 4;
|
|
|
|
tmp_p+= 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
res= 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
/* Better to give something back if we fail parsing, than nothing at all */
|
|
|
|
DBUG_PRINT("info", ("Error in explain_filename: %u", res));
|
|
|
|
sql_print_warning("Invalid (old?) table or database name '%s'", from);
|
|
|
|
DBUG_RETURN(my_snprintf(to, to_length,
|
|
|
|
"<result %u when explaining filename '%s'>",
|
|
|
|
res, from));
|
|
|
|
}
|
|
|
|
if (part_name)
|
|
|
|
{
|
|
|
|
table_name_len= part_name - table_name - 3;
|
|
|
|
if (subpart_name)
|
|
|
|
subpart_name_len= strlen(subpart_name);
|
|
|
|
else
|
|
|
|
part_name_len= strlen(part_name);
|
|
|
|
if (name_type != NORMAL)
|
|
|
|
{
|
|
|
|
if (subpart_name)
|
|
|
|
subpart_name_len-= 5;
|
|
|
|
else
|
|
|
|
part_name_len-= 5;
|
|
|
|
}
|
|
|
|
}
|
2009-08-07 15:08:32 +02:00
|
|
|
else
|
|
|
|
table_name_len= strlen(table_name);
|
2009-06-02 11:07:17 +02:00
|
|
|
if (db_name)
|
|
|
|
{
|
|
|
|
if (explain_mode == EXPLAIN_ALL_VERBOSE)
|
|
|
|
{
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME),
|
|
|
|
end_p - to_p);
|
2009-08-07 15:08:32 +02:00
|
|
|
*(to_p++)= ' ';
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
|
2009-06-02 11:07:17 +02:00
|
|
|
to_p= strnmov(to_p, ", ", end_p - to_p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
|
2009-06-02 11:07:17 +02:00
|
|
|
to_p= strnmov(to_p, ".", end_p - to_p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (explain_mode == EXPLAIN_ALL_VERBOSE)
|
2009-08-07 15:08:32 +02:00
|
|
|
{
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p);
|
2009-08-07 15:08:32 +02:00
|
|
|
*(to_p++)= ' ';
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
|
2009-08-07 15:08:32 +02:00
|
|
|
}
|
2009-06-02 11:07:17 +02:00
|
|
|
else
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
|
2009-06-02 11:07:17 +02:00
|
|
|
if (part_name)
|
|
|
|
{
|
2009-09-25 11:26:49 +02:00
|
|
|
if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
|
2009-06-02 11:07:17 +02:00
|
|
|
to_p= strnmov(to_p, " /* ", end_p - to_p);
|
|
|
|
else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE)
|
|
|
|
to_p= strnmov(to_p, " ", end_p - to_p);
|
|
|
|
else
|
|
|
|
to_p= strnmov(to_p, ", ", end_p - to_p);
|
|
|
|
if (name_type != NORMAL)
|
|
|
|
{
|
|
|
|
if (name_type == TEMP)
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
|
|
|
|
end_p - to_p);
|
2009-06-02 11:07:17 +02:00
|
|
|
else
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME),
|
|
|
|
end_p - to_p);
|
2009-06-02 11:07:17 +02:00
|
|
|
to_p= strnmov(to_p, " ", end_p - to_p);
|
|
|
|
}
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME),
|
|
|
|
end_p - to_p);
|
2009-08-07 15:08:32 +02:00
|
|
|
*(to_p++)= ' ';
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len);
|
2009-06-02 11:07:17 +02:00
|
|
|
if (subpart_name)
|
|
|
|
{
|
|
|
|
to_p= strnmov(to_p, ", ", end_p - to_p);
|
2010-02-10 10:47:14 +01:00
|
|
|
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME),
|
|
|
|
end_p - to_p);
|
2009-08-07 15:08:32 +02:00
|
|
|
*(to_p++)= ' ';
|
2009-09-25 11:26:49 +02:00
|
|
|
to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len);
|
2009-06-02 11:07:17 +02:00
|
|
|
}
|
2009-09-25 11:26:49 +02:00
|
|
|
if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
|
2009-06-02 11:07:17 +02:00
|
|
|
to_p= strnmov(to_p, " */", end_p - to_p);
|
|
|
|
}
|
|
|
|
DBUG_PRINT("exit", ("to '%s'", to));
|
|
|
|
DBUG_RETURN(to_p - to);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
/*
|
|
|
|
Translate a file name to a table name (WL #1324).
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
filename_to_tablename()
|
|
|
|
from The file name in my_charset_filename.
|
|
|
|
to OUT The table name in system_charset_info.
|
|
|
|
to_length The size of the table name buffer.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
Table name length.
|
|
|
|
*/
|
|
|
|
|
2010-11-22 15:08:51 +01:00
|
|
|
uint filename_to_tablename(const char *from, char *to, uint to_length
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
, bool stay_quiet
|
|
|
|
#endif /* DBUG_OFF */
|
|
|
|
)
|
2005-12-31 09:34:39 +01:00
|
|
|
{
|
2006-08-02 17:57:06 +02:00
|
|
|
uint errors;
|
2009-02-13 17:41:47 +01:00
|
|
|
size_t res;
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_ENTER("filename_to_tablename");
|
|
|
|
DBUG_PRINT("enter", ("from '%s'", from));
|
|
|
|
|
|
|
|
if (!memcmp(from, tmp_file_prefix, tmp_file_prefix_length))
|
2005-12-31 09:34:39 +01:00
|
|
|
{
|
2006-08-02 17:57:06 +02:00
|
|
|
/* Temporary table name. */
|
|
|
|
res= (strnmov(to, from, to_length) - to);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res= strconvert(&my_charset_filename, from,
|
|
|
|
system_charset_info, to, to_length, &errors);
|
|
|
|
if (errors) // Old 5.0 name
|
|
|
|
{
|
|
|
|
res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
|
|
|
|
to);
|
2010-11-22 15:08:51 +01:00
|
|
|
#ifndef DBUG_OFF
|
|
|
|
if (!stay_quiet) {
|
|
|
|
#endif /* DBUG_OFF */
|
|
|
|
sql_print_error("Invalid (old?) table or database name '%s'", from);
|
|
|
|
#ifndef DBUG_OFF
|
|
|
|
}
|
|
|
|
#endif /* DBUG_OFF */
|
2006-08-02 17:57:06 +02:00
|
|
|
/*
|
|
|
|
TODO: add a stored procedure for fix table and database names,
|
|
|
|
and mention its name in error log.
|
|
|
|
*/
|
|
|
|
}
|
2005-12-31 09:34:39 +01:00
|
|
|
}
|
2006-08-02 17:57:06 +02:00
|
|
|
|
|
|
|
DBUG_PRINT("exit", ("to '%s'", to));
|
|
|
|
DBUG_RETURN(res);
|
2005-12-31 09:34:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-21 20:47:32 +02:00
|
|
|
/**
|
|
|
|
Check if given string begins with "#mysql50#" prefix
|
|
|
|
|
|
|
|
@param name string to check cut
|
|
|
|
|
|
|
|
@retval
|
|
|
|
FALSE no prefix found
|
|
|
|
@retval
|
|
|
|
TRUE prefix found
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool check_mysql50_prefix(const char *name)
|
|
|
|
{
|
|
|
|
return (name[0] == '#' &&
|
|
|
|
!strncmp(name, MYSQL50_TABLE_NAME_PREFIX,
|
|
|
|
MYSQL50_TABLE_NAME_PREFIX_LENGTH));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-14 15:50:51 +01:00
|
|
|
/**
|
|
|
|
Check if given string begins with "#mysql50#" prefix, cut it if so.
|
|
|
|
|
|
|
|
@param from string to check and cut
|
|
|
|
@param to[out] buffer for result string
|
|
|
|
@param to_length its size
|
|
|
|
|
|
|
|
@retval
|
|
|
|
0 no prefix found
|
|
|
|
@retval
|
|
|
|
non-0 result string length
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length)
|
|
|
|
{
|
2010-05-21 20:47:32 +02:00
|
|
|
if (check_mysql50_prefix(from))
|
2009-01-14 15:50:51 +01:00
|
|
|
return (uint) (strmake(to, from + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
|
|
|
|
to_length - 1) - to);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
/*
|
|
|
|
Translate a table name to a file name (WL #1324).
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
tablename_to_filename()
|
|
|
|
from The table name in system_charset_info.
|
|
|
|
to OUT The file name in my_charset_filename.
|
|
|
|
to_length The size of the file name buffer.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
File name length.
|
|
|
|
*/
|
|
|
|
|
2005-12-31 09:34:39 +01:00
|
|
|
uint tablename_to_filename(const char *from, char *to, uint to_length)
|
|
|
|
{
|
2006-04-11 15:16:14 +02:00
|
|
|
uint errors, length;
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_ENTER("tablename_to_filename");
|
|
|
|
DBUG_PRINT("enter", ("from '%s'", from));
|
|
|
|
|
2009-01-14 15:50:51 +01:00
|
|
|
if ((length= check_n_cut_mysql50_prefix(from, to, to_length)))
|
2000-11-18 01:15:06 +01:00
|
|
|
{
|
2010-05-04 16:03:28 +02:00
|
|
|
/*
|
|
|
|
Check if the name supplied is a valid mysql 5.0 name and
|
|
|
|
make the name a zero length string if it's not.
|
|
|
|
Note that just returning zero length is not enough :
|
|
|
|
a lot of places don't check the return value and expect
|
|
|
|
a zero terminated string.
|
|
|
|
*/
|
|
|
|
if (check_table_name(to, length, TRUE))
|
2000-11-04 21:58:07 +01:00
|
|
|
{
|
2010-05-04 16:03:28 +02:00
|
|
|
to[0]= 0;
|
|
|
|
length= 0;
|
2000-11-18 01:15:06 +01:00
|
|
|
}
|
2009-01-14 15:50:51 +01:00
|
|
|
DBUG_RETURN(length);
|
2000-11-18 01:15:06 +01:00
|
|
|
}
|
2006-04-11 15:16:14 +02:00
|
|
|
length= strconvert(system_charset_info, from,
|
|
|
|
&my_charset_filename, to, to_length, &errors);
|
|
|
|
if (check_if_legal_tablename(to) &&
|
|
|
|
length + 4 < to_length)
|
|
|
|
{
|
|
|
|
memcpy(to + length, "@@@", 4);
|
|
|
|
length+= 3;
|
|
|
|
}
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("exit", ("to '%s'", to));
|
|
|
|
DBUG_RETURN(length);
|
2005-12-31 09:34:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-26 05:26:40 +02:00
|
|
|
/*
|
2005-12-31 06:01:26 +01:00
|
|
|
Creates path to a file: mysql_data_dir/db/table.ext
|
2005-05-26 05:26:40 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
2005-12-31 06:01:26 +01:00
|
|
|
build_table_filename()
|
2006-08-02 17:57:06 +02:00
|
|
|
buff Where to write result in my_charset_filename.
|
2007-08-14 23:35:19 +02:00
|
|
|
This may be the same as table_name.
|
2006-08-02 17:57:06 +02:00
|
|
|
bufflen buff size
|
|
|
|
db Database name in system_charset_info.
|
|
|
|
table_name Table name in system_charset_info.
|
|
|
|
ext File extension.
|
|
|
|
flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
|
|
|
|
table_name is temporary, do not change.
|
2005-12-31 06:01:26 +01:00
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
|
|
|
Uses database and table name, and extension to create
|
|
|
|
a file name in mysql_data_dir. Database and table
|
|
|
|
names are converted from system_charset_info into "fscs".
|
2006-08-02 17:57:06 +02:00
|
|
|
Unless flags indicate a temporary table name.
|
|
|
|
'db' is always converted.
|
2005-12-31 06:01:26 +01:00
|
|
|
'ext' is not converted.
|
2005-05-26 05:26:40 +02:00
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
The conversion suppression is required for ALTER TABLE. This
|
|
|
|
statement creates intermediate tables. These are regular
|
|
|
|
(non-temporary) tables with a temporary name. Their path names must
|
|
|
|
be derivable from the table name. So we cannot use
|
|
|
|
build_tmptable_filename() for them.
|
2005-05-26 05:26:40 +02:00
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
RETURN
|
|
|
|
path length
|
2005-12-31 06:01:26 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
uint build_table_filename(char *buff, size_t bufflen, const char *db,
|
2006-08-02 17:57:06 +02:00
|
|
|
const char *table_name, const char *ext, uint flags)
|
2005-12-31 06:01:26 +01:00
|
|
|
{
|
|
|
|
char dbbuff[FN_REFLEN];
|
|
|
|
char tbbuff[FN_REFLEN];
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_ENTER("build_table_filename");
|
2007-08-14 23:35:19 +02:00
|
|
|
DBUG_PRINT("enter", ("db: '%s' table_name: '%s' ext: '%s' flags: %x",
|
|
|
|
db, table_name, ext, flags));
|
2006-08-02 17:57:06 +02:00
|
|
|
|
|
|
|
if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
|
|
|
|
strnmov(tbbuff, table_name, sizeof(tbbuff));
|
|
|
|
else
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
|
2006-08-02 17:57:06 +02:00
|
|
|
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) tablename_to_filename(db, dbbuff, sizeof(dbbuff));
|
2007-08-14 23:35:19 +02:00
|
|
|
|
|
|
|
char *end = buff + bufflen;
|
|
|
|
/* Don't add FN_ROOTDIR if mysql_data_home already includes it */
|
|
|
|
char *pos = strnmov(buff, mysql_data_home, bufflen);
|
2009-02-13 17:41:47 +01:00
|
|
|
size_t rootdir_len= strlen(FN_ROOTDIR);
|
2007-08-14 23:35:19 +02:00
|
|
|
if (pos - rootdir_len >= buff &&
|
|
|
|
memcmp(pos - rootdir_len, FN_ROOTDIR, rootdir_len) != 0)
|
|
|
|
pos= strnmov(pos, FN_ROOTDIR, end - pos);
|
2007-12-14 21:49:51 +01:00
|
|
|
pos= strxnmov(pos, end - pos, dbbuff, FN_ROOTDIR, NullS);
|
|
|
|
#ifdef USE_SYMDIR
|
|
|
|
unpack_dirname(buff, buff);
|
|
|
|
pos= strend(buff);
|
|
|
|
#endif
|
|
|
|
pos= strxnmov(pos, end - pos, tbbuff, ext, NullS);
|
2007-08-14 23:35:19 +02:00
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("exit", ("buff: '%s'", buff));
|
2007-08-14 23:35:19 +02:00
|
|
|
DBUG_RETURN(pos - buff);
|
2005-12-31 06:01:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
/*
|
|
|
|
Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
build_tmptable_filename()
|
|
|
|
thd The thread handle.
|
|
|
|
buff Where to write result in my_charset_filename.
|
|
|
|
bufflen buff size
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
|
|
|
Uses current_pid, thread_id, and tmp_table counter to create
|
|
|
|
a file name in mysql_tmpdir.
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
path length
|
|
|
|
*/
|
|
|
|
|
2006-01-23 13:28:42 +01:00
|
|
|
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
|
2005-05-26 05:26:40 +02:00
|
|
|
{
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_ENTER("build_tmptable_filename");
|
|
|
|
|
2007-05-01 10:38:19 +02:00
|
|
|
char *p= strnmov(buff, mysql_tmpdir, bufflen);
|
|
|
|
my_snprintf(p, bufflen - (p - buff), "/%s%lx_%lx_%x%s",
|
|
|
|
tmp_file_prefix, current_pid,
|
|
|
|
thd->thread_id, thd->tmp_table++, reg_ext);
|
2006-08-02 17:57:06 +02:00
|
|
|
|
2007-05-01 10:38:19 +02:00
|
|
|
if (lower_case_table_names)
|
|
|
|
{
|
|
|
|
/* Convert all except tmpdir to lower case */
|
|
|
|
my_casedn_str(files_charset_info, p);
|
|
|
|
}
|
2006-08-02 17:57:06 +02:00
|
|
|
|
2009-02-13 17:41:47 +01:00
|
|
|
size_t length= unpack_filename(buff, buff);
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("exit", ("buff: '%s'", buff));
|
|
|
|
DBUG_RETURN(length);
|
2005-05-26 05:26:40 +02:00
|
|
|
}
|
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
/*
|
|
|
|
--------------------------------------------------------------------------
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
MODULE: DDL log
|
2006-02-07 10:45:07 +01:00
|
|
|
-----------------
|
|
|
|
|
|
|
|
This module is used to ensure that we can recover from crashes that occur
|
|
|
|
in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2;
|
|
|
|
We need to ensure that both t1 and t2 are dropped and not only t1 and
|
|
|
|
also that each table drop is entirely done and not "half-baked".
|
|
|
|
|
|
|
|
To support this we create log entries for each meta-data statement in the
|
2006-03-25 00:19:13 +01:00
|
|
|
ddl log while we are executing. These entries are dropped when the
|
2006-02-07 10:45:07 +01:00
|
|
|
operation is completed.
|
|
|
|
|
|
|
|
At recovery those entries that were not completed will be executed.
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
There is only one ddl log in the system and it is protected by a mutex
|
2006-02-07 10:45:07 +01:00
|
|
|
and there is a global struct that contains information about its current
|
|
|
|
state.
|
|
|
|
|
2006-02-08 15:14:15 +01:00
|
|
|
History:
|
|
|
|
First version written in 2006 by Mikael Ronstrom
|
2006-02-07 10:45:07 +01:00
|
|
|
--------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2007-11-13 10:09:59 +01:00
|
|
|
struct st_global_ddl_log
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-04-16 03:49:13 +02:00
|
|
|
/*
|
|
|
|
We need to adjust buffer size to be able to handle downgrades/upgrades
|
|
|
|
where IO_SIZE has changed. We'll set the buffer size such that we can
|
|
|
|
handle that the buffer size was upto 4 times bigger in the version
|
|
|
|
that wrote the DDL log.
|
|
|
|
*/
|
2006-03-25 00:19:13 +01:00
|
|
|
char file_entry_buf[4*IO_SIZE];
|
2006-02-07 10:45:07 +01:00
|
|
|
char file_name_str[FN_REFLEN];
|
|
|
|
char *file_name;
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *first_free;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *first_used;
|
|
|
|
uint num_entries;
|
2006-02-07 10:45:07 +01:00
|
|
|
File file_id;
|
|
|
|
uint name_len;
|
2006-02-09 11:05:05 +01:00
|
|
|
uint io_size;
|
2006-03-25 00:19:13 +01:00
|
|
|
bool inited;
|
2007-11-13 10:09:59 +01:00
|
|
|
bool do_release;
|
2006-04-01 16:37:36 +02:00
|
|
|
bool recovery_phase;
|
2007-11-13 10:09:59 +01:00
|
|
|
st_global_ddl_log() : inited(false), do_release(false) {}
|
|
|
|
};
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2007-11-13 10:09:59 +01:00
|
|
|
st_global_ddl_log global_ddl_log;
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_t LOCK_gdl;
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
#define DDL_LOG_ENTRY_TYPE_POS 0
|
|
|
|
#define DDL_LOG_ACTION_TYPE_POS 1
|
|
|
|
#define DDL_LOG_PHASE_POS 2
|
|
|
|
#define DDL_LOG_NEXT_ENTRY_POS 4
|
|
|
|
#define DDL_LOG_NAME_POS 8
|
2006-02-10 22:36:01 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
#define DDL_LOG_NUM_ENTRY_POS 0
|
|
|
|
#define DDL_LOG_NAME_LEN_POS 4
|
2006-04-16 03:49:13 +02:00
|
|
|
#define DDL_LOG_IO_SIZE_POS 8
|
2006-01-17 08:40:00 +01:00
|
|
|
|
2006-02-07 16:26:34 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Read one entry from ddl log file
|
2006-02-07 16:26:34 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
read_ddl_log_file_entry()
|
2006-02-10 22:36:01 +01:00
|
|
|
entry_no Entry number to read
|
2006-02-07 16:26:34 +01:00
|
|
|
RETURN VALUES
|
2006-02-10 22:36:01 +01:00
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
2006-02-07 16:26:34 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static bool read_ddl_log_file_entry(uint entry_no)
|
2006-02-07 16:26:34 +01:00
|
|
|
{
|
|
|
|
bool error= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
File file_id= global_ddl_log.file_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
|
|
|
uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
|
2006-03-25 00:19:13 +01:00
|
|
|
uint io_size= global_ddl_log.io_size;
|
|
|
|
DBUG_ENTER("read_ddl_log_file_entry");
|
2006-02-07 16:26:34 +01:00
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
|
|
|
|
MYF(MY_WME)) != io_size)
|
2006-02-07 16:26:34 +01:00
|
|
|
error= TRUE;
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Write one entry from ddl log file
|
2006-02-07 16:26:34 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
write_ddl_log_file_entry()
|
2010-01-18 17:49:18 +01:00
|
|
|
entry_no Entry number to write
|
2006-02-07 16:26:34 +01:00
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static bool write_ddl_log_file_entry(uint entry_no)
|
2006-02-07 16:26:34 +01:00
|
|
|
{
|
|
|
|
bool error= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
File file_id= global_ddl_log.file_id;
|
|
|
|
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
|
|
|
|
DBUG_ENTER("write_ddl_log_file_entry");
|
2006-02-07 16:26:34 +01:00
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_pwrite(file_id, (uchar*)file_entry_buf,
|
|
|
|
IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
|
2006-02-07 16:26:34 +01:00
|
|
|
error= TRUE;
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Write ddl log header
|
2006-02-07 16:26:34 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
write_ddl_log_header()
|
2006-02-07 16:26:34 +01:00
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static bool write_ddl_log_header()
|
2006-02-07 16:26:34 +01:00
|
|
|
{
|
|
|
|
uint16 const_var;
|
2006-02-08 15:14:15 +01:00
|
|
|
bool error= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("write_ddl_log_header");
|
2006-02-07 16:26:34 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
|
|
|
|
global_ddl_log.num_entries);
|
2006-02-09 00:04:58 +01:00
|
|
|
const_var= FN_LEN;
|
2006-03-25 00:19:13 +01:00
|
|
|
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
|
2007-02-23 12:13:55 +01:00
|
|
|
(ulong) const_var);
|
2006-02-09 11:05:05 +01:00
|
|
|
const_var= IO_SIZE;
|
2006-03-25 00:19:13 +01:00
|
|
|
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
|
2007-02-23 12:13:55 +01:00
|
|
|
(ulong) const_var);
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_file_entry(0UL))
|
2006-04-01 16:37:36 +02:00
|
|
|
{
|
|
|
|
sql_print_error("Error writing ddl log header");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-02-08 15:14:15 +01:00
|
|
|
DBUG_RETURN(error);
|
2006-02-06 21:47:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-08 15:14:15 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Create ddl log file name
|
2006-02-08 15:14:15 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
create_ddl_log_file_name()
|
2006-02-08 15:14:15 +01:00
|
|
|
file_name Filename setup
|
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static inline void create_ddl_log_file_name(char *file_name)
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS);
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-06 21:47:03 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Read header of ddl log file
|
2006-02-06 21:47:03 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
read_ddl_log_header()
|
2006-02-06 21:47:03 +01:00
|
|
|
RETURN VALUES
|
2006-03-25 00:19:13 +01:00
|
|
|
> 0 Last entry in ddl log
|
|
|
|
0 No entries in ddl log
|
2006-02-06 21:47:03 +01:00
|
|
|
DESCRIPTION
|
2006-03-25 00:19:13 +01:00
|
|
|
When we read the ddl log header we get information about maximum sizes
|
|
|
|
of names in the ddl log and we also get information about the number
|
|
|
|
of entries in the ddl log.
|
2006-02-06 21:47:03 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static uint read_ddl_log_header()
|
2006-02-06 21:47:03 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
|
2006-02-08 15:14:15 +01:00
|
|
|
char file_name[FN_REFLEN];
|
2006-02-09 00:04:58 +01:00
|
|
|
uint entry_no;
|
2006-02-09 11:05:05 +01:00
|
|
|
bool successful_open= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("read_ddl_log_header");
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
create_ddl_log_file_name(file_name);
|
2010-01-07 06:42:07 +01:00
|
|
|
if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
|
|
|
|
file_name,
|
|
|
|
O_RDWR | O_BINARY, MYF(0))) >= 0)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (read_ddl_log_file_entry(0UL))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
/* Write message into error log */
|
|
|
|
sql_print_error("Failed to read ddl log file in recovery");
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-02-09 11:05:05 +01:00
|
|
|
else
|
|
|
|
successful_open= TRUE;
|
2006-02-07 10:45:07 +01:00
|
|
|
}
|
2006-04-16 03:49:13 +02:00
|
|
|
if (successful_open)
|
|
|
|
{
|
2010-01-18 17:49:18 +01:00
|
|
|
entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
|
|
|
|
global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
|
2006-04-16 03:49:13 +02:00
|
|
|
DBUG_ASSERT(global_ddl_log.io_size <=
|
|
|
|
sizeof(global_ddl_log.file_entry_buf));
|
|
|
|
}
|
2006-02-20 22:22:19 +01:00
|
|
|
else
|
2006-04-01 16:37:36 +02:00
|
|
|
{
|
|
|
|
entry_no= 0;
|
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.first_free= NULL;
|
|
|
|
global_ddl_log.first_used= NULL;
|
|
|
|
global_ddl_log.num_entries= 0;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_FAST);
|
2007-11-13 10:09:59 +01:00
|
|
|
global_ddl_log.do_release= true;
|
2006-02-07 10:45:07 +01:00
|
|
|
DBUG_RETURN(entry_no);
|
2006-02-06 21:47:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Read a ddl log entry
|
2006-02-06 21:47:03 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
read_ddl_log_entry()
|
2006-02-06 21:47:03 +01:00
|
|
|
read_entry Number of entry to read
|
|
|
|
out:entry_info Information from entry
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
DESCRIPTION
|
2006-03-25 00:19:13 +01:00
|
|
|
Read a specified entry in the ddl log
|
2006-02-06 21:47:03 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
|
2006-02-06 21:47:03 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf;
|
2006-02-09 00:04:58 +01:00
|
|
|
uint inx;
|
2006-04-20 02:04:00 +02:00
|
|
|
uchar single_char;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("read_ddl_log_entry");
|
2006-02-08 15:14:15 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (read_ddl_log_file_entry(read_entry))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
ddl_log_entry->entry_pos= read_entry;
|
2006-04-20 02:04:00 +02:00
|
|
|
single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS];
|
|
|
|
ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char;
|
|
|
|
single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS];
|
|
|
|
ddl_log_entry->action_type= (enum ddl_log_action_code)single_char;
|
2006-03-25 00:19:13 +01:00
|
|
|
ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS];
|
|
|
|
ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]);
|
|
|
|
ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS];
|
|
|
|
inx= DDL_LOG_NAME_POS + global_ddl_log.name_len;
|
|
|
|
ddl_log_entry->from_name= &file_entry_buf[inx];
|
|
|
|
inx+= global_ddl_log.name_len;
|
|
|
|
ddl_log_entry->handler_name= &file_entry_buf[inx];
|
2006-02-06 21:47:03 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Initialise ddl log
|
2006-02-06 21:47:03 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
init_ddl_log()
|
2006-05-03 18:40:52 +02:00
|
|
|
|
2006-02-06 21:47:03 +01:00
|
|
|
DESCRIPTION
|
2006-03-25 00:19:13 +01:00
|
|
|
Write the header of the ddl log file and length of names. Also set
|
2006-02-06 21:47:03 +01:00
|
|
|
number of entries to zero.
|
2006-05-03 18:40:52 +02:00
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
2006-02-06 21:47:03 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static bool init_ddl_log()
|
2006-02-06 21:47:03 +01:00
|
|
|
{
|
2006-02-08 15:14:15 +01:00
|
|
|
char file_name[FN_REFLEN];
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("init_ddl_log");
|
2006-02-07 16:26:34 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (global_ddl_log.inited)
|
2006-05-03 18:40:52 +02:00
|
|
|
goto end;
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.io_size= IO_SIZE;
|
2010-01-18 17:49:18 +01:00
|
|
|
global_ddl_log.name_len= FN_LEN;
|
2006-04-19 22:08:59 +02:00
|
|
|
create_ddl_log_file_name(file_name);
|
2010-01-07 06:42:07 +01:00
|
|
|
if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log,
|
|
|
|
file_name, CREATE_MODE,
|
|
|
|
O_RDWR | O_TRUNC | O_BINARY,
|
|
|
|
MYF(MY_WME))) < 0)
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
/* Couldn't create ddl log file, this is serious error */
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to open ddl log file");
|
|
|
|
DBUG_RETURN(TRUE);
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-04-03 18:26:35 +02:00
|
|
|
global_ddl_log.inited= TRUE;
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_header())
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
(void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
|
2006-04-03 18:26:35 +02:00
|
|
|
global_ddl_log.inited= FALSE;
|
2006-04-01 16:37:36 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-05-03 18:40:52 +02:00
|
|
|
|
|
|
|
end:
|
2006-04-01 16:37:36 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2006-02-06 21:47:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Execute one action in a ddl log entry
|
2006-02-06 21:47:03 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
execute_ddl_log_action()
|
|
|
|
ddl_log_entry Information in action entry to execute
|
2006-02-06 21:47:03 +01:00
|
|
|
RETURN VALUES
|
2006-02-08 15:14:15 +01:00
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
2006-02-06 21:47:03 +01:00
|
|
|
*/
|
|
|
|
|
2006-04-20 02:57:42 +02:00
|
|
|
static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
|
2006-02-06 21:47:03 +01:00
|
|
|
{
|
2006-02-14 11:08:58 +01:00
|
|
|
bool frm_action= FALSE;
|
|
|
|
LEX_STRING handler_name;
|
2006-04-20 02:04:00 +02:00
|
|
|
handler *file= NULL;
|
2006-02-20 21:07:03 +01:00
|
|
|
MEM_ROOT mem_root;
|
2006-04-20 02:57:42 +02:00
|
|
|
int error= TRUE;
|
2006-04-20 02:04:00 +02:00
|
|
|
char to_path[FN_REFLEN];
|
2006-02-14 11:08:58 +01:00
|
|
|
char from_path[FN_REFLEN];
|
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
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-02-20 21:07:03 +01:00
|
|
|
char *par_ext= (char*)".par";
|
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
|
|
|
#endif
|
2006-02-20 21:07:03 +01:00
|
|
|
handlerton *hton;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("execute_ddl_log_action");
|
2006-02-14 11:08:58 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE)
|
2006-02-14 11:08:58 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
2010-01-18 17:49:18 +01:00
|
|
|
DBUG_PRINT("ddl_log",
|
|
|
|
("execute type %c next %u name '%s' from_name '%s' handler '%s'",
|
|
|
|
ddl_log_entry->action_type,
|
|
|
|
ddl_log_entry->next_entry,
|
|
|
|
ddl_log_entry->name,
|
|
|
|
ddl_log_entry->from_name,
|
|
|
|
ddl_log_entry->handler_name));
|
2006-03-25 00:19:13 +01:00
|
|
|
handler_name.str= (char*)ddl_log_entry->handler_name;
|
|
|
|
handler_name.length= strlen(ddl_log_entry->handler_name);
|
2006-02-14 11:08:58 +01:00
|
|
|
init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
|
2006-04-20 02:04:00 +02:00
|
|
|
if (!strcmp(ddl_log_entry->handler_name, reg_ext))
|
2006-02-14 11:08:58 +01:00
|
|
|
frm_action= TRUE;
|
|
|
|
else
|
|
|
|
{
|
2007-03-02 17:43:45 +01:00
|
|
|
plugin_ref plugin= ha_resolve_by_name(thd, &handler_name);
|
|
|
|
if (!plugin)
|
2006-04-19 22:08:59 +02:00
|
|
|
{
|
|
|
|
my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name);
|
|
|
|
goto error;
|
|
|
|
}
|
2007-03-02 17:43:45 +01:00
|
|
|
hton= plugin_data(plugin, handlerton*);
|
|
|
|
file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
|
2006-02-14 11:08:58 +01:00
|
|
|
if (!file)
|
2006-02-14 14:22:21 +01:00
|
|
|
{
|
|
|
|
mem_alloc_error(sizeof(handler));
|
2006-02-14 11:08:58 +01:00
|
|
|
goto error;
|
2006-02-14 14:22:21 +01:00
|
|
|
}
|
2006-02-14 11:08:58 +01:00
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
switch (ddl_log_entry->action_type)
|
2006-02-20 21:07:03 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
case DDL_LOG_REPLACE_ACTION:
|
2006-04-01 16:37:36 +02:00
|
|
|
case DDL_LOG_DELETE_ACTION:
|
2006-02-20 21:07:03 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
if (ddl_log_entry->phase == 0)
|
2006-02-14 11:08:58 +01:00
|
|
|
{
|
|
|
|
if (frm_action)
|
|
|
|
{
|
2006-04-20 02:04:00 +02:00
|
|
|
strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
|
2010-01-07 06:42:07 +01:00
|
|
|
if ((error= mysql_file_delete(key_file_frm, to_path, MYF(MY_WME))))
|
2006-04-20 02:04:00 +02:00
|
|
|
{
|
2006-04-20 02:57:42 +02:00
|
|
|
if (my_errno != ENOENT)
|
2006-04-20 02:04:00 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-04-01 16:37:36 +02:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-04-20 02:04:00 +02:00
|
|
|
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
|
2010-01-07 06:42:07 +01:00
|
|
|
(void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME));
|
2006-04-01 16:37:36 +02:00
|
|
|
#endif
|
2006-02-14 11:08:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-20 19:16:55 +01:00
|
|
|
if ((error= file->ha_delete_table(ddl_log_entry->name)))
|
2006-04-20 02:04:00 +02:00
|
|
|
{
|
|
|
|
if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE)
|
|
|
|
break;
|
|
|
|
}
|
2006-02-14 11:08:58 +01:00
|
|
|
}
|
2006-04-01 16:37:36 +02:00
|
|
|
if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
|
2006-04-20 02:04:00 +02:00
|
|
|
break;
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-04-20 02:04:00 +02:00
|
|
|
error= FALSE;
|
2006-04-01 16:37:36 +02:00
|
|
|
if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
|
|
|
|
break;
|
2006-02-14 11:08:58 +01:00
|
|
|
}
|
2006-04-01 16:37:36 +02:00
|
|
|
DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
|
|
|
|
/*
|
|
|
|
Fall through and perform the rename action of the replace
|
|
|
|
action. We have already indicated the success of the delete
|
|
|
|
action in the log entry by stepping up the phase.
|
|
|
|
*/
|
2006-02-20 21:07:03 +01:00
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
case DDL_LOG_RENAME_ACTION:
|
2006-02-20 21:07:03 +01:00
|
|
|
{
|
2006-02-14 11:08:58 +01:00
|
|
|
error= TRUE;
|
|
|
|
if (frm_action)
|
|
|
|
{
|
2006-04-20 02:04:00 +02:00
|
|
|
strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
|
2006-03-25 00:19:13 +01:00
|
|
|
strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME)))
|
2006-02-14 11:08:58 +01:00
|
|
|
break;
|
2006-04-01 16:37:36 +02:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-04-20 02:04:00 +02:00
|
|
|
strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
|
2006-03-25 00:19:13 +01:00
|
|
|
strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS);
|
2010-01-07 06:42:07 +01:00
|
|
|
(void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME));
|
2006-04-01 16:37:36 +02:00
|
|
|
#endif
|
2006-02-14 11:08:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-20 19:16:55 +01:00
|
|
|
if (file->ha_rename_table(ddl_log_entry->from_name,
|
|
|
|
ddl_log_entry->name))
|
2006-02-14 11:08:58 +01:00
|
|
|
break;
|
2006-04-01 16:37:36 +02:00
|
|
|
}
|
|
|
|
if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
|
2006-04-20 02:04:00 +02:00
|
|
|
break;
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-04-20 02:04:00 +02:00
|
|
|
error= FALSE;
|
2006-02-14 11:08:58 +01:00
|
|
|
break;
|
2006-02-20 21:07:03 +01:00
|
|
|
}
|
2006-02-14 11:08:58 +01:00
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
delete file;
|
|
|
|
error:
|
|
|
|
free_root(&mem_root, MYF(0));
|
|
|
|
DBUG_RETURN(error);
|
2006-02-06 21:47:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Get a free entry in the ddl log
|
2006-02-07 10:45:07 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
get_free_ddl_log_entry()
|
|
|
|
out:active_entry A ddl log memory entry returned
|
2006-02-07 10:45:07 +01:00
|
|
|
RETURN VALUES
|
2006-02-08 15:14:15 +01:00
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
2006-02-07 10:45:07 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
|
|
|
|
bool *write_header)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *used_entry;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used;
|
|
|
|
DBUG_ENTER("get_free_ddl_log_entry");
|
2006-02-09 00:04:58 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (global_ddl_log.first_free == NULL)
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(
|
|
|
|
sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to allocate memory for ddl log free list");
|
2006-02-08 15:14:15 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.num_entries++;
|
2006-04-01 16:37:36 +02:00
|
|
|
used_entry->entry_pos= global_ddl_log.num_entries;
|
2006-02-09 00:04:58 +01:00
|
|
|
*write_header= TRUE;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
used_entry= global_ddl_log.first_free;
|
|
|
|
global_ddl_log.first_free= used_entry->next_log_entry;
|
2006-02-09 00:04:58 +01:00
|
|
|
*write_header= FALSE;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
Move from free list to used list
|
|
|
|
*/
|
|
|
|
used_entry->next_log_entry= first_used;
|
|
|
|
used_entry->prev_log_entry= NULL;
|
2010-08-13 09:50:25 +02:00
|
|
|
used_entry->next_active_log_entry= NULL;
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.first_used= used_entry;
|
2006-02-08 15:14:15 +01:00
|
|
|
if (first_used)
|
|
|
|
first_used->prev_log_entry= used_entry;
|
|
|
|
|
|
|
|
*active_entry= used_entry;
|
2006-02-09 00:04:58 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
2006-02-07 10:45:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
External interface methods for the DDL log Module
|
2006-02-08 15:14:15 +01:00
|
|
|
---------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2006-02-07 10:45:07 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
write_ddl_log_entry()
|
|
|
|
ddl_log_entry Information about log entry
|
|
|
|
out:entry_written Entry information written into
|
2006-02-08 15:14:15 +01:00
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
RETURN VALUES
|
2006-02-08 15:14:15 +01:00
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
|
|
|
|
DESCRIPTION
|
2006-03-25 00:19:13 +01:00
|
|
|
A careful write of the ddl log is performed to ensure that we can
|
2006-02-08 15:14:15 +01:00
|
|
|
handle crashes occurring during CREATE and ALTER TABLE processing.
|
2006-02-07 10:45:07 +01:00
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
|
|
|
|
DDL_LOG_MEMORY_ENTRY **active_entry)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-02-09 00:04:58 +01:00
|
|
|
bool error, write_header;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("write_ddl_log_entry");
|
|
|
|
|
|
|
|
if (init_ddl_log())
|
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-04-20 02:04:00 +02:00
|
|
|
global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]=
|
|
|
|
(char)DDL_LOG_ENTRY_CODE;
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]=
|
2006-04-20 02:04:00 +02:00
|
|
|
(char)ddl_log_entry->action_type;
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0;
|
|
|
|
int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS],
|
|
|
|
ddl_log_entry->next_entry);
|
|
|
|
DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN);
|
2006-04-21 14:35:25 +02:00
|
|
|
strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
|
|
|
|
ddl_log_entry->name, FN_LEN - 1);
|
2006-03-25 00:19:13 +01:00
|
|
|
if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION ||
|
|
|
|
ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION)
|
2006-02-10 05:57:54 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN);
|
2006-04-21 14:35:25 +02:00
|
|
|
strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN],
|
|
|
|
ddl_log_entry->from_name, FN_LEN - 1);
|
2006-02-10 05:57:54 +01:00
|
|
|
}
|
2006-02-09 20:13:22 +01:00
|
|
|
else
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0;
|
|
|
|
DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN);
|
2006-04-21 14:35:25 +02:00
|
|
|
strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)],
|
|
|
|
ddl_log_entry->handler_name, FN_LEN - 1);
|
2006-03-25 00:19:13 +01:00
|
|
|
if (get_free_ddl_log_entry(active_entry, &write_header))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
error= FALSE;
|
2010-01-18 17:49:18 +01:00
|
|
|
DBUG_PRINT("ddl_log",
|
|
|
|
("write type %c next %u name '%s' from_name '%s' handler '%s'",
|
|
|
|
(char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS],
|
|
|
|
ddl_log_entry->next_entry,
|
|
|
|
(char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
|
|
|
|
(char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
|
|
|
|
+ FN_LEN],
|
|
|
|
(char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
|
|
|
|
+ (2*FN_LEN)]));
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_file_entry((*active_entry)->entry_pos))
|
2006-04-01 16:37:36 +02:00
|
|
|
{
|
2006-02-08 15:14:15 +01:00
|
|
|
error= TRUE;
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to write entry_no = %u",
|
|
|
|
(*active_entry)->entry_pos);
|
|
|
|
}
|
2006-02-09 00:04:58 +01:00
|
|
|
if (write_header && !error)
|
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_header())
|
2006-02-09 00:04:58 +01:00
|
|
|
error= TRUE;
|
|
|
|
}
|
2006-02-08 15:14:15 +01:00
|
|
|
if (error)
|
2006-03-25 00:19:13 +01:00
|
|
|
release_ddl_log_memory_entry(*active_entry);
|
2006-02-08 15:14:15 +01:00
|
|
|
DBUG_RETURN(error);
|
2006-02-07 10:45:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Write final entry in the ddl log
|
2006-02-07 10:45:07 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
write_execute_ddl_log_entry()
|
2006-02-08 15:14:15 +01:00
|
|
|
first_entry First entry in linked list of entries
|
|
|
|
to execute, if 0 = NULL it means that
|
|
|
|
the entry is removed and the entries
|
|
|
|
are put into the free list.
|
2006-04-16 03:49:13 +02:00
|
|
|
complete Flag indicating we are simply writing
|
|
|
|
info about that entry has been completed
|
|
|
|
in:out:active_entry Entry to execute, 0 = NULL if the entry
|
2006-02-08 15:14:15 +01:00
|
|
|
is written first time and needs to be
|
|
|
|
returned. In this case the entry written
|
|
|
|
is returned in this parameter
|
2006-02-07 10:45:07 +01:00
|
|
|
RETURN VALUES
|
2006-02-08 15:14:15 +01:00
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
|
|
|
|
DESCRIPTION
|
2006-03-25 00:19:13 +01:00
|
|
|
This is the last write in the ddl log. The previous log entries have
|
2006-02-08 15:14:15 +01:00
|
|
|
already been written but not yet synched to disk.
|
2006-04-01 16:37:36 +02:00
|
|
|
We write a couple of log entries that describes action to perform.
|
|
|
|
This entries are set-up in a linked list, however only when a first
|
|
|
|
execute entry is put as the first entry these will be executed.
|
|
|
|
This routine writes this first
|
2006-02-08 15:14:15 +01:00
|
|
|
*/
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
bool write_execute_ddl_log_entry(uint first_entry,
|
|
|
|
bool complete,
|
|
|
|
DDL_LOG_MEMORY_ENTRY **active_entry)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-02-10 12:30:51 +01:00
|
|
|
bool write_header= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
|
|
|
|
DBUG_ENTER("write_execute_ddl_log_entry");
|
2006-02-08 15:14:15 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (init_ddl_log())
|
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-02-09 20:20:21 +01:00
|
|
|
if (!complete)
|
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
/*
|
|
|
|
We haven't synched the log entries yet, we synch them now before
|
|
|
|
writing the execute entry. If complete is true we haven't written
|
|
|
|
any log entries before, we are only here to write the execute
|
|
|
|
entry to indicate it is done.
|
|
|
|
*/
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-04-20 02:04:00 +02:00
|
|
|
file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
|
2006-02-09 20:20:21 +01:00
|
|
|
}
|
|
|
|
else
|
2006-04-20 02:04:00 +02:00
|
|
|
file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE;
|
2006-03-25 00:19:13 +01:00
|
|
|
file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */
|
|
|
|
file_entry_buf[DDL_LOG_PHASE_POS]= 0;
|
|
|
|
int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry);
|
|
|
|
file_entry_buf[DDL_LOG_NAME_POS]= 0;
|
|
|
|
file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0;
|
|
|
|
file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0;
|
2006-02-09 20:13:22 +01:00
|
|
|
if (!(*active_entry))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (get_free_ddl_log_entry(active_entry, &write_header))
|
2006-02-09 20:13:22 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_file_entry((*active_entry)->entry_pos))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Error writing execute entry in ddl log");
|
2006-03-25 00:19:13 +01:00
|
|
|
release_ddl_log_memory_entry(*active_entry);
|
2006-02-08 15:14:15 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-02-09 00:04:58 +01:00
|
|
|
if (write_header)
|
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (write_ddl_log_header())
|
2006-02-09 00:04:58 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
release_ddl_log_memory_entry(*active_entry);
|
2006-02-09 00:04:58 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
}
|
2006-02-07 10:45:07 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-10 22:36:01 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
For complex rename operations we need to deactivate individual entries.
|
2006-02-10 22:36:01 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
deactivate_ddl_log_entry()
|
2006-02-10 22:36:01 +01:00
|
|
|
entry_no Entry position of record to change
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
DESCRIPTION
|
|
|
|
During replace operations where we start with an existing table called
|
|
|
|
t1 and a replacement table called t1#temp or something else and where
|
|
|
|
we want to delete t1 and rename t1#temp to t1 this is not possible to
|
2006-03-25 00:19:13 +01:00
|
|
|
do in a safe manner unless the ddl log is informed of the phases in
|
2006-02-10 22:36:01 +01:00
|
|
|
the change.
|
|
|
|
|
|
|
|
Delete actions are 1-phase actions that can be ignored immediately after
|
|
|
|
being executed.
|
|
|
|
Rename actions from x to y is also a 1-phase action since there is no
|
|
|
|
interaction with any other handlers named x and y.
|
|
|
|
Replace action where drop y and x -> y happens needs to be a two-phase
|
|
|
|
action. Thus the first phase will drop y and the second phase will
|
|
|
|
rename x -> y.
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
bool deactivate_ddl_log_entry(uint entry_no)
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
|
|
|
|
DBUG_ENTER("deactivate_ddl_log_entry");
|
2006-02-10 22:36:01 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
if (!read_ddl_log_file_entry(entry_no))
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
|
|
|
|
file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
|
|
|
|
(file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
|
|
|
|
file_entry_buf[DDL_LOG_PHASE_POS] == 1))
|
|
|
|
file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
|
|
|
|
else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0);
|
|
|
|
file_entry_buf[DDL_LOG_PHASE_POS]= 1;
|
2006-02-10 22:36:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
2006-04-01 16:37:36 +02:00
|
|
|
if (write_ddl_log_file_entry(entry_no))
|
|
|
|
{
|
|
|
|
sql_print_error("Error in deactivating log entry. Position = %u",
|
|
|
|
entry_no);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-02-10 22:36:01 +01:00
|
|
|
}
|
|
|
|
}
|
2006-04-01 16:37:36 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
sql_print_error("Failed in reading entry before deactivating it");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
DBUG_RETURN(FALSE);
|
2006-02-10 22:36:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Sync ddl log file
|
2006-02-10 22:36:01 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
sync_ddl_log()
|
2006-02-10 22:36:01 +01:00
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
bool sync_ddl_log()
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
|
|
|
bool error= FALSE;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("sync_ddl_log");
|
2006-02-10 22:36:01 +01:00
|
|
|
|
2006-04-01 16:37:36 +02:00
|
|
|
if ((!global_ddl_log.recovery_phase) &&
|
|
|
|
init_ddl_log())
|
2006-03-25 00:19:13 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_sync(global_ddl_log.file_id, MYF(0)))
|
2006-02-10 22:36:01 +01:00
|
|
|
{
|
|
|
|
/* Write to error log */
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to sync ddl log");
|
2006-02-10 22:36:01 +01:00
|
|
|
error= TRUE;
|
|
|
|
}
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-08 15:14:15 +01:00
|
|
|
/*
|
|
|
|
Release a log memory entry
|
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
release_ddl_log_memory_entry()
|
2006-02-08 15:14:15 +01:00
|
|
|
log_memory_entry Log memory entry to release
|
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry)
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry;
|
|
|
|
DBUG_ENTER("release_ddl_log_memory_entry");
|
2006-02-08 15:14:15 +01:00
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.first_free= log_entry;
|
2006-02-08 15:14:15 +01:00
|
|
|
log_entry->next_log_entry= first_free;
|
|
|
|
|
|
|
|
if (prev_log_entry)
|
|
|
|
prev_log_entry->next_log_entry= next_log_entry;
|
|
|
|
else
|
2006-03-25 00:19:13 +01:00
|
|
|
global_ddl_log.first_used= next_log_entry;
|
2006-02-08 15:14:15 +01:00
|
|
|
if (next_log_entry)
|
|
|
|
next_log_entry->prev_log_entry= prev_log_entry;
|
2006-02-09 00:04:58 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Execute one entry in the ddl log. Executing an entry means executing
|
2006-02-07 10:45:07 +01:00
|
|
|
a linked list of actions.
|
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
execute_ddl_log_entry()
|
2006-02-07 10:45:07 +01:00
|
|
|
first_entry Reference to first action in entry
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
*/
|
|
|
|
|
2006-04-01 16:37:36 +02:00
|
|
|
bool execute_ddl_log_entry(THD *thd, uint first_entry)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_ENTRY ddl_log_entry;
|
2006-02-07 10:45:07 +01:00
|
|
|
uint read_entry= first_entry;
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("execute_ddl_log_entry");
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_gdl);
|
2006-02-07 10:45:07 +01:00
|
|
|
do
|
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (read_ddl_log_entry(read_entry, &ddl_log_entry))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
|
|
|
/* Write to error log and continue with next log entry */
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to read entry = %u from ddl log",
|
|
|
|
read_entry);
|
2006-02-08 15:14:15 +01:00
|
|
|
break;
|
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE ||
|
|
|
|
ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE);
|
2006-02-14 11:08:58 +01:00
|
|
|
|
2006-04-01 16:37:36 +02:00
|
|
|
if (execute_ddl_log_action(thd, &ddl_log_entry))
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-02-08 15:14:15 +01:00
|
|
|
/* Write to error log and continue with next log entry */
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to execute action for entry = %u from ddl log",
|
|
|
|
read_entry);
|
2006-02-08 15:14:15 +01:00
|
|
|
break;
|
2006-02-07 10:45:07 +01:00
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
read_entry= ddl_log_entry.next_entry;
|
2006-02-07 10:45:07 +01:00
|
|
|
} while (read_entry);
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_gdl);
|
2006-02-07 10:45:07 +01:00
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
2006-02-14 11:08:58 +01:00
|
|
|
|
2006-09-19 17:40:21 +02:00
|
|
|
/*
|
|
|
|
Close the ddl log
|
|
|
|
SYNOPSIS
|
|
|
|
close_ddl_log()
|
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void close_ddl_log()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("close_ddl_log");
|
|
|
|
if (global_ddl_log.file_id >= 0)
|
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
(void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
|
2006-09-19 17:40:21 +02:00
|
|
|
global_ddl_log.file_id= (File) -1;
|
|
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Execute the ddl log at recovery of MySQL Server
|
2006-02-07 10:45:07 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
execute_ddl_log_recovery()
|
2006-02-07 10:45:07 +01:00
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
void execute_ddl_log_recovery()
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
uint num_entries, i;
|
2006-04-03 18:26:35 +02:00
|
|
|
THD *thd;
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_ENTRY ddl_log_entry;
|
2006-04-03 18:26:35 +02:00
|
|
|
char file_name[FN_REFLEN];
|
2006-03-25 00:19:13 +01:00
|
|
|
DBUG_ENTER("execute_ddl_log_recovery");
|
2006-02-07 10:45:07 +01:00
|
|
|
|
2006-04-25 23:33:54 +02:00
|
|
|
/*
|
|
|
|
Initialise global_ddl_log struct
|
|
|
|
*/
|
|
|
|
bzero(global_ddl_log.file_entry_buf, sizeof(global_ddl_log.file_entry_buf));
|
|
|
|
global_ddl_log.inited= FALSE;
|
|
|
|
global_ddl_log.recovery_phase= TRUE;
|
|
|
|
global_ddl_log.io_size= IO_SIZE;
|
2006-05-04 05:28:24 +02:00
|
|
|
global_ddl_log.file_id= (File) -1;
|
2006-04-25 23:33:54 +02:00
|
|
|
|
2006-04-01 16:37:36 +02:00
|
|
|
/*
|
|
|
|
To be able to run this from boot, we allocate a temporary THD
|
|
|
|
*/
|
|
|
|
if (!(thd=new THD))
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
thd->thread_stack= (char*) &thd;
|
|
|
|
thd->store_globals();
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
num_entries= read_ddl_log_header();
|
2006-04-20 02:04:00 +02:00
|
|
|
for (i= 1; i < num_entries + 1; i++)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
if (read_ddl_log_entry(i, &ddl_log_entry))
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
sql_print_error("Failed to read entry no = %u from ddl log",
|
|
|
|
i);
|
|
|
|
continue;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-03-25 00:19:13 +01:00
|
|
|
if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE)
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-04-03 18:26:35 +02:00
|
|
|
if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry))
|
2006-02-07 10:45:07 +01:00
|
|
|
{
|
2006-04-01 16:37:36 +02:00
|
|
|
/* Real unpleasant scenario but we continue anyways. */
|
|
|
|
continue;
|
2006-02-07 10:45:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-09-19 17:40:21 +02:00
|
|
|
close_ddl_log();
|
2006-04-01 16:37:36 +02:00
|
|
|
create_ddl_log_file_name(file_name);
|
2010-01-07 06:42:07 +01:00
|
|
|
(void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0));
|
2006-04-01 16:37:36 +02:00
|
|
|
global_ddl_log.recovery_phase= FALSE;
|
|
|
|
delete thd;
|
|
|
|
/* Remember that we don't have a THD */
|
|
|
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
2006-02-09 00:04:58 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2006-03-25 00:19:13 +01:00
|
|
|
Release all memory allocated to the ddl log
|
2006-02-08 15:14:15 +01:00
|
|
|
SYNOPSIS
|
2006-03-25 00:19:13 +01:00
|
|
|
release_ddl_log()
|
2006-02-08 15:14:15 +01:00
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
*/
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
void release_ddl_log()
|
2006-02-08 15:14:15 +01:00
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used;
|
|
|
|
DBUG_ENTER("release_ddl_log");
|
2006-02-08 15:14:15 +01:00
|
|
|
|
2007-11-13 10:09:59 +01:00
|
|
|
if (!global_ddl_log.do_release)
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_lock(&LOCK_gdl);
|
2006-02-08 15:14:15 +01:00
|
|
|
while (used_list)
|
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
|
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled
Essentially, the problem is that safemalloc is excruciatingly
slow as it checks all allocated blocks for overrun at each
memory management primitive, yielding a almost exponential
slowdown for the memory management functions (malloc, realloc,
free). The overrun check basically consists of verifying some
bytes of a block for certain magic keys, which catches some
simple forms of overrun. Another minor problem is violation
of aliasing rules and that its own internal list of blocks
is prone to corruption.
Another issue with safemalloc is rather the maintenance cost
as the tool has a significant impact on the server code.
Given the magnitude of memory debuggers available nowadays,
especially those that are provided with the platform malloc
implementation, maintenance of a in-house and largely obsolete
memory debugger becomes a burden that is not worth the effort
due to its slowness and lack of support for detecting more
common forms of heap corruption.
Since there are third-party tools that can provide the same
functionality at a lower or comparable performance cost, the
solution is to simply remove safemalloc. Third-party tools
can provide the same functionality at a lower or comparable
performance cost.
The removal of safemalloc also allows a simplification of the
malloc wrappers, removing quite a bit of kludge: redefinition
of my_malloc, my_free and the removal of the unused second
argument of my_free. Since free() always check whether the
supplied pointer is null, redudant checks are also removed.
Also, this patch adds unit testing for my_malloc and moves
my_realloc implementation into the same file as the other
memory allocation primitives.
2010-07-08 23:20:08 +02:00
|
|
|
my_free(used_list);
|
2006-02-10 19:33:08 +01:00
|
|
|
used_list= tmp;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
while (free_list)
|
|
|
|
{
|
2006-03-25 00:19:13 +01:00
|
|
|
DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
|
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled
Essentially, the problem is that safemalloc is excruciatingly
slow as it checks all allocated blocks for overrun at each
memory management primitive, yielding a almost exponential
slowdown for the memory management functions (malloc, realloc,
free). The overrun check basically consists of verifying some
bytes of a block for certain magic keys, which catches some
simple forms of overrun. Another minor problem is violation
of aliasing rules and that its own internal list of blocks
is prone to corruption.
Another issue with safemalloc is rather the maintenance cost
as the tool has a significant impact on the server code.
Given the magnitude of memory debuggers available nowadays,
especially those that are provided with the platform malloc
implementation, maintenance of a in-house and largely obsolete
memory debugger becomes a burden that is not worth the effort
due to its slowness and lack of support for detecting more
common forms of heap corruption.
Since there are third-party tools that can provide the same
functionality at a lower or comparable performance cost, the
solution is to simply remove safemalloc. Third-party tools
can provide the same functionality at a lower or comparable
performance cost.
The removal of safemalloc also allows a simplification of the
malloc wrappers, removing quite a bit of kludge: redefinition
of my_malloc, my_free and the removal of the unused second
argument of my_free. Since free() always check whether the
supplied pointer is null, redudant checks are also removed.
Also, this patch adds unit testing for my_malloc and moves
my_realloc implementation into the same file as the other
memory allocation primitives.
2010-07-08 23:20:08 +02:00
|
|
|
my_free(free_list);
|
2006-02-10 19:33:08 +01:00
|
|
|
free_list= tmp;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
2006-09-19 17:40:21 +02:00
|
|
|
close_ddl_log();
|
2006-05-04 05:28:24 +02:00
|
|
|
global_ddl_log.inited= 0;
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_mutex_unlock(&LOCK_gdl);
|
|
|
|
mysql_mutex_destroy(&LOCK_gdl);
|
2007-11-13 10:09:59 +01:00
|
|
|
global_ddl_log.do_release= false;
|
2006-02-09 00:04:58 +01:00
|
|
|
DBUG_VOID_RETURN;
|
2006-02-08 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-07 10:45:07 +01:00
|
|
|
/*
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
2006-03-25 00:19:13 +01:00
|
|
|
END MODULE DDL log
|
2006-02-07 10:45:07 +01:00
|
|
|
--------------------
|
|
|
|
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2006-01-17 08:40:00 +01:00
|
|
|
|
2007-06-04 17:56:29 +02:00
|
|
|
/**
|
|
|
|
@brief construct a temporary shadow file name.
|
|
|
|
|
|
|
|
@details Make a shadow file name used by ALTER TABLE to construct the
|
|
|
|
modified table (with keeping the original). The modified table is then
|
|
|
|
moved back as original table. The name must start with the temp file
|
|
|
|
prefix so it gets filtered out by table files listing routines.
|
|
|
|
|
|
|
|
@param[out] buff buffer to receive the constructed name
|
|
|
|
@param bufflen size of buff
|
|
|
|
@param lpt alter table data structure
|
|
|
|
|
|
|
|
@retval path length
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint build_table_shadow_filename(char *buff, size_t bufflen,
|
|
|
|
ALTER_PARTITION_PARAM_TYPE *lpt)
|
|
|
|
{
|
|
|
|
char tmp_name[FN_REFLEN];
|
|
|
|
my_snprintf (tmp_name, sizeof (tmp_name), "%s-%s", tmp_file_prefix,
|
|
|
|
lpt->table_name);
|
|
|
|
return build_table_filename(buff, bufflen, lpt->db, tmp_name, "", FN_IS_TMP);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-17 08:40:00 +01:00
|
|
|
/*
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_write_frm()
|
|
|
|
lpt Struct carrying many parameters needed for this
|
|
|
|
method
|
|
|
|
flags Flags as defined below
|
|
|
|
WFRM_INITIAL_WRITE If set we need to prepare table before
|
|
|
|
creating the frm file
|
2008-01-28 15:20:55 +01:00
|
|
|
WFRM_INSTALL_SHADOW If set we should install the new frm
|
|
|
|
WFRM_KEEP_SHARE If set we know that the share is to be
|
|
|
|
retained and thus we should ensure share
|
|
|
|
object is correct, if not set we don't
|
|
|
|
set the new partition syntax string since
|
|
|
|
we know the share object is destroyed.
|
2006-01-17 08:40:00 +01:00
|
|
|
WFRM_PACK_FRM If set we should pack the frm file and delete
|
|
|
|
the frm file
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Error
|
|
|
|
FALSE Success
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
A support method that creates a new frm file and in this process it
|
|
|
|
regenerates the partition data. It works fine also for non-partitioned
|
|
|
|
tables since it only handles partitioned data if it exists.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Prepare table to prepare for writing a new frm file where the
|
|
|
|
partitions in add/drop state have temporarily changed their state
|
|
|
|
We set tmp_table to avoid get errors on naming of primary key index.
|
|
|
|
*/
|
|
|
|
int error= 0;
|
|
|
|
char path[FN_REFLEN+1];
|
2006-02-01 10:06:07 +01:00
|
|
|
char shadow_path[FN_REFLEN+1];
|
|
|
|
char shadow_frm_name[FN_REFLEN+1];
|
2006-01-17 08:40:00 +01:00
|
|
|
char frm_name[FN_REFLEN+1];
|
2007-11-23 13:27:05 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
char *part_syntax_buf;
|
|
|
|
uint syntax_len;
|
|
|
|
#endif
|
2006-01-17 08:40:00 +01:00
|
|
|
DBUG_ENTER("mysql_write_frm");
|
|
|
|
|
2006-02-01 10:06:07 +01:00
|
|
|
/*
|
|
|
|
Build shadow frm file name
|
|
|
|
*/
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
|
2006-02-03 18:05:29 +01:00
|
|
|
strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
|
2006-02-01 10:06:07 +01:00
|
|
|
if (flags & WFRM_WRITE_SHADOW)
|
2006-01-17 08:40:00 +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
|
|
|
if (mysql_prepare_create_table(lpt->thd, lpt->create_info,
|
|
|
|
lpt->alter_info,
|
|
|
|
/*tmp_table*/ 1,
|
|
|
|
&lpt->db_options,
|
|
|
|
lpt->table->file,
|
|
|
|
&lpt->key_info_buffer,
|
|
|
|
&lpt->key_count,
|
|
|
|
/*select_field_count*/ 0))
|
2006-01-17 08:40:00 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
{
|
2006-02-01 10:06:07 +01:00
|
|
|
partition_info *part_info= lpt->table->part_info;
|
|
|
|
if (part_info)
|
2006-01-17 08:40:00 +01:00
|
|
|
{
|
2006-02-01 10:06:07 +01:00
|
|
|
if (!(part_syntax_buf= generate_partition_syntax(part_info,
|
|
|
|
&syntax_len,
|
2009-10-22 16:15:06 +02:00
|
|
|
TRUE, TRUE,
|
|
|
|
lpt->create_info,
|
|
|
|
lpt->alter_info)))
|
2006-02-01 10:06:07 +01:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
part_info->part_info_string= part_syntax_buf;
|
2007-11-23 13:27:05 +01:00
|
|
|
part_info->part_info_len= syntax_len;
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-01 10:06:07 +01:00
|
|
|
/* Write shadow frm file */
|
|
|
|
lpt->create_info->table_options= lpt->db_options;
|
|
|
|
if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
|
|
|
|
lpt->table_name, lpt->create_info,
|
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
|
|
|
lpt->alter_info->create_list, lpt->key_count,
|
2006-02-01 10:06:07 +01:00
|
|
|
lpt->key_info_buffer, lpt->table->file)) ||
|
2007-12-20 19:16:55 +01:00
|
|
|
lpt->table->file->ha_create_handler_files(shadow_path, NULL,
|
|
|
|
CHF_CREATE_FLAG,
|
|
|
|
lpt->create_info))
|
2006-02-01 10:06:07 +01:00
|
|
|
{
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
|
2006-02-01 10:06:07 +01:00
|
|
|
error= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
|
|
|
if (flags & WFRM_PACK_FRM)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We need to pack the frm file and after packing it we delete the
|
|
|
|
frm file to ensure it doesn't get used. This is only used for
|
|
|
|
handlers that have the main version of the frm file stored in the
|
|
|
|
handler.
|
|
|
|
*/
|
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 *data;
|
|
|
|
size_t length;
|
2006-02-01 10:06:07 +01:00
|
|
|
if (readfrm(shadow_path, &data, &length) ||
|
2006-01-17 08:40:00 +01:00
|
|
|
packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
|
|
|
|
{
|
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled
Essentially, the problem is that safemalloc is excruciatingly
slow as it checks all allocated blocks for overrun at each
memory management primitive, yielding a almost exponential
slowdown for the memory management functions (malloc, realloc,
free). The overrun check basically consists of verifying some
bytes of a block for certain magic keys, which catches some
simple forms of overrun. Another minor problem is violation
of aliasing rules and that its own internal list of blocks
is prone to corruption.
Another issue with safemalloc is rather the maintenance cost
as the tool has a significant impact on the server code.
Given the magnitude of memory debuggers available nowadays,
especially those that are provided with the platform malloc
implementation, maintenance of a in-house and largely obsolete
memory debugger becomes a burden that is not worth the effort
due to its slowness and lack of support for detecting more
common forms of heap corruption.
Since there are third-party tools that can provide the same
functionality at a lower or comparable performance cost, the
solution is to simply remove safemalloc. Third-party tools
can provide the same functionality at a lower or comparable
performance cost.
The removal of safemalloc also allows a simplification of the
malloc wrappers, removing quite a bit of kludge: redefinition
of my_malloc, my_free and the removal of the unused second
argument of my_free. Since free() always check whether the
supplied pointer is null, redudant checks are also removed.
Also, this patch adds unit testing for my_malloc and moves
my_realloc implementation into the same file as the other
memory allocation primitives.
2010-07-08 23:20:08 +02:00
|
|
|
my_free(data);
|
|
|
|
my_free(lpt->pack_frm_data);
|
2006-01-17 08:40:00 +01:00
|
|
|
mem_alloc_error(length);
|
|
|
|
error= 1;
|
|
|
|
goto end;
|
|
|
|
}
|
2010-01-07 06:42:07 +01:00
|
|
|
error= mysql_file_delete(key_file_frm, shadow_frm_name, MYF(MY_WME));
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
2006-02-01 10:06:07 +01:00
|
|
|
if (flags & WFRM_INSTALL_SHADOW)
|
|
|
|
{
|
2006-02-20 21:07:03 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
partition_info *part_info= lpt->part_info;
|
|
|
|
#endif
|
2006-02-01 10:06:07 +01:00
|
|
|
/*
|
|
|
|
Build frm file name
|
|
|
|
*/
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(path, sizeof(path) - 1, lpt->db,
|
2006-08-02 17:57:06 +02:00
|
|
|
lpt->table_name, "", 0);
|
2006-02-01 10:06:07 +01:00
|
|
|
strxmov(frm_name, path, reg_ext, NullS);
|
|
|
|
/*
|
|
|
|
When we are changing to use new frm file we need to ensure that we
|
|
|
|
don't collide with another thread in process to open the frm file.
|
2006-04-18 16:58:12 +02:00
|
|
|
We start by deleting the .frm file and possible .par file. Then we
|
|
|
|
write to the DDL log that we have completed the delete phase by
|
|
|
|
increasing the phase of the log entry. Next step is to rename the
|
|
|
|
new .frm file and the new .par file to the real name. After
|
|
|
|
completing this we write a new phase to the log entry that will
|
|
|
|
deactivate it.
|
2006-02-01 10:06:07 +01:00
|
|
|
*/
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
|
2006-02-20 21:07:03 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2007-12-20 19:16:55 +01:00
|
|
|
lpt->table->file->ha_create_handler_files(path, shadow_path,
|
|
|
|
CHF_DELETE_FLAG, NULL) ||
|
2006-03-25 00:19:13 +01:00
|
|
|
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
|
|
|
|
(sync_ddl_log(), FALSE) ||
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_rename(key_file_frm,
|
|
|
|
shadow_frm_name, frm_name, MYF(MY_WME)) ||
|
2007-12-20 19:16:55 +01:00
|
|
|
lpt->table->file->ha_create_handler_files(path, shadow_path,
|
|
|
|
CHF_RENAME_FLAG, NULL))
|
2006-04-18 16:58:12 +02:00
|
|
|
#else
|
2010-01-07 06:42:07 +01:00
|
|
|
mysql_file_rename(key_file_frm,
|
|
|
|
shadow_frm_name, frm_name, MYF(MY_WME)))
|
2006-04-18 16:58:12 +02:00
|
|
|
#endif
|
2006-02-01 10:06:07 +01:00
|
|
|
{
|
|
|
|
error= 1;
|
2007-11-23 13:27:05 +01:00
|
|
|
goto err;
|
2006-02-01 10:06:07 +01:00
|
|
|
}
|
2007-11-23 13:27:05 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2008-01-28 15:20:55 +01:00
|
|
|
if (part_info && (flags & WFRM_KEEP_SHARE))
|
2007-11-23 13:27:05 +01:00
|
|
|
{
|
|
|
|
TABLE_SHARE *share= lpt->table->s;
|
|
|
|
char *tmp_part_syntax_str;
|
|
|
|
if (!(part_syntax_buf= generate_partition_syntax(part_info,
|
|
|
|
&syntax_len,
|
2009-10-22 16:15:06 +02:00
|
|
|
TRUE, TRUE,
|
|
|
|
lpt->create_info,
|
|
|
|
lpt->alter_info)))
|
2007-11-23 13:27:05 +01:00
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (share->partition_info_buffer_size < syntax_len + 1)
|
|
|
|
{
|
|
|
|
share->partition_info_buffer_size= syntax_len+1;
|
|
|
|
if (!(tmp_part_syntax_str= (char*) strmake_root(&share->mem_root,
|
|
|
|
part_syntax_buf,
|
|
|
|
syntax_len)))
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
goto err;
|
|
|
|
}
|
2010-03-30 22:52:45 +02:00
|
|
|
share->partition_info_str= tmp_part_syntax_str;
|
2007-11-23 13:27:05 +01:00
|
|
|
}
|
|
|
|
else
|
2010-03-30 22:52:45 +02:00
|
|
|
memcpy((char*) share->partition_info_str, part_syntax_buf,
|
|
|
|
syntax_len + 1);
|
|
|
|
share->partition_info_str_len= part_info->part_info_len= syntax_len;
|
2007-11-23 13:27:05 +01:00
|
|
|
part_info->part_info_string= part_syntax_buf;
|
2006-02-01 10:06:07 +01:00
|
|
|
}
|
2007-11-23 13:27:05 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
err:
|
2006-02-20 21:07:03 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-03-25 00:19:13 +01:00
|
|
|
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
|
2006-02-13 13:52:23 +01:00
|
|
|
part_info->frm_log_entry= NULL;
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) sync_ddl_log();
|
2006-02-20 21:07:03 +01:00
|
|
|
#endif
|
2010-08-10 14:12:11 +02:00
|
|
|
;
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
2006-02-01 10:06:07 +01:00
|
|
|
|
2006-01-17 08:40:00 +01:00
|
|
|
end:
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
SYNOPSIS
|
|
|
|
write_bin_log()
|
|
|
|
thd Thread object
|
|
|
|
clear_error is clear_error to be called
|
|
|
|
query Query to log
|
|
|
|
query_length Length of query
|
2010-08-20 04:59:58 +02:00
|
|
|
is_trans if the event changes either
|
|
|
|
a trans or non-trans engine.
|
2006-01-17 08:40:00 +01:00
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
NONE
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Write the binlog if open, routine used in multiple places in this
|
|
|
|
file
|
|
|
|
*/
|
|
|
|
|
2010-02-04 21:15:47 +01:00
|
|
|
int write_bin_log(THD *thd, bool clear_error,
|
2010-01-07 16:39:11 +01:00
|
|
|
char const *query, ulong query_length, bool is_trans)
|
2006-01-17 08:40:00 +01:00
|
|
|
{
|
2010-02-04 21:15:47 +01:00
|
|
|
int error= 0;
|
2006-01-17 08:40:00 +01:00
|
|
|
if (mysql_bin_log.is_open())
|
|
|
|
{
|
2009-05-30 15:32:28 +02:00
|
|
|
int errcode= 0;
|
2006-01-17 08:40:00 +01:00
|
|
|
if (clear_error)
|
|
|
|
thd->clear_error();
|
2009-05-30 15:32:28 +02:00
|
|
|
else
|
|
|
|
errcode= query_error_code(thd, TRUE);
|
2010-02-04 21:15:47 +01:00
|
|
|
error= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
2010-01-07 16:39:11 +01:00
|
|
|
query, query_length, is_trans, FALSE, FALSE,
|
|
|
|
errcode);
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
2010-02-04 21:15:47 +01:00
|
|
|
return error;
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
|
|
|
|
2005-05-26 05:26:40 +02:00
|
|
|
|
2003-01-29 18:10:33 +01:00
|
|
|
/*
|
|
|
|
delete (drop) tables.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_rm_table()
|
|
|
|
thd Thread handle
|
|
|
|
tables List of tables to delete
|
|
|
|
if_exists If 1, don't give error if one table doesn't exists
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
Will delete all tables that can be deleted and give a compact error
|
|
|
|
messages for tables that could not be deleted.
|
|
|
|
If a table is in use, we will wait for all users to free the table
|
|
|
|
before dropping it
|
|
|
|
|
2009-11-20 21:12:57 +01:00
|
|
|
Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but
|
|
|
|
not if under LOCK TABLES.
|
2003-01-29 18:10:33 +01:00
|
|
|
|
|
|
|
RETURN
|
2004-10-20 03:04:37 +02:00
|
|
|
FALSE OK. In this case ok packet is sent to user
|
|
|
|
TRUE Error
|
2003-01-29 18:10:33 +01:00
|
|
|
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-10-20 03:04:37 +02:00
|
|
|
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
|
|
|
|
my_bool drop_temporary)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-12-09 15:25:48 +01:00
|
|
|
bool error;
|
2010-03-13 11:58:27 +01:00
|
|
|
Drop_table_error_handler err_handler;
|
2010-11-16 11:00:12 +01:00
|
|
|
TABLE_LIST *table;
|
2009-12-09 15:25:48 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("mysql_rm_table");
|
|
|
|
|
2010-11-16 11:00:12 +01:00
|
|
|
/* Disable drop of enabled log tables, must be done before name locking */
|
|
|
|
for (table= tables; table; table= table->next_local)
|
|
|
|
{
|
|
|
|
if (check_if_log_table(table->db_length, table->db,
|
|
|
|
table->table_name_length, table->table_name, true))
|
|
|
|
{
|
|
|
|
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mysql_ha_rm_tables(thd, tables);
|
|
|
|
|
|
|
|
if (!drop_temporary)
|
|
|
|
{
|
|
|
|
if (!thd->locked_tables_mode)
|
|
|
|
{
|
|
|
|
if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
|
|
|
|
MYSQL_OPEN_SKIP_TEMPORARY))
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
for (table= tables; table; table= table->next_local)
|
|
|
|
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (table= tables; table; table= table->next_local)
|
|
|
|
if (table->open_type != OT_BASE_ONLY &&
|
|
|
|
find_temporary_table(thd, table))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
A temporary table.
|
|
|
|
|
|
|
|
Don't try to find a corresponding MDL lock or assign it
|
|
|
|
to table->mdl_request.ticket. There can't be metadata
|
|
|
|
locks for temporary tables: they are local to the session.
|
|
|
|
|
|
|
|
Later in this function we release the MDL lock only if
|
|
|
|
table->mdl_requeset.ticket is not NULL. Thus here we
|
|
|
|
ensure that we won't release the metadata lock on the base
|
|
|
|
table locked with LOCK TABLES as a side effect of temporary
|
|
|
|
table drop.
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(table->mdl_request.ticket == NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Not a temporary table.
|
|
|
|
|
|
|
|
Since 'tables' list can't contain duplicates (this is ensured
|
|
|
|
by parser) it is safe to cache pointer to the TABLE instances
|
|
|
|
in its elements.
|
|
|
|
*/
|
2011-03-07 10:08:10 +01:00
|
|
|
table->table= find_table_for_mdl_upgrade(thd, table->db,
|
2010-11-16 11:00:12 +01:00
|
|
|
table->table_name, false);
|
|
|
|
if (!table->table)
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
table->mdl_request.ticket= table->table->mdl_ticket;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* mark for close and remove all cached entries */
|
2009-09-10 10:49:49 +02:00
|
|
|
thd->push_internal_handler(&err_handler);
|
2010-11-16 11:00:12 +01:00
|
|
|
error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
|
|
|
|
false, false);
|
2009-09-10 10:49:49 +02:00
|
|
|
thd->pop_internal_handler();
|
|
|
|
|
2001-09-02 12:47:00 +02:00
|
|
|
if (error)
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2008-02-19 13:45:21 +01:00
|
|
|
my_ok(thd);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2001-09-02 12:47:00 +02:00
|
|
|
}
|
|
|
|
|
2003-01-04 14:37:20 +01:00
|
|
|
|
2010-11-16 11:00:12 +01:00
|
|
|
/**
|
|
|
|
Execute the drop of a normal or temporary table.
|
|
|
|
|
|
|
|
@param thd Thread handler
|
|
|
|
@param tables Tables to drop
|
|
|
|
@param if_exists If set, don't give an error if table doesn't exists.
|
|
|
|
In this case we give an warning of level 'NOTE'
|
|
|
|
@param drop_temporary Only drop temporary tables
|
|
|
|
@param drop_view Allow to delete VIEW .frm
|
|
|
|
@param dont_log_query Don't write query to log files. This will also not
|
|
|
|
generate warnings if the handler files doesn't exists
|
|
|
|
|
|
|
|
@retval 0 ok
|
|
|
|
@retval 1 Error
|
|
|
|
@retval -1 Thread was killed
|
|
|
|
|
|
|
|
@note This function assumes that metadata locks have already been taken.
|
|
|
|
It is also assumed that the tables have been removed from TDC.
|
|
|
|
|
|
|
|
@todo When logging to the binary log, we should log
|
|
|
|
tmp_tables and transactional tables as separate statements if we
|
|
|
|
are in a transaction; This is needed to get these tables into the
|
|
|
|
cached binary log that is only written on COMMIT.
|
|
|
|
The current code only writes DROP statements that only uses temporary
|
|
|
|
tables to the cache binary log. This should be ok on most cases, but
|
|
|
|
not all.
|
2002-11-07 03:02:37 +01:00
|
|
|
*/
|
2001-09-02 12:47:00 +02:00
|
|
|
|
2010-11-16 11:00:12 +01:00
|
|
|
int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|
|
|
bool drop_temporary, bool drop_view,
|
|
|
|
bool dont_log_query)
|
2001-09-02 12:47:00 +02:00
|
|
|
{
|
|
|
|
TABLE_LIST *table;
|
2010-05-26 16:12:23 +02:00
|
|
|
char path[FN_REFLEN + 1], *alias= NULL;
|
|
|
|
uint path_length= 0;
|
2001-09-02 12:47:00 +02:00
|
|
|
String wrong_tables;
|
2007-11-01 21:52:56 +01:00
|
|
|
int error= 0;
|
2005-12-22 06:39:02 +01:00
|
|
|
int non_temp_tables_count= 0;
|
2010-08-20 04:59:58 +02:00
|
|
|
bool foreign_key_error=0;
|
|
|
|
bool non_tmp_error= 0;
|
|
|
|
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
|
|
|
bool non_tmp_table_deleted= 0;
|
2005-12-22 06:39:02 +01:00
|
|
|
String built_query;
|
2010-08-20 04:59:58 +02:00
|
|
|
String built_trans_tmp_query, built_non_trans_tmp_query;
|
2010-11-16 11:00:12 +01:00
|
|
|
DBUG_ENTER("mysql_rm_table_no_locks");
|
2001-09-02 12:47:00 +02:00
|
|
|
|
2010-08-20 04:59:58 +02:00
|
|
|
/*
|
|
|
|
Prepares the drop statements that will be written into the binary
|
|
|
|
log as follows:
|
|
|
|
|
|
|
|
1 - If we are not processing a "DROP TEMPORARY" it prepares a
|
|
|
|
"DROP".
|
|
|
|
|
|
|
|
2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
|
|
|
|
not true.
|
|
|
|
|
|
|
|
3 - If the current format is row, the IF EXISTS token needs to be
|
|
|
|
appended because one does not know if CREATE TEMPORARY was previously
|
|
|
|
written to the binary log.
|
|
|
|
|
|
|
|
4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
|
|
|
|
|
|
|
|
5 - For temporary tables, there is a need to differentiate tables
|
|
|
|
in transactional and non-transactional storage engines. For that,
|
|
|
|
reason, two types of drop statements are prepared.
|
|
|
|
|
|
|
|
The need to different the type of tables when dropping a temporary
|
|
|
|
table stems from the fact that such drop does not commit an ongoing
|
|
|
|
transaction and changes to non-transactional tables must be written
|
|
|
|
ahead of the transaction in some circumstances.
|
|
|
|
*/
|
|
|
|
if (!dont_log_query)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
if (!drop_temporary)
|
|
|
|
{
|
|
|
|
built_query.set_charset(system_charset_info);
|
|
|
|
if (if_exists)
|
|
|
|
built_query.append("DROP TABLE IF EXISTS ");
|
|
|
|
else
|
|
|
|
built_query.append("DROP TABLE ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thd->is_current_stmt_binlog_format_row() || if_exists)
|
|
|
|
{
|
|
|
|
built_trans_tmp_query.set_charset(system_charset_info);
|
|
|
|
built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
|
|
|
built_non_trans_tmp_query.set_charset(system_charset_info);
|
|
|
|
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
else
|
2010-08-20 04:59:58 +02:00
|
|
|
{
|
|
|
|
built_trans_tmp_query.set_charset(system_charset_info);
|
|
|
|
built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
|
|
|
|
built_non_trans_tmp_query.set_charset(system_charset_info);
|
|
|
|
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
2007-07-14 00:04:48 +02:00
|
|
|
|
2004-07-16 00:15:55 +02:00
|
|
|
for (table= tables; table; table= table->next_local)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
bool is_trans;
|
2003-03-04 12:36:59 +01:00
|
|
|
char *db=table->db;
|
2005-12-21 19:18:40 +01:00
|
|
|
handlerton *table_type;
|
2010-02-01 16:07:00 +01:00
|
|
|
enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
|
2005-11-03 15:10:11 +01:00
|
|
|
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx",
|
|
|
|
table->db, table->table_name, (long) table->table,
|
|
|
|
table->table ? (long) table->table->s : (long) -1));
|
2007-11-01 21:52:56 +01:00
|
|
|
|
2010-11-16 11:00:12 +01:00
|
|
|
/*
|
|
|
|
If we are in locked tables mode and are dropping a temporary table,
|
|
|
|
the ticket should be NULL to ensure that we don't release a lock
|
|
|
|
on a base table later.
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(!(thd->locked_tables_mode &&
|
|
|
|
table->open_type != OT_BASE_ONLY &&
|
|
|
|
find_temporary_table(thd, table) &&
|
|
|
|
table->mdl_request.ticket != NULL));
|
|
|
|
|
2010-08-20 04:59:58 +02:00
|
|
|
/*
|
|
|
|
drop_temporary_table may return one of the following error codes:
|
|
|
|
. 0 - a temporary table was successfully dropped.
|
|
|
|
. 1 - a temporary table was not found.
|
|
|
|
. -1 - a temporary table is used by an outer statement.
|
|
|
|
*/
|
Backport from mysql-6.0-codebase of:
------------------------------------------------------------
revno: 3672
committer: lars-erik.bjork@sun.com
branch nick: 48067-mysql-6.0-codebase-bugfixing
timestamp: Mon 2009-10-26 13:51:43 +0100
message:
This is a patch for bug#48067
"A temp table with the same name as an existing table, makes drop
database fail"
When dropping the database, mysql_rm_known_files() reads the contents
of the database directory, and creates a TABLE_LIST object, for each
.frm file encountered. Temporary tables, however, are not associated
with any .frm file.
The list of tables to drop are passed to mysql_rm_table_part2().
This method prefers temporary tables over regular tables, so if
there is a temporary table with the same name as a regular, the
temporary is removed, leaving the regular table intact.
Regular tables are only deleted if there are no temporary tables
with the same name.
This fix ensures, that for all TABLE_LIST objects that are created
by mysql_rm_known_files(), 'open_type' is set to 'OT_BASE_ONLY', to
indicate that this is a regular table. In all cases in
mysql_rm_table_part2() where we prefer a temporary table to a
non-temporary table, we chek if 'open_type' equals 'OT_BASE_ONLY'.
2010-06-23 13:34:40 +02:00
|
|
|
if (table->open_type == OT_BASE_ONLY)
|
|
|
|
error= 1;
|
2010-08-20 04:59:58 +02:00
|
|
|
else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(thd->in_sub_stmt);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((drop_temporary && if_exists) || !error)
|
|
|
|
{
|
2010-04-20 11:10:43 +02:00
|
|
|
/*
|
2010-08-20 04:59:58 +02:00
|
|
|
This handles the case of temporary tables. We have the following cases:
|
|
|
|
|
|
|
|
. "DROP TEMPORARY" was executed and a temporary table was affected
|
|
|
|
(i.e. drop_temporary && !error) or the if_exists was specified (i.e.
|
|
|
|
drop_temporary && if_exists).
|
|
|
|
|
|
|
|
. "DROP" was executed but a temporary table was affected (.i.e
|
|
|
|
!error).
|
2010-04-20 11:10:43 +02:00
|
|
|
*/
|
2010-08-20 04:59:58 +02:00
|
|
|
if (!dont_log_query)
|
2009-07-26 23:48:24 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
/*
|
|
|
|
If there is an error, we don't know the type of the engine
|
|
|
|
at this point. So, we keep it in the trx-cache.
|
|
|
|
*/
|
|
|
|
is_trans= error ? TRUE : is_trans;
|
|
|
|
if (is_trans)
|
|
|
|
trans_tmp_table_deleted= TRUE;
|
|
|
|
else
|
|
|
|
non_trans_tmp_table_deleted= TRUE;
|
2009-07-26 23:48:24 +02:00
|
|
|
|
2010-08-20 04:59:58 +02:00
|
|
|
String *built_ptr_query=
|
|
|
|
(is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
|
|
|
|
/*
|
|
|
|
Don't write the database name if it is the current one (or if
|
|
|
|
thd->db is NULL).
|
|
|
|
*/
|
|
|
|
built_ptr_query->append("`");
|
2009-07-26 23:48:24 +02:00
|
|
|
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
built_ptr_query->append(db);
|
|
|
|
built_ptr_query->append("`.`");
|
2009-07-26 23:48:24 +02:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
built_ptr_query->append(table->table_name);
|
|
|
|
built_ptr_query->append("`,");
|
2009-07-26 23:48:24 +02:00
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
/*
|
2010-08-20 04:59:58 +02:00
|
|
|
This means that a temporary table was droped and as such there
|
|
|
|
is no need to proceed with the code that tries to drop a regular
|
|
|
|
table.
|
2005-12-22 06:39:02 +01:00
|
|
|
*/
|
2010-08-20 04:59:58 +02:00
|
|
|
if (!error) continue;
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
else if (!drop_temporary)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
non_temp_tables_count++;
|
|
|
|
|
2009-12-01 15:39:03 +01:00
|
|
|
if (thd->locked_tables_mode)
|
2009-11-30 16:55:03 +01:00
|
|
|
{
|
2009-12-02 16:22:15 +01:00
|
|
|
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
|
2009-11-30 16:55:03 +01:00
|
|
|
{
|
|
|
|
error= -1;
|
2009-12-02 16:22:15 +01:00
|
|
|
goto err;
|
2009-11-30 16:55:03 +01:00
|
|
|
}
|
2009-12-02 16:22:15 +01:00
|
|
|
close_all_tables_for_name(thd, table->table->s, TRUE);
|
2009-11-30 23:39:13 +01:00
|
|
|
table->table= 0;
|
2009-11-30 16:55:03 +01:00
|
|
|
}
|
2006-03-29 13:27:36 +02:00
|
|
|
|
2010-11-16 11:00:12 +01:00
|
|
|
/* Check that we have an exclusive lock on the table to be dropped. */
|
|
|
|
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
|
|
|
|
table->table_name,
|
|
|
|
MDL_EXCLUSIVE));
|
2003-01-04 14:37:20 +01:00
|
|
|
if (thd->killed)
|
2005-02-24 22:33:42 +01:00
|
|
|
{
|
2007-07-14 00:04:48 +02:00
|
|
|
error= -1;
|
2009-12-02 16:22:15 +01:00
|
|
|
goto err;
|
2005-02-24 22:33:42 +01:00
|
|
|
}
|
2005-01-06 12:00:13 +01:00
|
|
|
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
|
2005-11-23 21:45:02 +01:00
|
|
|
/* remove .frm file and engine files */
|
2009-06-19 10:24:43 +02:00
|
|
|
path_length= build_table_filename(path, sizeof(path) - 1, db, alias,
|
|
|
|
reg_ext,
|
2007-11-23 15:21:24 +01:00
|
|
|
table->internal_tmp_table ?
|
|
|
|
FN_IS_TMP : 0);
|
2010-08-20 04:59:58 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
This handles the case where a "DROP" was executed and a regular
|
|
|
|
table "may be" dropped as drop_temporary is FALSE and error is
|
|
|
|
TRUE. If the error was FALSE a temporary table was dropped and
|
|
|
|
regardless of the status of drop_tempoary a "DROP TEMPORARY"
|
|
|
|
must be used.
|
|
|
|
*/
|
|
|
|
if (!dont_log_query)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Note that unless if_exists is TRUE or a temporary table was deleted,
|
|
|
|
there is no means to know if the statement should be written to the
|
|
|
|
binary log. See further information on this variable in what follows.
|
|
|
|
*/
|
|
|
|
non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted);
|
|
|
|
/*
|
|
|
|
Don't write the database name if it is the current one (or if
|
|
|
|
thd->db is NULL).
|
|
|
|
*/
|
|
|
|
built_query.append("`");
|
|
|
|
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
|
|
|
{
|
|
|
|
built_query.append(db);
|
|
|
|
built_query.append("`.`");
|
|
|
|
}
|
|
|
|
|
|
|
|
built_query.append(table->table_name);
|
|
|
|
built_query.append("`,");
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-11-16 11:00:12 +01:00
|
|
|
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
|
|
|
|
DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table",
|
2010-03-02 00:05:30 +01:00
|
|
|
my_sleep(100000););
|
2010-08-20 04:59:58 +02:00
|
|
|
error= 0;
|
2006-03-29 13:27:36 +02:00
|
|
|
if (drop_temporary ||
|
2010-02-01 16:07:00 +01:00
|
|
|
((access(path, F_OK) &&
|
2005-11-23 21:45:02 +01:00
|
|
|
ha_create_table_from_engine(thd, db, alias)) ||
|
|
|
|
(!drop_view &&
|
2010-05-25 22:01:38 +02:00
|
|
|
dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
/*
|
|
|
|
One of the following cases happened:
|
|
|
|
. "DROP TEMPORARY" but a temporary table was not found.
|
|
|
|
. "DROP" but table was not found on disk and table can't be
|
|
|
|
created from engine.
|
|
|
|
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
|
|
|
*/
|
2002-12-04 12:19:08 +01:00
|
|
|
if (if_exists)
|
2003-01-06 00:48:59 +01:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
|
2005-01-06 12:00:13 +01:00
|
|
|
table->table_name);
|
2002-12-04 12:19:08 +01:00
|
|
|
else
|
2010-08-20 04:59:58 +02:00
|
|
|
{
|
|
|
|
non_tmp_error = (drop_temporary ? non_tmp_error : TRUE);
|
2005-06-08 13:31:59 +02:00
|
|
|
error= 1;
|
2010-08-20 04:59:58 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-12-08 16:04:57 +01:00
|
|
|
char *end;
|
2010-02-01 16:07:00 +01:00
|
|
|
/*
|
|
|
|
Cannot use the db_type from the table, since that might have changed
|
2010-08-09 20:33:47 +02:00
|
|
|
while waiting for the exclusive name lock.
|
2010-02-01 16:07:00 +01:00
|
|
|
*/
|
|
|
|
if (frm_db_type == DB_TYPE_UNKNOWN)
|
2005-12-21 19:18:40 +01:00
|
|
|
{
|
2010-05-25 22:01:38 +02:00
|
|
|
dd_frm_type(thd, path, &frm_db_type);
|
2010-02-01 16:07:00 +01:00
|
|
|
DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
|
2005-12-21 19:18:40 +01:00
|
|
|
}
|
2010-02-01 16:07:00 +01:00
|
|
|
table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
|
2005-12-31 06:01:26 +01:00
|
|
|
// Remove extension for delete
|
|
|
|
*(end= path + path_length - reg_ext_length)= '\0';
|
2010-02-01 16:07:00 +01:00
|
|
|
DBUG_PRINT("info", ("deleting table of type %d",
|
|
|
|
(table_type ? table_type->db_type : 0)));
|
2005-11-23 21:45:02 +01:00
|
|
|
error= ha_delete_table(thd, table_type, path, db, table->table_name,
|
2005-02-21 19:41:48 +01:00
|
|
|
!dont_log_query);
|
2010-02-01 16:07:00 +01:00
|
|
|
|
|
|
|
/* No error if non existent table and 'IF EXIST' clause or view */
|
2005-10-24 15:05:06 +02:00
|
|
|
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
|
2005-12-21 19:18:40 +01:00
|
|
|
(if_exists || table_type == NULL))
|
2007-12-12 16:21:01 +01:00
|
|
|
{
|
2005-02-21 13:47:57 +01:00
|
|
|
error= 0;
|
2007-12-12 16:21:01 +01:00
|
|
|
thd->clear_error();
|
|
|
|
}
|
2004-02-01 23:10:45 +01:00
|
|
|
if (error == HA_ERR_ROW_IS_REFERENCED)
|
2004-02-11 00:06:46 +01:00
|
|
|
{
|
|
|
|
/* the table is referenced by a foreign key constraint */
|
2010-08-20 04:59:58 +02:00
|
|
|
foreign_key_error= 1;
|
2004-02-11 00:06:46 +01:00
|
|
|
}
|
2005-02-21 13:47:57 +01:00
|
|
|
if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
|
2000-12-08 16:04:57 +01:00
|
|
|
{
|
2005-02-21 13:47:57 +01:00
|
|
|
int new_error;
|
2000-12-08 16:04:57 +01:00
|
|
|
/* Delete the table definition file */
|
|
|
|
strmov(end,reg_ext);
|
2010-01-07 06:42:07 +01:00
|
|
|
if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
|
2005-03-27 14:15:21 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
non_tmp_table_deleted= TRUE;
|
2005-07-19 18:06:49 +02:00
|
|
|
new_error= Table_triggers_list::drop_all_triggers(thd, db,
|
|
|
|
table->table_name);
|
2005-03-27 14:15:21 +02:00
|
|
|
}
|
2005-02-21 13:47:57 +01:00
|
|
|
error|= new_error;
|
2005-02-17 14:22:44 +01:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
non_tmp_error= error ? TRUE : non_tmp_error;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
if (wrong_tables.length())
|
|
|
|
wrong_tables.append(',');
|
2005-01-06 12:00:13 +01:00
|
|
|
wrong_tables.append(String(table->table_name,system_charset_info));
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
|
|
|
|
table->table ? (long) table->table->s : (long) -1));
|
2009-10-22 20:22:53 +02:00
|
|
|
|
|
|
|
DBUG_EXECUTE_IF("bug43138",
|
|
|
|
my_printf_error(ER_BAD_TABLE_ERROR,
|
|
|
|
ER(ER_BAD_TABLE_ERROR), MYF(0),
|
|
|
|
table->table_name););
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-11-16 11:00:12 +01:00
|
|
|
DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
|
2010-08-20 04:59:58 +02:00
|
|
|
thd->thread_specific_used|= (trans_tmp_table_deleted ||
|
|
|
|
non_trans_tmp_table_deleted);
|
2004-06-09 16:07:01 +02:00
|
|
|
error= 0;
|
2010-08-20 04:59:58 +02:00
|
|
|
err:
|
2004-06-09 16:07:01 +02:00
|
|
|
if (wrong_tables.length())
|
|
|
|
{
|
|
|
|
if (!foreign_key_error)
|
2005-04-02 20:13:19 +02:00
|
|
|
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
|
2005-04-03 08:36:18 +02:00
|
|
|
wrong_tables.c_ptr());
|
2004-06-09 16:07:01 +02:00
|
|
|
else
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
|
2004-06-09 16:07:01 +02:00
|
|
|
error= 1;
|
|
|
|
}
|
|
|
|
|
2010-08-20 04:59:58 +02:00
|
|
|
if (non_trans_tmp_table_deleted ||
|
|
|
|
trans_tmp_table_deleted || non_tmp_table_deleted)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-03-22 21:55:08 +01:00
|
|
|
query_cache_invalidate3(thd, tables, 0);
|
2010-07-01 18:03:40 +02:00
|
|
|
if (!dont_log_query && mysql_bin_log.is_open())
|
2005-08-20 22:56:54 +02:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
if (non_trans_tmp_table_deleted)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
/* Chop of the last comma */
|
|
|
|
built_non_trans_tmp_query.chop();
|
|
|
|
built_non_trans_tmp_query.append(" /* generated by server */");
|
|
|
|
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
|
|
|
built_non_trans_tmp_query.ptr(),
|
|
|
|
built_non_trans_tmp_query.length(),
|
|
|
|
FALSE, FALSE, FALSE, 0);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
if (trans_tmp_table_deleted)
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
2010-08-20 04:59:58 +02:00
|
|
|
/* Chop of the last comma */
|
|
|
|
built_trans_tmp_query.chop();
|
|
|
|
built_trans_tmp_query.append(" /* generated by server */");
|
|
|
|
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
|
|
|
built_trans_tmp_query.ptr(),
|
|
|
|
built_trans_tmp_query.length(),
|
|
|
|
TRUE, FALSE, FALSE, 0);
|
|
|
|
}
|
|
|
|
if (non_tmp_table_deleted)
|
|
|
|
{
|
|
|
|
/* Chop of the last comma */
|
|
|
|
built_query.chop();
|
2009-07-26 23:48:24 +02:00
|
|
|
built_query.append(" /* generated by server */");
|
2010-08-20 04:59:58 +02:00
|
|
|
int error_code = (non_tmp_error ?
|
|
|
|
(foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
|
|
|
|
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
|
|
|
built_query.ptr(),
|
|
|
|
built_query.length(),
|
|
|
|
TRUE, FALSE, FALSE,
|
|
|
|
error_code);
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
2005-08-20 22:56:54 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
|
2009-11-30 16:55:03 +01:00
|
|
|
if (!drop_temporary)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Under LOCK TABLES we should release meta-data locks on the tables
|
2010-07-27 12:25:53 +02:00
|
|
|
which were dropped.
|
2009-11-30 23:39:13 +01:00
|
|
|
|
|
|
|
Leave LOCK TABLES mode if we managed to drop all tables which were
|
|
|
|
locked. Additional check for 'non_temp_tables_count' is to avoid
|
|
|
|
leaving LOCK TABLES mode if we have dropped only temporary tables.
|
2009-11-30 16:55:03 +01:00
|
|
|
*/
|
2010-07-27 12:25:53 +02:00
|
|
|
if (thd->locked_tables_mode)
|
2009-11-30 23:39:13 +01:00
|
|
|
{
|
2010-01-21 21:43:03 +01:00
|
|
|
if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
|
2009-11-30 23:39:13 +01:00
|
|
|
{
|
2010-01-21 21:43:03 +01:00
|
|
|
thd->locked_tables_list.unlock_locked_tables(thd);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
for (table= tables; table; table= table->next_local)
|
|
|
|
{
|
2010-07-27 12:25:53 +02:00
|
|
|
/* Drop locks for all successfully dropped tables. */
|
|
|
|
if (table->table == NULL && table->mdl_request.ticket)
|
2010-01-21 21:43:03 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Under LOCK TABLES we may have several instances of table open
|
|
|
|
and locked and therefore have to remove several metadata lock
|
|
|
|
requests associated with them.
|
|
|
|
*/
|
|
|
|
thd->mdl_context.release_all_locks_for_name(table->mdl_request.ticket);
|
|
|
|
}
|
2009-11-30 23:39:13 +01:00
|
|
|
}
|
|
|
|
}
|
2010-07-27 12:25:53 +02:00
|
|
|
/*
|
|
|
|
Rely on the caller to implicitly commit the transaction
|
|
|
|
and release metadata locks.
|
|
|
|
*/
|
2009-11-30 16:55:03 +01:00
|
|
|
}
|
|
|
|
|
2009-11-30 23:39:13 +01:00
|
|
|
end:
|
2001-09-02 12:47:00 +02:00
|
|
|
DBUG_RETURN(error);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
/*
|
|
|
|
Quickly remove a table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
quick_rm_table()
|
|
|
|
base The handlerton handle.
|
|
|
|
db The database name.
|
|
|
|
table_name The table name.
|
|
|
|
flags flags for build_table_filename().
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 OK
|
|
|
|
!= 0 Error
|
|
|
|
*/
|
|
|
|
|
2005-12-21 19:18:40 +01:00
|
|
|
bool quick_rm_table(handlerton *base,const char *db,
|
2006-08-02 17:57:06 +02:00
|
|
|
const char *table_name, uint flags)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-06-19 10:24:43 +02:00
|
|
|
char path[FN_REFLEN + 1];
|
2005-11-23 21:45:02 +01:00
|
|
|
bool error= 0;
|
|
|
|
DBUG_ENTER("quick_rm_table");
|
|
|
|
|
2009-06-19 10:24:43 +02:00
|
|
|
uint path_length= build_table_filename(path, sizeof(path) - 1,
|
2006-08-02 17:57:06 +02:00
|
|
|
db, table_name, reg_ext, flags);
|
2010-01-07 06:42:07 +01:00
|
|
|
if (mysql_file_delete(key_file_frm, path, MYF(0)))
|
2005-11-23 21:45:02 +01:00
|
|
|
error= 1; /* purecov: inspected */
|
2005-12-31 06:01:26 +01:00
|
|
|
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
|
2008-09-15 11:19:56 +02:00
|
|
|
if (!(flags & FRM_ONLY))
|
|
|
|
error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
|
|
|
|
DBUG_RETURN(error);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2002-01-02 20:29:41 +01:00
|
|
|
/*
|
|
|
|
Sort keys in the following order:
|
|
|
|
- PRIMARY KEY
|
2007-10-29 14:34:01 +01:00
|
|
|
- UNIQUE keys where all column are NOT NULL
|
|
|
|
- UNIQUE keys that don't contain partial segments
|
2002-01-02 20:29:41 +01:00
|
|
|
- Other UNIQUE keys
|
|
|
|
- Normal keys
|
|
|
|
- Fulltext keys
|
|
|
|
|
|
|
|
This will make checking for duplicated keys faster and ensure that
|
|
|
|
PRIMARY keys are prioritized.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int sort_keys(KEY *a, KEY *b)
|
|
|
|
{
|
2007-10-29 14:34:01 +01:00
|
|
|
ulong a_flags= a->flags, b_flags= b->flags;
|
|
|
|
|
|
|
|
if (a_flags & HA_NOSAME)
|
2002-01-02 20:29:41 +01:00
|
|
|
{
|
2007-10-29 14:34:01 +01:00
|
|
|
if (!(b_flags & HA_NOSAME))
|
2002-01-02 20:29:41 +01:00
|
|
|
return -1;
|
2009-12-22 10:35:56 +01:00
|
|
|
if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
|
2002-01-02 20:29:41 +01:00
|
|
|
{
|
|
|
|
/* Sort NOT NULL keys before other keys */
|
2009-12-22 10:35:56 +01:00
|
|
|
return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
|
|
|
if (a->name == primary_key_name)
|
|
|
|
return -1;
|
|
|
|
if (b->name == primary_key_name)
|
|
|
|
return 1;
|
2007-10-29 14:34:01 +01:00
|
|
|
/* Sort keys don't containing partial segments before others */
|
|
|
|
if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
|
|
|
|
return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
2007-10-29 14:34:01 +01:00
|
|
|
else if (b_flags & HA_NOSAME)
|
2002-01-02 20:29:41 +01:00
|
|
|
return 1; // Prefer b
|
|
|
|
|
2007-10-29 14:34:01 +01:00
|
|
|
if ((a_flags ^ b_flags) & HA_FULLTEXT)
|
2002-01-02 20:29:41 +01:00
|
|
|
{
|
2007-10-29 14:34:01 +01:00
|
|
|
return (a_flags & HA_FULLTEXT) ? 1 : -1;
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
2002-01-05 21:51:42 +01:00
|
|
|
/*
|
2004-04-08 16:56:45 +02:00
|
|
|
Prefer original key order. usable_key_parts contains here
|
2002-01-05 21:51:42 +01:00
|
|
|
the original key position.
|
|
|
|
*/
|
|
|
|
return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
|
|
|
|
(a->usable_key_parts > b->usable_key_parts) ? 1 :
|
|
|
|
0);
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
|
|
|
|
2004-03-13 20:13:31 +01:00
|
|
|
/*
|
|
|
|
Check TYPELIB (set or enum) for duplicates
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2004-03-13 20:13:31 +01:00
|
|
|
SYNOPSIS
|
|
|
|
check_duplicates_in_interval()
|
|
|
|
set_or_name "SET" or "ENUM" string for warning message
|
2004-04-08 16:56:45 +02:00
|
|
|
name name of the checked column
|
|
|
|
typelib list of values for the column
|
2007-04-02 12:01:19 +02:00
|
|
|
dup_val_count returns count of duplicate elements
|
2004-03-13 20:13:31 +01:00
|
|
|
|
|
|
|
DESCRIPTION
|
2004-04-08 16:56:45 +02:00
|
|
|
This function prints an warning for each value in list
|
2004-03-13 20:13:31 +01:00
|
|
|
which has some duplicates on its right
|
|
|
|
|
|
|
|
RETURN VALUES
|
2007-04-10 12:01:04 +02:00
|
|
|
0 ok
|
|
|
|
1 Error
|
2004-03-13 20:13:31 +01:00
|
|
|
*/
|
|
|
|
|
2007-04-10 12:01:04 +02:00
|
|
|
bool check_duplicates_in_interval(const char *set_or_name,
|
2004-10-26 07:41:14 +02:00
|
|
|
const char *name, TYPELIB *typelib,
|
2007-04-02 12:01:19 +02:00
|
|
|
CHARSET_INFO *cs, unsigned int *dup_val_count)
|
2004-03-13 20:13:31 +01:00
|
|
|
{
|
2004-10-26 07:41:14 +02:00
|
|
|
TYPELIB tmp= *typelib;
|
2004-03-13 20:13:31 +01:00
|
|
|
const char **cur_value= typelib->type_names;
|
2004-10-26 07:41:14 +02:00
|
|
|
unsigned int *cur_length= typelib->type_lengths;
|
2007-04-02 12:01:19 +02:00
|
|
|
*dup_val_count= 0;
|
2004-10-26 07:41:14 +02:00
|
|
|
|
|
|
|
for ( ; tmp.count > 1; cur_value++, cur_length++)
|
2004-03-13 20:13:31 +01:00
|
|
|
{
|
2004-10-26 07:41:14 +02:00
|
|
|
tmp.type_names++;
|
|
|
|
tmp.type_lengths++;
|
|
|
|
tmp.count--;
|
|
|
|
if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
|
2004-03-13 20:13:31 +01:00
|
|
|
{
|
2009-10-15 14:23:43 +02:00
|
|
|
THD *thd= current_thd;
|
|
|
|
ErrConvString err(*cur_value, *cur_length, cs);
|
2007-04-10 12:01:04 +02:00
|
|
|
if ((current_thd->variables.sql_mode &
|
|
|
|
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
|
|
|
|
{
|
|
|
|
my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
|
2009-10-15 14:23:43 +02:00
|
|
|
name, err.ptr(), set_or_name);
|
2007-04-10 12:01:04 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2009-10-15 14:23:43 +02:00
|
|
|
push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_DUPLICATED_VALUE_IN_TYPE,
|
|
|
|
ER(ER_DUPLICATED_VALUE_IN_TYPE),
|
|
|
|
name, err.ptr(), set_or_name);
|
2007-04-02 12:01:19 +02:00
|
|
|
(*dup_val_count)++;
|
2004-03-13 20:13:31 +01:00
|
|
|
}
|
|
|
|
}
|
2007-04-10 12:01:04 +02:00
|
|
|
return 0;
|
2004-03-13 20:13:31 +01:00
|
|
|
}
|
2002-01-02 20:29:41 +01:00
|
|
|
|
2004-12-02 09:48:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check TYPELIB (set or enum) max and total lengths
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
calculate_interval_lengths()
|
|
|
|
cs charset+collation pair of the interval
|
|
|
|
typelib list of values for the column
|
|
|
|
max_length length of the longest item
|
|
|
|
tot_length sum of the item lengths
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
After this function call:
|
|
|
|
- ENUM uses max_length
|
|
|
|
- SET uses tot_length.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
void
|
|
|
|
*/
|
|
|
|
void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
|
|
|
|
uint32 *max_length, uint32 *tot_length)
|
|
|
|
{
|
|
|
|
const char **pos;
|
|
|
|
uint *len;
|
|
|
|
*max_length= *tot_length= 0;
|
|
|
|
for (pos= interval->type_names, len= interval->type_lengths;
|
|
|
|
*pos ; pos++, len++)
|
|
|
|
{
|
2009-02-13 17:41:47 +01:00
|
|
|
size_t length= cs->cset->numchars(cs, *pos, *pos + *len);
|
2004-12-02 09:48:43 +01:00
|
|
|
*tot_length+= length;
|
|
|
|
set_if_bigger(*max_length, (uint32)length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-04 22:14:35 +01:00
|
|
|
/*
|
|
|
|
Prepare a create_table instance for packing
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
prepare_create_field()
|
|
|
|
sql_field field to prepare for packing
|
|
|
|
blob_columns count for BLOBs
|
|
|
|
timestamps count for timestamps
|
|
|
|
table_flags table flags
|
|
|
|
|
|
|
|
DESCRIPTION
|
2007-06-10 12:43:57 +02:00
|
|
|
This function prepares a Create_field instance.
|
2005-03-04 22:14:35 +01:00
|
|
|
Fields such as pack_flag are valid after this call.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
0 ok
|
|
|
|
1 Error
|
|
|
|
*/
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
int prepare_create_field(Create_field *sql_field,
|
2005-03-16 15:11:01 +01:00
|
|
|
uint *blob_columns,
|
|
|
|
int *timestamps, int *timestamps_with_niladic,
|
2006-11-30 02:40:42 +01:00
|
|
|
longlong table_flags)
|
2005-03-04 22:14:35 +01:00
|
|
|
{
|
2007-04-02 12:01:19 +02:00
|
|
|
unsigned int dup_val_count;
|
2005-03-04 22:14:35 +01:00
|
|
|
DBUG_ENTER("prepare_field");
|
2005-03-16 15:11:01 +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
|
|
|
This code came from mysql_prepare_create_table.
|
2005-03-16 15:11:01 +01:00
|
|
|
Indent preserved to make patching easier
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(sql_field->charset);
|
|
|
|
|
|
|
|
switch (sql_field->sql_type) {
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
|
|
case MYSQL_TYPE_LONG_BLOB:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=FIELDFLAG_BLOB |
|
|
|
|
pack_length_to_packflag(sql_field->pack_length -
|
|
|
|
portable_sizeof_char_ptr);
|
|
|
|
if (sql_field->charset->state & MY_CS_BINSORT)
|
|
|
|
sql_field->pack_flag|=FIELDFLAG_BINARY;
|
|
|
|
sql_field->length=8; // Unireg field length
|
|
|
|
sql_field->unireg_check=Field::BLOB_FIELD;
|
2005-03-17 00:22:12 +01:00
|
|
|
(*blob_columns)++;
|
2005-03-16 15:11:01 +01:00
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_GEOMETRY:
|
2005-03-04 22:14:35 +01:00
|
|
|
#ifdef HAVE_SPATIAL
|
2005-03-16 15:11:01 +01:00
|
|
|
if (!(table_flags & HA_CAN_GEOMETRY))
|
|
|
|
{
|
|
|
|
my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
|
|
|
|
MYF(0), "GEOMETRY");
|
2005-03-04 22:14:35 +01:00
|
|
|
DBUG_RETURN(1);
|
2005-03-16 15:11:01 +01:00
|
|
|
}
|
|
|
|
sql_field->pack_flag=FIELDFLAG_GEOM |
|
|
|
|
pack_length_to_packflag(sql_field->pack_length -
|
|
|
|
portable_sizeof_char_ptr);
|
|
|
|
if (sql_field->charset->state & MY_CS_BINSORT)
|
|
|
|
sql_field->pack_flag|=FIELDFLAG_BINARY;
|
|
|
|
sql_field->length=8; // Unireg field length
|
|
|
|
sql_field->unireg_check=Field::BLOB_FIELD;
|
2005-03-17 00:22:12 +01:00
|
|
|
(*blob_columns)++;
|
2005-03-16 15:11:01 +01:00
|
|
|
break;
|
|
|
|
#else
|
|
|
|
my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
|
|
|
|
sym_group_geom.name, sym_group_geom.needed_define);
|
|
|
|
DBUG_RETURN(1);
|
2005-03-04 22:14:35 +01:00
|
|
|
#endif /*HAVE_SPATIAL*/
|
2005-03-16 15:11:01 +01:00
|
|
|
case MYSQL_TYPE_VARCHAR:
|
2005-03-04 22:14:35 +01:00
|
|
|
#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
|
2005-03-16 15:11:01 +01:00
|
|
|
if (table_flags & HA_NO_VARCHAR)
|
|
|
|
{
|
|
|
|
/* convert VARCHAR to CHAR because handler is not yet up to date */
|
|
|
|
sql_field->sql_type= MYSQL_TYPE_VAR_STRING;
|
|
|
|
sql_field->pack_length= calc_pack_length(sql_field->sql_type,
|
|
|
|
(uint) sql_field->length);
|
|
|
|
if ((sql_field->length / sql_field->charset->mbmaxlen) >
|
|
|
|
MAX_FIELD_CHARLENGTH)
|
2005-03-04 22:14:35 +01:00
|
|
|
{
|
2005-03-16 15:11:01 +01:00
|
|
|
my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
|
Fix for BUG#11755168 '46895: test "outfile_loaddata" fails (reproducible)'.
In sql_class.cc, 'row_count', of type 'ha_rows', was used as last argument for
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD which is
"Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld".
So 'ha_rows' was used as 'long'.
On SPARC32 Solaris builds, 'long' is 4 bytes and 'ha_rows' is 'longlong' i.e. 8 bytes.
So the printf-like code was reading only the first 4 bytes.
Because the CPU is big-endian, 1LL is 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
so the first four bytes yield 0. So the warning message had "row 0" instead of
"row 1" in test outfile_loaddata.test:
-Warning 1366 Incorrect string value: '\xE1\xE2\xF7' for column 'b' at row 1
+Warning 1366 Incorrect string value: '\xE1\xE2\xF7' for column 'b' at row 0
All error-messaging functions which internally invoke some printf-life function
are potential candidate for such mistakes.
One apparently easy way to catch such mistakes is to use
ATTRIBUTE_FORMAT (from my_attribute.h).
But this works only when call site has both:
a) the format as a string literal
b) the types of arguments.
So:
func(ER(ER_BLAH), 10);
will silently not be checked, because ER(ER_BLAH) is not known at
compile time (it is known at run-time, and depends on the chosen
language).
And
func("%s", a va_list argument);
has the same problem, as the *real* type of arguments is not
known at this site at compile time (it's known in some caller).
Moreover,
func(ER(ER_BLAH));
though possibly correct (if ER(ER_BLAH) has no '%' markers), will not
compile (gcc says "error: format not a string literal and no format
arguments").
Consequences:
1) ATTRIBUTE_FORMAT is here added only to functions which in practice
take "string literal" formats: "my_error_reporter" and "print_admin_msg".
2) it cannot be added to the other functions: my_error(),
push_warning_printf(), Table_check_intact::report_error(),
general_log_print().
To do a one-time check of functions listed in (2), the following
"static code analysis" has been done:
1) replace
my_error(ER_xxx, arguments for substitution in format)
with the equivalent
my_printf_error(ER_xxx,ER(ER_xxx), arguments for substitution in
format),
so that we have ER(ER_xxx) and the arguments *in the same call site*
2) add ATTRIBUTE_FORMAT to push_warning_printf(),
Table_check_intact::report_error(), general_log_print()
3) replace ER(xxx) with the hard-coded English text found in
errmsg.txt (like: ER(ER_UNKNOWN_ERROR) is replaced with
"Unknown error"), so that a call site has the format as string literal
4) this way, ATTRIBUTE_FORMAT can effectively do its job
5) compile, fix errors detected by ATTRIBUTE_FORMAT
6) revert steps 1-2-3.
The present patch has no compiler error when submitted again to the
static code analysis above.
It cannot catch all problems though: see Field::set_warning(), in
which a call to push_warning_printf() has a variable error
(thus, not replacable by a string literal); I checked set_warning() calls
by hand though.
See also WL 5883 for one proposal to avoid such bugs from appearing
again in the future.
The issues fixed in the patch are:
a) mismatch in types (like 'int' passed to '%ld')
b) more arguments passed than specified in the format.
This patch resolves mismatches by changing the type/number of arguments,
not by changing error messages of sql/share/errmsg.txt. The latter would be wrong,
per the following old rule: errmsg.txt must be as stable as possible; no insertions
or deletions of messages, no changes of type or number of printf-like format specifiers,
are allowed, as long as the change impacts a message already released in a GA version.
If this rule is not followed:
- Connectors, which use error message numbers, will be confused (by insertions/deletions
of messages)
- using errmsg.sys of MySQL 5.1.n with mysqld of MySQL 5.1.(n+1)
could produce wrong messages or crash; such usage can easily happen if
installing 5.1.(n+1) while /etc/my.cnf still has --language=/path/to/5.1.n/xxx;
or if copying mysqld from 5.1.(n+1) into a 5.1.n installation.
When fixing b), I have verified that the superfluous arguments were not used in the format
in the first 5.1 GA (5.1.30 'bteam@astra04-20081114162938-z8mctjp6st27uobm').
Had they been used, then passing them today, even if the message doesn't use them
anymore, would have been necessary, as explained above.
2011-05-16 22:04:01 +02:00
|
|
|
MYF(0), sql_field->field_name,
|
|
|
|
static_cast<ulong>(MAX_FIELD_CHARLENGTH));
|
2005-03-04 22:14:35 +01:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
2005-03-16 15:11:01 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* fall through */
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_STRING:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=0;
|
|
|
|
if (sql_field->charset->state & MY_CS_BINSORT)
|
|
|
|
sql_field->pack_flag|=FIELDFLAG_BINARY;
|
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_ENUM:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
|
|
|
|
FIELDFLAG_INTERVAL;
|
|
|
|
if (sql_field->charset->state & MY_CS_BINSORT)
|
|
|
|
sql_field->pack_flag|=FIELDFLAG_BINARY;
|
|
|
|
sql_field->unireg_check=Field::INTERVAL_FIELD;
|
2007-04-10 12:01:04 +02:00
|
|
|
if (check_duplicates_in_interval("ENUM",sql_field->field_name,
|
|
|
|
sql_field->interval,
|
|
|
|
sql_field->charset, &dup_val_count))
|
|
|
|
DBUG_RETURN(1);
|
2005-03-16 15:11:01 +01:00
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_SET:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
|
|
|
|
FIELDFLAG_BITFIELD;
|
|
|
|
if (sql_field->charset->state & MY_CS_BINSORT)
|
|
|
|
sql_field->pack_flag|=FIELDFLAG_BINARY;
|
|
|
|
sql_field->unireg_check=Field::BIT_FIELD;
|
2007-04-10 12:01:04 +02:00
|
|
|
if (check_duplicates_in_interval("SET",sql_field->field_name,
|
|
|
|
sql_field->interval,
|
|
|
|
sql_field->charset, &dup_val_count))
|
|
|
|
DBUG_RETURN(1);
|
2007-04-02 12:01:19 +02:00
|
|
|
/* Check that count of unique members is not more then 64 */
|
|
|
|
if (sql_field->interval->count - dup_val_count > sizeof(longlong)*8)
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_BIG_SET, MYF(0), sql_field->field_name);
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
2005-03-16 15:11:01 +01:00
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_DATE: // Rest of string types
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
case MYSQL_TYPE_TIME:
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
|
|
case MYSQL_TYPE_NULL:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
|
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_BIT:
|
2005-04-12 20:12:00 +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
|
|
|
We have sql_field->pack_flag already set here, see
|
|
|
|
mysql_prepare_create_table().
|
2005-04-12 20:12:00 +02:00
|
|
|
*/
|
2005-03-16 15:11:01 +01:00
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->pack_flag=(FIELDFLAG_NUMBER |
|
|
|
|
(sql_field->flags & UNSIGNED_FLAG ? 0 :
|
|
|
|
FIELDFLAG_DECIMAL) |
|
|
|
|
(sql_field->flags & ZEROFILL_FLAG ?
|
|
|
|
FIELDFLAG_ZEROFILL : 0) |
|
|
|
|
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
|
|
|
|
break;
|
2006-12-02 02:26:52 +01:00
|
|
|
case MYSQL_TYPE_TIMESTAMP:
|
2005-03-16 15:11:01 +01:00
|
|
|
/* We should replace old TIMESTAMP fields with their newer analogs */
|
|
|
|
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
|
|
|
|
{
|
2005-03-17 00:22:12 +01:00
|
|
|
if (!*timestamps)
|
2005-03-04 22:14:35 +01:00
|
|
|
{
|
2005-03-16 15:11:01 +01:00
|
|
|
sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
|
2005-03-17 00:22:12 +01:00
|
|
|
(*timestamps_with_niladic)++;
|
2005-03-04 22:14:35 +01:00
|
|
|
}
|
2005-03-16 15:11:01 +01:00
|
|
|
else
|
|
|
|
sql_field->unireg_check= Field::NONE;
|
|
|
|
}
|
|
|
|
else if (sql_field->unireg_check != Field::NONE)
|
2005-03-17 00:22:12 +01:00
|
|
|
(*timestamps_with_niladic)++;
|
2005-03-16 15:11:01 +01:00
|
|
|
|
2005-03-17 00:22:12 +01:00
|
|
|
(*timestamps)++;
|
2005-03-16 15:11:01 +01:00
|
|
|
/* fall-through */
|
|
|
|
default:
|
|
|
|
sql_field->pack_flag=(FIELDFLAG_NUMBER |
|
|
|
|
(sql_field->flags & UNSIGNED_FLAG ? 0 :
|
|
|
|
FIELDFLAG_DECIMAL) |
|
|
|
|
(sql_field->flags & ZEROFILL_FLAG ?
|
|
|
|
FIELDFLAG_ZEROFILL : 0) |
|
|
|
|
f_settype((uint) sql_field->sql_type) |
|
|
|
|
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!(sql_field->flags & NOT_NULL_FLAG))
|
|
|
|
sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
|
|
|
|
if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
|
|
|
|
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
|
2005-03-04 22:14:35 +01:00
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
2009-10-22 16:15:06 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Get character set from field object generated by parser using
|
|
|
|
default values when not set.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
get_sql_field_charset()
|
|
|
|
sql_field The sql_field object
|
|
|
|
create_info Info generated by parser
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
cs Character set
|
|
|
|
*/
|
|
|
|
|
|
|
|
CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
|
|
|
|
HA_CREATE_INFO *create_info)
|
|
|
|
{
|
|
|
|
CHARSET_INFO *cs= sql_field->charset;
|
|
|
|
|
|
|
|
if (!cs)
|
|
|
|
cs= create_info->default_table_charset;
|
|
|
|
/*
|
|
|
|
table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname
|
|
|
|
if we want change character set for all varchar/char columns.
|
|
|
|
But the table charset must not affect the BLOB fields, so don't
|
|
|
|
allow to change my_charset_bin to somethig else.
|
|
|
|
*/
|
|
|
|
if (create_info->table_charset && cs != &my_charset_bin)
|
|
|
|
cs= create_info->table_charset;
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-20 11:07:32 +01:00
|
|
|
bool check_duplicate_warning(THD *thd, char *msg, ulong length)
|
|
|
|
{
|
|
|
|
List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
|
|
|
|
MYSQL_ERROR *err;
|
|
|
|
while ((err= it++))
|
|
|
|
{
|
|
|
|
if (strncmp(msg, err->get_message_text(), length) == 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-03 14:44:25 +02:00
|
|
|
/*
|
2004-03-30 19:22:14 +02:00
|
|
|
Preparation for table creation
|
2002-09-03 14:44:25 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
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
|
|
|
mysql_prepare_create_table()
|
2006-01-12 10:05:07 +01:00
|
|
|
thd Thread object.
|
|
|
|
create_info Create information (like MAX_ROWS).
|
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
|
|
|
alter_info List of columns and indexes to create
|
2006-01-12 10:05:07 +01:00
|
|
|
tmp_table If a temporary table is to be created.
|
|
|
|
db_options INOUT Table options (like HA_OPTION_PACK_RECORD).
|
|
|
|
file The handler for the new table.
|
|
|
|
key_info_buffer OUT An array of KEY structs for the indexes.
|
|
|
|
key_count OUT The number of elements in the array.
|
|
|
|
select_field_count The number of fields coming from a select table.
|
2002-09-03 14:44:25 +02:00
|
|
|
|
2003-09-03 11:34:32 +02:00
|
|
|
DESCRIPTION
|
2004-03-30 19:22:14 +02:00
|
|
|
Prepares the table and key structures for table creation.
|
2002-09-03 14:44:25 +02:00
|
|
|
|
2004-12-06 01:00:37 +01:00
|
|
|
NOTES
|
2005-03-22 14:48:06 +01:00
|
|
|
sets create_info->varchar if the table has a varchar
|
2004-12-06 01:00:37 +01:00
|
|
|
|
2002-09-03 14:44:25 +02:00
|
|
|
RETURN VALUES
|
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
|
|
|
FALSE OK
|
|
|
|
TRUE error
|
2002-09-03 14:44:25 +02:00
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2008-03-23 13:29:35 +01:00
|
|
|
static int
|
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
|
|
|
mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
|
|
|
|
Alter_info *alter_info,
|
|
|
|
bool tmp_table,
|
|
|
|
uint *db_options,
|
|
|
|
handler *file, KEY **key_info_buffer,
|
|
|
|
uint *key_count, int select_field_count)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-08 16:56:45 +02:00
|
|
|
const char *key_name;
|
2007-06-10 12:43:57 +02:00
|
|
|
Create_field *sql_field,*dup_field;
|
2005-05-16 14:21:35 +02:00
|
|
|
uint field,null_fields,blob_columns,max_key_length;
|
2005-05-13 23:01:40 +02:00
|
|
|
ulong record_offset= 0;
|
2004-04-08 16:56:45 +02:00
|
|
|
KEY *key_info;
|
2000-07-31 21:29:14 +02:00
|
|
|
KEY_PART_INFO *key_part_info;
|
2004-04-08 16:56:45 +02:00
|
|
|
int timestamps= 0, timestamps_with_niladic= 0;
|
|
|
|
int field_no,dup_no;
|
|
|
|
int select_field_pos,auto_increment=0;
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Create_field> it(alter_info->create_list);
|
|
|
|
List_iterator<Create_field> it2(alter_info->create_list);
|
2004-12-17 15:06:05 +01:00
|
|
|
uint total_uneven_bit_length= 0;
|
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
|
|
|
DBUG_ENTER("mysql_prepare_create_table");
|
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
|
|
|
select_field_pos= alter_info->create_list.elements - select_field_count;
|
2000-07-31 21:29:14 +02:00
|
|
|
null_fields=blob_columns=0;
|
2004-12-06 01:00:37 +01:00
|
|
|
create_info->varchar= 0;
|
2005-05-16 14:21:35 +02:00
|
|
|
max_key_length= file->max_key_length();
|
2001-06-06 21:45:07 +02:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
for (field_no=0; (sql_field=it++) ; field_no++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
CHARSET_INFO *save_cs;
|
|
|
|
|
2006-02-21 17:52:20 +01:00
|
|
|
/*
|
|
|
|
Initialize length from its original value (number of characters),
|
|
|
|
which was set in the parser. This is necessary if we're
|
|
|
|
executing a prepared statement for the second time.
|
|
|
|
*/
|
|
|
|
sql_field->length= sql_field->char_length;
|
2009-10-22 16:15:06 +02:00
|
|
|
save_cs= sql_field->charset= get_sql_field_charset(sql_field,
|
|
|
|
create_info);
|
2004-03-26 13:11:46 +01:00
|
|
|
if ((sql_field->flags & BINCMP_FLAG) &&
|
|
|
|
!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
|
|
|
|
MY_CS_BINSORT,MYF(0))))
|
|
|
|
{
|
2009-12-18 19:44:24 +01:00
|
|
|
char tmp[65];
|
2005-11-20 19:47:07 +01:00
|
|
|
strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
|
|
|
|
STRING_WITH_LEN("_bin"));
|
2004-03-26 13:11:46 +01:00
|
|
|
my_error(ER_UNKNOWN_COLLATION, MYF(0), 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
|
|
|
DBUG_RETURN(TRUE);
|
2004-03-26 13:11:46 +01:00
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2006-08-15 12:24:07 +02:00
|
|
|
/*
|
2006-09-01 08:53:56 +02:00
|
|
|
Convert the default value from client character
|
2006-08-15 12:24:07 +02:00
|
|
|
set into the column character set if necessary.
|
|
|
|
*/
|
|
|
|
if (sql_field->def &&
|
2006-09-01 08:53:56 +02:00
|
|
|
save_cs != sql_field->def->collation.collation &&
|
2006-12-02 02:26:52 +01:00
|
|
|
(sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_STRING ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_SET ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_ENUM))
|
2006-08-15 12:24:07 +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
|
|
|
/*
|
2007-06-10 12:43:57 +02:00
|
|
|
Starting from 5.1 we work here with a copy of Create_field
|
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
|
|
|
created by the caller, not with the instance that was
|
|
|
|
originally created during parsing. It's OK to create
|
|
|
|
a temporary item and initialize with it a member of the
|
|
|
|
copy -- this item will be thrown away along with the copy
|
|
|
|
at the end of execution, and thus not introduce a dangling
|
|
|
|
pointer in the parsed tree of a prepared statement or a
|
|
|
|
stored procedure statement.
|
|
|
|
*/
|
2006-09-01 08:53:56 +02:00
|
|
|
sql_field->def= sql_field->def->safe_charset_converter(save_cs);
|
2006-08-15 12:24:07 +02:00
|
|
|
|
|
|
|
if (sql_field->def == NULL)
|
|
|
|
{
|
|
|
|
/* Could not convert */
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-08-15 12:24:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_SET ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_ENUM)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
|
|
|
uint32 dummy;
|
|
|
|
CHARSET_INFO *cs= sql_field->charset;
|
2004-12-07 12:08:56 +01:00
|
|
|
TYPELIB *interval= sql_field->interval;
|
2004-12-02 09:48:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Create typelib from interval_list, and if necessary
|
|
|
|
convert strings from client character set to the
|
|
|
|
column character set.
|
|
|
|
*/
|
2004-12-07 12:08:56 +01:00
|
|
|
if (!interval)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
2005-11-25 11:25:31 +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
|
|
|
Create the typelib in runtime memory - we will free the
|
|
|
|
occupied memory at the same time when we free this
|
|
|
|
sql_field -- at the end of execution.
|
2005-11-25 11:25:31 +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
|
|
|
interval= sql_field->interval= typelib(thd->mem_root,
|
2005-11-25 11:25:31 +01:00
|
|
|
sql_field->interval_list);
|
2006-12-14 23:51:37 +01:00
|
|
|
List_iterator<String> int_it(sql_field->interval_list);
|
2004-12-07 12:08:56 +01:00
|
|
|
String conv, *tmp;
|
2010-02-24 10:15:34 +01:00
|
|
|
char comma_buf[4]; /* 4 bytes for utf32 */
|
2006-03-29 16:52:26 +02:00
|
|
|
int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
|
|
|
|
(uchar*) comma_buf +
|
|
|
|
sizeof(comma_buf));
|
|
|
|
DBUG_ASSERT(comma_length > 0);
|
2006-12-14 23:51:37 +01:00
|
|
|
for (uint i= 0; (tmp= int_it++); i++)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
2009-02-13 17:41:47 +01:00
|
|
|
size_t lengthsp;
|
2004-12-07 12:08:56 +01:00
|
|
|
if (String::needs_conversion(tmp->length(), tmp->charset(),
|
|
|
|
cs, &dummy))
|
|
|
|
{
|
|
|
|
uint cnv_errs;
|
|
|
|
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
|
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
|
|
|
interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
|
2005-05-06 10:39:30 +02:00
|
|
|
conv.length());
|
2004-12-07 12:08:56 +01:00
|
|
|
interval->type_lengths[i]= conv.length();
|
|
|
|
}
|
2004-12-02 09:48:43 +01:00
|
|
|
|
2004-12-07 12:08:56 +01:00
|
|
|
// Strip trailing spaces.
|
2005-05-06 10:39:30 +02:00
|
|
|
lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
|
|
|
|
interval->type_lengths[i]);
|
2004-12-07 12:08:56 +01:00
|
|
|
interval->type_lengths[i]= lengthsp;
|
|
|
|
((uchar *)interval->type_names[i])[lengthsp]= '\0';
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_SET)
|
2006-03-29 16:52:26 +02:00
|
|
|
{
|
|
|
|
if (cs->coll->instr(cs, interval->type_names[i],
|
|
|
|
interval->type_lengths[i],
|
|
|
|
comma_buf, comma_length, NULL, 0))
|
|
|
|
{
|
2009-10-15 14:23:43 +02:00
|
|
|
ErrConvString err(tmp->ptr(), tmp->length(), cs);
|
|
|
|
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-03-29 16:52:26 +02:00
|
|
|
}
|
|
|
|
}
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
2004-12-07 12:08:56 +01:00
|
|
|
sql_field->interval_list.empty(); // Don't need interval_list anymore
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
|
|
|
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_SET)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
2004-12-07 14:47:00 +01:00
|
|
|
uint32 field_length;
|
2006-04-28 18:15:29 +02:00
|
|
|
if (sql_field->def != NULL)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
|
|
|
char *not_used;
|
|
|
|
uint not_used2;
|
|
|
|
bool not_found= 0;
|
|
|
|
String str, *def= sql_field->def->val_str(&str);
|
2006-04-28 18:15:29 +02:00
|
|
|
if (def == NULL) /* SQL "NULL" maps to NULL */
|
|
|
|
{
|
|
|
|
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
|
|
|
|
{
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-04-28 18:15:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* else, NULL is an allowed value */
|
|
|
|
(void) find_set(interval, NULL, 0,
|
|
|
|
cs, ¬_used, ¬_used2, ¬_found);
|
|
|
|
}
|
|
|
|
else /* not NULL */
|
|
|
|
{
|
|
|
|
(void) find_set(interval, def->ptr(), def->length(),
|
|
|
|
cs, ¬_used, ¬_used2, ¬_found);
|
|
|
|
}
|
|
|
|
|
2004-12-02 09:48:43 +01:00
|
|
|
if (not_found)
|
|
|
|
{
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
|
|
|
}
|
2004-12-07 14:47:00 +01:00
|
|
|
calculate_interval_lengths(cs, interval, &dummy, &field_length);
|
|
|
|
sql_field->length= field_length + (interval->count - 1);
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
2006-12-02 02:26:52 +01:00
|
|
|
else /* MYSQL_TYPE_ENUM */
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
2004-12-07 14:47:00 +01:00
|
|
|
uint32 field_length;
|
2006-12-02 02:26:52 +01:00
|
|
|
DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
|
2006-04-28 18:15:29 +02:00
|
|
|
if (sql_field->def != NULL)
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
|
|
|
String str, *def= sql_field->def->val_str(&str);
|
2006-04-28 18:15:29 +02:00
|
|
|
if (def == NULL) /* SQL "NULL" maps to NULL */
|
2004-12-02 09:48:43 +01:00
|
|
|
{
|
2006-04-28 18:15:29 +02:00
|
|
|
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
|
|
|
|
{
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-04-28 18:15:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* else, the defaults yield the correct length for NULLs. */
|
|
|
|
}
|
|
|
|
else /* not NULL */
|
|
|
|
{
|
|
|
|
def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
|
|
|
|
if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
|
|
|
|
{
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-04-28 18:15:29 +02:00
|
|
|
}
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
|
|
|
}
|
2004-12-07 14:47:00 +01:00
|
|
|
calculate_interval_lengths(cs, interval, &field_length, &dummy);
|
|
|
|
sql_field->length= field_length;
|
2004-12-02 09:48:43 +01:00
|
|
|
}
|
|
|
|
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
|
|
|
|
}
|
|
|
|
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_BIT)
|
2005-04-12 09:27:43 +02:00
|
|
|
{
|
2005-04-12 20:12:00 +02:00
|
|
|
sql_field->pack_flag= FIELDFLAG_NUMBER;
|
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
|
|
|
if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
|
2005-04-12 09:27:43 +02:00
|
|
|
total_uneven_bit_length+= sql_field->length & 7;
|
|
|
|
else
|
|
|
|
sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
|
|
|
|
}
|
|
|
|
|
2003-09-10 14:25:26 +02:00
|
|
|
sql_field->create_length_to_internal_length();
|
2005-05-06 10:39:30 +02:00
|
|
|
if (prepare_blob_field(thd, sql_field))
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2003-10-15 13:40:20 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!(sql_field->flags & NOT_NULL_FLAG))
|
|
|
|
null_fields++;
|
2004-12-17 15:06:05 +01:00
|
|
|
|
2003-03-14 16:08:42 +01:00
|
|
|
if (check_column_name(sql_field->field_name))
|
|
|
|
{
|
2003-11-18 16:28:00 +01:00
|
|
|
my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2003-03-14 16:08:42 +01:00
|
|
|
}
|
2003-03-16 18:17:54 +01:00
|
|
|
|
2002-10-02 12:33:08 +02:00
|
|
|
/* Check if we have used the same field name before */
|
|
|
|
for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-07-20 16:36:56 +02:00
|
|
|
if (my_strcasecmp(system_charset_info,
|
2004-04-08 16:56:45 +02:00
|
|
|
sql_field->field_name,
|
|
|
|
dup_field->field_name) == 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2002-10-02 12:33:08 +02:00
|
|
|
/*
|
|
|
|
If this was a CREATE ... SELECT statement, accept a field
|
|
|
|
redefinition if we are changing a field in the SELECT part
|
|
|
|
*/
|
2004-04-08 16:56:45 +02:00
|
|
|
if (field_no < select_field_pos || dup_no >= select_field_pos)
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-10-02 12:33:08 +02:00
|
|
|
/* Field redefined */
|
2005-11-09 07:34:46 +01:00
|
|
|
sql_field->def= dup_field->def;
|
2003-08-11 15:18:34 +02:00
|
|
|
sql_field->sql_type= dup_field->sql_type;
|
2003-11-18 12:47:27 +01:00
|
|
|
sql_field->charset= (dup_field->charset ?
|
|
|
|
dup_field->charset :
|
|
|
|
create_info->default_table_charset);
|
2006-02-21 17:52:20 +01:00
|
|
|
sql_field->length= dup_field->char_length;
|
2005-10-25 22:56:17 +02:00
|
|
|
sql_field->pack_length= dup_field->pack_length;
|
2004-12-07 14:47:00 +01:00
|
|
|
sql_field->key_length= dup_field->key_length;
|
2002-10-02 12:33:08 +02:00
|
|
|
sql_field->decimals= dup_field->decimals;
|
2007-10-24 09:43:16 +02:00
|
|
|
sql_field->create_length_to_internal_length();
|
2002-10-02 12:33:08 +02:00
|
|
|
sql_field->unireg_check= dup_field->unireg_check;
|
2005-11-07 07:23:43 +01:00
|
|
|
/*
|
|
|
|
We're making one field from two, the result field will have
|
|
|
|
dup_field->flags as flags. If we've incremented null_fields
|
|
|
|
because of sql_field->flags, decrement it back.
|
|
|
|
*/
|
|
|
|
if (!(sql_field->flags & NOT_NULL_FLAG))
|
|
|
|
null_fields--;
|
|
|
|
sql_field->flags= dup_field->flags;
|
2005-09-01 00:13:02 +02:00
|
|
|
sql_field->interval= dup_field->interval;
|
2002-10-02 12:33:08 +02:00
|
|
|
it2.remove(); // Remove first (create) definition
|
|
|
|
select_field_pos--;
|
|
|
|
break;
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2004-12-07 14:47:00 +01:00
|
|
|
/* Don't pack rows in old tables if the user has requested this */
|
|
|
|
if ((sql_field->flags & BLOB_FLAG) ||
|
2009-06-17 16:56:44 +02:00
|
|
|
(sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
|
|
|
|
create_info->row_type != ROW_TYPE_FIXED))
|
2005-04-01 14:04:50 +02:00
|
|
|
(*db_options)|= HA_OPTION_PACK_RECORD;
|
2000-07-31 21:29:14 +02:00
|
|
|
it2.rewind();
|
|
|
|
}
|
2005-05-13 10:11:50 +02:00
|
|
|
|
|
|
|
/* record_offset will be increased with 'length-of-null-bits' later */
|
|
|
|
record_offset= 0;
|
2005-05-14 17:31:22 +02:00
|
|
|
null_fields+= total_uneven_bit_length;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
it.rewind();
|
|
|
|
while ((sql_field=it++))
|
|
|
|
{
|
2005-02-25 15:53:22 +01:00
|
|
|
DBUG_ASSERT(sql_field->charset != 0);
|
2003-11-18 12:47:27 +01:00
|
|
|
|
2005-03-16 15:11:01 +01:00
|
|
|
if (prepare_create_field(sql_field, &blob_columns,
|
|
|
|
×tamps, ×tamps_with_niladic,
|
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
|
|
|
file->ha_table_flags()))
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2005-03-22 14:48:06 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
|
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
|
|
|
create_info->varchar= TRUE;
|
2005-05-13 10:11:50 +02:00
|
|
|
sql_field->offset= record_offset;
|
2000-07-31 21:29:14 +02:00
|
|
|
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
|
|
|
|
auto_increment++;
|
2005-05-13 10:11:50 +02:00
|
|
|
record_offset+= sql_field->pack_length;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-04-02 08:12:53 +02:00
|
|
|
if (timestamps_with_niladic > 1)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
|
|
|
|
ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-02 08:12:53 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
if (auto_increment > 1)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
if (auto_increment &&
|
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
|
|
|
(file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
|
|
|
|
ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02: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
|
|
|
if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
|
|
|
|
MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create keys */
|
2000-12-10 20:10:03 +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
|
|
|
List_iterator<Key> key_iterator(alter_info->key_list);
|
|
|
|
List_iterator<Key> key_iterator2(alter_info->key_list);
|
2004-03-30 19:22:14 +02:00
|
|
|
uint key_parts=0, fk_key_count=0;
|
2002-01-02 20:29:41 +01:00
|
|
|
bool primary_key=0,unique_key=0;
|
2004-04-21 12:15:43 +02:00
|
|
|
Key *key, *key2;
|
2002-01-05 21:51:42 +01:00
|
|
|
uint tmp, key_number;
|
2004-04-21 12:15:43 +02:00
|
|
|
/* special marker for keys to be ignored */
|
|
|
|
static char ignore_key[1];
|
2000-12-10 20:10:03 +01:00
|
|
|
|
2002-01-02 20:29:41 +01:00
|
|
|
/* Calculate number of key segements */
|
2004-04-08 16:56:45 +02:00
|
|
|
*key_count= 0;
|
2000-12-10 20:10:03 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
while ((key=key_iterator++))
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
DBUG_PRINT("info", ("key name: '%s' type: %d", key->name.str ? key->name.str :
|
2006-01-12 10:05:07 +01:00
|
|
|
"(none)" , key->type));
|
2002-06-02 20:22:20 +02:00
|
|
|
if (key->type == Key::FOREIGN_KEY)
|
|
|
|
{
|
|
|
|
fk_key_count++;
|
2007-06-10 12:43:57 +02:00
|
|
|
Foreign_key *fk_key= (Foreign_key*) key;
|
2002-06-02 20:22:20 +02:00
|
|
|
if (fk_key->ref_columns.elements &&
|
|
|
|
fk_key->ref_columns.elements != fk_key->columns.elements)
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_WRONG_FK_DEF, MYF(0),
|
2009-10-09 16:29:51 +02:00
|
|
|
(fk_key->name.str ? fk_key->name.str :
|
|
|
|
"foreign key without name"),
|
2004-11-13 18:35:51 +01:00
|
|
|
ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2002-06-02 20:22:20 +02:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
(*key_count)++;
|
2004-06-23 12:29:05 +02:00
|
|
|
tmp=file->max_key_parts();
|
2000-07-31 21:29:14 +02:00
|
|
|
if (key->columns.elements > tmp)
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2009-10-09 16:29:51 +02:00
|
|
|
if (check_string_char_length(&key->name, "", NAME_CHAR_LEN,
|
2007-04-03 13:13:27 +02:00
|
|
|
system_charset_info, 1))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-04-21 12:15:43 +02:00
|
|
|
key_iterator2.rewind ();
|
2004-05-11 23:29:52 +02:00
|
|
|
if (key->type != Key::FOREIGN_KEY)
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2004-05-11 23:29:52 +02:00
|
|
|
while ((key2 = key_iterator2++) != key)
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
2004-05-14 08:02:06 +02:00
|
|
|
/*
|
2004-05-15 10:57:40 +02:00
|
|
|
foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
|
|
|
|
'generated', and a generated key is a prefix of the other key.
|
|
|
|
Then we do not need the generated shorter key.
|
2004-05-14 08:02:06 +02:00
|
|
|
*/
|
2004-05-15 10:57:40 +02:00
|
|
|
if ((key2->type != Key::FOREIGN_KEY &&
|
2009-10-09 16:29:51 +02:00
|
|
|
key2->name.str != ignore_key &&
|
2004-05-15 10:57:40 +02:00
|
|
|
!foreign_key_prefix(key, key2)))
|
2004-05-11 23:29:52 +02:00
|
|
|
{
|
2004-05-14 12:49:18 +02:00
|
|
|
/* TODO: issue warning message */
|
2004-05-11 23:29:52 +02:00
|
|
|
/* mark that the generated key should be ignored */
|
|
|
|
if (!key2->generated ||
|
|
|
|
(key->generated && key->columns.elements <
|
|
|
|
key2->columns.elements))
|
2009-10-09 16:29:51 +02:00
|
|
|
key->name.str= ignore_key;
|
2004-05-11 23:29:52 +02:00
|
|
|
else
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
key2->name.str= ignore_key;
|
2004-05-14 12:49:18 +02:00
|
|
|
key_parts-= key2->columns.elements;
|
|
|
|
(*key_count)--;
|
2004-05-11 23:29:52 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2004-04-21 12:15:43 +02:00
|
|
|
}
|
|
|
|
}
|
2009-10-09 16:29:51 +02:00
|
|
|
if (key->name.str != ignore_key)
|
2004-04-21 12:15:43 +02:00
|
|
|
key_parts+=key->columns.elements;
|
|
|
|
else
|
|
|
|
(*key_count)--;
|
2009-10-09 16:29:51 +02:00
|
|
|
if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
|
|
|
|
!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
|
2004-03-13 22:31:30 +01:00
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-03-13 22:31:30 +01:00
|
|
|
}
|
2000-12-10 20:10:03 +01:00
|
|
|
}
|
2004-06-23 12:29:05 +02:00
|
|
|
tmp=file->max_keys();
|
2004-04-08 16:56:45 +02:00
|
|
|
if (*key_count > tmp)
|
2002-06-02 20:22:20 +02:00
|
|
|
{
|
|
|
|
my_error(ER_TOO_MANY_KEYS,MYF(0),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
|
|
|
DBUG_RETURN(TRUE);
|
2002-06-02 20:22:20 +02:00
|
|
|
}
|
2000-12-10 20:10:03 +01:00
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
(*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
|
2000-12-10 20:10:03 +01:00
|
|
|
key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
|
2005-04-01 14:04:50 +02:00
|
|
|
if (!*key_info_buffer || ! key_part_info)
|
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
|
|
|
DBUG_RETURN(TRUE); // Out of memory
|
2000-12-10 20:10:03 +01:00
|
|
|
|
2002-01-02 20:29:41 +01:00
|
|
|
key_iterator.rewind();
|
2002-01-05 21:51:42 +01:00
|
|
|
key_number=0;
|
2002-11-15 15:37:44 +01:00
|
|
|
for (; (key=key_iterator++) ; key_number++)
|
2000-12-10 20:10:03 +01:00
|
|
|
{
|
|
|
|
uint key_length=0;
|
2007-06-10 12:43:57 +02:00
|
|
|
Key_part_spec *column;
|
2000-12-10 20:10:03 +01:00
|
|
|
|
2009-10-09 16:29:51 +02:00
|
|
|
if (key->name.str == ignore_key)
|
2004-04-21 12:15:43 +02:00
|
|
|
{
|
|
|
|
/* ignore redundant keys */
|
|
|
|
do
|
|
|
|
key=key_iterator++;
|
2009-10-09 16:29:51 +02:00
|
|
|
while (key && key->name.str == ignore_key);
|
2004-04-21 12:15:43 +02:00
|
|
|
if (!key)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-05-03 14:59:17 +02:00
|
|
|
switch (key->type) {
|
2002-11-15 15:37:44 +01:00
|
|
|
case Key::MULTIPLE:
|
2004-05-11 23:29:52 +02:00
|
|
|
key_info->flags= 0;
|
2004-04-08 16:56:45 +02:00
|
|
|
break;
|
2002-11-15 15:37:44 +01:00
|
|
|
case Key::FULLTEXT:
|
2004-05-11 23:29:52 +02:00
|
|
|
key_info->flags= HA_FULLTEXT;
|
2006-05-03 18:40:52 +02:00
|
|
|
if ((key_info->parser_name= &key->key_create_info.parser_name)->str)
|
2005-11-06 13:13:06 +01:00
|
|
|
key_info->flags|= HA_USES_PARSER;
|
2006-05-03 14:59:17 +02:00
|
|
|
else
|
|
|
|
key_info->parser_name= 0;
|
2004-04-08 16:56:45 +02:00
|
|
|
break;
|
2002-11-15 15:37:44 +01:00
|
|
|
case Key::SPATIAL:
|
2004-01-15 18:06:22 +01:00
|
|
|
#ifdef HAVE_SPATIAL
|
2004-05-11 23:29:52 +02:00
|
|
|
key_info->flags= HA_SPATIAL;
|
2004-04-08 16:56:45 +02:00
|
|
|
break;
|
2004-01-15 18:06:22 +01:00
|
|
|
#else
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_FEATURE_DISABLED, MYF(0),
|
|
|
|
sym_group_geom.name, sym_group_geom.needed_define);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-01-15 18:06:22 +01:00
|
|
|
#endif
|
2002-06-02 20:22:20 +02:00
|
|
|
case Key::FOREIGN_KEY:
|
|
|
|
key_number--; // Skip this key
|
|
|
|
continue;
|
|
|
|
default:
|
2004-05-11 23:29:52 +02:00
|
|
|
key_info->flags = HA_NOSAME;
|
|
|
|
break;
|
2002-02-22 12:24:42 +01:00
|
|
|
}
|
2004-05-11 23:29:52 +02:00
|
|
|
if (key->generated)
|
|
|
|
key_info->flags|= HA_GENERATED_KEY;
|
2002-02-22 12:24:42 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
key_info->key_parts=(uint8) key->columns.elements;
|
|
|
|
key_info->key_part=key_part_info;
|
2002-01-05 21:51:42 +01:00
|
|
|
key_info->usable_key_parts= key_number;
|
2006-05-03 18:40:52 +02:00
|
|
|
key_info->algorithm= key->key_create_info.algorithm;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2001-10-23 10:52:51 +02:00
|
|
|
if (key->type == Key::FULLTEXT)
|
|
|
|
{
|
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
|
|
|
if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
|
2001-10-23 10:52:51 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
|
|
|
|
MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2001-10-23 10:52:51 +02:00
|
|
|
}
|
|
|
|
}
|
2002-02-22 12:24:42 +01:00
|
|
|
/*
|
|
|
|
Make SPATIAL to be RTREE by default
|
|
|
|
SPATIAL only on BLOB or at least BINARY, this
|
2003-09-03 11:34:32 +02:00
|
|
|
actually should be replaced by special GEOM type
|
2002-02-22 12:24:42 +01:00
|
|
|
in near future when new frm file is ready
|
|
|
|
checking for proper key parts number:
|
|
|
|
*/
|
2003-09-03 11:34:32 +02:00
|
|
|
|
2003-10-15 13:40:20 +02:00
|
|
|
/* TODO: Add proper checks if handler supports key_type and algorithm */
|
2004-05-11 23:29:52 +02:00
|
|
|
if (key_info->flags & HA_SPATIAL)
|
2002-05-22 17:51:21 +02: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
|
|
|
if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
|
2006-04-12 19:05:23 +02:00
|
|
|
{
|
|
|
|
my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
|
|
|
|
MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2006-04-12 19:05:23 +02:00
|
|
|
}
|
2002-05-22 17:51:21 +02:00
|
|
|
if (key_info->key_parts != 1)
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2002-02-22 12:24:42 +01:00
|
|
|
}
|
2002-05-22 17:51:21 +02:00
|
|
|
}
|
2004-12-02 13:43:51 +01:00
|
|
|
else if (key_info->algorithm == HA_KEY_ALG_RTREE)
|
2002-02-22 12:24:42 +01:00
|
|
|
{
|
2004-01-15 18:06:22 +01:00
|
|
|
#ifdef HAVE_RTREE_KEYS
|
2002-05-22 17:51:21 +02:00
|
|
|
if ((key_info->key_parts & 1) == 1)
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2002-02-22 12:24:42 +01:00
|
|
|
}
|
2003-02-12 20:55:37 +01:00
|
|
|
/* TODO: To be deleted */
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-01-15 18:06:22 +01:00
|
|
|
#else
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_FEATURE_DISABLED, MYF(0),
|
|
|
|
sym_group_rtree.name, sym_group_rtree.needed_define);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-01-15 18:06:22 +01:00
|
|
|
#endif
|
2002-02-22 12:24:42 +01:00
|
|
|
}
|
2003-09-03 11:34:32 +02:00
|
|
|
|
2006-05-03 14:59:17 +02:00
|
|
|
/* Take block size from key part or table part */
|
|
|
|
/*
|
|
|
|
TODO: Add warning if block size changes. We can't do it here, as
|
|
|
|
this may depend on the size of the key
|
|
|
|
*/
|
2006-05-03 18:40:52 +02:00
|
|
|
key_info->block_size= (key->key_create_info.block_size ?
|
|
|
|
key->key_create_info.block_size :
|
2006-05-03 14:59:17 +02:00
|
|
|
create_info->key_block_size);
|
|
|
|
|
|
|
|
if (key_info->block_size)
|
|
|
|
key_info->flags|= HA_USES_BLOCK_SIZE;
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
|
2003-10-15 13:40:20 +02:00
|
|
|
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
|
2000-07-31 21:29:14 +02:00
|
|
|
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
|
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
uint length;
|
2007-06-10 12:43:57 +02:00
|
|
|
Key_part_spec *dup_column;
|
2004-12-02 13:43:51 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
it.rewind();
|
|
|
|
field=0;
|
|
|
|
while ((sql_field=it++) &&
|
2002-03-12 18:37:58 +01:00
|
|
|
my_strcasecmp(system_charset_info,
|
2009-10-09 16:29:51 +02:00
|
|
|
column->field_name.str,
|
2004-04-08 16:56:45 +02:00
|
|
|
sql_field->field_name))
|
2000-07-31 21:29:14 +02:00
|
|
|
field++;
|
|
|
|
if (!sql_field)
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2004-12-02 13:43:51 +01:00
|
|
|
while ((dup_column= cols2++) != column)
|
2004-11-22 19:07:04 +01:00
|
|
|
{
|
|
|
|
if (!my_strcasecmp(system_charset_info,
|
2009-10-09 16:29:51 +02:00
|
|
|
column->field_name.str, dup_column->field_name.str))
|
2004-11-22 19:07:04 +01:00
|
|
|
{
|
|
|
|
my_printf_error(ER_DUP_FIELDNAME,
|
|
|
|
ER(ER_DUP_FIELDNAME),MYF(0),
|
2009-10-09 16:29:51 +02:00
|
|
|
column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-11-22 19:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cols2.rewind();
|
2003-04-23 13:44:39 +02:00
|
|
|
if (key->type == Key::FULLTEXT)
|
2003-10-15 13:40:20 +02:00
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
|
|
|
|
sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
|
2004-04-08 16:56:45 +02:00
|
|
|
!f_is_blob(sql_field->pack_flag)) ||
|
|
|
|
sql_field->charset == &my_charset_bin ||
|
2004-06-11 13:29:16 +02:00
|
|
|
sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
|
2004-04-08 16:56:45 +02:00
|
|
|
(ft_key_charset && sql_field->charset != ft_key_charset))
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
|
2004-04-08 16:56:45 +02:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
ft_key_charset=sql_field->charset;
|
|
|
|
/*
|
|
|
|
for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
|
|
|
|
code anyway, and 0 (set to column width later) for char's. it has
|
|
|
|
to be correct col width for char's, as char data are not prefixed
|
|
|
|
with length (unlike blobs, where ft code takes data length from a
|
|
|
|
data prefix, ignoring column->length).
|
|
|
|
*/
|
|
|
|
column->length=test(f_is_blob(sql_field->pack_flag));
|
2003-10-15 13:40:20 +02:00
|
|
|
}
|
2003-09-15 11:45:42 +02:00
|
|
|
else
|
2003-10-15 13:40:20 +02:00
|
|
|
{
|
2004-04-08 16:56:45 +02:00
|
|
|
column->length*= sql_field->charset->mbmaxlen;
|
|
|
|
|
2010-02-11 18:25:34 +01:00
|
|
|
if (key->type == Key::SPATIAL)
|
2007-03-14 11:20:34 +01:00
|
|
|
{
|
2010-02-11 18:25:34 +01:00
|
|
|
if (column->length)
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_SUB_KEY, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
if (!f_is_geom(sql_field->pack_flag))
|
|
|
|
{
|
|
|
|
my_error(ER_SPATIAL_MUST_HAVE_GEOM_COL, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
}
|
2007-03-14 11:20:34 +01:00
|
|
|
|
2005-09-26 11:55:52 +02:00
|
|
|
if (f_is_blob(sql_field->pack_flag) ||
|
|
|
|
(f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
|
2004-04-08 16:56:45 +02: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
|
|
|
if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
2005-10-15 19:23:13 +02:00
|
|
|
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
|
|
|
|
Field::GEOM_POINT)
|
2007-10-23 10:44:14 +02:00
|
|
|
column->length= 25;
|
2004-04-08 16:56:45 +02:00
|
|
|
if (!column->length)
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
}
|
2004-01-15 18:06:22 +01:00
|
|
|
#ifdef HAVE_SPATIAL
|
2004-12-06 01:00:37 +01:00
|
|
|
if (key->type == Key::SPATIAL)
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
2004-12-06 01:00:37 +01:00
|
|
|
if (!column->length)
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
|
|
|
/*
|
2004-12-06 01:00:37 +01:00
|
|
|
4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
|
|
|
|
Lately we'll extend this code to support more dimensions
|
2004-04-08 16:56:45 +02:00
|
|
|
*/
|
2004-12-06 01:00:37 +01:00
|
|
|
column->length= 4*sizeof(double);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
}
|
2004-01-15 18:06:22 +01:00
|
|
|
#endif
|
2004-04-08 16:56:45 +02:00
|
|
|
if (!(sql_field->flags & NOT_NULL_FLAG))
|
|
|
|
{
|
|
|
|
if (key->type == Key::PRIMARY)
|
|
|
|
{
|
|
|
|
/* Implicitly set primary key fields to NOT NULL for ISO conf. */
|
|
|
|
sql_field->flags|= NOT_NULL_FLAG;
|
|
|
|
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
|
2005-05-13 23:01:40 +02:00
|
|
|
null_fields--;
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
else
|
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
|
|
|
{
|
|
|
|
key_info->flags|= HA_NULL_PART_KEY;
|
|
|
|
if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
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
|
|
|
}
|
|
|
|
if (key->type == Key::SPATIAL)
|
|
|
|
{
|
|
|
|
my_message(ER_SPATIAL_CANT_HAVE_NULL,
|
|
|
|
ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
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
|
|
|
}
|
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
|
|
|
|
{
|
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
|
|
|
if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
|
2004-04-08 16:56:45 +02:00
|
|
|
auto_increment--; // Field is used
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-10-15 13:40:20 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
key_part_info->fieldnr= field;
|
|
|
|
key_part_info->offset= (uint16) sql_field->offset;
|
|
|
|
key_part_info->key_type=sql_field->pack_flag;
|
2004-12-06 01:00:37 +01:00
|
|
|
length= sql_field->key_length;
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (column->length)
|
|
|
|
{
|
|
|
|
if (f_is_blob(sql_field->pack_flag))
|
|
|
|
{
|
2005-05-16 14:21:35 +02:00
|
|
|
if ((length=column->length) > max_key_length ||
|
2000-10-22 00:19:05 +02:00
|
|
|
length > file->max_key_part_length())
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
2005-05-16 14:21:35 +02:00
|
|
|
length=min(max_key_length, file->max_key_part_length());
|
2004-04-08 16:56:45 +02:00
|
|
|
if (key->type == Key::MULTIPLE)
|
|
|
|
{
|
|
|
|
/* not a critical problem */
|
|
|
|
char warn_buff[MYSQL_ERRMSG_SIZE];
|
|
|
|
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
|
|
|
|
length);
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_TOO_LONG_KEY, warn_buff);
|
2007-07-20 07:30:40 +02:00
|
|
|
/* Align key length to multibyte char boundary */
|
|
|
|
length-= length % sql_field->charset->mbmaxlen;
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_LONG_KEY,MYF(0),length);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-02-11 18:02:41 +01:00
|
|
|
// Catch invalid use of partial keys
|
2004-02-17 16:57:39 +01:00
|
|
|
else if (!f_is_geom(sql_field->pack_flag) &&
|
2010-02-11 18:02:41 +01:00
|
|
|
// is the key partial?
|
|
|
|
column->length != length &&
|
|
|
|
// is prefix length bigger than field length?
|
|
|
|
(column->length > length ||
|
|
|
|
// can the field have a partial key?
|
|
|
|
!Field::type_can_have_key_part (sql_field->sql_type) ||
|
|
|
|
// a packed field can't be used in a partial key
|
|
|
|
f_is_packed(sql_field->pack_flag) ||
|
|
|
|
// does the storage engine allow prefixed search?
|
|
|
|
((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
|
|
|
|
// and is this a 'unique' key?
|
|
|
|
(key_info->flags & HA_NOSAME))))
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02: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
|
|
|
else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
|
2004-04-08 16:56:45 +02:00
|
|
|
length=column->length;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
else if (length == 0)
|
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-01-13 18:25:12 +01:00
|
|
|
if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
|
2004-02-13 14:58:02 +01:00
|
|
|
{
|
2006-02-21 16:09:32 +01:00
|
|
|
length= file->max_key_part_length();
|
2004-04-08 16:56:45 +02:00
|
|
|
if (key->type == Key::MULTIPLE)
|
|
|
|
{
|
|
|
|
/* not a critical problem */
|
|
|
|
char warn_buff[MYSQL_ERRMSG_SIZE];
|
|
|
|
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_KEY),
|
|
|
|
length);
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_TOO_LONG_KEY, warn_buff);
|
2007-07-20 07:30:40 +02:00
|
|
|
/* Align key length to multibyte char boundary */
|
|
|
|
length-= length % sql_field->charset->mbmaxlen;
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_LONG_KEY,MYF(0),length);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
2004-02-13 14:58:02 +01:00
|
|
|
}
|
|
|
|
key_part_info->length=(uint16) length;
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Use packed keys for long strings on the first column */
|
2005-04-01 14:04:50 +02:00
|
|
|
if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
|
2010-09-16 12:51:08 +02:00
|
|
|
!((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
|
2000-07-31 21:29:14 +02:00
|
|
|
(length >= KEY_DEFAULT_PACK_LENGTH &&
|
2004-12-06 01:00:37 +01:00
|
|
|
(sql_field->sql_type == MYSQL_TYPE_STRING ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
|
2000-07-31 21:29:14 +02:00
|
|
|
sql_field->pack_flag & FIELDFLAG_BLOB)))
|
|
|
|
{
|
2009-06-17 16:56:44 +02:00
|
|
|
if ((column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB)) ||
|
2004-12-06 01:00:37 +01:00
|
|
|
sql_field->sql_type == MYSQL_TYPE_VARCHAR)
|
|
|
|
key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
key_info->flags|= HA_PACK_KEY;
|
|
|
|
}
|
2007-10-29 14:34:01 +01:00
|
|
|
/* Check if the key segment is partial, set the key flag accordingly */
|
|
|
|
if (length != sql_field->key_length)
|
|
|
|
key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
key_length+=length;
|
|
|
|
key_part_info++;
|
|
|
|
|
|
|
|
/* Create the key name based on the first column (if not given) */
|
|
|
|
if (column_nr == 0)
|
|
|
|
{
|
|
|
|
if (key->type == Key::PRIMARY)
|
2002-01-02 20:29:41 +01:00
|
|
|
{
|
|
|
|
if (primary_key)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
|
|
|
|
MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
|
|
|
key_name=primary_key_name;
|
|
|
|
primary_key=1;
|
|
|
|
}
|
2009-10-09 16:29:51 +02:00
|
|
|
else if (!(key_name= key->name.str))
|
2000-07-31 21:29:14 +02:00
|
|
|
key_name=make_unique_key_name(sql_field->field_name,
|
2005-04-01 14:04:50 +02:00
|
|
|
*key_info_buffer, key_info);
|
|
|
|
if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_DUP_KEYNAME, MYF(0), key_name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
key_info->name=(char*) key_name;
|
|
|
|
}
|
|
|
|
}
|
2003-10-16 17:33:44 +02:00
|
|
|
if (!key_info->name || check_column_name(key_info->name))
|
|
|
|
{
|
2003-11-18 10:23:49 +01:00
|
|
|
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2003-10-16 17:33:44 +02:00
|
|
|
}
|
2002-01-02 20:29:41 +01:00
|
|
|
if (!(key_info->flags & HA_NULL_PART_KEY))
|
|
|
|
unique_key=1;
|
2000-07-31 21:29:14 +02:00
|
|
|
key_info->key_length=(uint16) key_length;
|
2001-12-23 01:43:46 +01:00
|
|
|
if (key_length > max_key_length && key->type != Key::FULLTEXT)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-12-23 01:43:46 +01:00
|
|
|
my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-02-20 11:07:32 +01:00
|
|
|
|
|
|
|
uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
|
|
|
|
key->key_create_info.comment.str,
|
|
|
|
key->key_create_info.comment.str +
|
|
|
|
key->key_create_info.comment.length,
|
|
|
|
INDEX_COMMENT_MAXLEN);
|
|
|
|
|
|
|
|
if (tmp_len < key->key_create_info.comment.length)
|
|
|
|
{
|
|
|
|
if ((thd->variables.sql_mode &
|
|
|
|
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_LONG_INDEX_COMMENT, MYF(0),
|
2011-05-21 10:21:08 +02:00
|
|
|
key_info->name, static_cast<ulong>(INDEX_COMMENT_MAXLEN));
|
2010-02-20 11:07:32 +01:00
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
|
|
|
char warn_buff[MYSQL_ERRMSG_SIZE];
|
|
|
|
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_INDEX_COMMENT),
|
2011-05-21 10:21:08 +02:00
|
|
|
key_info->name, static_cast<ulong>(INDEX_COMMENT_MAXLEN));
|
2010-02-20 11:07:32 +01:00
|
|
|
/* do not push duplicate warnings */
|
|
|
|
if (!check_duplicate_warning(thd, warn_buff, strlen(warn_buff)))
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
ER_TOO_LONG_INDEX_COMMENT, warn_buff);
|
|
|
|
|
|
|
|
key->key_create_info.comment.length= tmp_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
key_info->comment.length= key->key_create_info.comment.length;
|
|
|
|
if (key_info->comment.length > 0)
|
|
|
|
{
|
|
|
|
key_info->flags|= HA_USES_COMMENT;
|
|
|
|
key_info->comment.str= key->key_create_info.comment.str;
|
|
|
|
}
|
|
|
|
|
2002-11-15 15:37:44 +01:00
|
|
|
key_info++;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-01-02 20:29:41 +01:00
|
|
|
if (!unique_key && !primary_key &&
|
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
|
|
|
(file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
|
2002-01-02 20:29:41 +01:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2002-01-02 20:29:41 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
if (auto_increment > 0)
|
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
|
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
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2002-01-02 20:29:41 +01:00
|
|
|
/* Sort keys in optimized order */
|
2007-10-18 12:32:43 +02:00
|
|
|
my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
|
|
|
|
(qsort_cmp) sort_keys);
|
2005-05-14 15:24:36 +02:00
|
|
|
create_info->null_bits= null_fields;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2008-02-14 16:13:40 +01:00
|
|
|
/* Check fields. */
|
|
|
|
it.rewind();
|
|
|
|
while ((sql_field=it++))
|
|
|
|
{
|
|
|
|
Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
|
|
|
|
|
|
|
|
if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
|
|
|
|
!sql_field->def &&
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
|
|
|
|
(sql_field->flags & NOT_NULL_FLAG) &&
|
|
|
|
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
An error should be reported if:
|
|
|
|
- NO_ZERO_DATE SQL mode is active;
|
|
|
|
- there is no explicit DEFAULT clause (default column value);
|
|
|
|
- this is a TIMESTAMP column;
|
|
|
|
- the column is not NULL;
|
|
|
|
- this is not the DEFAULT CURRENT_TIMESTAMP column.
|
|
|
|
|
|
|
|
In other words, an error should be reported if
|
|
|
|
- NO_ZERO_DATE SQL mode is active;
|
|
|
|
- the column definition is equivalent to
|
|
|
|
'column_name TIMESTAMP DEFAULT 0'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
DBUG_RETURN(FALSE);
|
2004-03-30 19:22:14 +02:00
|
|
|
}
|
|
|
|
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/*
|
|
|
|
Set table default charset, if not set
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
set_table_default_charset()
|
|
|
|
create_info Table create information
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
If the table character set was not given explicitely,
|
|
|
|
let's fetch the database default character set and
|
|
|
|
apply it to the table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void set_table_default_charset(THD *thd,
|
|
|
|
HA_CREATE_INFO *create_info, char *db)
|
|
|
|
{
|
2006-08-12 19:06:51 +02:00
|
|
|
/*
|
|
|
|
If the table character set was not given explicitly,
|
|
|
|
let's fetch the database default character set and
|
|
|
|
apply it to the table.
|
|
|
|
*/
|
2005-07-22 22:43:59 +02:00
|
|
|
if (!create_info->default_table_charset)
|
|
|
|
{
|
|
|
|
HA_CREATE_INFO db_info;
|
2006-08-12 19:06:51 +02:00
|
|
|
|
|
|
|
load_db_opt_by_name(thd, db, &db_info);
|
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
create_info->default_table_charset= db_info.default_table_charset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-06 10:39:30 +02:00
|
|
|
/*
|
|
|
|
Extend long VARCHAR fields to blob & prepare field if it's a blob
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
prepare_blob_field()
|
|
|
|
sql_field Field to check
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 ok
|
|
|
|
1 Error (sql_field can't be converted to blob)
|
|
|
|
In this case the error is given
|
|
|
|
*/
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
static bool prepare_blob_field(THD *thd, Create_field *sql_field)
|
2005-05-06 10:39:30 +02:00
|
|
|
{
|
|
|
|
DBUG_ENTER("prepare_blob_field");
|
|
|
|
|
|
|
|
if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
|
|
|
|
!(sql_field->flags & BLOB_FLAG))
|
|
|
|
{
|
|
|
|
/* Convert long VARCHAR columns to TEXT or BLOB */
|
|
|
|
char warn_buff[MYSQL_ERRMSG_SIZE];
|
|
|
|
|
2005-05-12 12:56:04 +02:00
|
|
|
if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
|
|
|
|
MODE_STRICT_ALL_TABLES)))
|
2005-05-06 10:39:30 +02:00
|
|
|
{
|
|
|
|
my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
|
Fix for BUG#11755168 '46895: test "outfile_loaddata" fails (reproducible)'.
In sql_class.cc, 'row_count', of type 'ha_rows', was used as last argument for
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD which is
"Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld".
So 'ha_rows' was used as 'long'.
On SPARC32 Solaris builds, 'long' is 4 bytes and 'ha_rows' is 'longlong' i.e. 8 bytes.
So the printf-like code was reading only the first 4 bytes.
Because the CPU is big-endian, 1LL is 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
so the first four bytes yield 0. So the warning message had "row 0" instead of
"row 1" in test outfile_loaddata.test:
-Warning 1366 Incorrect string value: '\xE1\xE2\xF7' for column 'b' at row 1
+Warning 1366 Incorrect string value: '\xE1\xE2\xF7' for column 'b' at row 0
All error-messaging functions which internally invoke some printf-life function
are potential candidate for such mistakes.
One apparently easy way to catch such mistakes is to use
ATTRIBUTE_FORMAT (from my_attribute.h).
But this works only when call site has both:
a) the format as a string literal
b) the types of arguments.
So:
func(ER(ER_BLAH), 10);
will silently not be checked, because ER(ER_BLAH) is not known at
compile time (it is known at run-time, and depends on the chosen
language).
And
func("%s", a va_list argument);
has the same problem, as the *real* type of arguments is not
known at this site at compile time (it's known in some caller).
Moreover,
func(ER(ER_BLAH));
though possibly correct (if ER(ER_BLAH) has no '%' markers), will not
compile (gcc says "error: format not a string literal and no format
arguments").
Consequences:
1) ATTRIBUTE_FORMAT is here added only to functions which in practice
take "string literal" formats: "my_error_reporter" and "print_admin_msg".
2) it cannot be added to the other functions: my_error(),
push_warning_printf(), Table_check_intact::report_error(),
general_log_print().
To do a one-time check of functions listed in (2), the following
"static code analysis" has been done:
1) replace
my_error(ER_xxx, arguments for substitution in format)
with the equivalent
my_printf_error(ER_xxx,ER(ER_xxx), arguments for substitution in
format),
so that we have ER(ER_xxx) and the arguments *in the same call site*
2) add ATTRIBUTE_FORMAT to push_warning_printf(),
Table_check_intact::report_error(), general_log_print()
3) replace ER(xxx) with the hard-coded English text found in
errmsg.txt (like: ER(ER_UNKNOWN_ERROR) is replaced with
"Unknown error"), so that a call site has the format as string literal
4) this way, ATTRIBUTE_FORMAT can effectively do its job
5) compile, fix errors detected by ATTRIBUTE_FORMAT
6) revert steps 1-2-3.
The present patch has no compiler error when submitted again to the
static code analysis above.
It cannot catch all problems though: see Field::set_warning(), in
which a call to push_warning_printf() has a variable error
(thus, not replacable by a string literal); I checked set_warning() calls
by hand though.
See also WL 5883 for one proposal to avoid such bugs from appearing
again in the future.
The issues fixed in the patch are:
a) mismatch in types (like 'int' passed to '%ld')
b) more arguments passed than specified in the format.
This patch resolves mismatches by changing the type/number of arguments,
not by changing error messages of sql/share/errmsg.txt. The latter would be wrong,
per the following old rule: errmsg.txt must be as stable as possible; no insertions
or deletions of messages, no changes of type or number of printf-like format specifiers,
are allowed, as long as the change impacts a message already released in a GA version.
If this rule is not followed:
- Connectors, which use error message numbers, will be confused (by insertions/deletions
of messages)
- using errmsg.sys of MySQL 5.1.n with mysqld of MySQL 5.1.(n+1)
could produce wrong messages or crash; such usage can easily happen if
installing 5.1.(n+1) while /etc/my.cnf still has --language=/path/to/5.1.n/xxx;
or if copying mysqld from 5.1.(n+1) into a 5.1.n installation.
When fixing b), I have verified that the superfluous arguments were not used in the format
in the first 5.1 GA (5.1.30 'bteam@astra04-20081114162938-z8mctjp6st27uobm').
Had they been used, then passing them today, even if the message doesn't use them
anymore, would have been necessary, as explained above.
2011-05-16 22:04:01 +02:00
|
|
|
static_cast<ulong>(MAX_FIELD_VARCHARLENGTH /
|
|
|
|
sql_field->charset->mbmaxlen));
|
2005-05-06 10:39:30 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
}
|
2006-12-02 02:26:52 +01:00
|
|
|
sql_field->sql_type= MYSQL_TYPE_BLOB;
|
2005-05-06 10:39:30 +02:00
|
|
|
sql_field->flags|= BLOB_FLAG;
|
2009-05-04 22:33:23 +02:00
|
|
|
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_AUTO_CONVERT), sql_field->field_name,
|
2005-05-12 12:56:04 +02:00
|
|
|
(sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
|
2005-05-06 10:39:30 +02:00
|
|
|
(sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
|
|
|
|
warn_buff);
|
|
|
|
}
|
2008-12-09 14:31:22 +01:00
|
|
|
|
2005-05-06 10:39:30 +02:00
|
|
|
if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
|
|
|
|
{
|
2008-12-09 14:31:22 +01:00
|
|
|
if (sql_field->sql_type == FIELD_TYPE_BLOB ||
|
|
|
|
sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
|
|
|
|
sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB)
|
2005-05-06 10:39:30 +02:00
|
|
|
{
|
|
|
|
/* The user has given a length to the blob column */
|
|
|
|
sql_field->sql_type= get_blob_type_from_length(sql_field->length);
|
|
|
|
sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
|
|
|
|
}
|
|
|
|
sql_field->length= 0;
|
|
|
|
}
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-19 10:09:25 +02:00
|
|
|
/*
|
2007-06-10 12:43:57 +02:00
|
|
|
Preparation of Create_field for SP function return values.
|
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
|
|
|
Based on code used in the inner loop of mysql_prepare_create_table()
|
|
|
|
above.
|
2005-04-19 10:09:25 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
sp_prepare_create_field()
|
|
|
|
thd Thread object
|
|
|
|
sql_field Field to prepare
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Prepares the field structures for field creation.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
void sp_prepare_create_field(THD *thd, Create_field *sql_field)
|
2005-04-19 10:09:25 +02:00
|
|
|
{
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_SET ||
|
|
|
|
sql_field->sql_type == MYSQL_TYPE_ENUM)
|
2005-04-19 10:09:25 +02:00
|
|
|
{
|
|
|
|
uint32 field_length, dummy;
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_SET)
|
2005-04-19 10:09:25 +02:00
|
|
|
{
|
|
|
|
calculate_interval_lengths(sql_field->charset,
|
|
|
|
sql_field->interval, &dummy,
|
|
|
|
&field_length);
|
|
|
|
sql_field->length= field_length +
|
|
|
|
(sql_field->interval->count - 1);
|
|
|
|
}
|
2006-12-02 02:26:52 +01:00
|
|
|
else /* MYSQL_TYPE_ENUM */
|
2005-04-19 10:09:25 +02:00
|
|
|
{
|
|
|
|
calculate_interval_lengths(sql_field->charset,
|
|
|
|
sql_field->interval,
|
|
|
|
&field_length, &dummy);
|
|
|
|
sql_field->length= field_length;
|
|
|
|
}
|
|
|
|
set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
|
|
|
|
}
|
|
|
|
|
2006-12-02 02:26:52 +01:00
|
|
|
if (sql_field->sql_type == MYSQL_TYPE_BIT)
|
2005-04-19 10:09:25 +02:00
|
|
|
{
|
|
|
|
sql_field->pack_flag= FIELDFLAG_NUMBER |
|
|
|
|
FIELDFLAG_TREAT_BIT_AS_CHAR;
|
|
|
|
}
|
|
|
|
sql_field->create_length_to_internal_length();
|
2005-05-06 10:39:30 +02:00
|
|
|
DBUG_ASSERT(sql_field->def == 0);
|
|
|
|
/* Can't go wrong as sql_field->def is not defined */
|
|
|
|
(void) prepare_blob_field(thd, sql_field);
|
|
|
|
}
|
2005-04-19 10:09:25 +02:00
|
|
|
|
2010-11-19 08:26:09 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Auxiliary function which allows to check if freshly created .FRM
|
|
|
|
file for table can be opened.
|
|
|
|
|
|
|
|
@retval FALSE - Success.
|
|
|
|
@retval TRUE - Failure.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool check_if_created_table_can_be_opened(THD *thd,
|
|
|
|
const char *path,
|
|
|
|
const char *db,
|
|
|
|
const char *table_name,
|
|
|
|
HA_CREATE_INFO *create_info,
|
|
|
|
handler *file)
|
|
|
|
{
|
|
|
|
TABLE table;
|
|
|
|
TABLE_SHARE share;
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
It is impossible to open definition of partitioned table without .par file.
|
|
|
|
*/
|
|
|
|
if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
init_tmp_table_share(thd, &share, db, 0, table_name, path);
|
|
|
|
|
|
|
|
result= (open_table_def(thd, &share, 0) ||
|
|
|
|
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
|
|
|
|
0, &table, TRUE));
|
|
|
|
if (! result)
|
|
|
|
(void) closefrm(&table, 0);
|
|
|
|
|
|
|
|
free_table_share(&share);
|
|
|
|
(void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-30 19:22:14 +02:00
|
|
|
/*
|
|
|
|
Create a table
|
|
|
|
|
|
|
|
SYNOPSIS
|
2007-05-11 19:51:03 +02:00
|
|
|
mysql_create_table_no_lock()
|
2004-04-08 16:56:45 +02:00
|
|
|
thd Thread object
|
|
|
|
db Database
|
|
|
|
table_name Table name
|
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
|
|
|
create_info Create information (like MAX_ROWS)
|
2004-04-08 16:56:45 +02:00
|
|
|
fields List of fields to create
|
|
|
|
keys List of keys to create
|
2005-01-27 22:38:56 +01:00
|
|
|
internal_tmp_table Set to 1 if this is an internal temporary table
|
2004-04-08 16:56:45 +02:00
|
|
|
(From ALTER TABLE)
|
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
|
|
|
select_field_count
|
2010-08-20 04:59:58 +02:00
|
|
|
is_trans identifies the type of engine where the table
|
|
|
|
was created: either trans or non-trans.
|
2004-03-30 19:22:14 +02:00
|
|
|
|
|
|
|
DESCRIPTION
|
2004-10-21 18:10:58 +02:00
|
|
|
If one creates a temporary table, this is automatically opened
|
2004-03-30 19:22:14 +02:00
|
|
|
|
2007-05-11 19:51:03 +02:00
|
|
|
Note that this function assumes that caller already have taken
|
2009-12-01 14:51:50 +01:00
|
|
|
exclusive metadata lock on table being created or used some other
|
|
|
|
way to ensure that concurrent operations won't intervene.
|
|
|
|
mysql_create_table() is a wrapper that can be used for this.
|
2007-05-11 19:51:03 +02:00
|
|
|
|
2004-03-30 19:22:14 +02:00
|
|
|
no_log is needed for the case of CREATE ... SELECT,
|
|
|
|
as the logging will be done later in sql_insert.cc
|
|
|
|
select_field_count is also used for CREATE ... SELECT,
|
|
|
|
and must be zero for standard create of table.
|
|
|
|
|
|
|
|
RETURN VALUES
|
2004-10-20 03:04:37 +02:00
|
|
|
FALSE OK
|
|
|
|
TRUE error
|
2004-03-30 19:22:14 +02:00
|
|
|
*/
|
|
|
|
|
2007-05-11 19:51:03 +02:00
|
|
|
bool mysql_create_table_no_lock(THD *thd,
|
2006-02-13 08:49:28 +01:00
|
|
|
const char *db, const char *table_name,
|
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
|
|
|
HA_CREATE_INFO *create_info,
|
|
|
|
Alter_info *alter_info,
|
|
|
|
bool internal_tmp_table,
|
2010-08-20 04:59:58 +02:00
|
|
|
uint select_field_count,
|
|
|
|
bool *is_trans)
|
2004-03-30 19:22:14 +02:00
|
|
|
{
|
2009-06-19 10:24:43 +02:00
|
|
|
char path[FN_REFLEN + 1];
|
2005-12-31 06:01:26 +01:00
|
|
|
uint path_length;
|
2004-04-08 16:56:45 +02:00
|
|
|
const char *alias;
|
|
|
|
uint db_options, key_count;
|
|
|
|
KEY *key_info_buffer;
|
|
|
|
handler *file;
|
2004-10-20 03:04:37 +02:00
|
|
|
bool error= TRUE;
|
2007-05-11 19:51:03 +02:00
|
|
|
DBUG_ENTER("mysql_create_table_no_lock");
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
|
|
|
|
db, table_name, internal_tmp_table));
|
2004-03-30 19:22: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
|
|
|
|
2004-03-30 19:22:14 +02:00
|
|
|
/* Check for duplicate fields and check type of table to create */
|
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
|
|
|
if (!alter_info->create_list.elements)
|
2004-03-30 19:22:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
|
|
|
|
MYF(0));
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2004-03-30 19:22:14 +02:00
|
|
|
}
|
2006-02-17 17:12:35 +01:00
|
|
|
if (check_engine(thd, table_name, create_info))
|
2005-06-17 23:14:44 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2009-10-22 16:15:06 +02:00
|
|
|
|
|
|
|
set_table_default_charset(thd, create_info, (char*) db);
|
|
|
|
|
2005-04-01 14:04:50 +02:00
|
|
|
db_options= create_info->table_options;
|
2004-03-30 19:22:14 +02:00
|
|
|
if (create_info->row_type == ROW_TYPE_DYNAMIC)
|
|
|
|
db_options|=HA_OPTION_PACK_RECORD;
|
|
|
|
alias= table_case_name(create_info, table_name);
|
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
|
|
|
if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
|
|
|
|
create_info->db_type)))
|
2005-07-18 13:31:02 +02:00
|
|
|
{
|
2006-01-17 08:40:00 +01:00
|
|
|
mem_alloc_error(sizeof(handler));
|
2005-07-18 13:31:02 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2005-11-07 16:25:06 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-03-20 14:30:01 +01:00
|
|
|
partition_info *part_info= thd->work_part_info;
|
|
|
|
|
2006-01-17 08:40:00 +01:00
|
|
|
if (!part_info && create_info->db_type->partition_flags &&
|
|
|
|
(create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Table is not defined as a partitioned table but the engine handles
|
|
|
|
all tables as partitioned. The handler will set up the partition info
|
|
|
|
object with the default settings.
|
|
|
|
*/
|
2006-03-18 15:48:21 +01:00
|
|
|
thd->work_part_info= part_info= new partition_info();
|
2006-01-17 08:40:00 +01:00
|
|
|
if (!part_info)
|
|
|
|
{
|
|
|
|
mem_alloc_error(sizeof(partition_info));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
file->set_auto_partitions(part_info);
|
2006-03-20 20:36:21 +01:00
|
|
|
part_info->default_engine_type= create_info->db_type;
|
2006-05-10 18:53:40 +02:00
|
|
|
part_info->is_auto_partitioned= TRUE;
|
2006-01-17 08:40:00 +01:00
|
|
|
}
|
2005-07-18 13:31:02 +02:00
|
|
|
if (part_info)
|
|
|
|
{
|
|
|
|
/*
|
2006-01-17 08:40:00 +01:00
|
|
|
The table has been specified as a partitioned table.
|
|
|
|
If this is part of an ALTER TABLE the handler will be the partition
|
|
|
|
handler but we need to specify the default handler to use for
|
|
|
|
partitions also in the call to check_partition_info. We transport
|
|
|
|
this information in the default_db_type variable, it is either
|
|
|
|
DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command.
|
|
|
|
|
|
|
|
Check that we don't use foreign keys in the table since it won't
|
|
|
|
work even with InnoDB beneath it.
|
2005-07-18 13:31:02 +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_iterator<Key> key_iterator(alter_info->key_list);
|
2006-01-17 08:40:00 +01:00
|
|
|
Key *key;
|
2005-12-21 19:18:40 +01:00
|
|
|
handlerton *part_engine_type= create_info->db_type;
|
2005-07-18 13:31:02 +02:00
|
|
|
char *part_syntax_buf;
|
|
|
|
uint syntax_len;
|
2006-01-17 08:40:00 +01:00
|
|
|
handlerton *engine_type;
|
2006-03-08 18:48:40 +01:00
|
|
|
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
|
|
|
|
goto err;
|
|
|
|
}
|
2006-01-17 08:40:00 +01:00
|
|
|
while ((key= key_iterator++))
|
|
|
|
{
|
2006-06-01 14:51:58 +02:00
|
|
|
if (key->type == Key::FOREIGN_KEY &&
|
|
|
|
!part_info->is_auto_partitioned)
|
2006-01-17 08:40:00 +01:00
|
|
|
{
|
2009-02-18 21:10:19 +01:00
|
|
|
my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
|
2006-01-17 08:40:00 +01:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
2006-09-15 19:28:00 +02:00
|
|
|
if ((part_engine_type == partition_hton) &&
|
2006-03-20 14:30:01 +01:00
|
|
|
part_info->default_engine_type)
|
2005-07-18 13:31:02 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
This only happens at ALTER TABLE.
|
|
|
|
default_engine_type was assigned from the engine set in the ALTER
|
|
|
|
TABLE command.
|
|
|
|
*/
|
2006-01-17 08:40:00 +01:00
|
|
|
;
|
2005-07-18 13:31:02 +02:00
|
|
|
}
|
2005-09-20 16:29:59 +02:00
|
|
|
else
|
|
|
|
{
|
2006-01-17 08:40:00 +01:00
|
|
|
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
|
|
|
|
{
|
|
|
|
part_info->default_engine_type= create_info->db_type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (part_info->default_engine_type == NULL)
|
|
|
|
{
|
|
|
|
part_info->default_engine_type= ha_checktype(thd,
|
|
|
|
DB_TYPE_DEFAULT, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
2005-09-20 16:29:59 +02:00
|
|
|
}
|
2008-02-25 21:18:50 +01:00
|
|
|
DBUG_PRINT("info", ("db_type = %s create_info->db_type = %s",
|
|
|
|
ha_resolve_storage_engine_name(part_info->default_engine_type),
|
|
|
|
ha_resolve_storage_engine_name(create_info->db_type)));
|
2006-04-18 04:51:34 +02:00
|
|
|
if (part_info->check_partition_info(thd, &engine_type, file,
|
2009-09-15 17:07:52 +02:00
|
|
|
create_info, FALSE))
|
2005-11-05 00:32:55 +01:00
|
|
|
goto err;
|
2006-01-17 08:40:00 +01:00
|
|
|
part_info->default_engine_type= engine_type;
|
2005-11-05 00:32:55 +01:00
|
|
|
|
2005-07-18 13:31:02 +02:00
|
|
|
/*
|
|
|
|
We reverse the partitioning parser and generate a standard format
|
|
|
|
for syntax stored in frm file.
|
|
|
|
*/
|
|
|
|
if (!(part_syntax_buf= generate_partition_syntax(part_info,
|
|
|
|
&syntax_len,
|
2009-10-22 16:15:06 +02:00
|
|
|
TRUE, TRUE,
|
|
|
|
create_info,
|
|
|
|
alter_info)))
|
2005-11-05 00:32:55 +01:00
|
|
|
goto err;
|
2005-07-18 13:31:02 +02:00
|
|
|
part_info->part_info_string= part_syntax_buf;
|
|
|
|
part_info->part_info_len= syntax_len;
|
2006-01-17 08:40:00 +01:00
|
|
|
if ((!(engine_type->partition_flags &&
|
|
|
|
engine_type->partition_flags() & HA_CAN_PARTITION)) ||
|
2006-09-15 19:28:00 +02:00
|
|
|
create_info->db_type == partition_hton)
|
2005-07-18 13:31:02 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The handler assigned to the table cannot handle partitioning.
|
|
|
|
Assign the partition handler as the handler of the table.
|
|
|
|
*/
|
2008-02-26 07:58:46 +01:00
|
|
|
DBUG_PRINT("info", ("db_type: %s",
|
2008-02-25 21:18:50 +01:00
|
|
|
ha_resolve_storage_engine_name(create_info->db_type)));
|
2005-07-18 13:31:02 +02:00
|
|
|
delete file;
|
2006-09-15 19:28:00 +02:00
|
|
|
create_info->db_type= partition_hton;
|
2005-07-18 13:31:02 +02:00
|
|
|
if (!(file= get_ha_partition(part_info)))
|
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-03-23 22:00:58 +01:00
|
|
|
/*
|
|
|
|
If we have default number of partitions or subpartitions we
|
|
|
|
might require to set-up the part_info object such that it
|
|
|
|
creates a proper .par file. The current part_info object is
|
|
|
|
only used to create the frm-file and .par-file.
|
|
|
|
*/
|
2009-10-01 15:04:42 +02:00
|
|
|
if (part_info->use_default_num_partitions &&
|
|
|
|
part_info->num_parts &&
|
|
|
|
(int)part_info->num_parts !=
|
2006-06-27 22:19:27 +02:00
|
|
|
file->get_default_no_partitions(create_info))
|
2006-03-23 22:00:58 +01:00
|
|
|
{
|
2006-03-25 00:21:43 +01:00
|
|
|
uint i;
|
2006-03-23 22:00:58 +01:00
|
|
|
List_iterator<partition_element> part_it(part_info->partitions);
|
2006-03-25 00:21:43 +01:00
|
|
|
part_it++;
|
|
|
|
DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
|
|
|
|
for (i= 1; i < part_info->partitions.elements; i++)
|
|
|
|
(part_it++)->part_state= PART_TO_BE_DROPPED;
|
2006-03-23 22:00:58 +01:00
|
|
|
}
|
|
|
|
else if (part_info->is_sub_partitioned() &&
|
2009-10-01 15:04:42 +02:00
|
|
|
part_info->use_default_num_subpartitions &&
|
|
|
|
part_info->num_subparts &&
|
|
|
|
(int)part_info->num_subparts !=
|
2006-06-27 22:19:27 +02:00
|
|
|
file->get_default_no_partitions(create_info))
|
2006-03-23 22:00:58 +01:00
|
|
|
{
|
2006-03-25 00:21:43 +01:00
|
|
|
DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
|
2009-10-01 15:04:42 +02:00
|
|
|
part_info->num_subparts= file->get_default_no_partitions(create_info);
|
2006-03-23 22:00:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (create_info->db_type != engine_type)
|
|
|
|
{
|
2006-05-09 03:41:10 +02:00
|
|
|
/*
|
|
|
|
We come here when we don't use a partitioned handler.
|
|
|
|
Since we use a partitioned table it must be "native partitioned".
|
|
|
|
We have switched engine from defaults, most likely only specified
|
|
|
|
engines in partition clauses.
|
|
|
|
*/
|
2006-03-23 22:00:58 +01:00
|
|
|
delete file;
|
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
|
|
|
if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
|
|
|
|
engine_type)))
|
2006-03-23 22:00:58 +01:00
|
|
|
{
|
|
|
|
mem_alloc_error(sizeof(handler));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2005-07-18 13:31:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2004-03-30 19:22: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
|
|
|
if (mysql_prepare_create_table(thd, create_info, alter_info,
|
|
|
|
internal_tmp_table,
|
|
|
|
&db_options, file,
|
|
|
|
&key_info_buffer, &key_count,
|
|
|
|
select_field_count))
|
2005-07-18 13:31:02 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
|
|
|
/* Check if table exists */
|
|
|
|
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
|
|
|
{
|
2006-01-23 13:28:42 +01:00
|
|
|
path_length= build_tmptable_filename(thd, path, sizeof(path));
|
2000-07-31 21:29:14 +02:00
|
|
|
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
|
|
|
|
}
|
2006-06-23 18:15:39 +02:00
|
|
|
else
|
|
|
|
{
|
2009-06-19 10:24:43 +02:00
|
|
|
path_length= build_table_filename(path, sizeof(path) - 1, db, alias, reg_ext,
|
2006-08-02 17:57:06 +02:00
|
|
|
internal_tmp_table ? FN_IS_TMP : 0);
|
2006-06-23 18:15:39 +02:00
|
|
|
}
|
2005-05-26 05:26:40 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Check if table already exists */
|
2005-11-23 21:45:02 +01:00
|
|
|
if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
|
|
|
|
find_temporary_table(thd, db, table_name))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2000-10-16 23:47:15 +02:00
|
|
|
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
2003-10-15 20:41:13 +02:00
|
|
|
{
|
2005-09-12 14:09:19 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
|
|
|
|
alias);
|
2010-02-04 23:08:08 +01:00
|
|
|
error= 0;
|
2005-11-05 00:32:55 +01:00
|
|
|
goto err;
|
2003-10-15 20:41:13 +02:00
|
|
|
}
|
2004-02-11 00:06:46 +01:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
|
2005-07-18 13:31:02 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-07-04 10:02:11 +02:00
|
|
|
|
2005-01-27 22:38:56 +01:00
|
|
|
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (!access(path,F_OK))
|
|
|
|
{
|
|
|
|
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
2005-09-12 14:09:19 +02:00
|
|
|
goto warn;
|
|
|
|
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-07-25 14:52:24 +02:00
|
|
|
/*
|
|
|
|
We don't assert here, but check the result, because the table could be
|
|
|
|
in the table definition cache and in the same time the .frm could be
|
|
|
|
missing from the disk, in case of manual intervention which deletes
|
|
|
|
the .frm file. The user has to use FLUSH TABLES; to clear the cache.
|
|
|
|
Then she could create the table. This case is pretty obscure and
|
|
|
|
therefore we don't introduce a new error message only for it.
|
|
|
|
*/
|
2010-08-09 20:33:47 +02:00
|
|
|
mysql_mutex_lock(&LOCK_open);
|
2009-10-09 11:00:18 +02:00
|
|
|
if (get_cached_table_share(db, table_name))
|
2006-07-25 14:52:24 +02:00
|
|
|
{
|
2010-08-09 20:33:47 +02:00
|
|
|
mysql_mutex_unlock(&LOCK_open);
|
2006-07-25 14:52:24 +02:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2006-07-25 14:52:24 +02:00
|
|
|
}
|
2010-08-09 20:33:47 +02:00
|
|
|
mysql_mutex_unlock(&LOCK_open);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-04-15 09:14:14 +02:00
|
|
|
/*
|
|
|
|
Check that table with given name does not already
|
|
|
|
exist in any storage engine. In such a case it should
|
|
|
|
be discovered and the error ER_TABLE_EXISTS_ERROR be returned
|
|
|
|
unless user specified CREATE TABLE IF EXISTS
|
2010-08-09 20:33:47 +02:00
|
|
|
An exclusive metadata lock ensures that no
|
2004-04-15 09:14:14 +02:00
|
|
|
one else is attempting to discover the table. Since
|
|
|
|
it's not on disk as a frm file, no one could be using it!
|
|
|
|
*/
|
|
|
|
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
|
|
|
{
|
|
|
|
bool create_if_not_exists =
|
|
|
|
create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
|
2007-04-16 09:15:47 +02:00
|
|
|
int retcode = ha_table_exists_in_engine(thd, db, table_name);
|
|
|
|
DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
|
|
|
|
switch (retcode)
|
2004-04-15 09:14:14 +02:00
|
|
|
{
|
2007-04-16 09:15:47 +02:00
|
|
|
case HA_ERR_NO_SUCH_TABLE:
|
|
|
|
/* Normal case, no table exists. we can go and create it */
|
|
|
|
break;
|
|
|
|
case HA_ERR_TABLE_EXIST:
|
|
|
|
DBUG_PRINT("info", ("Table existed in handler"));
|
2004-04-15 09:14:14 +02:00
|
|
|
|
2007-04-16 09:15:47 +02:00
|
|
|
if (create_if_not_exists)
|
|
|
|
goto warn;
|
|
|
|
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2007-04-16 09:15:47 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DBUG_PRINT("info", ("error: %u from storage engine", retcode));
|
|
|
|
my_error(retcode, MYF(0),table_name);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "creating table");
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-12-07 14:40:42 +01:00
|
|
|
#ifdef HAVE_READLINK
|
2008-03-14 14:03:47 +01:00
|
|
|
{
|
2009-11-26 20:24:08 +01:00
|
|
|
size_t dirlen;
|
|
|
|
char dirpath[FN_REFLEN];
|
|
|
|
|
|
|
|
/*
|
|
|
|
data_file_name and index_file_name include the table name without
|
|
|
|
extension. Mostly this does not refer to an existing file. When
|
|
|
|
comparing data_file_name or index_file_name against the data
|
|
|
|
directory, we try to resolve all symbolic links. On some systems,
|
|
|
|
we use realpath(3) for the resolution. This returns ENOENT if the
|
|
|
|
resolved path does not refer to an existing file. my_realpath()
|
|
|
|
does then copy the requested path verbatim, without symlink
|
|
|
|
resolution. Thereafter the comparison can fail even if the
|
|
|
|
requested path is within the data directory. E.g. if symlinks to
|
|
|
|
another file system are used. To make realpath(3) return the
|
|
|
|
resolved path, we strip the table name and compare the directory
|
|
|
|
path only. If the directory doesn't exist either, table creation
|
|
|
|
will fail anyway.
|
|
|
|
*/
|
|
|
|
if (create_info->data_file_name)
|
|
|
|
{
|
|
|
|
dirname_part(dirpath, create_info->data_file_name, &dirlen);
|
|
|
|
if (test_if_data_home_dir(dirpath))
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2009-11-26 20:24:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (create_info->index_file_name)
|
|
|
|
{
|
|
|
|
dirname_part(dirpath, create_info->index_file_name, &dirlen);
|
|
|
|
if (test_if_data_home_dir(dirpath))
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2009-11-26 20:24:08 +01:00
|
|
|
}
|
|
|
|
}
|
2008-03-14 14:03:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
if (check_partition_dirs(thd->lex->part_info))
|
|
|
|
{
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2008-03-14 14:03:47 +01:00
|
|
|
}
|
|
|
|
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
|
|
|
|
2007-12-07 14:40:42 +01:00
|
|
|
if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
|
2008-03-14 14:03:47 +01:00
|
|
|
#endif /* HAVE_READLINK */
|
2007-12-07 14:40:42 +01:00
|
|
|
{
|
|
|
|
if (create_info->data_file_name)
|
2008-10-06 22:36:15 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
|
|
|
|
"DATA DIRECTORY");
|
2007-12-07 14:40:42 +01:00
|
|
|
if (create_info->index_file_name)
|
2008-10-06 22:36:15 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
|
|
WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
|
|
|
|
"INDEX DIRECTORY");
|
2003-08-23 11:25:39 +02:00
|
|
|
create_info->data_file_name= create_info->index_file_name= 0;
|
2007-12-07 14:40:42 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
create_info->table_options=db_options;
|
2003-08-23 11:25:39 +02:00
|
|
|
|
2005-12-31 06:01:26 +01:00
|
|
|
path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
|
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
|
|
|
if (rea_create_table(thd, path, db, table_name,
|
|
|
|
create_info, alter_info->create_list,
|
2005-11-23 21:45:02 +01:00
|
|
|
key_count, key_info_buffer, file))
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2005-11-23 21:45:02 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
|
|
|
{
|
2010-08-31 12:03:36 +02:00
|
|
|
/*
|
|
|
|
Open a table (skipping table cache) and add it into
|
|
|
|
THD::temporary_tables list.
|
|
|
|
*/
|
|
|
|
|
|
|
|
TABLE *table= open_table_uncached(thd, path, db, table_name, TRUE);
|
|
|
|
|
|
|
|
if (!table)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
(void) rm_temporary_table(create_info->db_type, path);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
|
|
|
|
if (is_trans != NULL)
|
|
|
|
*is_trans= table->file->has_transactions();
|
|
|
|
|
2007-08-01 16:20:25 +02:00
|
|
|
thd->thread_specific_used= TRUE;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-11-19 08:26:09 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
else if (part_info && create_info->frm_only)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
For partitioned tables we can't find some problems with table
|
|
|
|
until table is opened. Therefore in order to disallow creation
|
|
|
|
of corrupted tables we have to try to open table as the part
|
|
|
|
of its creation process.
|
|
|
|
In cases when both .FRM and SE part of table are created table
|
|
|
|
is implicitly open in ha_create_table() call.
|
|
|
|
In cases when we create .FRM without SE part we have to open
|
|
|
|
table explicitly.
|
|
|
|
*/
|
|
|
|
if (check_if_created_table_can_be_opened(thd, path, db, table_name,
|
|
|
|
create_info, file))
|
|
|
|
{
|
|
|
|
char frm_name[FN_REFLEN];
|
|
|
|
strxmov(frm_name, path, reg_ext, NullS);
|
|
|
|
(void) mysql_file_delete(key_file_frm, frm_name, MYF(0));
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2004-12-06 10:38:56 +01:00
|
|
|
|
2010-02-04 23:08:08 +01:00
|
|
|
error= FALSE;
|
2005-11-05 00:32:55 +01:00
|
|
|
err:
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "After create");
|
2005-11-05 00:32:55 +01:00
|
|
|
delete file;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(error);
|
2005-09-12 14:09:19 +02:00
|
|
|
|
|
|
|
warn:
|
2005-10-07 23:57:40 +02:00
|
|
|
error= FALSE;
|
2005-09-12 14:09:19 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
|
|
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
|
|
|
|
alias);
|
2010-08-09 20:33:47 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2006-02-13 08:49:28 +01:00
|
|
|
|
2010-07-27 12:25:53 +02:00
|
|
|
/**
|
|
|
|
Implementation of SQLCOM_CREATE_TABLE.
|
|
|
|
|
|
|
|
Take the metadata locks (including a shared lock on the affected
|
|
|
|
schema) and create the table. Is written to be called from
|
|
|
|
mysql_execute_command(), to which it delegates the common parts
|
|
|
|
with other commands (i.e. implicit commit before and after,
|
|
|
|
close of thread tables.
|
2006-02-13 08:49:28 +01:00
|
|
|
*/
|
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
|
2006-02-13 08:49:28 +01:00
|
|
|
HA_CREATE_INFO *create_info,
|
2009-12-10 11:53:20 +01:00
|
|
|
Alter_info *alter_info)
|
2006-02-13 08:49:28 +01:00
|
|
|
{
|
|
|
|
bool result;
|
2010-08-24 00:31:12 +02:00
|
|
|
bool is_trans= FALSE;
|
2006-02-13 08:49:28 +01:00
|
|
|
DBUG_ENTER("mysql_create_table");
|
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
/*
|
|
|
|
Open or obtain an exclusive metadata lock on table being created.
|
|
|
|
*/
|
2010-02-24 18:04:00 +01:00
|
|
|
if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
|
2007-05-11 19:51:03 +02:00
|
|
|
{
|
2009-12-10 11:53:20 +01:00
|
|
|
result= TRUE;
|
2010-07-27 12:25:53 +02:00
|
|
|
goto end;
|
2007-05-11 19:51:03 +02:00
|
|
|
}
|
2006-02-13 08:49:28 +01:00
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
/* Got lock. */
|
|
|
|
DEBUG_SYNC(thd, "locked_table_name");
|
2006-02-13 08:49:28 +01:00
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
result= mysql_create_table_no_lock(thd, create_table->db,
|
|
|
|
create_table->table_name, create_info,
|
2010-08-20 04:59:58 +02:00
|
|
|
alter_info, FALSE, 0, &is_trans);
|
2009-12-10 11:53:20 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Don't write statement if:
|
|
|
|
- Table creation has failed
|
|
|
|
- Row-based logging is used and we are creating a temporary table
|
|
|
|
Otherwise, the statement shall be binlogged.
|
|
|
|
*/
|
|
|
|
if (!result &&
|
2010-02-04 23:08:08 +01:00
|
|
|
(!thd->is_current_stmt_binlog_format_row() ||
|
|
|
|
(thd->is_current_stmt_binlog_format_row() &&
|
2009-12-10 11:53:20 +01:00
|
|
|
!(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
|
2010-08-20 04:59:58 +02:00
|
|
|
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
|
2009-12-10 11:53:20 +01:00
|
|
|
|
2010-07-27 12:25:53 +02:00
|
|
|
end:
|
2006-02-13 08:49:28 +01:00
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
|
|
|
** Give the key name after the first field with an optional '_#' after
|
|
|
|
**/
|
|
|
|
|
|
|
|
static bool
|
|
|
|
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
|
|
|
|
{
|
|
|
|
for (KEY *key=start ; key != end ; key++)
|
2002-03-12 18:37:58 +01:00
|
|
|
if (!my_strcasecmp(system_charset_info,name,key->name))
|
2000-07-31 21:29:14 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
make_unique_key_name(const char *field_name,KEY *start,KEY *end)
|
|
|
|
{
|
|
|
|
char buff[MAX_FIELD_NAME],*buff_end;
|
|
|
|
|
2004-03-13 22:31:30 +01:00
|
|
|
if (!check_if_keyname_exists(field_name,start,end) &&
|
|
|
|
my_strcasecmp(system_charset_info,field_name,primary_key_name))
|
2000-07-31 21:29:14 +02:00
|
|
|
return (char*) field_name; // Use fieldname
|
2004-04-08 16:56:45 +02:00
|
|
|
buff_end=strmake(buff,field_name, sizeof(buff)-4);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Only 3 chars + '\0' left, so need to limit to 2 digit
|
|
|
|
This is ok as we can't have more than 100 keys anyway
|
|
|
|
*/
|
2004-04-07 13:12:05 +02:00
|
|
|
for (uint i=2 ; i< 100; i++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-08 16:56:45 +02:00
|
|
|
*buff_end= '_';
|
|
|
|
int10_to_str(i, buff_end+1, 10);
|
2000-07-31 21:29:14 +02:00
|
|
|
if (!check_if_keyname_exists(buff,start,end))
|
|
|
|
return sql_strdup(buff);
|
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
return (char*) "not_specified"; // Should never happen
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/****************************************************************************
|
|
|
|
** Alter a table definition
|
|
|
|
****************************************************************************/
|
|
|
|
|
2006-08-02 17:57:06 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Rename a table.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_rename_table()
|
|
|
|
base The handlerton handle.
|
|
|
|
old_db The old database name.
|
|
|
|
old_name The old table name.
|
|
|
|
new_db The new database name.
|
|
|
|
new_name The new table name.
|
|
|
|
flags flags for build_table_filename().
|
|
|
|
FN_FROM_IS_TMP old_name is temporary.
|
|
|
|
FN_TO_IS_TMP new_name is temporary.
|
2006-12-04 18:22:38 +01:00
|
|
|
NO_FRM_RENAME Don't rename the FRM file
|
|
|
|
but only the table in the storage engine.
|
2006-08-02 17:57:06 +02:00
|
|
|
|
|
|
|
RETURN
|
2006-12-04 18:22:38 +01:00
|
|
|
FALSE OK
|
|
|
|
TRUE Error
|
2006-08-02 17:57:06 +02:00
|
|
|
*/
|
|
|
|
|
2000-08-21 02:00:52 +02:00
|
|
|
bool
|
2006-08-02 17:57:06 +02:00
|
|
|
mysql_rename_table(handlerton *base, const char *old_db,
|
|
|
|
const char *old_name, const char *new_db,
|
|
|
|
const char *new_name, uint flags)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2005-11-03 12:20:13 +01:00
|
|
|
THD *thd= current_thd;
|
2009-06-19 10:24:43 +02:00
|
|
|
char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
|
|
|
|
lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
|
2005-05-26 05:26:40 +02:00
|
|
|
char *from_base= from, *to_base= to;
|
|
|
|
char tmp_name[NAME_LEN+1];
|
2005-11-23 21:45:02 +01:00
|
|
|
handler *file;
|
2000-08-21 23:18:32 +02:00
|
|
|
int error=0;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("mysql_rename_table");
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
|
|
|
|
old_db, old_name, new_db, new_name));
|
2003-12-30 12:14:21 +01:00
|
|
|
|
2005-12-21 19:18:40 +01:00
|
|
|
file= (base == NULL ? 0 :
|
2005-11-23 21:45:02 +01:00
|
|
|
get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
|
|
|
|
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(from, sizeof(from) - 1, old_db, old_name, "",
|
2006-08-02 17:57:06 +02:00
|
|
|
flags & FN_FROM_IS_TMP);
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(to, sizeof(to) - 1, new_db, new_name, "",
|
2006-08-02 17:57:06 +02:00
|
|
|
flags & FN_TO_IS_TMP);
|
2005-05-26 05:26:40 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
If lower_case_table_names == 2 (case-preserving but case-insensitive
|
|
|
|
file system) and the storage is not HA_FILE_BASED, we need to provide
|
|
|
|
a lowercase file name, but we leave the .frm in mixed case.
|
|
|
|
*/
|
2004-10-21 18:10:58 +02:00
|
|
|
if (lower_case_table_names == 2 && file &&
|
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
|
|
|
!(file->ha_table_flags() & HA_FILE_BASED))
|
2003-12-30 12:14:21 +01:00
|
|
|
{
|
2005-05-26 05:26:40 +02:00
|
|
|
strmov(tmp_name, old_name);
|
|
|
|
my_casedn_str(files_charset_info, tmp_name);
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "",
|
2006-08-02 17:57:06 +02:00
|
|
|
flags & FN_FROM_IS_TMP);
|
2005-05-26 05:26:40 +02:00
|
|
|
from_base= lc_from;
|
2003-12-30 12:14:21 +01:00
|
|
|
|
2005-05-26 05:26:40 +02:00
|
|
|
strmov(tmp_name, new_name);
|
|
|
|
my_casedn_str(files_charset_info, tmp_name);
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "",
|
2006-08-02 17:57:06 +02:00
|
|
|
flags & FN_TO_IS_TMP);
|
2005-05-26 05:26:40 +02:00
|
|
|
to_base= lc_to;
|
2003-12-30 12:14:21 +01:00
|
|
|
}
|
|
|
|
|
2007-12-20 19:16:55 +01:00
|
|
|
if (!file || !(error=file->ha_rename_table(from_base, to_base)))
|
2000-08-21 02:00:52 +02:00
|
|
|
{
|
2006-12-04 18:22:38 +01:00
|
|
|
if (!(flags & NO_FRM_RENAME) && rename_file_ext(from,to,reg_ext))
|
2000-08-21 02:00:52 +02:00
|
|
|
{
|
2000-08-21 23:18:32 +02:00
|
|
|
error=my_errno;
|
2000-08-21 02:00:52 +02:00
|
|
|
/* Restore old file name */
|
2004-10-21 18:10:58 +02:00
|
|
|
if (file)
|
2007-12-20 19:16:55 +01:00
|
|
|
file->ha_rename_table(to_base, from_base);
|
2000-08-21 02:00:52 +02:00
|
|
|
}
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
delete file;
|
2006-04-25 12:27:28 +02:00
|
|
|
if (error == HA_ERR_WRONG_COMMAND)
|
|
|
|
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
|
|
|
|
else if (error)
|
2000-08-21 23:18:32 +02:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
|
|
|
|
DBUG_RETURN(error != 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2003-12-30 12:14:21 +01:00
|
|
|
|
2002-12-28 10:38:29 +01:00
|
|
|
/*
|
|
|
|
Create a table identical to the specified table
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_create_like_table()
|
2004-04-08 16:56:45 +02:00
|
|
|
thd Thread object
|
2007-05-23 13:26:16 +02:00
|
|
|
table Table list element for target table
|
|
|
|
src_table Table list element for source table
|
2002-12-28 10:38:29 +01:00
|
|
|
create_info Create info
|
|
|
|
|
|
|
|
RETURN VALUES
|
2004-10-20 03:04:37 +02:00
|
|
|
FALSE OK
|
|
|
|
TRUE error
|
2002-12-28 10:38:29 +01:00
|
|
|
*/
|
|
|
|
|
2007-05-23 13:26:16 +02:00
|
|
|
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
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
|
|
|
HA_CREATE_INFO *create_info)
|
2002-12-28 10:38:29 +01:00
|
|
|
{
|
2009-12-10 11:53:20 +01:00
|
|
|
HA_CREATE_INFO local_create_info;
|
|
|
|
Alter_info local_alter_info;
|
2007-05-11 19:51:03 +02:00
|
|
|
bool res= TRUE;
|
2010-08-24 00:31:12 +02:00
|
|
|
bool is_trans= FALSE;
|
2007-05-23 13:26:16 +02:00
|
|
|
uint not_used;
|
2002-12-28 10:38:29 +01:00
|
|
|
DBUG_ENTER("mysql_create_like_table");
|
2006-06-21 16:57:30 +02:00
|
|
|
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2007-05-23 13:26:16 +02:00
|
|
|
/*
|
2009-12-10 11:53:20 +01:00
|
|
|
We the open source table to get its description in HA_CREATE_INFO
|
|
|
|
and Alter_info objects. This also acquires a shared metadata lock
|
|
|
|
on this table which ensures that no concurrent DDL operation will
|
|
|
|
mess with it.
|
|
|
|
Also in case when we create non-temporary table open_tables()
|
|
|
|
call obtains an exclusive metadata lock on target table ensuring
|
|
|
|
that we can safely perform table creation.
|
|
|
|
Thus by holding both these locks we ensure that our statement is
|
|
|
|
properly isolated from all concurrent operations which matter.
|
2005-08-03 07:29:48 +02:00
|
|
|
*/
|
2009-12-10 11:53:20 +01:00
|
|
|
if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0))
|
|
|
|
goto err;
|
|
|
|
src_table->table->use_all_columns();
|
2002-12-28 10:38:29 +01:00
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
/* Fill HA_CREATE_INFO and Alter_info with description of source table. */
|
|
|
|
bzero((char*) &local_create_info, sizeof(local_create_info));
|
|
|
|
local_create_info.db_type= src_table->table->s->db_type();
|
|
|
|
local_create_info.row_type= src_table->table->s->row_type;
|
|
|
|
if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
|
|
|
|
&local_alter_info))
|
|
|
|
goto err;
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
/* Partition info is not handled by mysql_prepare_alter_table() call. */
|
|
|
|
if (src_table->table->part_info)
|
|
|
|
thd->work_part_info= src_table->table->part_info->get_clone();
|
|
|
|
#endif
|
2002-12-28 10:38:29 +01:00
|
|
|
|
2007-05-23 13:26:16 +02:00
|
|
|
/*
|
2009-12-10 11:53:20 +01:00
|
|
|
Adjust description of source table before using it for creation of
|
|
|
|
target table.
|
2009-12-08 10:57:07 +01:00
|
|
|
|
2009-12-10 11:53:20 +01:00
|
|
|
Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
|
|
|
|
temporary table which represents I_S table.
|
2004-04-08 16:56:45 +02:00
|
|
|
*/
|
2007-11-28 12:37:00 +01:00
|
|
|
if (src_table->schema_table)
|
2009-12-10 11:53:20 +01:00
|
|
|
local_create_info.max_rows= 0;
|
|
|
|
/* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
|
|
|
|
local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
|
|
|
|
/* Replace type of source table with one specified in the statement. */
|
|
|
|
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
|
|
|
|
local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
|
|
|
|
/* Reset auto-increment counter for the new table. */
|
|
|
|
local_create_info.auto_increment_value= 0;
|
2011-06-09 14:54:12 +02:00
|
|
|
/*
|
|
|
|
Do not inherit values of DATA and INDEX DIRECTORY options from
|
|
|
|
the original table. This is documented behavior.
|
|
|
|
*/
|
|
|
|
local_create_info.data_file_name= local_create_info.index_file_name= NULL;
|
2009-12-10 11:53:20 +01:00
|
|
|
|
|
|
|
if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
|
|
|
|
&local_create_info, &local_alter_info,
|
2010-08-20 04:59:58 +02:00
|
|
|
FALSE, 0, &is_trans)))
|
2004-04-01 20:13:25 +02:00
|
|
|
goto err;
|
2002-12-28 10:38:29 +01:00
|
|
|
|
|
|
|
/*
|
2009-12-10 11:53:20 +01:00
|
|
|
Ensure that we have an exclusive lock on target table if we are creating
|
|
|
|
non-temporary table.
|
2006-01-17 08:40:00 +01:00
|
|
|
*/
|
2009-12-10 11:53:20 +01:00
|
|
|
DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
|
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
|
|
|
thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
|
|
|
|
table->table_name,
|
|
|
|
MDL_EXCLUSIVE));
|
2005-12-22 06:39:02 +01:00
|
|
|
/*
|
|
|
|
We have to write the query before we unlock the tables.
|
|
|
|
*/
|
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 (thd->is_current_stmt_binlog_format_row())
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Since temporary tables are not replicated under row-based
|
|
|
|
replication, CREATE TABLE ... LIKE ... needs special
|
|
|
|
treatement. We have four cases to consider, according to the
|
|
|
|
following decision table:
|
|
|
|
|
|
|
|
==== ========= ========= ==============================
|
|
|
|
Case Target Source Write to binary log
|
|
|
|
==== ========= ========= ==============================
|
|
|
|
1 normal normal Original statement
|
|
|
|
2 normal temporary Generated statement
|
|
|
|
3 temporary normal Nothing
|
|
|
|
4 temporary temporary Nothing
|
|
|
|
==== ========= ========= ==============================
|
|
|
|
*/
|
|
|
|
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
|
|
|
{
|
2007-05-23 13:26:16 +02:00
|
|
|
if (src_table->table->s->tmp_table) // Case 2
|
2005-12-22 06:39:02 +01:00
|
|
|
{
|
|
|
|
char buf[2048];
|
|
|
|
String query(buf, sizeof(buf), system_charset_info);
|
|
|
|
query.length(0); // Have to zero it since constructor doesn't
|
2010-06-01 12:49:35 +02:00
|
|
|
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
|
2010-02-05 15:58:43 +01:00
|
|
|
|
2006-10-25 10:54:59 +02:00
|
|
|
/*
|
2010-02-05 15:58:43 +01:00
|
|
|
The condition avoids a crash as described in BUG#48506. Other
|
|
|
|
binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
|
|
|
|
when the existing object is a view will be solved by BUG 47442.
|
2006-10-25 10:54:59 +02:00
|
|
|
*/
|
2010-02-05 15:58:43 +01:00
|
|
|
if (!table->view)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Here we open the destination table, on which we already have
|
|
|
|
exclusive metadata lock. This is needed for store_create_info()
|
|
|
|
to work. The table will be closed by close_thread_table() at
|
|
|
|
the end of this branch.
|
|
|
|
*/
|
2010-06-01 12:49:35 +02:00
|
|
|
if (open_table(thd, table, thd->mem_root, &ot_ctx))
|
2010-02-05 15:58:43 +01:00
|
|
|
goto err;
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2010-02-05 15:58:43 +01:00
|
|
|
int result __attribute__((unused))=
|
|
|
|
store_create_info(thd, table, &query,
|
|
|
|
create_info, FALSE /* show_database */);
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2010-02-05 15:58:43 +01:00
|
|
|
DBUG_ASSERT(result == 0); // store_create_info() always return 0
|
|
|
|
if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
|
|
|
|
goto err;
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2010-02-05 15:58:43 +01:00
|
|
|
DBUG_ASSERT(thd->open_tables == table->table);
|
|
|
|
/*
|
|
|
|
When opening the table, we ignored the locked tables
|
|
|
|
(MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
|
|
|
|
risking to close some locked table.
|
|
|
|
*/
|
|
|
|
close_thread_table(thd, &thd->open_tables);
|
|
|
|
}
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
else // Case 1
|
2010-02-04 21:15:47 +01:00
|
|
|
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
|
|
|
goto err;
|
2005-12-22 06:39:02 +01:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
Case 3 and 4 does nothing under RBR
|
|
|
|
*/
|
|
|
|
}
|
2010-08-20 04:59:58 +02:00
|
|
|
else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
|
2010-02-04 21:15:47 +01:00
|
|
|
goto err;
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2004-04-02 23:44:38 +02:00
|
|
|
err:
|
|
|
|
DBUG_RETURN(res);
|
2002-12-28 10:38:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-13 10:20:19 +02:00
|
|
|
/* table_list should contain just one table */
|
2004-10-07 09:50:13 +02:00
|
|
|
static int
|
|
|
|
mysql_discard_or_import_tablespace(THD *thd,
|
|
|
|
TABLE_LIST *table_list,
|
|
|
|
enum tablespace_op_type tablespace_op)
|
2003-10-13 10:20:19 +02:00
|
|
|
{
|
|
|
|
TABLE *table;
|
|
|
|
my_bool discard;
|
|
|
|
int error;
|
|
|
|
DBUG_ENTER("mysql_discard_or_import_tablespace");
|
|
|
|
|
2004-10-07 09:50:13 +02:00
|
|
|
/*
|
|
|
|
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
|
|
|
|
ALTER TABLE
|
|
|
|
*/
|
2003-10-13 10:20:19 +02:00
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "discard_or_import_tablespace");
|
2003-10-13 10:20:19 +02:00
|
|
|
|
2004-10-07 09:50:13 +02:00
|
|
|
discard= test(tablespace_op == DISCARD_TABLESPACE);
|
2003-10-13 10:20:19 +02:00
|
|
|
|
2004-10-07 09:50:13 +02:00
|
|
|
/*
|
|
|
|
We set this flag so that ha_innobase::open and ::external_lock() do
|
|
|
|
not complain when we lock the table
|
|
|
|
*/
|
|
|
|
thd->tablespace_op= TRUE;
|
2010-05-25 14:35:01 +02:00
|
|
|
table_list->mdl_request.set_type(MDL_SHARED_WRITE);
|
WL#3984 (Revise locking of mysql.general_log and mysql.slow_log)
Bug#25422 (Hang with log tables)
Bug 17876 (Truncating mysql.slow_log in a SP after using cursor locks the
thread)
Bug 23044 (Warnings on flush of a log table)
Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
a deadlock)
Prior to this fix, the server would hang when performing concurrent
ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES,
which are mysql.general_log and mysql.slow_log.
The root cause traces to the following code:
in sql_base.cc, open_table()
if (table->in_use != thd)
{
/* wait_for_condition will unlock LOCK_open for us */
wait_for_condition(thd, &LOCK_open, &COND_refresh);
}
The problem with this code is that the current implementation of the
LOGGER creates 'fake' THD objects, like
- Log_to_csv_event_handler::general_log_thd
- Log_to_csv_event_handler::slow_log_thd
which are not associated to a real thread running in the server,
so that waiting for these non-existing threads to release table locks
cause the dead lock.
In general, the design of Log_to_csv_event_handler does not fit into the
general architecture of the server, so that the concept of general_log_thd
and slow_log_thd has to be abandoned:
- this implementation does not work with table locking
- it will not work with commands like SHOW PROCESSLIST
- having the log tables always opened does not integrate well with DDL
operations / FLUSH TABLES / SET GLOBAL READ_ONLY
With this patch, the fundamental design of the LOGGER has been changed to:
- always open and close a log table when writing a log
- remove totally the usage of fake THD objects
- clarify how locking of log tables is implemented in general.
See WL#3984 for details related to the new locking design.
Additional changes (misc bugs exposed and fixed):
1)
mysqldump which would ignore some tables in dump_all_tables_in_db(),
but forget to ignore the same in dump_all_views_in_db().
2)
mysqldump would also issue an empty "LOCK TABLE" command when all the tables
to lock are to be ignored (numrows == 0), instead of not issuing the query.
3)
Internal errors handlers could intercept errors but not warnings
(see sql_error.cc).
4)
Implementing a nested call to open tables, for the performance schema tables,
exposed an existing bug in remove_table_from_cache(), which would perform:
in_use->some_tables_deleted=1;
against another thread, without any consideration about thread locking.
This call inside remove_table_from_cache() was not required anyway,
since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads
that might hold a lock on a table.
This line (in_use->some_tables_deleted=1) has been removed.
2007-07-27 08:31:06 +02:00
|
|
|
if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
|
2003-10-13 10:20:19 +02:00
|
|
|
{
|
|
|
|
thd->tablespace_op=FALSE;
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2007-12-20 19:16:55 +01:00
|
|
|
error= table->file->ha_discard_or_import_tablespace(discard);
|
2003-10-13 10:20:19 +02:00
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "end");
|
2003-10-13 10:20:19 +02:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto err;
|
|
|
|
|
2004-10-07 09:50:13 +02:00
|
|
|
/*
|
|
|
|
The 0 in the call below means 'not in a transaction', which means
|
|
|
|
immediate invalidation; that is probably what we wish here
|
|
|
|
*/
|
2003-10-13 10:20:19 +02:00
|
|
|
query_cache_invalidate3(thd, table_list, 0);
|
|
|
|
|
|
|
|
/* The ALTER TABLE is always in its own transaction */
|
2009-12-03 19:37:38 +01:00
|
|
|
error= trans_commit_stmt(thd);
|
|
|
|
if (trans_commit_implicit(thd))
|
2003-10-13 10:20:19 +02:00
|
|
|
error=1;
|
|
|
|
if (error)
|
|
|
|
goto err;
|
2010-02-04 21:15:47 +01:00
|
|
|
error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
|
2006-05-05 19:08:40 +02:00
|
|
|
|
2003-10-13 10:20:19 +02:00
|
|
|
err:
|
2009-12-03 19:37:38 +01:00
|
|
|
trans_rollback_stmt(thd);
|
2003-10-14 00:52:03 +02:00
|
|
|
thd->tablespace_op=FALSE;
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2004-03-30 01:32:41 +02:00
|
|
|
if (error == 0)
|
|
|
|
{
|
2008-02-19 13:45:21 +01:00
|
|
|
my_ok(thd);
|
2004-03-30 01:32:41 +02:00
|
|
|
DBUG_RETURN(0);
|
2003-10-13 10:20:19 +02:00
|
|
|
}
|
2004-12-27 04:03:11 +01:00
|
|
|
|
2005-08-29 21:00:43 +02:00
|
|
|
table->file->print_error(error, MYF(0));
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2004-12-27 04:03:11 +01:00
|
|
|
DBUG_RETURN(-1);
|
2003-10-13 10:20:19 +02:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2010-03-17 15:18:46 +01:00
|
|
|
/**
|
|
|
|
@brief Check if both DROP and CREATE are present for an index in ALTER TABLE
|
|
|
|
|
|
|
|
@details Checks if any index is being modified (present as both DROP INDEX
|
|
|
|
and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
in-place ALTER TABLE.
|
2010-03-17 15:18:46 +01:00
|
|
|
|
|
|
|
@param table The table being altered
|
|
|
|
@param alter_info The ALTER TABLE structure
|
|
|
|
@return presence of index being altered
|
|
|
|
@retval FALSE No such index
|
|
|
|
@retval TRUE Have at least 1 index modified
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool
|
|
|
|
is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
|
|
|
|
{
|
|
|
|
List_iterator<Key> key_it(alter_info->key_list);
|
|
|
|
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
|
|
|
|
Key *key;
|
|
|
|
|
|
|
|
while ((key= key_it++))
|
|
|
|
{
|
2010-03-20 21:23:42 +01:00
|
|
|
if (key->name.str)
|
2010-03-17 15:18:46 +01:00
|
|
|
{
|
|
|
|
Alter_drop *drop;
|
|
|
|
|
|
|
|
drop_it.rewind();
|
|
|
|
while ((drop= drop_it++))
|
|
|
|
{
|
|
|
|
if (drop->type == Alter_drop::KEY &&
|
2010-03-20 21:23:42 +01:00
|
|
|
!my_strcasecmp(system_charset_info, key->name.str, drop->name))
|
2010-03-17 15:18:46 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/*
|
|
|
|
SYNOPSIS
|
2010-08-16 14:53:30 +02:00
|
|
|
mysql_compare_tables()
|
2006-01-12 10:05:07 +01:00
|
|
|
table The original table.
|
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
|
|
|
alter_info Alter options, fields and keys for the new
|
|
|
|
table.
|
2006-01-12 10:05:07 +01:00
|
|
|
create_info Create options for the new table.
|
|
|
|
order_num Number of order list elements.
|
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
|
|
|
need_copy_table OUT Result of the comparison. Undefined if error.
|
|
|
|
Otherwise is one of:
|
|
|
|
ALTER_TABLE_METADATA_ONLY No copy needed
|
|
|
|
ALTER_TABLE_DATA_CHANGED Data changes,
|
|
|
|
copy needed
|
|
|
|
ALTER_TABLE_INDEX_CHANGED Index changes,
|
|
|
|
copy might be needed
|
|
|
|
key_info_buffer OUT An array of KEY structs for new indexes
|
2006-01-12 10:05:07 +01:00
|
|
|
index_drop_buffer OUT An array of offsets into table->key_info.
|
|
|
|
index_drop_count OUT The number of elements in the array.
|
|
|
|
index_add_buffer OUT An array of offsets into key_info_buffer.
|
|
|
|
index_add_count OUT The number of elements in the array.
|
2008-09-15 11:19:56 +02:00
|
|
|
candidate_key_count OUT The number of candidate keys in original table.
|
2005-07-22 22:43:59 +02:00
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
'table' (first argument) contains information of the original
|
|
|
|
table, which includes all corresponding parts that the new
|
|
|
|
table has in arguments create_list, key_list and create_info.
|
|
|
|
|
|
|
|
By comparing the changes between the original and new table
|
|
|
|
we can determine how much it has changed after ALTER TABLE
|
|
|
|
and whether we need to make a copy of the table, or just change
|
|
|
|
the .frm file.
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
If there are no data changes, but index changes, 'index_drop_buffer'
|
|
|
|
and/or 'index_add_buffer' are populated with offsets into
|
|
|
|
table->key_info or key_info_buffer respectively for the indexes
|
|
|
|
that need to be dropped and/or (re-)created.
|
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
RETURN VALUES
|
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
|
|
|
TRUE error
|
|
|
|
FALSE success
|
2005-07-22 22:43:59 +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
|
|
|
bool
|
2010-08-16 14:53:30 +02:00
|
|
|
mysql_compare_tables(TABLE *table,
|
|
|
|
Alter_info *alter_info,
|
|
|
|
HA_CREATE_INFO *create_info,
|
|
|
|
uint order_num,
|
|
|
|
enum_alter_table_change_level *need_copy_table,
|
|
|
|
KEY **key_info_buffer,
|
|
|
|
uint **index_drop_buffer, uint *index_drop_count,
|
|
|
|
uint **index_add_buffer, uint *index_add_count,
|
|
|
|
uint *candidate_key_count)
|
2005-07-22 22:43:59 +02:00
|
|
|
{
|
|
|
|
Field **f_ptr, *field;
|
|
|
|
uint changes= 0, 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
|
|
|
uint key_count;
|
2008-06-17 16:12:21 +02:00
|
|
|
List_iterator_fast<Create_field> new_field_it, tmp_new_field_it;
|
|
|
|
Create_field *new_field, *tmp_new_field;
|
2006-03-06 10:24:06 +01:00
|
|
|
KEY_PART_INFO *key_part;
|
|
|
|
KEY_PART_INFO *end;
|
2008-06-17 16:12:21 +02:00
|
|
|
THD *thd= table->in_use;
|
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
|
|
|
/*
|
|
|
|
Remember if the new definition has new VARCHAR column;
|
|
|
|
create_info->varchar will be reset in mysql_prepare_create_table.
|
|
|
|
*/
|
|
|
|
bool varchar= create_info->varchar;
|
2008-09-15 11:19:56 +02:00
|
|
|
bool not_nullable= true;
|
2010-08-16 14:53:30 +02:00
|
|
|
DBUG_ENTER("mysql_compare_tables");
|
2008-09-15 11:19:56 +02:00
|
|
|
|
2008-06-17 16:12:21 +02:00
|
|
|
/*
|
|
|
|
Create a copy of alter_info.
|
|
|
|
To compare the new and old table definitions, we need to "prepare"
|
|
|
|
the new definition - transform it from parser output to a format
|
|
|
|
that describes the final table layout (all column defaults are
|
|
|
|
initialized, duplicate columns are removed). This is done by
|
|
|
|
mysql_prepare_create_table. Unfortunately,
|
|
|
|
mysql_prepare_create_table performs its transformations
|
|
|
|
"in-place", that is, modifies the argument. Since we would
|
2010-08-16 14:53:30 +02:00
|
|
|
like to keep mysql_compare_tables() idempotent (not altering any
|
2008-06-17 16:12:21 +02:00
|
|
|
of the arguments) we create a copy of alter_info here and
|
|
|
|
pass it to mysql_prepare_create_table, then use the result
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
to evaluate possibility of in-place ALTER TABLE, and then
|
2008-06-17 16:12:21 +02:00
|
|
|
destroy the copy.
|
|
|
|
*/
|
|
|
|
Alter_info tmp_alter_info(*alter_info, thd->mem_root);
|
|
|
|
uint db_options= 0; /* not used */
|
2010-03-17 15:18:46 +01:00
|
|
|
|
2008-06-17 16:12:21 +02:00
|
|
|
/* Create the prepared information. */
|
|
|
|
if (mysql_prepare_create_table(thd, create_info,
|
2008-09-15 11:19:56 +02:00
|
|
|
&tmp_alter_info,
|
|
|
|
(table->s->tmp_table != NO_TMP_TABLE),
|
|
|
|
&db_options,
|
|
|
|
table->file, key_info_buffer,
|
|
|
|
&key_count, 0))
|
2008-06-17 16:12:21 +02:00
|
|
|
DBUG_RETURN(1);
|
|
|
|
/* Allocate result buffers. */
|
|
|
|
if (! (*index_drop_buffer=
|
2008-09-15 11:19:56 +02:00
|
|
|
(uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
|
2008-06-17 16:12:21 +02:00
|
|
|
! (*index_add_buffer=
|
2008-09-15 11:19:56 +02:00
|
|
|
(uint*) thd->alloc(sizeof(uint) * tmp_alter_info.key_list.elements)))
|
2008-06-17 16:12:21 +02:00
|
|
|
DBUG_RETURN(1);
|
2008-09-15 11:19:56 +02:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/*
|
|
|
|
Some very basic checks. If number of fields changes, or the
|
|
|
|
handler, we need to run full ALTER TABLE. In the future
|
|
|
|
new fields can be added and old dropped without copy, but
|
|
|
|
not yet.
|
|
|
|
|
|
|
|
Test also that engine was not given during ALTER TABLE, or
|
|
|
|
we are force to run regular alter table (copy).
|
|
|
|
E.g. ALTER TABLE tbl_name ENGINE=MyISAM.
|
|
|
|
|
|
|
|
For the following ones we also want to run regular alter table:
|
|
|
|
ALTER TABLE tbl_name ORDER BY ..
|
|
|
|
ALTER TABLE tbl_name CONVERT TO CHARACTER SET ..
|
|
|
|
|
|
|
|
At the moment we can't handle altering temporary tables without a copy.
|
|
|
|
We also test if OPTIMIZE TABLE was given and was mapped to alter table.
|
|
|
|
In that case we always do full copy.
|
2006-06-14 13:45:29 +02:00
|
|
|
|
|
|
|
There was a bug prior to mysql-4.0.25. Number of null fields was
|
|
|
|
calculated incorrectly. As a result frm and data files gets out of
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
sync after in-place alter table. There is no way to determine by which
|
2006-06-14 13:45:29 +02:00
|
|
|
mysql version (in 4.0 and 4.1 branches) table was created, thus we
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
disable in-place alter table for all tables created by mysql versions
|
2006-06-14 13:45:29 +02:00
|
|
|
prior to 5.0 branch.
|
|
|
|
See BUG#6236.
|
2005-07-22 22:43:59 +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
|
|
|
if (table->s->fields != alter_info->create_list.elements ||
|
2007-03-02 17:43:45 +01:00
|
|
|
table->s->db_type() != create_info->db_type ||
|
2005-07-22 22:43:59 +02:00
|
|
|
table->s->tmp_table ||
|
|
|
|
create_info->used_fields & HA_CREATE_USED_ENGINE ||
|
|
|
|
create_info->used_fields & HA_CREATE_USED_CHARSET ||
|
|
|
|
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
|
2009-05-29 16:22:24 +02:00
|
|
|
(table->s->row_type != create_info->row_type) ||
|
2008-10-09 12:49:13 +02:00
|
|
|
create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
|
|
|
|
create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
|
2006-03-30 20:55:54 +02:00
|
|
|
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
|
2006-05-30 15:07:49 +02:00
|
|
|
order_num ||
|
2006-06-14 13:45:29 +02:00
|
|
|
!table->s->mysql_version ||
|
2006-05-30 15:07:49 +02:00
|
|
|
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
|
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
|
|
|
{
|
|
|
|
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2005-07-22 22:43:59 +02:00
|
|
|
|
2008-06-17 16:12:21 +02:00
|
|
|
/*
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
Use transformed info to evaluate possibility of in-place ALTER TABLE
|
2008-06-17 16:12:21 +02:00
|
|
|
but use the preserved field to persist modifications.
|
|
|
|
*/
|
|
|
|
new_field_it.init(alter_info->create_list);
|
|
|
|
tmp_new_field_it.init(tmp_alter_info.create_list);
|
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/*
|
|
|
|
Go through fields and check if the original ones are compatible
|
|
|
|
with new table.
|
|
|
|
*/
|
2008-06-17 16:12:21 +02:00
|
|
|
for (f_ptr= table->field, new_field= new_field_it++,
|
|
|
|
tmp_new_field= tmp_new_field_it++;
|
|
|
|
(field= *f_ptr);
|
|
|
|
f_ptr++, new_field= new_field_it++,
|
|
|
|
tmp_new_field= tmp_new_field_it++)
|
2005-07-22 22:43:59 +02:00
|
|
|
{
|
|
|
|
/* Make sure we have at least the default charset in use. */
|
|
|
|
if (!new_field->charset)
|
|
|
|
new_field->charset= create_info->default_table_charset;
|
2006-01-12 10:05:07 +01:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/* Check that NULL behavior is same for old and new fields */
|
2008-06-17 16:12:21 +02:00
|
|
|
if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
|
2005-07-22 22:43:59 +02:00
|
|
|
(uint) (field->flags & NOT_NULL_FLAG))
|
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
|
|
|
{
|
|
|
|
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2005-07-22 22:43:59 +02:00
|
|
|
|
|
|
|
/* Don't pack rows in old tables if the user has requested this. */
|
|
|
|
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
|
2008-06-17 16:12:21 +02:00
|
|
|
(tmp_new_field->flags & BLOB_FLAG) ||
|
2009-06-17 16:56:44 +02:00
|
|
|
(tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
|
|
|
|
create_info->row_type != ROW_TYPE_FIXED))
|
2005-07-22 22:43:59 +02:00
|
|
|
create_info->table_options|= HA_OPTION_PACK_RECORD;
|
|
|
|
|
2006-06-14 11:08:36 +02:00
|
|
|
/* Check if field was renamed */
|
2006-06-14 12:01:06 +02:00
|
|
|
field->flags&= ~FIELD_IS_RENAMED;
|
2006-06-14 11:08:36 +02:00
|
|
|
if (my_strcasecmp(system_charset_info,
|
|
|
|
field->field_name,
|
2008-06-17 16:12:21 +02:00
|
|
|
tmp_new_field->field_name))
|
2006-06-14 11:08:36 +02:00
|
|
|
field->flags|= FIELD_IS_RENAMED;
|
2006-06-14 12:01:06 +02:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
|
2008-06-17 16:12:21 +02:00
|
|
|
if (!(tmp= field->is_equal(tmp_new_field)))
|
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
|
|
|
{
|
|
|
|
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2006-01-27 17:23:14 +01:00
|
|
|
// Clear indexed marker
|
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
|
|
|
field->flags&= ~FIELD_IN_ADD_INDEX;
|
2005-07-22 22:43:59 +02:00
|
|
|
changes|= tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Go through keys and check if the original ones are compatible
|
|
|
|
with new table.
|
|
|
|
*/
|
2006-01-12 10:05:07 +01:00
|
|
|
KEY *table_key;
|
|
|
|
KEY *table_key_end= table->key_info + table->s->keys;
|
|
|
|
KEY *new_key;
|
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 *new_key_end= *key_info_buffer + key_count;
|
2005-07-22 22:43:59 +02:00
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
DBUG_PRINT("info", ("index count old: %d new: %d",
|
|
|
|
table->s->keys, key_count));
|
|
|
|
/*
|
|
|
|
Step through all keys of the old table and search matching new keys.
|
|
|
|
*/
|
|
|
|
*index_drop_count= 0;
|
|
|
|
*index_add_count= 0;
|
2008-09-15 11:19:56 +02:00
|
|
|
*candidate_key_count= 0;
|
2006-01-12 10:05:07 +01:00
|
|
|
for (table_key= table->key_info; table_key < table_key_end; table_key++)
|
2005-07-22 22:43:59 +02:00
|
|
|
{
|
2006-01-12 10:05:07 +01:00
|
|
|
KEY_PART_INFO *table_part;
|
|
|
|
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
|
|
|
|
KEY_PART_INFO *new_part;
|
|
|
|
|
2008-09-15 11:19:56 +02:00
|
|
|
/*
|
|
|
|
Check if key is a candidate key, i.e. a unique index with no index
|
|
|
|
fields nullable, then key is either already primary key or could
|
|
|
|
be promoted to primary key if the original primary key is dropped.
|
|
|
|
Count all candidate keys.
|
|
|
|
*/
|
|
|
|
not_nullable= true;
|
|
|
|
for (table_part= table_key->key_part;
|
|
|
|
table_part < table_part_end;
|
|
|
|
table_part++)
|
|
|
|
{
|
|
|
|
not_nullable= not_nullable && (! table_part->field->maybe_null());
|
|
|
|
}
|
|
|
|
if ((table_key->flags & HA_NOSAME) && not_nullable)
|
|
|
|
(*candidate_key_count)++;
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Search a new key with the same name. */
|
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
|
|
|
for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
|
|
|
if (! strcmp(table_key->name, new_key->name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (new_key >= new_key_end)
|
|
|
|
{
|
|
|
|
/* Key not found. Add the offset of the key to the drop buffer. */
|
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
|
|
|
(*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
|
2006-01-12 10:05:07 +01:00
|
|
|
DBUG_PRINT("info", ("index dropped: '%s'", table_key->name));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that the key types are compatible between old and new tables. */
|
|
|
|
if ((table_key->algorithm != new_key->algorithm) ||
|
|
|
|
((table_key->flags & HA_KEYFLAG_MASK) !=
|
|
|
|
(new_key->flags & HA_KEYFLAG_MASK)) ||
|
|
|
|
(table_key->key_parts != new_key->key_parts))
|
|
|
|
goto index_changed;
|
2005-07-22 22:43:59 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check that the key parts remain compatible between the old and
|
|
|
|
new tables.
|
|
|
|
*/
|
2006-01-12 10:05:07 +01:00
|
|
|
for (table_part= table_key->key_part, new_part= new_key->key_part;
|
|
|
|
table_part < table_part_end;
|
|
|
|
table_part++, new_part++)
|
2005-07-22 22:43:59 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Key definition has changed if we are using a different field or
|
2006-01-12 10:05:07 +01:00
|
|
|
if the used key part length is different. We know that the fields
|
|
|
|
did not change. Comparing field numbers is sufficient.
|
2005-07-22 22:43:59 +02:00
|
|
|
*/
|
2006-01-12 10:05:07 +01:00
|
|
|
if ((table_part->length != new_part->length) ||
|
|
|
|
(table_part->fieldnr - 1 != new_part->fieldnr))
|
|
|
|
goto index_changed;
|
2005-07-22 22:43:59 +02:00
|
|
|
}
|
2006-01-12 10:05:07 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
index_changed:
|
|
|
|
/* Key modified. Add the offset of the key to both buffers. */
|
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
|
|
|
(*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
|
|
|
|
(*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
|
2006-03-06 10:24:06 +01:00
|
|
|
key_part= new_key->key_part;
|
|
|
|
end= key_part + new_key->key_parts;
|
|
|
|
for(; key_part != end; key_part++)
|
|
|
|
{
|
|
|
|
// Mark field to be part of new key
|
|
|
|
field= table->field[key_part->fieldnr];
|
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
|
|
|
field->flags|= FIELD_IN_ADD_INDEX;
|
2006-03-06 10:24:06 +01:00
|
|
|
}
|
2006-01-12 10:05:07 +01:00
|
|
|
DBUG_PRINT("info", ("index changed: '%s'", table_key->name));
|
2005-07-22 22:43:59 +02:00
|
|
|
}
|
2006-01-12 10:05:07 +01:00
|
|
|
/*end of for (; table_key < table_key_end;) */
|
2005-07-22 22:43:59 +02:00
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
/*
|
|
|
|
Step through all keys of the new table and find matching old keys.
|
|
|
|
*/
|
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
|
|
|
for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
|
|
|
/* Search an old key with the same name. */
|
|
|
|
for (table_key= table->key_info; table_key < table_key_end; table_key++)
|
|
|
|
{
|
|
|
|
if (! strcmp(table_key->name, new_key->name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (table_key >= table_key_end)
|
|
|
|
{
|
|
|
|
/* Key not found. Add the offset of the key to the add buffer. */
|
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
|
|
|
(*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
|
2006-03-06 10:24:06 +01:00
|
|
|
key_part= new_key->key_part;
|
|
|
|
end= key_part + new_key->key_parts;
|
|
|
|
for(; key_part != end; key_part++)
|
|
|
|
{
|
|
|
|
// Mark field to be part of new key
|
|
|
|
field= table->field[key_part->fieldnr];
|
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
|
|
|
field->flags|= FIELD_IN_ADD_INDEX;
|
2006-03-06 10:24:06 +01:00
|
|
|
}
|
2006-01-31 15:53:35 +01:00
|
|
|
DBUG_PRINT("info", ("index added: '%s'", new_key->name));
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
2006-01-27 17:23:14 +01:00
|
|
|
|
|
|
|
/* Check if changes are compatible with current handler without a copy */
|
|
|
|
if (table->file->check_if_incompatible_data(create_info, changes))
|
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
|
|
|
{
|
|
|
|
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2006-01-27 17:23:14 +01:00
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
if (*index_drop_count || *index_add_count)
|
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
|
|
|
{
|
|
|
|
*need_copy_table= ALTER_TABLE_INDEX_CHANGED;
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2006-01-12 10:05:07 +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
|
|
|
*need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible
|
|
|
|
DBUG_RETURN(0);
|
2005-07-22 22:43:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-28 18:27:32 +01:00
|
|
|
/*
|
|
|
|
Manages enabling/disabling of indexes for ALTER TABLE
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
alter_table_manage_keys()
|
|
|
|
table Target table
|
|
|
|
indexes_were_disabled Whether the indexes of the from table
|
|
|
|
were disabled
|
|
|
|
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
static
|
|
|
|
bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
|
|
|
|
enum enum_enable_or_disable keys_onoff)
|
|
|
|
{
|
|
|
|
int error= 0;
|
|
|
|
DBUG_ENTER("alter_table_manage_keys");
|
|
|
|
DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d",
|
|
|
|
table, indexes_were_disabled, keys_onoff));
|
|
|
|
|
|
|
|
switch (keys_onoff) {
|
|
|
|
case ENABLE:
|
2007-12-20 19:16:55 +01:00
|
|
|
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
2006-11-28 18:27:32 +01:00
|
|
|
break;
|
|
|
|
case LEAVE_AS_IS:
|
|
|
|
if (!indexes_were_disabled)
|
|
|
|
break;
|
|
|
|
/* fall-through: disabled indexes */
|
|
|
|
case DISABLE:
|
2007-12-20 19:16:55 +01:00
|
|
|
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
2006-11-28 18:27:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (error == HA_ERR_WRONG_COMMAND)
|
|
|
|
{
|
|
|
|
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
2007-10-25 03:01:08 +02:00
|
|
|
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
|
|
|
|
table->s->table_name.str);
|
2006-11-28 18:27:32 +01:00
|
|
|
error= 0;
|
|
|
|
} else if (error)
|
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
2009-11-09 12:35:18 +01:00
|
|
|
/**
|
|
|
|
maximum possible length for certain blob types.
|
|
|
|
|
|
|
|
@param[in] type Blob type (e.g. MYSQL_TYPE_TINY_BLOB)
|
|
|
|
|
|
|
|
@return
|
|
|
|
length
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint
|
|
|
|
blob_length_by_type(enum_field_types type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
|
|
return 255;
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
return 65535;
|
|
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
|
|
return 16777215;
|
|
|
|
case MYSQL_TYPE_LONG_BLOB:
|
|
|
|
return 4294967295U;
|
|
|
|
default:
|
|
|
|
DBUG_ASSERT(0); // we should never go here
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
/**
|
|
|
|
Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
|
|
|
|
|
|
|
|
This function transforms parse output of ALTER TABLE - lists of
|
|
|
|
columns and keys to add, drop or modify into, essentially,
|
|
|
|
CREATE TABLE definition - a list of columns and keys of the new
|
|
|
|
table. While doing so, it also performs some (bug not all)
|
|
|
|
semantic checks.
|
|
|
|
|
|
|
|
This function is invoked when we know that we're going to
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE
|
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
|
|
|
is not possible, perhaps because the ALTER statement contains
|
|
|
|
instructions that require change in table data, not only in
|
|
|
|
table definition or indexes.
|
|
|
|
|
|
|
|
@param[in,out] thd thread handle. Used as a memory pool
|
|
|
|
and source of environment information.
|
|
|
|
@param[in] table the source table, open and locked
|
|
|
|
Used as an interface to the storage engine
|
|
|
|
to acquire additional information about
|
|
|
|
the original table.
|
|
|
|
@param[in,out] create_info A blob with CREATE/ALTER TABLE
|
|
|
|
parameters
|
|
|
|
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
|
|
|
|
Originally create_info was used only in
|
|
|
|
CREATE TABLE and alter_info only in ALTER TABLE.
|
|
|
|
But since ALTER might end-up doing CREATE,
|
|
|
|
this distinction is gone and we just carry
|
|
|
|
around two structures.
|
|
|
|
|
|
|
|
@return
|
|
|
|
Fills various create_info members based on information retrieved
|
|
|
|
from the storage engine.
|
|
|
|
Sets create_info->varchar if the table has a VARCHAR column.
|
|
|
|
Prepares alter_info->create_list and alter_info->key_list with
|
|
|
|
columns and keys of the new table.
|
|
|
|
@retval TRUE error, out of memory or a semantical error in ALTER
|
|
|
|
TABLE instructions
|
|
|
|
@retval FALSE success
|
2004-04-08 16:56:45 +02:00
|
|
|
*/
|
2004-03-30 19:22:14 +02:00
|
|
|
|
2010-08-16 14:53:30 +02:00
|
|
|
bool
|
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
|
|
|
mysql_prepare_alter_table(THD *thd, TABLE *table,
|
|
|
|
HA_CREATE_INFO *create_info,
|
|
|
|
Alter_info *alter_info)
|
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
|
|
|
/* New column definitions are added here */
|
2007-06-10 12:43:57 +02:00
|
|
|
List<Create_field> new_create_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
|
|
|
/* New key definitions are added here */
|
|
|
|
List<Key> new_key_list;
|
|
|
|
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Create_field> def_it(alter_info->create_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
|
|
|
List_iterator<Alter_column> alter_it(alter_info->alter_list);
|
|
|
|
List_iterator<Key> key_it(alter_info->key_list);
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Create_field> find_it(new_create_list);
|
|
|
|
List_iterator<Create_field> field_it(new_create_list);
|
|
|
|
List<Key_part_spec> key_parts;
|
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
|
|
|
uint db_create_options= (table->s->db_create_options
|
|
|
|
& ~(HA_OPTION_PACK_RECORD));
|
|
|
|
uint used_fields= create_info->used_fields;
|
|
|
|
KEY *key_info=table->key_info;
|
|
|
|
bool rc= TRUE;
|
2006-08-03 19:28:15 +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
|
|
|
DBUG_ENTER("mysql_prepare_alter_table");
|
2006-08-03 19:28:15 +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
|
|
|
create_info->varchar= FALSE;
|
|
|
|
/* Let new create options override the old ones */
|
|
|
|
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
|
|
|
|
create_info->min_rows= table->s->min_rows;
|
|
|
|
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
|
|
|
|
create_info->max_rows= table->s->max_rows;
|
|
|
|
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
|
|
|
|
create_info->avg_row_length= table->s->avg_row_length;
|
|
|
|
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
|
|
|
|
create_info->default_table_charset= table->s->table_charset;
|
|
|
|
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
|
2006-06-15 20:03:17 +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
|
|
|
/* Table has an autoincrement, copy value to new table */
|
|
|
|
table->file->info(HA_STATUS_AUTO);
|
|
|
|
create_info->auto_increment_value= table->file->stats.auto_increment_value;
|
2006-06-15 20:03:17 +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
|
|
|
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
|
|
|
|
create_info->key_block_size= table->s->key_block_size;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2011-03-04 09:41:29 +01:00
|
|
|
if (!create_info->tablespace)
|
|
|
|
create_info->tablespace= table->s->tablespace;
|
|
|
|
|
|
|
|
if (create_info->storage_media == HA_SM_DEFAULT)
|
|
|
|
create_info->storage_media= table->s->default_storage_media;
|
|
|
|
|
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
|
|
|
restore_record(table, s->default_values); // Empty record for DEFAULT
|
2007-06-10 12:43:57 +02:00
|
|
|
Create_field *def;
|
2006-10-13 19:59:52 +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
|
|
|
/*
|
|
|
|
First collect all fields from table which isn't in drop_list
|
|
|
|
*/
|
|
|
|
Field **f_ptr,*field;
|
|
|
|
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
|
|
|
|
{
|
|
|
|
if (field->type() == MYSQL_TYPE_STRING)
|
|
|
|
create_info->varchar= TRUE;
|
|
|
|
/* Check if field should be dropped */
|
|
|
|
Alter_drop *drop;
|
|
|
|
drop_it.rewind();
|
|
|
|
while ((drop=drop_it++))
|
2006-10-13 19:59:52 +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
|
|
|
if (drop->type == Alter_drop::COLUMN &&
|
|
|
|
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
|
|
|
|
{
|
|
|
|
/* Reset auto_increment value if it was dropped */
|
|
|
|
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
|
|
|
|
!(used_fields & HA_CREATE_USED_AUTO))
|
|
|
|
{
|
|
|
|
create_info->auto_increment_value=0;
|
|
|
|
create_info->used_fields|=HA_CREATE_USED_AUTO;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2006-10-13 19:59:52 +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
|
|
|
if (drop)
|
2006-12-19 23:02:37 +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
|
|
|
drop_it.remove();
|
2011-06-17 00:02:52 +02:00
|
|
|
/*
|
|
|
|
ALTER TABLE DROP COLUMN always changes table data even in cases
|
|
|
|
when new version of the table has the same structure as the old
|
|
|
|
one.
|
|
|
|
*/
|
|
|
|
alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
|
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
|
|
|
continue;
|
2006-12-19 23:02:37 +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
|
|
|
/* Check if field is changed */
|
|
|
|
def_it.rewind();
|
|
|
|
while ((def=def_it++))
|
2006-10-13 19:59:52 +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
|
|
|
if (def->change &&
|
|
|
|
!my_strcasecmp(system_charset_info,field->field_name, def->change))
|
|
|
|
break;
|
2006-10-13 19:59:52 +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
|
|
|
if (def)
|
|
|
|
{ // Field is changed
|
|
|
|
def->field=field;
|
|
|
|
if (!def->after)
|
2003-12-30 12:14:21 +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
|
|
|
new_create_list.push_back(def);
|
|
|
|
def_it.remove();
|
2003-12-30 12:14:21 +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
|
|
|
else
|
2004-02-06 12:28:57 +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
|
|
|
This field was not dropped and not changed, add it to the list
|
|
|
|
for the new table.
|
2004-02-06 12:28:57 +01:00
|
|
|
*/
|
2007-06-10 12:43:57 +02:00
|
|
|
def= new Create_field(field, field);
|
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
|
|
|
new_create_list.push_back(def);
|
|
|
|
alter_it.rewind(); // Change default if ALTER
|
|
|
|
Alter_column *alter;
|
|
|
|
while ((alter=alter_it++))
|
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
|
|
|
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
|
|
|
|
break;
|
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
|
|
|
if (alter)
|
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
|
|
|
if (def->sql_type == MYSQL_TYPE_BLOB)
|
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
|
|
|
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
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
|
|
|
if ((def->def=alter->def)) // Use new default
|
|
|
|
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
|
|
|
|
else
|
|
|
|
def->flags|= NO_DEFAULT_VALUE_FLAG;
|
|
|
|
alter_it.remove();
|
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
|
|
|
def_it.rewind();
|
|
|
|
while ((def=def_it++)) // Add new columns
|
2006-06-14 04:46:38 +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
|
|
|
if (def->change && ! def->field)
|
2006-06-14 04:46:38 +02:00
|
|
|
{
|
2007-10-25 03:01:08 +02:00
|
|
|
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
|
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
|
|
|
goto err;
|
2006-06-14 04:46:38 +02:00
|
|
|
}
|
2007-06-04 12:03:15 +02:00
|
|
|
/*
|
|
|
|
Check that the DATE/DATETIME not null field we are going to add is
|
|
|
|
either has a default value or the '0000-00-00' is allowed by the
|
|
|
|
set sql mode.
|
|
|
|
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
|
|
|
|
flag to allow ALTER TABLE only if the table to be altered is empty.
|
|
|
|
*/
|
|
|
|
if ((def->sql_type == MYSQL_TYPE_DATE ||
|
|
|
|
def->sql_type == MYSQL_TYPE_NEWDATE ||
|
|
|
|
def->sql_type == MYSQL_TYPE_DATETIME) &&
|
|
|
|
!alter_info->datetime_field &&
|
|
|
|
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
|
|
|
|
thd->variables.sql_mode & MODE_NO_ZERO_DATE)
|
|
|
|
{
|
|
|
|
alter_info->datetime_field= def;
|
|
|
|
alter_info->error_if_not_empty= TRUE;
|
|
|
|
}
|
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
|
|
|
if (!def->after)
|
|
|
|
new_create_list.push_back(def);
|
|
|
|
else if (def->after == first_keyword)
|
2011-06-17 00:02:52 +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
|
|
|
new_create_list.push_front(def);
|
2011-06-17 00:02:52 +02:00
|
|
|
/*
|
|
|
|
Re-ordering columns in table can't be done using in-place algorithm
|
|
|
|
as it always changes table data.
|
|
|
|
*/
|
|
|
|
alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
}
|
2006-06-15 21:56:47 +02:00
|
|
|
else
|
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
|
|
|
{
|
2007-06-10 12:43:57 +02:00
|
|
|
Create_field *find;
|
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
|
|
|
find_it.rewind();
|
|
|
|
while ((find=find_it++)) // Add new columns
|
|
|
|
{
|
|
|
|
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!find)
|
|
|
|
{
|
2007-10-25 03:01:08 +02:00
|
|
|
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
|
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
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
find_it.after(def); // Put element after this
|
2011-06-17 00:02:52 +02:00
|
|
|
/*
|
|
|
|
Re-ordering columns in table can't be done using in-place algorithm
|
|
|
|
as it always changes table data.
|
|
|
|
*/
|
2007-06-04 12:03:15 +02:00
|
|
|
alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
|
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
|
|
|
}
|
2006-06-14 04:46:38 +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
|
|
|
if (alter_info->alter_list.elements)
|
2005-10-01 01:26:48 +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
|
|
|
my_error(ER_BAD_FIELD_ERROR, MYF(0),
|
2007-10-25 03:01:08 +02:00
|
|
|
alter_info->alter_list.head()->name, table->s->table_name.str);
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2005-10-01 01:26:48 +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
|
|
|
if (!new_create_list.elements)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-11-12 13:34:00 +01:00
|
|
|
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
|
|
|
|
MYF(0));
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-06-02 20:22:20 +02:00
|
|
|
Collect all keys which isn't in drop list. Add only those
|
|
|
|
for which some fields exists.
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
for (uint i=0 ; i < table->s->keys ; i++,key_info++)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-01-13 13:18:37 +01:00
|
|
|
char *key_name= key_info->name;
|
2000-07-31 21:29:14 +02:00
|
|
|
Alter_drop *drop;
|
|
|
|
drop_it.rewind();
|
|
|
|
while ((drop=drop_it++))
|
|
|
|
{
|
|
|
|
if (drop->type == Alter_drop::KEY &&
|
2002-03-12 18:37:58 +01:00
|
|
|
!my_strcasecmp(system_charset_info,key_name, drop->name))
|
2000-07-31 21:29:14 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (drop)
|
|
|
|
{
|
|
|
|
drop_it.remove();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
KEY_PART_INFO *key_part= key_info->key_part;
|
|
|
|
key_parts.empty();
|
|
|
|
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
|
|
|
|
{
|
|
|
|
if (!key_part->field)
|
|
|
|
continue; // Wrong field (from UNIREG)
|
|
|
|
const char *key_part_name=key_part->field->field_name;
|
2007-06-10 12:43:57 +02:00
|
|
|
Create_field *cfield;
|
2000-07-31 21:29:14 +02:00
|
|
|
field_it.rewind();
|
|
|
|
while ((cfield=field_it++))
|
|
|
|
{
|
|
|
|
if (cfield->change)
|
|
|
|
{
|
2002-06-04 07:23:57 +02:00
|
|
|
if (!my_strcasecmp(system_charset_info, key_part_name,
|
|
|
|
cfield->change))
|
2000-07-31 21:29:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2002-03-12 18:37:58 +01:00
|
|
|
else if (!my_strcasecmp(system_charset_info,
|
2004-04-08 16:56:45 +02:00
|
|
|
key_part_name, cfield->field_name))
|
2002-06-04 07:23:57 +02:00
|
|
|
break;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
if (!cfield)
|
|
|
|
continue; // Field is removed
|
|
|
|
uint key_part_length=key_part->length;
|
|
|
|
if (cfield->field) // Not new field
|
2005-05-26 03:11:47 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
If the field can't have only a part used in a key according to its
|
|
|
|
new type, or should not be used partially according to its
|
|
|
|
previous type, or the field length is less than the key part
|
|
|
|
length, unset the key part length.
|
|
|
|
|
2005-06-02 19:00:36 +02:00
|
|
|
We also unset the key part length if it is the same as the
|
|
|
|
old field's length, so the whole new field will be used.
|
|
|
|
|
2005-05-26 03:11:47 +02:00
|
|
|
BLOBs may have cfield->length == 0, which is why we test it before
|
|
|
|
checking whether cfield->length < key_part_length (in chars).
|
2009-11-09 12:35:18 +01:00
|
|
|
|
|
|
|
In case of TEXTs we check the data type maximum length *in bytes*
|
|
|
|
to key part length measured *in characters* (i.e. key_part_length
|
|
|
|
devided to mbmaxlen). This is because it's OK to have:
|
|
|
|
CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8);
|
|
|
|
In case of this example:
|
|
|
|
- data type maximum length is 255.
|
|
|
|
- key_part_length is 1016 (=254*4, where 4 is mbmaxlen)
|
2005-05-26 03:11:47 +02:00
|
|
|
*/
|
|
|
|
if (!Field::type_can_have_key_part(cfield->field->type()) ||
|
2007-03-14 16:07:48 +01:00
|
|
|
!Field::type_can_have_key_part(cfield->sql_type) ||
|
2007-03-14 11:20:34 +01:00
|
|
|
/* spatial keys can't have sub-key length */
|
|
|
|
(key_info->flags & HA_SPATIAL) ||
|
2005-07-01 12:07:06 +02:00
|
|
|
(cfield->field->field_length == key_part_length &&
|
|
|
|
!f_is_blob(key_part->key_type)) ||
|
2009-11-09 12:35:18 +01:00
|
|
|
(cfield->length && (((cfield->sql_type >= MYSQL_TYPE_TINY_BLOB &&
|
|
|
|
cfield->sql_type <= MYSQL_TYPE_BLOB) ?
|
|
|
|
blob_length_by_type(cfield->sql_type) :
|
|
|
|
cfield->length) <
|
|
|
|
key_part_length / key_part->field->charset()->mbmaxlen)))
|
2005-05-26 03:11:47 +02:00
|
|
|
key_part_length= 0; // Use whole field
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2003-09-15 11:45:42 +02:00
|
|
|
key_part_length /= key_part->field->charset()->mbmaxlen;
|
2007-06-10 12:43:57 +02:00
|
|
|
key_parts.push_back(new Key_part_spec(cfield->field_name,
|
2009-10-09 16:29:51 +02:00
|
|
|
strlen(cfield->field_name),
|
2000-07-31 21:29:14 +02:00
|
|
|
key_part_length));
|
|
|
|
}
|
|
|
|
if (key_parts.elements)
|
2006-05-03 14:59:17 +02:00
|
|
|
{
|
|
|
|
KEY_CREATE_INFO key_create_info;
|
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 *key;
|
|
|
|
enum Key::Keytype key_type;
|
2006-05-03 14:59:17 +02:00
|
|
|
bzero((char*) &key_create_info, sizeof(key_create_info));
|
|
|
|
|
|
|
|
key_create_info.algorithm= key_info->algorithm;
|
|
|
|
if (key_info->flags & HA_USES_BLOCK_SIZE)
|
|
|
|
key_create_info.block_size= key_info->block_size;
|
|
|
|
if (key_info->flags & HA_USES_PARSER)
|
2008-12-17 14:24:34 +01:00
|
|
|
key_create_info.parser_name= *plugin_name(key_info->parser);
|
2010-02-20 11:07:32 +01:00
|
|
|
if (key_info->flags & HA_USES_COMMENT)
|
|
|
|
key_create_info.comment= key_info->comment;
|
2006-05-03 14:59:17 +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
|
|
|
if (key_info->flags & HA_SPATIAL)
|
|
|
|
key_type= Key::SPATIAL;
|
|
|
|
else if (key_info->flags & HA_NOSAME)
|
|
|
|
{
|
|
|
|
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
|
|
|
|
key_type= Key::PRIMARY;
|
|
|
|
else
|
|
|
|
key_type= Key::UNIQUE;
|
|
|
|
}
|
|
|
|
else if (key_info->flags & HA_FULLTEXT)
|
|
|
|
key_type= Key::FULLTEXT;
|
|
|
|
else
|
|
|
|
key_type= Key::MULTIPLE;
|
|
|
|
|
2009-10-09 16:29:51 +02:00
|
|
|
key= new Key(key_type, key_name, strlen(key_name),
|
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_create_info,
|
|
|
|
test(key_info->flags & HA_GENERATED_KEY),
|
|
|
|
key_parts);
|
|
|
|
new_key_list.push_back(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
Key *key;
|
|
|
|
while ((key=key_it++)) // Add new keys
|
|
|
|
{
|
|
|
|
if (key->type != Key::FOREIGN_KEY)
|
|
|
|
new_key_list.push_back(key);
|
2009-10-09 16:29:51 +02:00
|
|
|
if (key->name.str &&
|
|
|
|
!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
|
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
|
|
|
{
|
2009-10-09 16:29:51 +02:00
|
|
|
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
|
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
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alter_info->drop_list.elements)
|
|
|
|
{
|
|
|
|
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
|
|
|
|
alter_info->drop_list.head()->name);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (alter_info->alter_list.elements)
|
|
|
|
{
|
|
|
|
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
|
|
|
|
alter_info->alter_list.head()->name);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!create_info->comment.str)
|
|
|
|
{
|
|
|
|
create_info->comment.str= table->s->comment.str;
|
|
|
|
create_info->comment.length= table->s->comment.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
table->file->update_create_info(create_info);
|
|
|
|
if ((create_info->table_options &
|
|
|
|
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
|
|
|
|
(used_fields & HA_CREATE_USED_PACK_KEYS))
|
|
|
|
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
|
|
|
|
if (create_info->table_options &
|
|
|
|
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
|
|
|
|
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
|
|
|
|
if (create_info->table_options &
|
|
|
|
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
|
|
|
|
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
|
|
|
|
HA_OPTION_NO_DELAY_KEY_WRITE);
|
|
|
|
create_info->table_options|= db_create_options;
|
|
|
|
|
|
|
|
if (table->s->tmp_table)
|
|
|
|
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
|
|
|
|
|
|
|
|
rc= FALSE;
|
|
|
|
alter_info->create_list.swap(new_create_list);
|
|
|
|
alter_info->key_list.swap(new_key_list);
|
|
|
|
err:
|
|
|
|
DBUG_RETURN(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Alter table
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_alter_table()
|
|
|
|
thd Thread handle
|
|
|
|
new_db If there is a RENAME clause
|
|
|
|
new_name If there is a RENAME clause
|
|
|
|
create_info Information from the parsing phase about new
|
|
|
|
table properties.
|
|
|
|
table_list The table to change.
|
|
|
|
alter_info Lists of fields, keys to be changed, added
|
|
|
|
or dropped.
|
|
|
|
order_num How many ORDER BY fields has been specified.
|
|
|
|
order List of fields to ORDER BY.
|
|
|
|
ignore Whether we have ALTER IGNORE TABLE
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
This is a veery long function and is everything but the kitchen sink :)
|
|
|
|
It is used to alter a table and not only by ALTER TABLE but also
|
|
|
|
CREATE|DROP INDEX are mapped on this function.
|
|
|
|
|
|
|
|
When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS,
|
|
|
|
or both, then this function short cuts its operation by renaming
|
|
|
|
the table and/or enabling/disabling the keys. In this case, the FRM is
|
|
|
|
not changed, directly by mysql_alter_table. However, if there is a
|
|
|
|
RENAME + change of a field, or an index, the short cut is not used.
|
|
|
|
See how `create_list` is used to generate the new FRM regarding the
|
|
|
|
structure of the fields. The same is done for the indices of the table.
|
|
|
|
|
|
|
|
Important is the fact, that this function tries to do as little work as
|
|
|
|
possible, by finding out whether a intermediate table is needed to copy
|
|
|
|
data into and when finishing the altering to use it as the original table.
|
2010-08-16 14:53:30 +02:00
|
|
|
For this reason the function mysql_compare_tables() is called, which decides
|
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
|
|
|
based on all kind of data how similar are the new and the original
|
|
|
|
tables.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|
|
|
HA_CREATE_INFO *create_info,
|
|
|
|
TABLE_LIST *table_list,
|
|
|
|
Alter_info *alter_info,
|
|
|
|
uint order_num, ORDER *order, bool ignore)
|
|
|
|
{
|
2009-11-30 16:55:03 +01:00
|
|
|
TABLE *table, *new_table= 0;
|
2009-12-04 00:52:05 +01:00
|
|
|
MDL_ticket *mdl_ticket;
|
2009-12-08 10:57:07 +01:00
|
|
|
MDL_request target_mdl_request;
|
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
|
|
|
int error= 0;
|
2009-06-19 10:24:43 +02:00
|
|
|
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
|
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
|
|
|
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
|
|
|
|
char index_file[FN_REFLEN], data_file[FN_REFLEN];
|
2009-06-19 10:24:43 +02:00
|
|
|
char path[FN_REFLEN + 1];
|
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
|
|
|
char reg_path[FN_REFLEN+1];
|
2000-08-07 23:28:56 +02:00
|
|
|
ha_rows copied,deleted;
|
2006-12-04 18:22:38 +01:00
|
|
|
handlerton *old_db_type, *new_db_type, *save_old_db_type;
|
2007-06-04 12:03:15 +02:00
|
|
|
enum_alter_table_change_level need_copy_table= ALTER_TABLE_METADATA_ONLY;
|
2005-11-07 16:25:06 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2010-10-01 13:22:11 +02:00
|
|
|
TABLE *table_for_fast_alter_partition= NULL;
|
2005-07-27 22:56:28 +02:00
|
|
|
bool partition_changed= FALSE;
|
|
|
|
#endif
|
2006-01-12 10:05:07 +01:00
|
|
|
bool need_lock_for_indexes= TRUE;
|
|
|
|
KEY *key_info_buffer;
|
2009-06-17 16:56:44 +02:00
|
|
|
uint index_drop_count= 0;
|
|
|
|
uint *index_drop_buffer= NULL;
|
|
|
|
uint index_add_count= 0;
|
2011-06-01 10:06:55 +02:00
|
|
|
handler_add_index *add= NULL;
|
|
|
|
bool pending_inplace_add_index= false;
|
2009-06-17 16:56:44 +02:00
|
|
|
uint *index_add_buffer= NULL;
|
|
|
|
uint candidate_key_count= 0;
|
2008-09-15 11:19:56 +02:00
|
|
|
bool no_pk;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("mysql_alter_table");
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
Check if we attempt to alter mysql.slow_log or
|
|
|
|
mysql.general_log table and return an error if
|
|
|
|
it is the case.
|
|
|
|
TODO: this design is obsolete and will be removed.
|
|
|
|
*/
|
2006-10-13 15:26:46 +02:00
|
|
|
if (table_list && table_list->db && table_list->table_name)
|
2006-08-03 19:28:15 +02:00
|
|
|
{
|
2006-10-13 15:26:46 +02:00
|
|
|
int table_kind= 0;
|
2006-08-03 19:28:15 +02:00
|
|
|
|
2006-10-13 15:26:46 +02:00
|
|
|
table_kind= check_if_log_table(table_list->db_length, table_list->db,
|
|
|
|
table_list->table_name_length,
|
|
|
|
table_list->table_name, 0);
|
2006-08-03 19:28:15 +02:00
|
|
|
|
2007-06-08 16:12:42 +02:00
|
|
|
if (table_kind)
|
2006-08-03 19:28:15 +02:00
|
|
|
{
|
2007-06-08 16:12:42 +02:00
|
|
|
/* Disable alter of enabled log tables */
|
|
|
|
if (logger.is_log_table_enabled(table_kind))
|
|
|
|
{
|
|
|
|
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2006-08-03 19:28:15 +02:00
|
|
|
|
2007-06-08 16:12:42 +02:00
|
|
|
/* Disable alter of log tables to unsupported engine */
|
|
|
|
if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
|
|
|
|
(!create_info->db_type || /* unknown engine */
|
|
|
|
!(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
|
|
|
|
{
|
|
|
|
my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
if (alter_info->flags & ALTER_PARTITION)
|
|
|
|
{
|
WL#3984 (Revise locking of mysql.general_log and mysql.slow_log)
Bug#25422 (Hang with log tables)
Bug 17876 (Truncating mysql.slow_log in a SP after using cursor locks the
thread)
Bug 23044 (Warnings on flush of a log table)
Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
a deadlock)
Prior to this fix, the server would hang when performing concurrent
ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES,
which are mysql.general_log and mysql.slow_log.
The root cause traces to the following code:
in sql_base.cc, open_table()
if (table->in_use != thd)
{
/* wait_for_condition will unlock LOCK_open for us */
wait_for_condition(thd, &LOCK_open, &COND_refresh);
}
The problem with this code is that the current implementation of the
LOGGER creates 'fake' THD objects, like
- Log_to_csv_event_handler::general_log_thd
- Log_to_csv_event_handler::slow_log_thd
which are not associated to a real thread running in the server,
so that waiting for these non-existing threads to release table locks
cause the dead lock.
In general, the design of Log_to_csv_event_handler does not fit into the
general architecture of the server, so that the concept of general_log_thd
and slow_log_thd has to be abandoned:
- this implementation does not work with table locking
- it will not work with commands like SHOW PROCESSLIST
- having the log tables always opened does not integrate well with DDL
operations / FLUSH TABLES / SET GLOBAL READ_ONLY
With this patch, the fundamental design of the LOGGER has been changed to:
- always open and close a log table when writing a log
- remove totally the usage of fake THD objects
- clarify how locking of log tables is implemented in general.
See WL#3984 for details related to the new locking design.
Additional changes (misc bugs exposed and fixed):
1)
mysqldump which would ignore some tables in dump_all_tables_in_db(),
but forget to ignore the same in dump_all_views_in_db().
2)
mysqldump would also issue an empty "LOCK TABLE" command when all the tables
to lock are to be ignored (numrows == 0), instead of not issuing the query.
3)
Internal errors handlers could intercept errors but not warnings
(see sql_error.cc).
4)
Implementing a nested call to open tables, for the performance schema tables,
exposed an existing bug in remove_table_from_cache(), which would perform:
in_use->some_tables_deleted=1;
against another thread, without any consideration about thread locking.
This call inside remove_table_from_cache() was not required anyway,
since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads
that might hold a lock on a table.
This line (in_use->some_tables_deleted=1) has been removed.
2007-07-27 08:31:06 +02:00
|
|
|
my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
|
2007-06-08 16:12:42 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
#endif
|
2006-08-03 19:28:15 +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
|
|
|
/*
|
|
|
|
Assign variables table_name, new_name, db, new_db, path, reg_path
|
|
|
|
to simplify further comparisions: we want to see if it's a RENAME
|
|
|
|
later just by comparing the pointers, avoiding the need for strcmp.
|
|
|
|
*/
|
2007-10-17 20:05:43 +02:00
|
|
|
thd_proc_info(thd, "init");
|
2005-01-06 12:00:13 +01:00
|
|
|
table_name=table_list->table_name;
|
2003-12-30 12:14:21 +01:00
|
|
|
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
|
2000-07-31 21:29:14 +02:00
|
|
|
db=table_list->db;
|
2004-02-11 00:06:46 +01:00
|
|
|
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
|
2004-02-09 12:29:31 +01:00
|
|
|
new_db= db;
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0);
|
|
|
|
build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
|
2006-01-12 10:05:07 +01:00
|
|
|
|
2009-11-30 16:55:03 +01:00
|
|
|
mysql_ha_rm_tables(thd, table_list);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2003-10-14 00:52:03 +02:00
|
|
|
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
|
2004-05-21 16:57:03 +02:00
|
|
|
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
|
2006-10-03 19:38:25 +02:00
|
|
|
/* Conditionally writes to binlog. */
|
2003-10-13 10:20:19 +02:00
|
|
|
DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
|
2004-05-21 16:57:03 +02:00
|
|
|
alter_info->tablespace_op));
|
2009-12-08 15:13:12 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Code below can handle only base tables so ensure that we won't open a view.
|
|
|
|
Note that RENAME TABLE the only ALTER clause which is supported for views
|
|
|
|
has been already processed.
|
|
|
|
*/
|
|
|
|
table_list->required_type= FRMTYPE_TABLE;
|
|
|
|
|
|
|
|
Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
|
|
|
|
|
2010-07-01 15:53:46 +02:00
|
|
|
DEBUG_SYNC(thd, "alter_table_before_open_tables");
|
2010-05-25 14:35:01 +02:00
|
|
|
error= open_and_lock_tables(thd, table_list, FALSE, 0,
|
2010-02-24 18:04:00 +01:00
|
|
|
&alter_prelocking_strategy);
|
2009-12-08 15:13:12 +01:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2009-12-08 15:13:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
table= table_list->table;
|
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
|
|
|
table->use_all_columns();
|
2009-12-04 00:52:05 +01:00
|
|
|
mdl_ticket= table->mdl_ticket;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
/*
|
|
|
|
Prohibit changing of the UNION list of a non-temporary MERGE table
|
|
|
|
under LOCK tables. It would be quite difficult to reuse a shrinked
|
|
|
|
set of tables from the old table or to open a new TABLE object for
|
|
|
|
an extended list and verify that they belong to locked tables.
|
|
|
|
*/
|
2009-12-08 15:13:12 +01:00
|
|
|
if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
|
|
|
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
(create_info->used_fields & HA_CREATE_USED_UNION) &&
|
|
|
|
(table->s->tmp_table == NO_TMP_TABLE))
|
|
|
|
{
|
|
|
|
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Check that we are not trying to rename to an existing table */
|
|
|
|
if (new_name)
|
|
|
|
{
|
2006-08-02 17:57:06 +02:00
|
|
|
DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name));
|
2000-07-31 21:29:14 +02:00
|
|
|
strmov(new_name_buff,new_name);
|
2004-02-06 14:40:44 +01:00
|
|
|
strmov(new_alias= new_alias_buff, new_name);
|
2001-08-10 16:37:37 +02:00
|
|
|
if (lower_case_table_names)
|
2003-12-30 12:14:21 +01:00
|
|
|
{
|
|
|
|
if (lower_case_table_names != 2)
|
|
|
|
{
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, new_name_buff);
|
2003-12-30 12:14:21 +01:00
|
|
|
new_alias= new_name; // Create lower case table name
|
|
|
|
}
|
2004-05-22 21:41:58 +02:00
|
|
|
my_casedn_str(files_charset_info, new_name);
|
2003-12-30 12:14:21 +01:00
|
|
|
}
|
2004-02-06 12:28:57 +01:00
|
|
|
if (new_db == db &&
|
2004-02-11 00:06:46 +01:00
|
|
|
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
|
2004-02-06 12:28:57 +01:00
|
|
|
{
|
|
|
|
/*
|
2004-04-08 16:56:45 +02:00
|
|
|
Source and destination table names are equal: make later check
|
|
|
|
easier.
|
2004-02-06 12:28:57 +01:00
|
|
|
*/
|
2004-02-06 13:23:41 +01:00
|
|
|
new_alias= new_name= table_name;
|
2004-02-06 12:28:57 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
else
|
|
|
|
{
|
2005-11-23 21:45:02 +01:00
|
|
|
if (table->s->tmp_table != NO_TMP_TABLE)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
if (find_temporary_table(thd,new_db,new_name_buff))
|
|
|
|
{
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-12-10 09:21:38 +01:00
|
|
|
target_mdl_request.init(MDL_key::TABLE, new_db, new_name,
|
2010-11-11 18:11:05 +01:00
|
|
|
MDL_EXCLUSIVE, MDL_TRANSACTION);
|
2010-01-21 21:43:03 +01:00
|
|
|
/*
|
|
|
|
Global intention exclusive lock must have been already acquired when
|
|
|
|
table to be altered was open, so there is no need to do it here.
|
|
|
|
*/
|
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(thd->mdl_context.is_lock_owner(MDL_key::GLOBAL,
|
|
|
|
"", "",
|
|
|
|
MDL_INTENTION_EXCLUSIVE));
|
2010-01-21 21:43:03 +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
|
|
|
if (thd->mdl_context.try_acquire_lock(&target_mdl_request))
|
2007-05-11 19:51:03 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2009-12-08 10:57:07 +01:00
|
|
|
if (target_mdl_request.ticket == NULL)
|
2007-05-11 19:51:03 +02:00
|
|
|
{
|
2009-12-08 10:57:07 +01:00
|
|
|
/* Table exists and is locked by some thread. */
|
2007-05-11 19:51:03 +02:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2009-12-08 10:57:07 +01:00
|
|
|
DEBUG_SYNC(thd, "locked_table_name");
|
|
|
|
/*
|
|
|
|
Table maybe does not exist, but we got an exclusive lock
|
|
|
|
on the name, now we can safely try to find out for sure.
|
|
|
|
*/
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(new_name_buff, sizeof(new_name_buff) - 1,
|
2006-08-02 17:57:06 +02:00
|
|
|
new_db, new_name_buff, reg_ext, 0);
|
|
|
|
if (!access(new_name_buff, F_OK))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
/* Table will be closed in do_command() */
|
2004-11-13 18:35:51 +01:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2004-06-23 15:44:34 +02:00
|
|
|
{
|
|
|
|
new_alias= (lower_case_table_names == 2) ? alias : table_name;
|
|
|
|
new_name= table_name;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2007-03-02 17:43:45 +01:00
|
|
|
old_db_type= table->s->db_type();
|
2006-05-28 14:51:01 +02:00
|
|
|
if (!create_info->db_type)
|
2006-06-14 04:46:38 +02:00
|
|
|
{
|
2006-06-16 21:04:35 +02:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-06-15 21:56:47 +02:00
|
|
|
if (table->part_info &&
|
|
|
|
create_info->used_fields & HA_CREATE_USED_ENGINE)
|
2006-06-14 04:46:38 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
This case happens when the user specified
|
|
|
|
ENGINE = x where x is a non-existing storage engine
|
2006-06-15 21:56:47 +02:00
|
|
|
We set create_info->db_type to default_engine_type
|
|
|
|
to ensure we don't change underlying engine type
|
|
|
|
due to a erroneously given engine name.
|
2006-06-14 04:46:38 +02:00
|
|
|
*/
|
2006-06-15 21:56:47 +02:00
|
|
|
create_info->db_type= table->part_info->default_engine_type;
|
2006-06-14 04:46:38 +02:00
|
|
|
}
|
2006-06-15 21:56:47 +02:00
|
|
|
else
|
2006-06-16 21:04:35 +02:00
|
|
|
#endif
|
2006-06-15 21:56:47 +02:00
|
|
|
create_info->db_type= old_db_type;
|
2006-06-14 04:46:38 +02:00
|
|
|
}
|
2005-08-19 16:26:05 +02:00
|
|
|
|
2006-02-17 17:12:35 +01:00
|
|
|
if (check_engine(thd, new_name, create_info))
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2005-06-17 23:14:44 +02:00
|
|
|
new_db_type= create_info->db_type;
|
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
|
|
|
|
2007-12-06 14:43:06 +01:00
|
|
|
if ((new_db_type != old_db_type ||
|
|
|
|
alter_info->flags & ALTER_PARTITION) &&
|
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
|
|
|
!table->file->can_switch_engines())
|
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
|
|
|
my_error(ER_ROW_IS_REFERENCED, MYF(0));
|
2000-07-31 21:29:14 +02:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2009-09-18 15:01:18 +02:00
|
|
|
/*
|
|
|
|
If this is an ALTER TABLE and no explicit row type specified reuse
|
|
|
|
the table's row type.
|
|
|
|
Note : this is the same as if the row type was specified explicitly.
|
|
|
|
*/
|
2001-09-30 04:47:35 +02:00
|
|
|
if (create_info->row_type == ROW_TYPE_NOT_USED)
|
2009-05-29 16:22:24 +02:00
|
|
|
{
|
2009-09-18 15:01:18 +02:00
|
|
|
/* ALTER TABLE without explicit row type */
|
2005-01-06 12:00:13 +01:00
|
|
|
create_info->row_type= table->s->row_type;
|
2009-09-18 15:01:18 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* ALTER TABLE with specific row type */
|
2009-05-29 16:22:24 +02:00
|
|
|
create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2006-01-17 09:25:12 +01:00
|
|
|
DBUG_PRINT("info", ("old type: %s new type: %s",
|
|
|
|
ha_resolve_storage_engine_name(old_db_type),
|
|
|
|
ha_resolve_storage_engine_name(new_db_type)));
|
2005-10-11 23:58:22 +02:00
|
|
|
if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
|
2006-07-10 20:46:05 +02:00
|
|
|
ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
|
2005-10-01 01:26:48 +02:00
|
|
|
{
|
|
|
|
DBUG_PRINT("info", ("doesn't support alter"));
|
|
|
|
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2005-10-01 01:26:48 +02:00
|
|
|
}
|
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "setup");
|
2004-10-21 18:10:58 +02:00
|
|
|
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
|
2005-01-06 12:00:13 +01:00
|
|
|
!table->s->tmp_table) // no need to touch frm
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-11-16 14:01:51 +01:00
|
|
|
switch (alter_info->keys_onoff) {
|
|
|
|
case LEAVE_AS_IS:
|
|
|
|
break;
|
|
|
|
case ENABLE:
|
2009-11-30 16:55:03 +01:00
|
|
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
|
|
|
goto err;
|
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
|
|
|
DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
|
2007-12-20 19:16:55 +01:00
|
|
|
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
2006-11-16 14:01:51 +01:00
|
|
|
break;
|
|
|
|
case DISABLE:
|
2009-11-30 16:55:03 +01:00
|
|
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
|
|
|
goto err;
|
2007-12-20 19:16:55 +01:00
|
|
|
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
|
2006-11-16 14:01:51 +01:00
|
|
|
break;
|
2006-12-19 23:02:37 +01:00
|
|
|
default:
|
|
|
|
DBUG_ASSERT(FALSE);
|
|
|
|
error= 0;
|
|
|
|
break;
|
2006-11-16 14:01:51 +01:00
|
|
|
}
|
|
|
|
if (error == HA_ERR_WRONG_COMMAND)
|
|
|
|
{
|
2006-12-15 05:21:15 +01:00
|
|
|
error= 0;
|
2006-11-16 14:01:51 +01:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
2009-12-01 14:14:06 +01:00
|
|
|
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
|
|
|
|
table->alias);
|
2006-11-16 14:01:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!error && (new_name != table_name || new_db != db))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "rename");
|
2007-05-11 19:51:03 +02:00
|
|
|
/*
|
|
|
|
Then do a 'simple' rename of the table. First we need to close all
|
|
|
|
instances of 'source' table.
|
2009-12-02 16:22:15 +01:00
|
|
|
Note that if wait_while_table_is_used() returns error here (i.e. if
|
2009-11-30 16:55:03 +01:00
|
|
|
this thread was killed) then it must be that previous step of
|
2009-12-02 16:22:15 +01:00
|
|
|
simple rename did nothing and therefore we can safely return
|
2009-11-30 16:55:03 +01:00
|
|
|
without additional clean-up.
|
2007-05-11 19:51:03 +02:00
|
|
|
*/
|
2009-12-02 16:22:15 +01:00
|
|
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err;
|
2009-12-02 16:22:15 +01:00
|
|
|
close_all_tables_for_name(thd, table->s, TRUE);
|
2007-05-11 19:51:03 +02:00
|
|
|
/*
|
|
|
|
Then, we want check once again that target table does not exist.
|
|
|
|
Actually the order of these two steps does not matter since
|
2009-12-01 14:51:50 +01:00
|
|
|
earlier we took exclusive metadata lock on the target table, so
|
|
|
|
we do them in this particular order only to be consistent with 5.0,
|
|
|
|
in which we don't take this lock and where this order really matters.
|
2007-05-11 19:51:03 +02:00
|
|
|
TODO: Investigate if we need this access() check at all.
|
|
|
|
*/
|
2001-05-11 22:26:12 +02:00
|
|
|
if (!access(new_name_buff,F_OK))
|
|
|
|
{
|
2009-12-01 14:14:06 +01:00
|
|
|
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
|
|
|
|
error= -1;
|
2001-05-11 22:26:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-12-01 14:14:06 +01:00
|
|
|
*fn_ext(new_name)=0;
|
|
|
|
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
|
|
|
|
error= -1;
|
2010-09-16 11:11:13 +02:00
|
|
|
else if (Table_triggers_list::change_table_name(thd, db,
|
|
|
|
alias, table_name,
|
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
|
|
|
new_db, new_alias))
|
|
|
|
{
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) mysql_rename_table(old_db_type, new_db, new_alias, db,
|
2009-12-01 14:14:06 +01:00
|
|
|
table_name, 0);
|
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
|
|
|
error= -1;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
}
|
2006-05-03 14:59:17 +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
|
|
|
if (error == HA_ERR_WRONG_COMMAND)
|
|
|
|
{
|
|
|
|
error= 0;
|
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
2009-12-01 14:14:06 +01:00
|
|
|
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
|
|
|
|
table->alias);
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
2006-05-03 14:59:17 +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
|
|
|
if (!error)
|
|
|
|
{
|
2010-02-04 21:15:47 +01:00
|
|
|
error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
|
|
|
if (!error)
|
|
|
|
my_ok(thd);
|
2006-05-03 14:59:17 +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
|
|
|
else if (error > 0)
|
2002-06-02 20:22:20 +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
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
error= -1;
|
2002-06-02 20:22:20 +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
|
|
|
table_list->table= NULL; // For query cache
|
|
|
|
query_cache_invalidate3(thd, table_list, 0);
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2009-12-08 15:13:12 +01:00
|
|
|
if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
|
|
|
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
|
2009-11-30 16:55:03 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Under LOCK TABLES we should adjust meta-data locks before finishing
|
2010-07-27 12:25:53 +02:00
|
|
|
statement. Otherwise we can rely on them being released
|
|
|
|
along with the implicit commit.
|
2009-11-30 16:55:03 +01:00
|
|
|
*/
|
|
|
|
if (new_name != table_name || new_db != db)
|
2009-12-04 00:52:05 +01:00
|
|
|
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
|
2009-11-30 16:55:03 +01:00
|
|
|
else
|
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
|
|
|
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
|
2009-11-30 16:55:03 +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
|
|
|
DBUG_RETURN(error);
|
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
|
|
|
/* We have to do full alter table. */
|
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
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
|
2010-10-01 13:22:11 +02:00
|
|
|
&partition_changed,
|
|
|
|
db, table_name, path,
|
|
|
|
&table_for_fast_alter_partition))
|
2005-04-07 11:16:41 +02:00
|
|
|
goto err;
|
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
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
If the old table had partitions and we are doing ALTER TABLE ...
|
|
|
|
engine= <new_engine>, the new table must preserve the original
|
|
|
|
partitioning. That means that the new engine is still the
|
|
|
|
partitioning engine, not the engine specified in the parser.
|
|
|
|
This is discovered in prep_alter_part_table, which in such case
|
|
|
|
updates create_info->db_type.
|
|
|
|
Now we need to update the stack copy of create_info->db_type,
|
|
|
|
as otherwise we won't be able to correctly move the files of the
|
|
|
|
temporary table to the result table files.
|
|
|
|
*/
|
|
|
|
new_db_type= create_info->db_type;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2010-03-17 15:18:46 +01:00
|
|
|
if (is_index_maintenance_unique (table, alter_info))
|
|
|
|
need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
|
|
|
|
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
|
|
|
if (mysql_prepare_alter_table(thd, table, create_info, alter_info))
|
|
|
|
goto err;
|
2007-06-04 12:03:15 +02:00
|
|
|
|
2010-03-17 15:18:46 +01:00
|
|
|
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
|
|
|
need_copy_table= alter_info->change_level;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2005-07-22 22:43:59 +02:00
|
|
|
set_table_default_charset(thd, create_info, db);
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
if (thd->variables.old_alter_table
|
2007-03-02 17:43:45 +01:00
|
|
|
|| (table->s->db_type() != create_info->db_type)
|
2005-11-07 16:25:06 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2006-01-12 10:05:07 +01:00
|
|
|
|| partition_changed
|
2005-07-27 22:56:28 +02:00
|
|
|
#endif
|
2006-01-12 10:05:07 +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
|
|
|
need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
2005-07-22 22:43:59 +02:00
|
|
|
else
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
2007-06-04 12:03:15 +02:00
|
|
|
enum_alter_table_change_level need_copy_table_res;
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Check how much the tables differ. */
|
2010-08-16 14:53:30 +02:00
|
|
|
if (mysql_compare_tables(table, alter_info,
|
|
|
|
create_info, order_num,
|
|
|
|
&need_copy_table_res,
|
|
|
|
&key_info_buffer,
|
|
|
|
&index_drop_buffer, &index_drop_count,
|
|
|
|
&index_add_buffer, &index_add_count,
|
|
|
|
&candidate_key_count))
|
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
|
|
|
goto err;
|
2007-06-04 07:52:02 +02:00
|
|
|
|
2010-04-25 13:06:40 +02:00
|
|
|
DBUG_EXECUTE_IF("alter_table_only_metadata_change", {
|
|
|
|
if (need_copy_table_res != ALTER_TABLE_METADATA_ONLY)
|
|
|
|
goto err; });
|
|
|
|
DBUG_EXECUTE_IF("alter_table_only_index_change", {
|
|
|
|
if (need_copy_table_res != ALTER_TABLE_INDEX_CHANGED)
|
|
|
|
goto err; });
|
|
|
|
|
2007-06-04 07:52:02 +02:00
|
|
|
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
|
|
|
need_copy_table= need_copy_table_res;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
If there are index changes only, try to do them in-place. "Index
|
2006-01-12 10:05:07 +01:00
|
|
|
changes only" means also that the handler for the table does not
|
|
|
|
change. The table is open and locked. The handler can be accessed.
|
|
|
|
*/
|
|
|
|
if (need_copy_table == ALTER_TABLE_INDEX_CHANGED)
|
|
|
|
{
|
|
|
|
int pk_changed= 0;
|
2006-01-17 08:40:00 +01:00
|
|
|
ulong alter_flags= 0;
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
ulong needed_inplace_with_read_flags= 0;
|
|
|
|
ulong needed_inplace_flags= 0;
|
2006-01-12 10:05:07 +01:00
|
|
|
KEY *key;
|
|
|
|
uint *idx_p;
|
|
|
|
uint *idx_end_p;
|
|
|
|
|
2008-10-05 00:40:30 +02:00
|
|
|
alter_flags= table->file->alter_table_flags(alter_info->flags);
|
2006-01-17 08:40:00 +01:00
|
|
|
DBUG_PRINT("info", ("alter_flags: %lu", alter_flags));
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Check dropped indexes. */
|
|
|
|
for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count;
|
|
|
|
idx_p < idx_end_p;
|
|
|
|
idx_p++)
|
|
|
|
{
|
|
|
|
key= table->key_info + *idx_p;
|
|
|
|
DBUG_PRINT("info", ("index dropped: '%s'", key->name));
|
|
|
|
if (key->flags & HA_NOSAME)
|
|
|
|
{
|
2008-09-15 11:19:56 +02:00
|
|
|
/*
|
|
|
|
Unique key. Check for "PRIMARY".
|
|
|
|
or if dropping last unique key
|
|
|
|
*/
|
|
|
|
if ((uint) (key - table->key_info) == table->s->primary_key)
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
2008-09-15 11:19:56 +02:00
|
|
|
DBUG_PRINT("info", ("Dropping primary key"));
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Primary key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE;
|
2006-01-12 10:05:07 +01:00
|
|
|
pk_changed++;
|
2008-09-15 11:19:56 +02:00
|
|
|
candidate_key_count--;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-15 11:19:56 +02:00
|
|
|
KEY_PART_INFO *part_end= key->key_part + key->key_parts;
|
|
|
|
bool is_candidate_key= true;
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Non-primary unique key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|=
|
|
|
|
HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE;
|
2008-09-15 11:19:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Check if all fields in key are declared
|
|
|
|
NOT NULL and adjust candidate_key_count
|
|
|
|
*/
|
|
|
|
for (KEY_PART_INFO *key_part= key->key_part;
|
|
|
|
key_part < part_end;
|
|
|
|
key_part++)
|
|
|
|
is_candidate_key=
|
|
|
|
(is_candidate_key &&
|
|
|
|
(! table->field[key_part->fieldnr-1]->maybe_null()));
|
|
|
|
if (is_candidate_key)
|
|
|
|
candidate_key_count--;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Non-unique key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_DROP_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
2008-09-15 11:19:56 +02:00
|
|
|
no_pk= ((table->s->primary_key == MAX_KEY) ||
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
(needed_inplace_with_read_flags &
|
|
|
|
HA_INPLACE_DROP_PK_INDEX_NO_WRITE));
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Check added indexes. */
|
|
|
|
for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count;
|
|
|
|
idx_p < idx_end_p;
|
|
|
|
idx_p++)
|
|
|
|
{
|
|
|
|
key= key_info_buffer + *idx_p;
|
|
|
|
DBUG_PRINT("info", ("index added: '%s'", key->name));
|
|
|
|
if (key->flags & HA_NOSAME)
|
|
|
|
{
|
2008-09-15 11:19:56 +02:00
|
|
|
/* Unique key */
|
|
|
|
|
|
|
|
KEY_PART_INFO *part_end= key->key_part + key->key_parts;
|
|
|
|
bool is_candidate_key= true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check if all fields in key are declared
|
|
|
|
NOT NULL
|
|
|
|
*/
|
|
|
|
for (KEY_PART_INFO *key_part= key->key_part;
|
|
|
|
key_part < part_end;
|
|
|
|
key_part++)
|
|
|
|
is_candidate_key=
|
|
|
|
(is_candidate_key &&
|
|
|
|
(! table->field[key_part->fieldnr]->maybe_null()));
|
|
|
|
|
|
|
|
/*
|
|
|
|
Check for "PRIMARY"
|
|
|
|
or if adding first unique key
|
|
|
|
defined on non-nullable fields
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((!my_strcasecmp(system_charset_info,
|
|
|
|
key->name, primary_key_name)) ||
|
|
|
|
(no_pk && candidate_key_count == 0 && is_candidate_key))
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
2008-09-15 11:19:56 +02:00
|
|
|
DBUG_PRINT("info", ("Adding primary key"));
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Primary key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE;
|
2006-01-12 10:05:07 +01:00
|
|
|
pk_changed++;
|
2008-09-15 11:19:56 +02:00
|
|
|
no_pk= false;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Non-primary unique key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Non-unique key. */
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_ADD_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_ADD_INDEX_NO_READ_WRITE;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
if ((candidate_key_count > 0) &&
|
|
|
|
(needed_inplace_with_read_flags & HA_INPLACE_DROP_PK_INDEX_NO_WRITE))
|
2008-09-15 11:19:56 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Dropped primary key when there is some other unique
|
|
|
|
not null key that should be converted to primary key
|
|
|
|
*/
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE;
|
|
|
|
needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE;
|
2008-09-15 11:19:56 +02:00
|
|
|
pk_changed= 2;
|
|
|
|
}
|
|
|
|
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
DBUG_PRINT("info",
|
|
|
|
("needed_inplace_with_read_flags: 0x%lx, needed_inplace_flags: 0x%lx",
|
|
|
|
needed_inplace_with_read_flags, needed_inplace_flags));
|
2006-01-12 10:05:07 +01:00
|
|
|
/*
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
In-place add/drop index is possible only if
|
2006-01-12 10:05:07 +01:00
|
|
|
the primary key is not added and dropped in the same statement.
|
|
|
|
Otherwise we have to recreate the table.
|
|
|
|
need_copy_table is no-zero at this place.
|
|
|
|
*/
|
|
|
|
if ( pk_changed < 2 )
|
|
|
|
{
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
if ((alter_flags & needed_inplace_with_read_flags) ==
|
|
|
|
needed_inplace_with_read_flags)
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
/* All required in-place flags to allow concurrent reads are present. */
|
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
|
|
|
need_copy_table= ALTER_TABLE_METADATA_ONLY;
|
2006-01-12 10:05:07 +01:00
|
|
|
need_lock_for_indexes= FALSE;
|
|
|
|
}
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
else if ((alter_flags & needed_inplace_flags) == needed_inplace_flags)
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
/* All required in-place flags are present. */
|
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
|
|
|
need_copy_table= ALTER_TABLE_METADATA_ONLY;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("need_copy_table: %u need_lock: %d",
|
|
|
|
need_copy_table, need_lock_for_indexes));
|
|
|
|
}
|
2005-07-22 22:43:59 +02:00
|
|
|
|
2004-10-21 18:10:58 +02:00
|
|
|
/*
|
|
|
|
better have a negative test here, instead of positive, like
|
2005-05-14 17:31:22 +02:00
|
|
|
alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
|
2004-10-21 18:10:58 +02:00
|
|
|
so that ALTER TABLE won't break when somebody will add new flag
|
|
|
|
*/
|
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
|
|
|
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
2005-07-22 22:43:59 +02:00
|
|
|
create_info->frm_only= 1;
|
2004-10-21 18:10:58 +02:00
|
|
|
|
2005-11-07 16:25:06 +01:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
2010-10-01 13:22:11 +02:00
|
|
|
if (table_for_fast_alter_partition)
|
2005-08-19 16:26:05 +02:00
|
|
|
{
|
2006-01-17 08:40:00 +01:00
|
|
|
DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
|
|
|
|
create_info, table_list,
|
|
|
|
db, table_name,
|
2010-10-01 13:22:11 +02:00
|
|
|
table_for_fast_alter_partition));
|
2005-08-19 16:26:05 +02:00
|
|
|
}
|
2005-08-20 22:56:54 +02:00
|
|
|
#endif
|
2005-08-19 16:26:05 +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
|
|
|
my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
|
|
|
|
current_pid, thd->thread_id);
|
|
|
|
/* Safety fix for innodb */
|
|
|
|
if (lower_case_table_names)
|
|
|
|
my_casedn_str(files_charset_info, tmp_name);
|
|
|
|
|
2001-06-01 03:27:59 +02:00
|
|
|
/*
|
|
|
|
Handling of symlinked tables:
|
|
|
|
If no rename:
|
|
|
|
Create new data file and index file on the same disk as the
|
|
|
|
old data and index files.
|
|
|
|
Copy data.
|
|
|
|
Rename new data file over old data file and new index file over
|
|
|
|
old index file.
|
|
|
|
Symlinks are not changed.
|
|
|
|
|
|
|
|
If rename:
|
|
|
|
Create new data file and index file on the same disk as the
|
|
|
|
old data and index files. Create also symlinks to point at
|
|
|
|
the new tables.
|
|
|
|
Copy data.
|
2006-12-04 18:22:38 +01:00
|
|
|
At end, rename intermediate tables, and symlinks to intermediate
|
|
|
|
table, to final table name.
|
2001-06-01 03:27:59 +02:00
|
|
|
Remove old table and old symlinks
|
|
|
|
|
|
|
|
If rename is made to another database:
|
|
|
|
Create new tables in new database.
|
|
|
|
Copy data.
|
|
|
|
Remove old table and symlinks.
|
|
|
|
*/
|
|
|
|
if (!strcmp(db, new_db)) // Ignore symlink if db changed
|
|
|
|
{
|
|
|
|
if (create_info->index_file_name)
|
|
|
|
{
|
|
|
|
/* Fix index_file_name to have 'tmp_name' as basename */
|
|
|
|
strmov(index_file, tmp_name);
|
|
|
|
create_info->index_file_name=fn_same(index_file,
|
|
|
|
create_info->index_file_name,
|
|
|
|
1);
|
|
|
|
}
|
|
|
|
if (create_info->data_file_name)
|
|
|
|
{
|
|
|
|
/* Fix data_file_name to have 'tmp_name' as basename */
|
|
|
|
strmov(data_file, tmp_name);
|
|
|
|
create_info->data_file_name=fn_same(data_file,
|
|
|
|
create_info->data_file_name,
|
|
|
|
1);
|
|
|
|
}
|
|
|
|
}
|
2001-06-05 02:38:10 +02:00
|
|
|
else
|
|
|
|
create_info->data_file_name=create_info->index_file_name=0;
|
2004-10-29 18:26:52 +02:00
|
|
|
|
2010-02-01 16:07:00 +01:00
|
|
|
DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
|
2010-03-02 00:05:30 +01:00
|
|
|
DBUG_EXECUTE_IF("sleep_before_create_table_no_lock",
|
|
|
|
my_sleep(100000););
|
2006-01-12 10:05:07 +01:00
|
|
|
/*
|
|
|
|
Create a table with a temporary name.
|
|
|
|
With create_info->frm_only == 1 this creates a .frm file only.
|
|
|
|
We don't log the statement, it will be logged later.
|
|
|
|
*/
|
|
|
|
tmp_disable_binlog(thd);
|
2007-05-11 19:51:03 +02:00
|
|
|
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
|
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
|
|
|
create_info,
|
|
|
|
alter_info,
|
2010-08-20 04:59:58 +02:00
|
|
|
1, 0, NULL);
|
2006-01-12 10:05:07 +01:00
|
|
|
reenable_binlog(thd);
|
|
|
|
if (error)
|
2007-05-11 19:51:03 +02:00
|
|
|
goto err;
|
2006-01-12 10:05:07 +01:00
|
|
|
|
|
|
|
/* Open the table if we need to copy the data. */
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_PRINT("info", ("need_copy_table: %u", need_copy_table));
|
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
|
|
|
if (need_copy_table != ALTER_TABLE_METADATA_ONLY)
|
2001-05-09 22:02:36 +02:00
|
|
|
{
|
2005-01-06 12:00:13 +01:00
|
|
|
if (table->s->tmp_table)
|
2004-10-21 18:10:58 +02:00
|
|
|
{
|
2010-06-01 12:49:35 +02:00
|
|
|
Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
|
|
|
|
MYSQL_LOCK_IGNORE_TIMEOUT));
|
2004-10-21 18:10:58 +02:00
|
|
|
TABLE_LIST tbl;
|
|
|
|
bzero((void*) &tbl, sizeof(tbl));
|
|
|
|
tbl.db= new_db;
|
2005-01-06 12:00:13 +01:00
|
|
|
tbl.table_name= tbl.alias= tmp_name;
|
2005-11-23 21:45:02 +01:00
|
|
|
/* Table is in thd->temporary_tables */
|
2010-06-01 12:49:35 +02:00
|
|
|
(void) open_table(thd, &tbl, thd->mem_root, &ot_ctx);
|
2009-12-01 15:58:31 +01:00
|
|
|
new_table= tbl.table;
|
2004-10-21 18:10:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-19 10:24:43 +02:00
|
|
|
char path[FN_REFLEN + 1];
|
2005-11-23 21:45:02 +01:00
|
|
|
/* table is a normal table: Create temporary table in same directory */
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(path, sizeof(path) - 1, new_db, tmp_name, "",
|
2006-08-02 17:57:06 +02:00
|
|
|
FN_IS_TMP);
|
2010-08-31 12:03:36 +02:00
|
|
|
/* Open our intermediate table. */
|
|
|
|
new_table= open_table_uncached(thd, path, new_db, tmp_name, TRUE);
|
2004-10-21 18:10:58 +02:00
|
|
|
}
|
|
|
|
if (!new_table)
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
/*
|
|
|
|
Note: In case of MERGE table, we do not attach children. We do not
|
|
|
|
copy data for MERGE tables. Only the children have data.
|
|
|
|
*/
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
/* Copy the data if necessary. */
|
2003-10-11 22:26:39 +02:00
|
|
|
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
|
2000-07-31 21:29:14 +02:00
|
|
|
thd->cuted_fields=0L;
|
2001-01-28 20:35:50 +01:00
|
|
|
copied=deleted=0;
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
/*
|
|
|
|
We do not copy data for MERGE tables. Only the children have data.
|
|
|
|
MERGE tables have HA_NO_COPY_ON_ALTER set.
|
|
|
|
*/
|
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
|
|
|
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
|
2004-10-21 18:10:58 +02:00
|
|
|
{
|
2006-01-12 10:05:07 +01:00
|
|
|
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
|
2004-11-03 19:07:17 +01:00
|
|
|
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
2004-10-21 18:10:58 +02:00
|
|
|
new_table->next_number_field=new_table->found_next_number_field;
|
2008-10-05 00:40:30 +02:00
|
|
|
thd_proc_info(thd, "copy to tmp table");
|
2009-12-10 14:26:00 +01:00
|
|
|
DBUG_EXECUTE_IF("abort_copy_table", {
|
|
|
|
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
|
|
|
|
goto err_new_table_cleanup;
|
|
|
|
});
|
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
|
|
|
error= copy_data_between_tables(table, new_table,
|
|
|
|
alter_info->create_list, ignore,
|
|
|
|
order_num, order, &copied, &deleted,
|
2007-06-04 07:52:02 +02:00
|
|
|
alter_info->keys_onoff,
|
2007-06-04 12:03:15 +02:00
|
|
|
alter_info->error_if_not_empty);
|
2004-10-21 18:10:58 +02:00
|
|
|
}
|
2006-12-01 11:37:33 +01:00
|
|
|
else
|
2006-11-30 18:36:15 +01:00
|
|
|
{
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
/*
|
|
|
|
Ensure that we will upgrade the metadata lock if
|
|
|
|
handler::enable/disable_indexes() will be called.
|
|
|
|
*/
|
|
|
|
if (alter_info->keys_onoff != LEAVE_AS_IS ||
|
|
|
|
table->file->indexes_are_disabled())
|
|
|
|
need_lock_for_indexes= true;
|
|
|
|
if (!table->s->tmp_table && need_lock_for_indexes &&
|
2009-12-03 00:09:22 +01:00
|
|
|
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2008-10-05 00:40:30 +02:00
|
|
|
thd_proc_info(thd, "manage keys");
|
Bug #42230 during add index, cannot do queries on storage engines
that implement add_index
The problem was that ALTER TABLE blocked reads on an InnoDB table
while adding a secondary index, even if this was not needed. It is
only needed for the final step where the .frm file is updated.
The reason queries were blocked, was that ALTER TABLE upgraded the
metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to
MDL_EXCLUSIVE (which blocks all accesses) before index creation.
The way the server handles index creation, is that storage engines
publish their capabilities to the server and the server determines
which of the following three ways this can be handled: 1) build a
new version of the table; 2) change the existing table but with
exclusive metadata lock; 3) change the existing table but without
metadata lock upgrade.
For InnoDB and secondary index creation, option 3) should have been
selected. However this failed for two reasons. First, InnoDB did
not publish this capability properly.
Second, the ALTER TABLE code failed to made proper use of the
information supplied by the storage engine. A variable
need_lock_for_indexes was set accordingly, but was not later used.
This patch fixes this problem by only doing metadata lock upgrade
before index creation/deletion if this variable has been set.
This patch also changes some of the related terminology used
in the code. Specifically the use of "fast" and "online" with
respect to ALTER TABLE. "Fast" was used to indicate that an
ALTER TABLE operation could be done without involving a
temporary table. "Fast" has been renamed "in-place" to more
accurately describe the behavior.
"Online" meant that the operation could be done without taking
a table lock. However, in the current implementation writes
are always prohibited during ALTER TABLE and an exclusive
metadata lock is held while updating the .frm, so ALTER TABLE
is not completely online. This patch replaces "online" with
"in-place", with additional comments indicating if concurrent
reads are allowed during index creation/deletion or not.
An important part of this update of terminology is renaming
of the handler flags used by handlers to indicate if index
creation/deletion can be done in-place and if concurrent reads
are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
Note that this is a rename to clarify current behavior, the
flag values have not changed and no flags have been removed or
added.
Test case added to innodb_mysql_sync.test.
2011-01-26 14:23:29 +01:00
|
|
|
DEBUG_SYNC(thd, "alter_table_manage_keys");
|
2006-11-30 18:36:15 +01:00
|
|
|
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
|
|
|
|
alter_info->keys_onoff);
|
2009-12-03 19:37:38 +01:00
|
|
|
error= trans_commit_stmt(thd);
|
|
|
|
if (trans_commit_implicit(thd))
|
2007-06-01 19:53:50 +02:00
|
|
|
error= 1;
|
2004-10-21 18:10:58 +02:00
|
|
|
}
|
2003-10-11 22:26:39 +02:00
|
|
|
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2011-06-01 10:06:55 +02:00
|
|
|
if (error)
|
|
|
|
goto err_new_table_cleanup;
|
|
|
|
|
2006-01-12 10:05:07 +01:00
|
|
|
/* If we did not need to copy, we might still need to add/drop indexes. */
|
|
|
|
if (! new_table)
|
|
|
|
{
|
|
|
|
uint *key_numbers;
|
|
|
|
uint *keyno_p;
|
|
|
|
KEY *key_info;
|
|
|
|
KEY *key;
|
|
|
|
uint *idx_p;
|
|
|
|
uint *idx_end_p;
|
|
|
|
KEY_PART_INFO *key_part;
|
|
|
|
KEY_PART_INFO *part_end;
|
|
|
|
DBUG_PRINT("info", ("No new_table, checking add/drop index"));
|
|
|
|
|
2007-12-20 19:16:55 +01:00
|
|
|
table->file->ha_prepare_for_alter();
|
2006-01-12 10:05:07 +01:00
|
|
|
if (index_add_count)
|
|
|
|
{
|
|
|
|
/* The add_index() method takes an array of KEY structs. */
|
|
|
|
key_info= (KEY*) thd->alloc(sizeof(KEY) * index_add_count);
|
|
|
|
key= key_info;
|
|
|
|
for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count;
|
|
|
|
idx_p < idx_end_p;
|
|
|
|
idx_p++, key++)
|
|
|
|
{
|
|
|
|
/* Copy the KEY struct. */
|
|
|
|
*key= key_info_buffer[*idx_p];
|
|
|
|
/* Fix the key parts. */
|
|
|
|
part_end= key->key_part + key->key_parts;
|
|
|
|
for (key_part= key->key_part; key_part < part_end; key_part++)
|
|
|
|
key_part->field= table->field[key_part->fieldnr];
|
|
|
|
}
|
|
|
|
/* Add the indexes. */
|
2011-06-01 10:06:55 +02:00
|
|
|
if ((error= table->file->add_index(table, key_info, index_add_count,
|
|
|
|
&add)))
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Exchange the key_info for the error message. If we exchange
|
|
|
|
key number by key name in the message later, we need correct info.
|
|
|
|
*/
|
|
|
|
KEY *save_key_info= table->key_info;
|
|
|
|
table->key_info= key_info;
|
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
table->key_info= save_key_info;
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
2011-06-01 10:06:55 +02:00
|
|
|
pending_inplace_add_index= true;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
/*end of if (index_add_count)*/
|
|
|
|
|
|
|
|
if (index_drop_count)
|
|
|
|
{
|
2011-06-01 10:06:55 +02:00
|
|
|
/* Currently we must finalize add index if we also drop indexes */
|
|
|
|
if (pending_inplace_add_index)
|
|
|
|
{
|
|
|
|
/* Committing index changes needs exclusive metadata lock. */
|
|
|
|
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
|
|
|
|
table_list->db,
|
|
|
|
table_list->table_name,
|
|
|
|
MDL_EXCLUSIVE));
|
|
|
|
if ((error= table->file->final_add_index(add, true)))
|
|
|
|
{
|
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
goto err_new_table_cleanup;
|
|
|
|
}
|
|
|
|
pending_inplace_add_index= false;
|
|
|
|
}
|
2006-01-12 10:05:07 +01:00
|
|
|
/* The prepare_drop_index() method takes an array of key numbers. */
|
|
|
|
key_numbers= (uint*) thd->alloc(sizeof(uint) * index_drop_count);
|
|
|
|
keyno_p= key_numbers;
|
|
|
|
/* Get the number of each key. */
|
|
|
|
for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count;
|
|
|
|
idx_p < idx_end_p;
|
|
|
|
idx_p++, keyno_p++)
|
|
|
|
*keyno_p= *idx_p;
|
|
|
|
/*
|
|
|
|
Tell the handler to prepare for drop indexes.
|
|
|
|
This re-numbers the indexes to get rid of gaps.
|
|
|
|
*/
|
|
|
|
if ((error= table->file->prepare_drop_index(table, key_numbers,
|
|
|
|
index_drop_count)))
|
|
|
|
{
|
|
|
|
table->file->print_error(error, MYF(0));
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell the handler to finally drop the indexes. */
|
|
|
|
if ((error= table->file->final_drop_index(table)))
|
|
|
|
{
|
|
|
|
table->file->print_error(error, MYF(0));
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*end of if (index_drop_count)*/
|
|
|
|
|
2006-04-11 14:06:32 +02:00
|
|
|
/*
|
|
|
|
The final .frm file is already created as a temporary file
|
|
|
|
and will be renamed to the original table name later.
|
|
|
|
*/
|
2006-01-12 10:05:07 +01:00
|
|
|
|
2006-04-11 14:06:32 +02:00
|
|
|
/* Need to commit before a table is unlocked (NDB requirement). */
|
|
|
|
DBUG_PRINT("info", ("Committing before unlocking table"));
|
2009-12-03 19:37:38 +01:00
|
|
|
if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
|
|
|
/*end of if (! new_table) for add/drop index*/
|
|
|
|
|
2005-11-23 21:45:02 +01:00
|
|
|
if (table->s->tmp_table != NO_TMP_TABLE)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2011-06-01 10:06:55 +02:00
|
|
|
/*
|
|
|
|
In-place operations are not supported for temporary tables, so
|
|
|
|
we don't have to call final_add_index() in this case. The assert
|
|
|
|
verifies that in-place add index has not been done.
|
|
|
|
*/
|
|
|
|
DBUG_ASSERT(!pending_inplace_add_index);
|
2001-11-07 22:18:12 +01:00
|
|
|
/* Close lock if this is a transactional table */
|
|
|
|
if (thd->lock)
|
|
|
|
{
|
2010-07-07 14:18:20 +02:00
|
|
|
if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
|
|
|
|
thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
|
|
|
|
{
|
|
|
|
mysql_unlock_tables(thd, thd->lock);
|
|
|
|
thd->lock=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
If LOCK TABLES list is not empty and contains this table,
|
|
|
|
unlock the table and remove the table from this list.
|
|
|
|
*/
|
|
|
|
mysql_lock_remove(thd, thd->lock, table);
|
|
|
|
}
|
2001-11-07 22:18:12 +01:00
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
/* Remove link to old table and rename the new one */
|
2005-11-23 21:45:02 +01:00
|
|
|
close_temporary_table(thd, table, 1, 1);
|
2005-01-21 12:14:31 +01:00
|
|
|
/* Should pass the 'new_name' as we store table name in the cache */
|
|
|
|
if (rename_temporary_table(thd, new_table, new_db, new_name))
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2005-12-22 06:39:02 +01:00
|
|
|
/* We don't replicate alter table statement on temporary tables */
|
2010-01-07 16:39:11 +01:00
|
|
|
if (!thd->is_current_stmt_binlog_format_row() &&
|
2010-02-04 21:15:47 +01:00
|
|
|
write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
goto end_temporary;
|
|
|
|
}
|
|
|
|
|
2009-11-30 16:55:03 +01:00
|
|
|
/*
|
|
|
|
Close the intermediate table that will be the new table, but do
|
|
|
|
not delete it! Even altough MERGE tables do not have their children
|
|
|
|
attached here it is safe to call close_temporary_table().
|
|
|
|
*/
|
2004-10-21 18:10:58 +02:00
|
|
|
if (new_table)
|
|
|
|
{
|
2009-11-30 16:55:03 +01:00
|
|
|
close_temporary_table(thd, new_table, 1, 0);
|
|
|
|
new_table= 0;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2010-02-01 16:07:00 +01:00
|
|
|
DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
|
2004-03-10 12:46:11 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
/*
|
2007-05-19 08:49:56 +02:00
|
|
|
Data is copied. Now we:
|
2009-12-01 14:51:50 +01:00
|
|
|
1) Wait until all other threads will stop using old version of table
|
|
|
|
by upgrading shared metadata lock to exclusive one.
|
2007-05-19 08:49:56 +02:00
|
|
|
2) Close instances of table open by this thread and replace them
|
2009-12-01 14:51:50 +01:00
|
|
|
with placeholders to simplify reopen process.
|
2007-05-19 08:49:56 +02:00
|
|
|
3) Rename the old table to a temp name, rename the new one to the
|
|
|
|
old name.
|
|
|
|
4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
|
|
|
|
we reopen new version of table.
|
|
|
|
5) Write statement to the binary log.
|
|
|
|
6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
|
2009-12-01 14:51:50 +01:00
|
|
|
remove placeholders and release metadata locks.
|
2010-07-27 12:25:53 +02:00
|
|
|
7) If we are not not under LOCK TABLES we rely on the caller
|
|
|
|
(mysql_execute_command()) to release metadata locks.
|
2000-07-31 21:29:14 +02:00
|
|
|
*/
|
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "rename result table");
|
2004-04-08 16:56:45 +02:00
|
|
|
my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
|
|
|
|
current_pid, thd->thread_id);
|
2004-05-25 00:30:09 +02:00
|
|
|
if (lower_case_table_names)
|
|
|
|
my_casedn_str(files_charset_info, old_name);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-30 16:55:03 +01:00
|
|
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
|
2011-06-01 10:06:55 +02:00
|
|
|
{
|
|
|
|
if (pending_inplace_add_index)
|
|
|
|
{
|
|
|
|
pending_inplace_add_index= false;
|
|
|
|
table->file->final_add_index(add, false);
|
|
|
|
}
|
|
|
|
// Mark this TABLE instance as stale to avoid out-of-sync index information.
|
|
|
|
table->m_needs_reopen= true;
|
2009-11-30 16:55:03 +01:00
|
|
|
goto err_new_table_cleanup;
|
2011-06-01 10:06:55 +02:00
|
|
|
}
|
|
|
|
if (pending_inplace_add_index)
|
|
|
|
{
|
|
|
|
pending_inplace_add_index= false;
|
|
|
|
DBUG_EXECUTE_IF("alter_table_rollback_new_index", {
|
|
|
|
table->file->final_add_index(add, false);
|
|
|
|
my_error(ER_UNKNOWN_ERROR, MYF(0));
|
|
|
|
goto err_new_table_cleanup;
|
|
|
|
});
|
|
|
|
if ((error= table->file->final_add_index(add, true)))
|
|
|
|
{
|
|
|
|
table->file->print_error(error, MYF(0));
|
|
|
|
goto err_new_table_cleanup;
|
|
|
|
}
|
|
|
|
}
|
2009-11-30 16:55:03 +01:00
|
|
|
|
2009-12-02 16:22:15 +01:00
|
|
|
close_all_tables_for_name(thd, table->s,
|
|
|
|
new_name != table_name || new_db != db);
|
2002-02-07 20:34:35 +01:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
error=0;
|
2009-12-02 16:22:15 +01:00
|
|
|
table_list->table= table= 0; /* Safety */
|
2006-12-04 18:22:38 +01:00
|
|
|
save_old_db_type= old_db_type;
|
|
|
|
|
|
|
|
/*
|
|
|
|
This leads to the storage engine (SE) not being notified for renames in
|
|
|
|
mysql_rename_table(), because we just juggle with the FRM and nothing
|
|
|
|
more. If we have an intermediate table, then we notify the SE that
|
|
|
|
it should become the actual table. Later, we will recycle the old table.
|
|
|
|
However, in case of ALTER TABLE RENAME there might be no intermediate
|
|
|
|
table. This is when the old and new tables are compatible, according to
|
2010-08-16 14:53:30 +02:00
|
|
|
mysql_compare_table(). Then, we need one additional call to
|
2006-12-04 18:22:38 +01:00
|
|
|
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
|
|
|
|
actual rename in the SE and the FRM is not touched. Note that, if the
|
|
|
|
table is renamed and the SE is also changed, then an intermediate table
|
|
|
|
is created and the additional call will not take place.
|
|
|
|
*/
|
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
|
|
|
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(new_db_type == old_db_type);
|
|
|
|
/* This type cannot happen in regular ALTER. */
|
|
|
|
new_db_type= old_db_type= NULL;
|
|
|
|
}
|
2006-08-02 17:57:06 +02:00
|
|
|
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
|
|
|
|
FN_TO_IS_TMP))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
error=1;
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
|
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
|
|
|
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
|
2006-12-04 18:22:38 +01:00
|
|
|
new_alias, FN_FROM_IS_TMP) ||
|
2009-06-10 16:04:07 +02:00
|
|
|
((new_name != table_name || new_db != db) && // we also do rename
|
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
|
|
|
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
|
2006-12-04 18:22:38 +01:00
|
|
|
mysql_rename_table(save_old_db_type, db, table_name, new_db,
|
|
|
|
new_alias, NO_FRM_RENAME)) &&
|
2010-09-16 11:11:13 +02:00
|
|
|
Table_triggers_list::change_table_name(thd, db, alias, table_name,
|
2009-06-10 16:04:07 +02:00
|
|
|
new_db, new_alias)))
|
2006-08-02 17:57:06 +02:00
|
|
|
{
|
|
|
|
/* Try to get everything back. */
|
2000-07-31 21:29:14 +02:00
|
|
|
error=1;
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) quick_rm_table(new_db_type,new_db,new_alias, 0);
|
|
|
|
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
|
|
|
|
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
|
|
|
|
FN_FROM_IS_TMP);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2006-12-04 18:22:38 +01:00
|
|
|
|
2009-12-02 16:22:15 +01:00
|
|
|
if (! error)
|
|
|
|
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
if (error)
|
|
|
|
{
|
2007-05-19 08:49:56 +02:00
|
|
|
/* This shouldn't happen. But let us play it safe. */
|
2009-12-02 16:22:15 +01:00
|
|
|
goto err_with_mdl;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2007-05-19 08:49:56 +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
|
|
|
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2001-12-06 00:05:30 +01:00
|
|
|
/*
|
2007-05-19 08:49:56 +02:00
|
|
|
Now we have to inform handler that new .FRM file is in place.
|
|
|
|
To do this we need to obtain a handler object for it.
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
NO need to tamper with MERGE tables. The real open is done later.
|
2001-12-06 00:05:30 +01:00
|
|
|
*/
|
2010-06-01 12:49:35 +02:00
|
|
|
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
|
2011-04-13 08:16:40 +02:00
|
|
|
TABLE_LIST temp_table_list;
|
|
|
|
TABLE_LIST *t_table_list;
|
2007-05-19 08:49:56 +02:00
|
|
|
if (new_name != table_name || new_db != db)
|
|
|
|
{
|
2011-04-13 08:16:40 +02:00
|
|
|
temp_table_list.init_one_table(new_db, strlen(new_db),
|
|
|
|
new_name, strlen(new_name),
|
|
|
|
new_name, TL_READ_NO_INSERT);
|
|
|
|
temp_table_list.mdl_request.ticket= target_mdl_request.ticket;
|
|
|
|
t_table_list= &temp_table_list;
|
2005-11-23 21:45:02 +01:00
|
|
|
}
|
2007-05-19 08:49:56 +02:00
|
|
|
else
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
2009-12-02 16:22:15 +01:00
|
|
|
/*
|
2009-12-04 00:29:40 +01:00
|
|
|
Under LOCK TABLES, we have a different mdl_lock_ticket
|
2009-12-02 16:22:15 +01:00
|
|
|
points to a different instance than the one set initially
|
|
|
|
to request the lock.
|
|
|
|
*/
|
2009-12-08 10:57:07 +01:00
|
|
|
table_list->mdl_request.ticket= mdl_ticket;
|
2011-04-13 08:16:40 +02:00
|
|
|
t_table_list= table_list;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
2011-04-13 08:16:40 +02:00
|
|
|
if (open_table(thd, t_table_list, thd->mem_root, &ot_ctx))
|
2006-01-12 10:05:07 +01:00
|
|
|
{
|
2009-12-02 16:22:15 +01:00
|
|
|
goto err_with_mdl;
|
2006-01-12 10:05:07 +01:00
|
|
|
}
|
2006-12-04 18:22:38 +01:00
|
|
|
|
2009-12-02 16:22:15 +01:00
|
|
|
/* Tell the handler that a new frm file is in place. */
|
2011-04-13 08:16:40 +02:00
|
|
|
error= t_table_list->table->file->ha_create_handler_files(path, NULL,
|
|
|
|
CHF_INDEX_FLAG,
|
|
|
|
create_info);
|
2009-12-02 16:22:15 +01:00
|
|
|
|
2011-04-13 08:16:40 +02:00
|
|
|
DBUG_ASSERT(thd->open_tables == t_table_list->table);
|
2009-12-02 16:22:15 +01:00
|
|
|
close_thread_table(thd, &thd->open_tables);
|
2011-04-13 08:16:40 +02:00
|
|
|
t_table_list->table= NULL;
|
2007-05-19 08:49:56 +02:00
|
|
|
|
2006-01-17 12:53:49 +01:00
|
|
|
if (error)
|
2009-12-02 16:22:15 +01:00
|
|
|
goto err_with_mdl;
|
2006-01-17 12:53:49 +01:00
|
|
|
}
|
2009-12-02 16:22:15 +01:00
|
|
|
if (thd->locked_tables_list.reopen_tables(thd))
|
|
|
|
goto err_with_mdl;
|
2007-05-19 08:49:56 +02:00
|
|
|
|
2007-02-22 16:03:08 +01:00
|
|
|
thd_proc_info(thd, "end");
|
2005-12-22 06:39:02 +01:00
|
|
|
|
2007-05-19 08:49:56 +02:00
|
|
|
DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
|
2010-02-01 16:07:00 +01:00
|
|
|
DEBUG_SYNC(thd, "alter_table_before_main_binlog");
|
2007-05-19 08:49:56 +02:00
|
|
|
|
2006-02-06 11:47:12 +01:00
|
|
|
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
|
2009-10-16 12:29:42 +02:00
|
|
|
thd->query(), thd->query_length(),
|
2006-02-06 11:47:12 +01:00
|
|
|
db, table_name);
|
|
|
|
|
2007-02-27 18:31:49 +01:00
|
|
|
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
|
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
|
|
|
thd->is_current_stmt_binlog_format_row() &&
|
2005-12-22 06:39:02 +01:00
|
|
|
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
|
2010-02-04 21:15:47 +01:00
|
|
|
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
|
|
|
DBUG_RETURN(TRUE);
|
2006-12-04 18:22:38 +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
|
|
|
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
|
2002-08-28 15:41:23 +02:00
|
|
|
{
|
2002-09-03 14:44:25 +02:00
|
|
|
/*
|
|
|
|
For the alter table to be properly flushed to the logs, we
|
|
|
|
have to open the new table. If not, we get a problem on server
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
shutdown. But we do not need to attach MERGE children.
|
2002-09-03 14:44:25 +02:00
|
|
|
*/
|
2002-10-24 00:29:29 +02:00
|
|
|
char path[FN_REFLEN];
|
2007-05-19 08:49:56 +02:00
|
|
|
TABLE *t_table;
|
2009-06-19 10:24:43 +02:00
|
|
|
build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
|
2010-08-31 12:03:36 +02:00
|
|
|
t_table= open_table_uncached(thd, path, new_db, tmp_name, FALSE);
|
2007-05-19 08:49:56 +02:00
|
|
|
if (t_table)
|
2002-09-03 14:44:25 +02:00
|
|
|
{
|
2007-05-19 08:49:56 +02:00
|
|
|
intern_close_table(t_table);
|
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled
Essentially, the problem is that safemalloc is excruciatingly
slow as it checks all allocated blocks for overrun at each
memory management primitive, yielding a almost exponential
slowdown for the memory management functions (malloc, realloc,
free). The overrun check basically consists of verifying some
bytes of a block for certain magic keys, which catches some
simple forms of overrun. Another minor problem is violation
of aliasing rules and that its own internal list of blocks
is prone to corruption.
Another issue with safemalloc is rather the maintenance cost
as the tool has a significant impact on the server code.
Given the magnitude of memory debuggers available nowadays,
especially those that are provided with the platform malloc
implementation, maintenance of a in-house and largely obsolete
memory debugger becomes a burden that is not worth the effort
due to its slowness and lack of support for detecting more
common forms of heap corruption.
Since there are third-party tools that can provide the same
functionality at a lower or comparable performance cost, the
solution is to simply remove safemalloc. Third-party tools
can provide the same functionality at a lower or comparable
performance cost.
The removal of safemalloc also allows a simplification of the
malloc wrappers, removing quite a bit of kludge: redefinition
of my_malloc, my_free and the removal of the unused second
argument of my_free. Since free() always check whether the
supplied pointer is null, redudant checks are also removed.
Also, this patch adds unit testing for my_malloc and moves
my_realloc implementation into the same file as the other
memory allocation primitives.
2010-07-08 23:20:08 +02:00
|
|
|
my_free(t_table);
|
2002-09-03 14:44:25 +02:00
|
|
|
}
|
2002-10-24 00:29:29 +02:00
|
|
|
else
|
2005-11-07 16:25:06 +01:00
|
|
|
sql_print_warning("Could not open table %s.%s after rename\n",
|
2004-09-04 20:17:09 +02:00
|
|
|
new_db,table_name);
|
2005-11-07 16:25:06 +01:00
|
|
|
ha_flush_logs(old_db_type);
|
2002-08-28 15:41:23 +02:00
|
|
|
}
|
2001-12-06 00:05:30 +01:00
|
|
|
table_list->table=0; // For query cache
|
2002-03-22 21:55:08 +01:00
|
|
|
query_cache_invalidate3(thd, table_list, 0);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-12-08 15:13:12 +01:00
|
|
|
if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
|
|
|
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
|
2007-05-11 19:51:03 +02:00
|
|
|
{
|
2009-11-30 16:55:03 +01:00
|
|
|
if ((new_name != table_name || new_db != db))
|
2009-12-04 00:52:05 +01:00
|
|
|
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
|
2009-11-30 16:55:03 +01:00
|
|
|
else
|
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
|
|
|
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
|
2007-05-11 19:51:03 +02:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
end_temporary:
|
2004-04-08 16:56:45 +02:00
|
|
|
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
|
|
|
|
(ulong) (copied + deleted), (ulong) deleted,
|
2009-10-16 15:41:43 +02:00
|
|
|
(ulong) thd->warning_info->statement_warn_count());
|
2008-02-19 13:45:21 +01:00
|
|
|
my_ok(thd, copied + deleted, 0L, tmp_name);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2009-11-30 16:55:03 +01:00
|
|
|
err_new_table_cleanup:
|
2006-04-13 16:19:19 +02:00
|
|
|
if (new_table)
|
|
|
|
{
|
|
|
|
/* close_temporary_table() frees the new_table pointer. */
|
|
|
|
close_temporary_table(thd, new_table, 1, 1);
|
|
|
|
}
|
|
|
|
else
|
2009-11-24 14:54:59 +01:00
|
|
|
(void) quick_rm_table(new_db_type, new_db, tmp_name,
|
|
|
|
create_info->frm_only ? FN_IS_TMP | FRM_ONLY : FN_IS_TMP);
|
2006-04-13 16:19:19 +02:00
|
|
|
|
2006-10-03 19:38:25 +02:00
|
|
|
err:
|
2010-10-01 13:22:11 +02:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
/* If prep_alter_part_table created an intermediate table, destroy it. */
|
|
|
|
if (table_for_fast_alter_partition)
|
|
|
|
close_temporary(table_for_fast_alter_partition, 1, 0);
|
|
|
|
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
2007-05-21 22:22:53 +02:00
|
|
|
/*
|
|
|
|
No default value was provided for a DATE/DATETIME field, the
|
|
|
|
current sql_mode doesn't allow the '0000-00-00' value and
|
|
|
|
the table to be altered isn't empty.
|
|
|
|
Report error here.
|
|
|
|
*/
|
2009-09-10 11:18:29 +02:00
|
|
|
if (alter_info->error_if_not_empty &&
|
|
|
|
thd->warning_info->current_row_for_warning())
|
2007-05-21 22:22:53 +02:00
|
|
|
{
|
2007-05-22 01:44:36 +02:00
|
|
|
const char *f_val= 0;
|
|
|
|
enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
|
2007-06-04 12:03:15 +02:00
|
|
|
switch (alter_info->datetime_field->sql_type)
|
2007-05-21 22:22:53 +02:00
|
|
|
{
|
|
|
|
case MYSQL_TYPE_DATE:
|
|
|
|
case MYSQL_TYPE_NEWDATE:
|
|
|
|
f_val= "0000-00-00";
|
|
|
|
t_type= MYSQL_TIMESTAMP_DATE;
|
|
|
|
break;
|
|
|
|
case MYSQL_TYPE_DATETIME:
|
|
|
|
f_val= "0000-00-00 00:00:00";
|
|
|
|
t_type= MYSQL_TIMESTAMP_DATETIME;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Shouldn't get here. */
|
|
|
|
DBUG_ASSERT(0);
|
|
|
|
}
|
|
|
|
bool save_abort_on_warning= thd->abort_on_warning;
|
|
|
|
thd->abort_on_warning= TRUE;
|
2009-09-10 11:18:29 +02:00
|
|
|
make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
2007-05-23 13:45:37 +02:00
|
|
|
f_val, strlength(f_val), t_type,
|
2007-06-04 12:03:15 +02:00
|
|
|
alter_info->datetime_field->field_name);
|
2007-05-21 22:22:53 +02:00
|
|
|
thd->abort_on_warning= save_abort_on_warning;
|
|
|
|
}
|
2009-12-08 10:57:07 +01:00
|
|
|
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2007-05-19 08:49:56 +02:00
|
|
|
|
2009-12-02 16:22:15 +01:00
|
|
|
err_with_mdl:
|
2007-05-19 08:49:56 +02:00
|
|
|
/*
|
2009-12-01 14:51:50 +01:00
|
|
|
An error happened while we were holding exclusive name metadata lock
|
2009-12-02 16:22:15 +01:00
|
|
|
on table being altered. To be safe under LOCK TABLES we should
|
|
|
|
remove all references to the altered table from the list of locked
|
|
|
|
tables and release the exclusive metadata lock.
|
2007-05-19 08:49:56 +02:00
|
|
|
*/
|
Backport of:
----------------------------------------------------------
revno: 2617.69.2
committer: Konstantin Osipov <kostja@sun.com>
branch nick: 5.4-azalea-bugfixing
timestamp: Mon 2009-08-03 19:26:04 +0400
message:
A fix and a test case for Bug#45035 "Altering table under LOCK TABLES
results in "Error 1213 Deadlock found...".
If a user had a table locked with LOCK TABLES
for READ and for WRITE in the same connection, ALTER TABLE
could fail.
Root cause analysis:
If a connection issues
LOCK TABLE t1 write, t1 a read, t1 b read;
the new LOCK TABLES code in 6.0 (part of WL 3726) will create
the following list of TABLE_LIST objects
(thd->locked_tables_list->m_locked_tables):
{"t1" "b" tl_read_no_insert}, {"t1" "a" tl_read_no_insert},
{"t1" "t1" tl_write }
Later on, when we try to ALTER table t1, mysql_alter_table()
closes all TABLE instances and releases its thr_lock locks,
keeping only an exclusive metadata lock on t1.
But when ALTER is finished, Locked_table_list::reopen_tables()
tries to restore the original list of open and locked tables.
Before this patch, it used to do so one by one:
Open t1 b, get TL_READ_NO_INSERT lock,
Open t1 a, get TL_READ_NO_INSERT lock
Open t1, try to get TL_WRITE lock, deadlock.
The cause of the deadlock is that thr_lock.c doesn't
resolve the situation when the read list only consists
of locks taken by the same thread, followed by this very
thread trying to take a WRITE lock. Indeed, since
thr_lock_multi always gets a sorted list of locks,
WRITE locks always precede READ locks in the list
to lock.
Don't try to fix thr_lock.c deficiency, keep this
code simple.
Instead, try to take all thr_lock locks at once
in ::reopen_tables().
2009-12-08 09:38:45 +01:00
|
|
|
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
2009-12-04 00:52:05 +01:00
|
|
|
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2005-07-22 22:43:59 +02:00
|
|
|
/* mysql_alter_table */
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2010-08-20 19:15:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Prepare the transaction for the alter table's copy phase.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_trans_prepare_alter_copy_data(THD *thd)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("mysql_prepare_alter_copy_data");
|
|
|
|
/*
|
|
|
|
Turn off recovery logging since rollback of an alter table is to
|
|
|
|
delete the new table so there is no need to log the changes to it.
|
|
|
|
|
|
|
|
This needs to be done before external_lock.
|
|
|
|
*/
|
|
|
|
if (ha_enable_transaction(thd, FALSE))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Commit the copy phase of the alter table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool mysql_trans_commit_alter_copy_data(THD *thd)
|
|
|
|
{
|
|
|
|
bool error= FALSE;
|
|
|
|
DBUG_ENTER("mysql_commit_alter_copy_data");
|
|
|
|
|
|
|
|
if (ha_enable_transaction(thd, TRUE))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Ensure that the new table is saved properly to disk before installing
|
|
|
|
the new .frm.
|
|
|
|
And that InnoDB's internal latches are released, to avoid deadlock
|
|
|
|
when waiting on other instances of the table before rename (Bug#54747).
|
|
|
|
*/
|
|
|
|
if (trans_commit_stmt(thd))
|
|
|
|
error= TRUE;
|
|
|
|
if (trans_commit_implicit(thd))
|
|
|
|
error= TRUE;
|
|
|
|
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
static int
|
2000-11-11 19:27:34 +01:00
|
|
|
copy_data_between_tables(TABLE *from,TABLE *to,
|
2007-06-10 12:43:57 +02:00
|
|
|
List<Create_field> &create,
|
2004-12-31 11:04:35 +01:00
|
|
|
bool ignore,
|
2004-04-08 16:56:45 +02:00
|
|
|
uint order_num, ORDER *order,
|
2000-11-11 19:27:34 +01:00
|
|
|
ha_rows *copied,
|
2006-11-28 18:27:32 +01:00
|
|
|
ha_rows *deleted,
|
2007-05-21 22:22:53 +02:00
|
|
|
enum enum_enable_or_disable keys_onoff,
|
|
|
|
bool error_if_not_empty)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
Copy_field *copy,*copy_end;
|
|
|
|
ulong found_count,delete_count;
|
|
|
|
THD *thd= current_thd;
|
2007-01-19 16:34:09 +01:00
|
|
|
uint length= 0;
|
2000-11-11 19:27:34 +01:00
|
|
|
SORT_FIELD *sortorder;
|
|
|
|
READ_RECORD info;
|
|
|
|
TABLE_LIST tables;
|
|
|
|
List<Item> fields;
|
|
|
|
List<Item> all_fields;
|
2001-04-25 21:44:27 +02:00
|
|
|
ha_rows examined_rows;
|
2004-08-24 17:00:45 +02:00
|
|
|
bool auto_increment_field_copied= 0;
|
2004-10-07 11:02:39 +02:00
|
|
|
ulong save_sql_mode;
|
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
|
|
|
ulonglong prev_insert_id;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_ENTER("copy_data_between_tables");
|
|
|
|
|
2010-08-20 19:15:48 +02:00
|
|
|
if (mysql_trans_prepare_alter_copy_data(thd))
|
2005-01-10 11:17:01 +01:00
|
|
|
DBUG_RETURN(-1);
|
2005-01-10 11:33:08 +01:00
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
if (!(copy= new Copy_field[to->s->fields]))
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(-1); /* purecov: inspected */
|
|
|
|
|
2006-01-26 09:25:37 +01:00
|
|
|
if (to->file->ha_external_lock(thd, F_WRLCK))
|
2004-09-18 20:33:39 +02:00
|
|
|
DBUG_RETURN(-1);
|
2005-04-01 14:04:50 +02:00
|
|
|
|
2006-11-28 18:27:32 +01:00
|
|
|
/* We need external lock before we can disable/enable keys */
|
|
|
|
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
|
|
|
|
|
2005-04-01 14:04:50 +02:00
|
|
|
/* We can abort alter table for any table type */
|
|
|
|
thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
|
|
|
|
(MODE_STRICT_TRANS_TABLES |
|
|
|
|
MODE_STRICT_ALL_TABLES));
|
|
|
|
|
2000-08-15 19:09:37 +02:00
|
|
|
from->file->info(HA_STATUS_VARIABLE);
|
2006-06-04 20:05:22 +02:00
|
|
|
to->file->ha_start_bulk_insert(from->file->stats.records);
|
2000-07-31 21:29:14 +02:00
|
|
|
|
2004-10-07 11:51:32 +02:00
|
|
|
save_sql_mode= thd->variables.sql_mode;
|
|
|
|
|
2007-06-10 12:43:57 +02:00
|
|
|
List_iterator<Create_field> it(create);
|
|
|
|
Create_field *def;
|
2000-07-31 21:29:14 +02:00
|
|
|
copy_end=copy;
|
|
|
|
for (Field **ptr=to->field ; *ptr ; ptr++)
|
|
|
|
{
|
|
|
|
def=it++;
|
|
|
|
if (def->field)
|
2004-07-30 14:17:12 +02:00
|
|
|
{
|
|
|
|
if (*ptr == to->next_number_field)
|
2004-10-07 11:02:39 +02:00
|
|
|
{
|
2004-08-24 17:00:45 +02:00
|
|
|
auto_increment_field_copied= TRUE;
|
2004-10-07 11:02:39 +02:00
|
|
|
/*
|
|
|
|
If we are going to copy contents of one auto_increment column to
|
|
|
|
another auto_increment column it is sensible to preserve zeroes.
|
|
|
|
This condition also covers case when we are don't actually alter
|
|
|
|
auto_increment column.
|
|
|
|
*/
|
|
|
|
if (def->field == from->found_next_number_field)
|
|
|
|
thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
|
|
|
|
}
|
2000-07-31 21:29:14 +02:00
|
|
|
(copy_end++)->set(*ptr,def->field,0);
|
2004-07-30 14:17:12 +02:00
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
|
2000-11-26 07:29:01 +01:00
|
|
|
found_count=delete_count=0;
|
|
|
|
|
2001-02-21 13:16:00 +01:00
|
|
|
if (order)
|
|
|
|
{
|
2007-11-07 16:59:58 +01:00
|
|
|
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
|
|
|
|
{
|
|
|
|
char warn_buff[MYSQL_ERRMSG_SIZE];
|
|
|
|
my_snprintf(warn_buff, sizeof(warn_buff),
|
|
|
|
"ORDER BY ignored as there is a user-defined clustered index"
|
|
|
|
" in the table '%-.192s'", from->s->table_name.str);
|
|
|
|
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
|
|
|
|
warn_buff);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
|
|
|
|
MYF(MY_FAE | MY_ZEROFILL));
|
|
|
|
bzero((char *) &tables, sizeof(tables));
|
|
|
|
tables.table= from;
|
|
|
|
tables.alias= tables.table_name= from->s->table_name.str;
|
|
|
|
tables.db= from->s->db.str;
|
|
|
|
error= 1;
|
2000-11-11 19:27:34 +01:00
|
|
|
|
2007-11-07 16:59:58 +01:00
|
|
|
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
|
|
|
|
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
|
|
|
|
&tables, fields, all_fields, order) ||
|
|
|
|
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
|
|
|
|
(from->sort.found_records= filesort(thd, from, sortorder, length,
|
|
|
|
(SQL_SELECT *) 0, HA_POS_ERROR,
|
|
|
|
1, &examined_rows)) ==
|
|
|
|
HA_POS_ERROR)
|
|
|
|
goto err;
|
|
|
|
}
|
2000-11-11 19:27:34 +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
|
|
|
/* Tell handler that we have values for all columns in the to table */
|
|
|
|
to->use_all_columns();
|
2008-07-15 16:13:21 +02:00
|
|
|
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE);
|
2006-07-01 23:51:10 +02:00
|
|
|
if (ignore)
|
2000-12-24 14:19:00 +01:00
|
|
|
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
2009-09-10 11:18:29 +02:00
|
|
|
thd->warning_info->reset_current_row_for_warning();
|
2005-01-06 12:00:13 +01:00
|
|
|
restore_record(to, s->default_values); // Create empty record
|
2000-07-31 21:29:14 +02:00
|
|
|
while (!(error=info.read_record(&info)))
|
|
|
|
{
|
|
|
|
if (thd->killed)
|
|
|
|
{
|
2003-04-08 16:18:33 +02:00
|
|
|
thd->send_kill_message();
|
2000-07-31 21:29:14 +02:00
|
|
|
error= 1;
|
|
|
|
break;
|
|
|
|
}
|
2007-05-21 22:22:53 +02:00
|
|
|
/* Return error if source table isn't empty. */
|
|
|
|
if (error_if_not_empty)
|
|
|
|
{
|
|
|
|
error= 1;
|
|
|
|
break;
|
|
|
|
}
|
2004-07-30 14:17:12 +02:00
|
|
|
if (to->next_number_field)
|
|
|
|
{
|
2004-08-24 17:00:45 +02:00
|
|
|
if (auto_increment_field_copied)
|
2004-07-30 14:17:12 +02:00
|
|
|
to->auto_increment_field_not_null= TRUE;
|
2004-08-24 17:00:45 +02:00
|
|
|
else
|
|
|
|
to->next_number_field->reset();
|
|
|
|
}
|
2005-04-01 14:04:50 +02:00
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
|
2004-08-24 17:00:45 +02:00
|
|
|
{
|
2000-07-31 21:29:14 +02:00
|
|
|
copy_ptr->do_copy(copy_ptr);
|
2004-07-30 14:17:12 +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
|
|
|
prev_insert_id= to->file->next_insert_id;
|
2007-12-19 20:15:02 +01:00
|
|
|
error=to->file->ha_write_row(to->record[0]);
|
2007-03-30 16:13:33 +02:00
|
|
|
to->auto_increment_field_not_null= FALSE;
|
|
|
|
if (error)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-07-01 23:51:10 +02:00
|
|
|
if (!ignore ||
|
2006-07-01 06:01:37 +02:00
|
|
|
to->file->is_fatal_error(error, HA_CHECK_DUP))
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2006-07-01 06:01:37 +02:00
|
|
|
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
|
2006-05-12 15:02:42 +02:00
|
|
|
{
|
|
|
|
uint key_nr= to->file->get_dup_key(error);
|
|
|
|
if ((int) key_nr >= 0)
|
|
|
|
{
|
2007-01-22 17:42:52 +01:00
|
|
|
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
|
2006-05-12 15:02:42 +02:00
|
|
|
if (key_nr == 0 &&
|
2006-06-05 05:16:08 +02:00
|
|
|
(to->key_info[0].key_part[0].field->flags &
|
|
|
|
AUTO_INCREMENT_FLAG))
|
2006-05-12 15:02:42 +02:00
|
|
|
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
|
2006-06-05 05:16:08 +02:00
|
|
|
to->file->print_keydup_error(key_nr, err_msg);
|
2006-05-12 15:02:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-07-31 21:29:14 +02:00
|
|
|
to->file->print_error(error,MYF(0));
|
|
|
|
break;
|
|
|
|
}
|
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
|
|
|
to->file->restore_auto_increment(prev_insert_id);
|
2000-07-31 21:29:14 +02:00
|
|
|
delete_count++;
|
|
|
|
}
|
|
|
|
else
|
2003-08-21 16:15:06 +02:00
|
|
|
found_count++;
|
2009-09-10 11:18:29 +02:00
|
|
|
thd->warning_info->inc_current_row_for_warning();
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
|
|
|
end_read_record(&info);
|
2001-01-23 00:25:07 +01:00
|
|
|
free_io_cache(from);
|
2001-10-08 03:58:07 +02:00
|
|
|
delete [] copy; // This is never 0
|
2004-04-07 16:04:28 +02:00
|
|
|
|
2006-06-02 22:21:32 +02:00
|
|
|
if (to->file->ha_end_bulk_insert() && error <= 0)
|
2000-07-31 21:29:14 +02:00
|
|
|
{
|
2004-04-07 16:04:28 +02:00
|
|
|
to->file->print_error(my_errno,MYF(0));
|
2009-12-11 12:12:47 +01:00
|
|
|
error= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
}
|
2000-12-24 14:19:00 +01:00
|
|
|
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
2000-11-24 00:51:18 +01:00
|
|
|
|
2010-08-20 19:15:48 +02:00
|
|
|
if (mysql_trans_commit_alter_copy_data(thd))
|
2007-06-01 19:53:50 +02:00
|
|
|
error= 1;
|
2004-10-06 00:24:21 +02:00
|
|
|
|
2000-11-11 19:27:34 +01:00
|
|
|
err:
|
2004-10-07 11:02:39 +02:00
|
|
|
thd->variables.sql_mode= save_sql_mode;
|
2005-04-01 14:04:50 +02:00
|
|
|
thd->abort_on_warning= 0;
|
2000-11-11 19:27:34 +01:00
|
|
|
free_io_cache(from);
|
2000-07-31 21:29:14 +02:00
|
|
|
*copied= found_count;
|
|
|
|
*deleted=delete_count;
|
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
|
|
|
to->file->ha_release_auto_increment();
|
2006-01-26 09:25:37 +01:00
|
|
|
if (to->file->ha_external_lock(thd,F_UNLCK))
|
2004-09-18 20:33:39 +02:00
|
|
|
error=1;
|
2009-12-11 12:12:47 +01:00
|
|
|
if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
|
|
|
|
error= 1;
|
2000-07-31 21:29:14 +02:00
|
|
|
DBUG_RETURN(error > 0 ? -1 : 0);
|
|
|
|
}
|
2003-08-21 16:15:06 +02:00
|
|
|
|
2003-09-11 18:06:23 +02:00
|
|
|
|
2004-06-10 16:41:24 +02:00
|
|
|
/*
|
|
|
|
Recreates tables by calling mysql_alter_table().
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
mysql_recreate_table()
|
|
|
|
thd Thread handler
|
|
|
|
tables Tables to recreate
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
Like mysql_alter_table().
|
|
|
|
*/
|
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
|
|
|
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
|
2004-06-10 16:41:24 +02:00
|
|
|
{
|
|
|
|
HA_CREATE_INFO create_info;
|
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
|
|
|
Alter_info alter_info;
|
|
|
|
|
|
|
|
DBUG_ENTER("mysql_recreate_table");
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
DBUG_ASSERT(!table_list->next_global);
|
|
|
|
/*
|
|
|
|
table_list->table has been closed and freed. Do not reference
|
|
|
|
uninitialized data. open_tables() could fail.
|
|
|
|
*/
|
|
|
|
table_list->table= NULL;
|
2009-12-08 10:57:07 +01:00
|
|
|
/* Same applies to MDL ticket. */
|
|
|
|
table_list->mdl_request.ticket= NULL;
|
2010-05-25 14:35:01 +02:00
|
|
|
/* Set lock type which is appropriate for ALTER TABLE. */
|
2010-05-26 14:18:08 +02:00
|
|
|
table_list->lock_type= TL_READ_NO_INSERT;
|
2010-05-25 14:35:01 +02:00
|
|
|
/* Same applies to MDL request. */
|
|
|
|
table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
|
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
|
|
|
|
|
|
|
bzero((char*) &create_info, sizeof(create_info));
|
2005-01-02 14:23:34 +01:00
|
|
|
create_info.row_type=ROW_TYPE_NOT_USED;
|
2004-06-10 16:41:24 +02:00
|
|
|
create_info.default_table_charset=default_charset_info;
|
2004-11-09 02:58:44 +01:00
|
|
|
/* Force alter table to recreate table */
|
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
|
|
|
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
|
2004-06-10 16:41:24 +02:00
|
|
|
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
|
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
|
|
|
table_list, &alter_info, 0,
|
|
|
|
(ORDER *) 0, 0));
|
2004-06-10 16:41:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-05 19:08:40 +02:00
|
|
|
bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
|
|
|
|
HA_CHECK_OPT *check_opt)
|
2003-08-21 16:15:06 +02:00
|
|
|
{
|
|
|
|
TABLE_LIST *table;
|
|
|
|
List<Item> field_list;
|
|
|
|
Item *item;
|
|
|
|
Protocol *protocol= thd->protocol;
|
2004-03-23 18:28:18 +01:00
|
|
|
DBUG_ENTER("mysql_checksum_table");
|
2003-08-21 16:15:06 +02:00
|
|
|
|
|
|
|
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
|
|
|
|
item->maybe_null= 1;
|
2007-03-09 06:05:08 +01:00
|
|
|
field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
|
|
|
|
MY_INT64_NUM_DECIMAL_DIGITS));
|
2003-08-21 16:15:06 +02:00
|
|
|
item->maybe_null= 1;
|
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_metadata(&field_list,
|
2004-08-03 12:32:21 +02:00
|
|
|
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2003-08-21 16:15:06 +02:00
|
|
|
|
Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Bug 25038 - Waiting TRUNCATE
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Bug 19627 - temporary merge table locking
Bug 27660 - Falcon: merge table possible
Bug 30273 - merge tables: Can't lock file (errno: 155)
The problems were:
Bug 26379 - Combination of FLUSH TABLE and REPAIR TABLE
corrupts a MERGE table
1. A thread trying to lock a MERGE table performs busy waiting while
REPAIR TABLE or a similar table administration task is ongoing on
one or more of its MyISAM tables.
2. A thread trying to lock a MERGE table performs busy waiting until all
threads that did REPAIR TABLE or similar table administration tasks
on one or more of its MyISAM tables in LOCK TABLES segments do UNLOCK
TABLES. The difference against problem #1 is that the busy waiting
takes place *after* the administration task. It is terminated by
UNLOCK TABLES only.
3. Two FLUSH TABLES within a LOCK TABLES segment can invalidate the
lock. This does *not* require a MERGE table. The first FLUSH TABLES
can be replaced by any statement that requires other threads to
reopen the table. In 5.0 and 5.1 a single FLUSH TABLES can provoke
the problem.
Bug 26867 - LOCK TABLES + REPAIR + merge table result in
memory/cpu hogging
Trying DML on a MERGE table, which has a child locked and
repaired by another thread, made an infinite loop in the server.
Bug 26377 - Deadlock with MERGE and FLUSH TABLE
Locking a MERGE table and its children in parent-child order
and flushing the child deadlocked the server.
Bug 25038 - Waiting TRUNCATE
Truncating a MERGE child, while the MERGE table was in use,
let the truncate fail instead of waiting for the table to
become free.
Bug 25700 - merge base tables get corrupted by
optimize/analyze/repair table
Repairing a child of an open MERGE table corrupted the child.
It was necessary to FLUSH the child first.
Bug 30275 - Merge tables: flush tables or unlock tables
causes server to crash
Flushing and optimizing locked MERGE children crashed the server.
Bug 19627 - temporary merge table locking
Use of a temporary MERGE table with non-temporary children
could corrupt the children.
Temporary tables are never locked. So we do now prohibit
non-temporary chidlren of a temporary MERGE table.
Bug 27660 - Falcon: merge table possible
It was possible to create a MERGE table with non-MyISAM children.
Bug 30273 - merge tables: Can't lock file (errno: 155)
This was a Windows-only bug. Table administration statements
sometimes failed with "Can't lock file (errno: 155)".
These bugs are fixed by a new implementation of MERGE table open.
When opening a MERGE table in open_tables() we do now add the
child tables to the list of tables to be opened by open_tables()
(the "query_list"). The children are not opened in the handler at
this stage.
After opening the parent, open_tables() opens each child from the
now extended query_list. When the last child is opened, we remove
the children from the query_list again and attach the children to
the parent. This behaves similar to the old open. However it does
not open the MyISAM tables directly, but grabs them from the already
open children.
When closing a MERGE table in close_thread_table() we detach the
children only. Closing of the children is done implicitly because
they are in thd->open_tables.
For more detail see the comment at the top of ha_myisammrg.cc.
Changed from open_ltable() to open_and_lock_tables() in all places
that can be relevant for MERGE tables. The latter can handle tables
added to the list on the fly. When open_ltable() was used in a loop
over a list of tables, the list must be temporarily terminated
after every table for open_and_lock_tables().
table_list->required_type is set to FRMTYPE_TABLE to avoid open of
special tables. Handling of derived tables is suppressed.
These details are handled by the new function
open_n_lock_single_table(), which has nearly the same signature as
open_ltable() and can replace it in most cases.
In reopen_tables() some of the tables open by a thread can be
closed and reopened. When a MERGE child is affected, the parent
must be closed and reopened too. Closing of the parent is forced
before the first child is closed. Reopen happens in the order of
thd->open_tables. MERGE parents do not attach their children
automatically at open. This is done after all tables are reopened.
So all children are open when attaching them.
Special lock handling like mysql_lock_abort() or mysql_lock_remove()
needs to be suppressed for MERGE children or forwarded to the parent.
This depends on the situation. In loops over all open tables one
suppresses child lock handling. When a single table is touched,
forwarding is done.
Behavioral changes:
===================
This patch changes the behavior of temporary MERGE tables.
Temporary MERGE must have temporary children.
The old behavior was wrong. A temporary table is not locked. Hence
even non-temporary children were not locked. See
Bug 19627 - temporary merge table locking.
You cannot change the union list of a non-temporary MERGE table
when LOCK TABLES is in effect. The following does *not* work:
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ...;
LOCK TABLES t1 WRITE, t2 WRITE, m1 WRITE;
ALTER TABLE m1 ... UNION=(t1,t2) ...;
However, you can do this with a temporary MERGE table.
You cannot create a MERGE table with CREATE ... SELECT, neither
as a temporary MERGE table, nor as a non-temporary MERGE table.
CREATE TABLE m1 ... ENGINE=MRG_MYISAM ... SELECT ...;
Gives error message: table is not BASE TABLE.
2007-11-15 20:25:43 +01:00
|
|
|
/* Open one table after the other to keep lock time as short as possible. */
|
2004-07-16 00:15:55 +02:00
|
|
|
for (table= tables; table; table= table->next_local)
|
2003-08-21 16:15:06 +02:00
|
|
|
{
|
|
|
|
char table_name[NAME_LEN*2+2];
|
2003-09-03 11:34:32 +02:00
|
|
|
TABLE *t;
|
2003-08-21 16:15:06 +02:00
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
strxmov(table_name, table->db ,".", table->table_name, NullS);
|
2003-09-11 18:06:23 +02:00
|
|
|
|
2009-12-01 14:38:00 +01:00
|
|
|
t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0);
|
2003-09-11 18:06:23 +02:00
|
|
|
thd->clear_error(); // these errors shouldn't get client
|
2003-08-21 16:15:06 +02:00
|
|
|
|
|
|
|
protocol->prepare_for_resend();
|
|
|
|
protocol->store(table_name, system_charset_info);
|
|
|
|
|
2003-09-03 11:34:32 +02:00
|
|
|
if (!t)
|
2003-08-21 16:15:06 +02:00
|
|
|
{
|
2003-09-11 18:06:23 +02:00
|
|
|
/* Table didn't exist */
|
2003-08-21 16:15:06 +02:00
|
|
|
protocol->store_null();
|
2004-10-20 03:04:37 +02:00
|
|
|
thd->clear_error();
|
2003-08-21 16:15:06 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
|
2004-04-08 16:56:45 +02:00
|
|
|
!(check_opt->flags & T_EXTEND))
|
|
|
|
protocol->store((ulonglong)t->file->checksum());
|
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
|
|
|
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
|
2003-09-11 18:06:23 +02:00
|
|
|
(check_opt->flags & T_QUICK))
|
2004-04-08 16:56:45 +02:00
|
|
|
protocol->store_null();
|
2003-09-03 11:34:32 +02:00
|
|
|
else
|
|
|
|
{
|
2004-04-08 16:56:45 +02:00
|
|
|
/* calculating table's checksum */
|
|
|
|
ha_checksum crc= 0;
|
2005-10-04 17:04:20 +02:00
|
|
|
uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
|
2004-04-08 16:56:45 +02: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
|
|
|
t->use_all_columns();
|
2004-04-08 16:56:45 +02:00
|
|
|
|
2004-06-23 12:29:05 +02:00
|
|
|
if (t->file->ha_rnd_init(1))
|
2004-04-08 16:56:45 +02:00
|
|
|
protocol->store_null();
|
|
|
|
else
|
|
|
|
{
|
2005-08-29 17:08:41 +02:00
|
|
|
for (;;)
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
2009-04-23 19:52:39 +02:00
|
|
|
if (thd->killed)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
we've been killed; let handler clean up, and remove the
|
|
|
|
partial current row from the recordset (embedded lib)
|
|
|
|
*/
|
|
|
|
t->file->ha_rnd_end();
|
|
|
|
thd->protocol->remove_last_row();
|
|
|
|
goto err;
|
|
|
|
}
|
2004-04-08 16:56:45 +02:00
|
|
|
ha_checksum row_crc= 0;
|
2005-08-29 17:08:41 +02:00
|
|
|
int error= t->file->rnd_next(t->record[0]);
|
|
|
|
if (unlikely(error))
|
|
|
|
{
|
|
|
|
if (error == HA_ERR_RECORD_DELETED)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
}
|
2005-10-04 17:04:20 +02:00
|
|
|
if (t->s->null_bytes)
|
|
|
|
{
|
|
|
|
/* fix undefined null bits */
|
|
|
|
t->record[0][t->s->null_bytes-1] |= null_mask;
|
2005-10-05 19:36:20 +02:00
|
|
|
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
|
|
|
|
t->record[0][0] |= 1;
|
|
|
|
|
2005-10-04 17:04:20 +02:00
|
|
|
row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
|
|
|
|
}
|
2003-09-03 11:34:32 +02:00
|
|
|
|
2005-01-06 12:00:13 +01:00
|
|
|
for (uint i= 0; i < t->s->fields; i++ )
|
2004-04-08 16:56:45 +02:00
|
|
|
{
|
|
|
|
Field *f= t->field[i];
|
2010-02-28 18:29:19 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
BLOB and VARCHAR have pointers in their field, we must convert
|
|
|
|
to string; GEOMETRY is implemented on top of BLOB.
|
|
|
|
BIT may store its data among NULL bits, convert as well.
|
|
|
|
*/
|
|
|
|
switch (f->type()) {
|
|
|
|
case MYSQL_TYPE_BLOB:
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
|
|
case MYSQL_TYPE_GEOMETRY:
|
|
|
|
case MYSQL_TYPE_BIT:
|
|
|
|
{
|
|
|
|
String tmp;
|
|
|
|
f->val_str(&tmp);
|
|
|
|
row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
|
|
|
|
tmp.length());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
|
|
|
|
break;
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
|
|
|
}
|
2003-09-03 11:34:32 +02:00
|
|
|
|
2004-04-08 16:56:45 +02:00
|
|
|
crc+= row_crc;
|
|
|
|
}
|
|
|
|
protocol->store((ulonglong)crc);
|
2004-06-23 12:29:05 +02:00
|
|
|
t->file->ha_rnd_end();
|
2004-04-08 16:56:45 +02:00
|
|
|
}
|
2003-09-03 11:34:32 +02:00
|
|
|
}
|
2003-09-11 18:06:23 +02:00
|
|
|
thd->clear_error();
|
2010-07-27 12:25:53 +02:00
|
|
|
if (! thd->in_sub_stmt)
|
|
|
|
trans_rollback_stmt(thd);
|
2003-08-21 16:15:06 +02:00
|
|
|
close_thread_tables(thd);
|
2010-07-27 12:25:53 +02:00
|
|
|
/*
|
|
|
|
Don't release metadata locks, this will be done at
|
|
|
|
statement end.
|
|
|
|
*/
|
2003-08-21 16:15:06 +02:00
|
|
|
table->table=0; // For query cache
|
|
|
|
}
|
|
|
|
if (protocol->write())
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2008-02-19 13:58:08 +01:00
|
|
|
my_eof(thd);
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
2003-09-11 18:06:23 +02:00
|
|
|
|
2010-07-27 12:25:53 +02:00
|
|
|
err:
|
2004-10-20 03:04:37 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2003-08-21 16:15:06 +02:00
|
|
|
}
|
2005-06-17 23:14:44 +02:00
|
|
|
|
|
|
|
static bool check_engine(THD *thd, const char *table_name,
|
2006-02-17 17:12:35 +01:00
|
|
|
HA_CREATE_INFO *create_info)
|
2005-06-17 23:14:44 +02:00
|
|
|
{
|
2006-02-17 17:12:35 +01:00
|
|
|
handlerton **new_engine= &create_info->db_type;
|
2005-12-21 19:18:40 +01:00
|
|
|
handlerton *req_engine= *new_engine;
|
2005-10-04 17:04:20 +02:00
|
|
|
bool no_substitution=
|
2005-06-17 23:14:44 +02:00
|
|
|
test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
|
2005-12-21 19:18:40 +01:00
|
|
|
if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine),
|
|
|
|
no_substitution, 1)))
|
2005-06-17 23:14:44 +02:00
|
|
|
return TRUE;
|
|
|
|
|
2006-05-28 14:51:01 +02:00
|
|
|
if (req_engine && req_engine != *new_engine)
|
2005-06-17 23:14:44 +02:00
|
|
|
{
|
2007-04-16 18:16:17 +02:00
|
|
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
2005-06-17 23:14:44 +02:00
|
|
|
ER_WARN_USING_OTHER_HANDLER,
|
|
|
|
ER(ER_WARN_USING_OTHER_HANDLER),
|
2005-12-21 19:18:40 +01:00
|
|
|
ha_resolve_storage_engine_name(*new_engine),
|
2005-06-17 23:14:44 +02:00
|
|
|
table_name);
|
|
|
|
}
|
2006-02-17 17:12:35 +01:00
|
|
|
if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
|
|
|
|
ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
|
|
|
|
{
|
|
|
|
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
|
|
|
|
{
|
2006-05-28 14:51:01 +02:00
|
|
|
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
|
2007-03-02 17:43:45 +01:00
|
|
|
ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
|
2006-02-17 17:12:35 +01:00
|
|
|
*new_engine= 0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
2006-09-15 19:28:00 +02:00
|
|
|
*new_engine= myisam_hton;
|
2006-02-17 17:12:35 +01:00
|
|
|
}
|
2005-06-17 23:14:44 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|