mirror of
https://github.com/MariaDB/server.git
synced 2025-12-03 05:41:09 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-4.1-runtime
into bodhi.local:/opt/local/work/mysql-4.1-4968-to-push sql/mysql_priv.h: Auto merged sql/sql_class.h: Auto merged sql/sql_insert.cc: Auto merged sql/sql_parse.cc: Manual merge. sql/sql_table.cc: Manual merge.
This commit is contained in:
@@ -1035,4 +1035,71 @@ EXECUTE stmt USING @a;
|
||||
0 0
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (i INT);
|
||||
PREPARE st_19182
|
||||
FROM "CREATE TABLE t2 (i INT, j INT, KEY (i), KEY(j)) SELECT i FROM t1";
|
||||
EXECUTE st_19182;
|
||||
DESC t2;
|
||||
Field Type Null Key Default Extra
|
||||
j int(11) YES MUL NULL
|
||||
i int(11) YES MUL NULL
|
||||
DROP TABLE t2;
|
||||
EXECUTE st_19182;
|
||||
DESC t2;
|
||||
Field Type Null Key Default Extra
|
||||
j int(11) YES MUL NULL
|
||||
i int(11) YES MUL NULL
|
||||
DEALLOCATE PREPARE st_19182;
|
||||
DROP TABLE t2, t1;
|
||||
drop database if exists mysqltest;
|
||||
drop table if exists t1, t2;
|
||||
create database mysqltest character set utf8;
|
||||
prepare stmt1 from "create table mysqltest.t1 (c char(10))";
|
||||
prepare stmt2 from "create table mysqltest.t2 select 'test'";
|
||||
execute stmt1;
|
||||
execute stmt2;
|
||||
show create table mysqltest.t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c` char(10) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8
|
||||
show create table mysqltest.t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`test` char(4) character set latin1 NOT NULL default ''
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8
|
||||
drop table mysqltest.t1;
|
||||
drop table mysqltest.t2;
|
||||
alter database mysqltest character set latin1;
|
||||
execute stmt1;
|
||||
execute stmt2;
|
||||
show create table mysqltest.t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c` char(10) character set utf8 default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
show create table mysqltest.t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`test` char(4) NOT NULL default ''
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop database mysqltest;
|
||||
deallocate prepare stmt1;
|
||||
deallocate prepare stmt2;
|
||||
execute stmt;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c` char(10) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/'
|
||||
drop table t1;
|
||||
execute stmt;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c` char(10) default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/'
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
End of 4.1 tests.
|
||||
|
||||
@@ -1068,5 +1068,77 @@ EXECUTE stmt USING @a;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug#19182: CREATE TABLE bar (m INT) SELECT n FROM foo; doesn't work
|
||||
# from stored procedure.
|
||||
#
|
||||
# The cause of a bug was that cached LEX::create_list was modified,
|
||||
# and then together with LEX::key_list was reset.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT);
|
||||
|
||||
PREPARE st_19182
|
||||
FROM "CREATE TABLE t2 (i INT, j INT, KEY (i), KEY(j)) SELECT i FROM t1";
|
||||
|
||||
EXECUTE st_19182;
|
||||
DESC t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
|
||||
# Check that on second execution we don't loose 'j' column and the keys
|
||||
# on 'i' and 'j' columns.
|
||||
EXECUTE st_19182;
|
||||
DESC t2;
|
||||
|
||||
DEALLOCATE PREPARE st_19182;
|
||||
DROP TABLE t2, t1;
|
||||
|
||||
#
|
||||
# Bug #22060 "ALTER TABLE x AUTO_INCREMENT=y in SP crashes server"
|
||||
#
|
||||
# Code which implemented CREATE/ALTER TABLE and CREATE DATABASE
|
||||
# statement modified HA_CREATE_INFO structure in LEX, making these
|
||||
# statements PS/SP-unsafe (their re-execution might have resulted
|
||||
# in incorrect results).
|
||||
#
|
||||
--disable_warnings
|
||||
drop database if exists mysqltest;
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
# CREATE TABLE and CREATE TABLE ... SELECT
|
||||
create database mysqltest character set utf8;
|
||||
prepare stmt1 from "create table mysqltest.t1 (c char(10))";
|
||||
prepare stmt2 from "create table mysqltest.t2 select 'test'";
|
||||
execute stmt1;
|
||||
execute stmt2;
|
||||
show create table mysqltest.t1;
|
||||
show create table mysqltest.t2;
|
||||
drop table mysqltest.t1;
|
||||
drop table mysqltest.t2;
|
||||
alter database mysqltest character set latin1;
|
||||
execute stmt1;
|
||||
execute stmt2;
|
||||
show create table mysqltest.t1;
|
||||
show create table mysqltest.t2;
|
||||
drop database mysqltest;
|
||||
deallocate prepare stmt1;
|
||||
deallocate prepare stmt2;
|
||||
# CREATE TABLE with DATA DIRECTORY option
|
||||
--disable_query_log
|
||||
eval prepare stmt from "create table t1 (c char(10)) data directory='$MYSQLTEST_VARDIR/tmp'";
|
||||
--enable_query_log
|
||||
execute stmt;
|
||||
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
execute stmt;
|
||||
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
--echo End of 4.1 tests.
|
||||
|
||||
@@ -563,25 +563,22 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
uint &key_count, int select_field_count);
|
||||
int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
List<create_field> &fields, List<Key> &keys,
|
||||
Alter_info *alter_info,
|
||||
bool tmp_table, uint select_field_count);
|
||||
|
||||
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
const char *db, const char *name,
|
||||
List<create_field> *extra_fields,
|
||||
List<Key> *keys,
|
||||
Alter_info *alter_info,
|
||||
List<Item> *items,
|
||||
MYSQL_LOCK **lock);
|
||||
int mysql_alter_table(THD *thd, char *new_db, char *new_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
TABLE_LIST *table_list,
|
||||
List<create_field> &fields,
|
||||
List<Key> &keys,
|
||||
Alter_info *alter_info,
|
||||
uint order_num, ORDER *order,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
bool ignore,
|
||||
ALTER_INFO *alter_info, bool do_send_ok=1);
|
||||
int mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
|
||||
bool ignore);
|
||||
int mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
|
||||
int mysql_create_like_table(THD *thd, TABLE_LIST *table,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Table_ident *src_table);
|
||||
@@ -590,9 +587,6 @@ bool mysql_rename_table(enum db_type base,
|
||||
const char * old_name,
|
||||
const char *new_db,
|
||||
const char * new_name);
|
||||
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
|
||||
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
|
||||
ALTER_INFO *alter_info);
|
||||
int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
TABLE_LIST *update_table_list,
|
||||
Item **conds, uint order_num, ORDER *order);
|
||||
@@ -679,7 +673,8 @@ int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
|
||||
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
|
||||
int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1);
|
||||
int mysqld_show_create(THD *thd, TABLE_LIST *table_list);
|
||||
int mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
|
||||
int mysqld_show_create_db(THD *thd, char *dbname,
|
||||
const HA_CREATE_INFO *create);
|
||||
|
||||
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
|
||||
int mysqld_show_status(THD *thd);
|
||||
|
||||
@@ -1293,20 +1293,21 @@ class select_create: public select_insert {
|
||||
ORDER *group;
|
||||
const char *db;
|
||||
const char *name;
|
||||
List<create_field> *extra_fields;
|
||||
List<Key> *keys;
|
||||
HA_CREATE_INFO *create_info;
|
||||
Alter_info *alter_info;
|
||||
MYSQL_LOCK *lock;
|
||||
Field **field;
|
||||
public:
|
||||
select_create(const char *db_name, const char *table_name,
|
||||
HA_CREATE_INFO *create_info_par,
|
||||
List<create_field> &fields_par,
|
||||
List<Key> &keys_par,
|
||||
List<Item> &select_fields,enum_duplicates duplic, bool ignore)
|
||||
:select_insert (NULL, &select_fields, duplic, ignore), db(db_name),
|
||||
name(table_name), extra_fields(&fields_par),keys(&keys_par),
|
||||
create_info(create_info_par), lock(0)
|
||||
HA_CREATE_INFO *create_info_arg,
|
||||
Alter_info *alter_info_arg,
|
||||
List<Item> &select_fields,
|
||||
enum_duplicates duplic, bool ignore)
|
||||
:select_insert(NULL, &select_fields, duplic, ignore),
|
||||
db(db_name), name(table_name),
|
||||
create_info(create_info_arg),
|
||||
alter_info(alter_info_arg),
|
||||
lock(0)
|
||||
{}
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
void store_values(List<Item> &values);
|
||||
|
||||
@@ -1805,7 +1805,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
|
||||
unit= u;
|
||||
table= create_table_from_items(thd, create_info, db, name,
|
||||
extra_fields, keys, &values, &lock);
|
||||
alter_info, &values, &lock);
|
||||
if (!table)
|
||||
DBUG_RETURN(-1); // abort() deletes table
|
||||
|
||||
|
||||
@@ -1015,6 +1015,18 @@ int yylex(void *arg, void *yythd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
|
||||
:drop_list(rhs.drop_list, mem_root),
|
||||
alter_list(rhs.alter_list, mem_root),
|
||||
key_list(rhs.key_list, mem_root),
|
||||
create_list(rhs.create_list, mem_root),
|
||||
flags(rhs.flags),
|
||||
keys_onoff(rhs.keys_onoff),
|
||||
tablespace_op(rhs.tablespace_op),
|
||||
is_simple(rhs.is_simple)
|
||||
{}
|
||||
|
||||
/*
|
||||
st_select_lex structures initialisations
|
||||
*/
|
||||
|
||||
@@ -571,19 +571,61 @@ typedef class st_select_lex SELECT_LEX;
|
||||
#define ALTER_ORDER 64
|
||||
#define ALTER_OPTIONS 128
|
||||
|
||||
typedef struct st_alter_info
|
||||
/**
|
||||
@brief Parsing data for CREATE or ALTER TABLE.
|
||||
|
||||
This structure contains a list of columns or indexes to be created,
|
||||
altered or dropped.
|
||||
*/
|
||||
|
||||
class Alter_info
|
||||
{
|
||||
public:
|
||||
List<Alter_drop> drop_list;
|
||||
List<Alter_column> alter_list;
|
||||
List<Key> key_list;
|
||||
List<create_field> create_list;
|
||||
uint flags;
|
||||
enum enum_enable_or_disable keys_onoff;
|
||||
enum tablespace_op_type tablespace_op;
|
||||
bool is_simple;
|
||||
|
||||
st_alter_info(){clear();}
|
||||
void clear(){keys_onoff= LEAVE_AS_IS;tablespace_op= NO_TABLESPACE_OP;}
|
||||
void reset(){drop_list.empty();alter_list.empty();clear();}
|
||||
} ALTER_INFO;
|
||||
Alter_info() :
|
||||
flags(0),
|
||||
keys_onoff(LEAVE_AS_IS),
|
||||
tablespace_op(NO_TABLESPACE_OP),
|
||||
is_simple(1)
|
||||
{}
|
||||
void reset()
|
||||
{
|
||||
drop_list.empty();
|
||||
alter_list.empty();
|
||||
key_list.empty();
|
||||
create_list.empty();
|
||||
flags= 0;
|
||||
keys_onoff= LEAVE_AS_IS;
|
||||
tablespace_op= NO_TABLESPACE_OP;
|
||||
is_simple= 1;
|
||||
}
|
||||
/**
|
||||
Construct a copy of this object to be used for mysql_alter_table
|
||||
and mysql_create_table. Historically, these two functions modify
|
||||
their Alter_info arguments. This behaviour breaks re-execution of
|
||||
prepared statements and stored procedures and is compensated by
|
||||
always supplying a copy of Alter_info to these functions.
|
||||
The constructed copy still shares key Key, Alter_drop, create_field
|
||||
and Alter_column elements of the lists - these structures are not
|
||||
modified and thus are not copied.
|
||||
|
||||
@note You need to use check thd->is_fatal_error for out
|
||||
of memory condition after calling this function.
|
||||
*/
|
||||
Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root);
|
||||
private:
|
||||
Alter_info &operator=(const Alter_info &rhs); // not implemented
|
||||
Alter_info(const Alter_info &rhs); // not implemented
|
||||
};
|
||||
|
||||
|
||||
/* The state of the lex parsing. This is saved in the THD struct */
|
||||
|
||||
@@ -620,8 +662,6 @@ typedef struct st_lex
|
||||
List<String> interval_list;
|
||||
List<LEX_USER> users_list;
|
||||
List<LEX_COLUMN> columns;
|
||||
List<Key> key_list;
|
||||
List<create_field> create_list;
|
||||
List<Item> *insert_list,field_list,value_list,update_list;
|
||||
List<List_item> many_values;
|
||||
List<set_var_base> var_list;
|
||||
@@ -654,7 +694,7 @@ typedef struct st_lex
|
||||
bool derived_tables;
|
||||
bool safe_to_cache_query;
|
||||
bool subqueries, ignore;
|
||||
ALTER_INFO alter_info;
|
||||
Alter_info alter_info;
|
||||
/* Prepared statements SQL syntax:*/
|
||||
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
|
||||
/*
|
||||
|
||||
@@ -66,9 +66,14 @@ public:
|
||||
pointer.
|
||||
*/
|
||||
|
||||
class list_node :public Sql_alloc
|
||||
|
||||
/**
|
||||
list_node - a node of a single-linked list.
|
||||
@note We never call a destructor for instances of this class.
|
||||
*/
|
||||
|
||||
struct list_node :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
list_node *next;
|
||||
void *info;
|
||||
list_node(void *info_par,list_node *next_par)
|
||||
@@ -79,8 +84,6 @@ public:
|
||||
info= 0;
|
||||
next= this;
|
||||
}
|
||||
friend class base_list;
|
||||
friend class base_list_iterator;
|
||||
};
|
||||
|
||||
|
||||
@@ -96,11 +99,56 @@ public:
|
||||
|
||||
inline void empty() { elements=0; first= &end_of_list; last=&first;}
|
||||
inline base_list() { empty(); }
|
||||
/**
|
||||
This is a shallow copy constructor that implicitly passes the ownership
|
||||
from the source list to the new instance. The old instance is not
|
||||
updated, so both objects end up sharing the same nodes. If one of
|
||||
the instances then adds or removes a node, the other becomes out of
|
||||
sync ('last' pointer), while still operational. Some old code uses and
|
||||
relies on this behaviour. This logic is quite tricky: please do not use
|
||||
it in any new code.
|
||||
*/
|
||||
inline base_list(const base_list &tmp) :Sql_alloc()
|
||||
{
|
||||
elements= tmp.elements;
|
||||
first= tmp.first;
|
||||
last=tmp.last;
|
||||
last= elements ? tmp.last : &first;
|
||||
}
|
||||
/**
|
||||
Construct a deep copy of the argument in memory root mem_root.
|
||||
The elements themselves are copied by pointer.
|
||||
*/
|
||||
inline base_list(const base_list &rhs, MEM_ROOT *mem_root)
|
||||
{
|
||||
if (rhs.elements)
|
||||
{
|
||||
/*
|
||||
It's okay to allocate an array of nodes at once: we never
|
||||
call a destructor for list_node objects anyway.
|
||||
*/
|
||||
first= (list_node*) alloc_root(mem_root,
|
||||
sizeof(list_node) * rhs.elements);
|
||||
if (first)
|
||||
{
|
||||
elements= rhs.elements;
|
||||
list_node *dst= first;
|
||||
list_node *src= rhs.first;
|
||||
for (; dst < first + elements - 1; dst++, src= src->next)
|
||||
{
|
||||
dst->info= src->info;
|
||||
dst->next= dst + 1;
|
||||
}
|
||||
/* Copy the last node */
|
||||
dst->info= src->info;
|
||||
dst->next= &end_of_list;
|
||||
/* Setup 'last' member */
|
||||
last= &dst->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
elements= 0;
|
||||
first= &end_of_list;
|
||||
last= &first;
|
||||
}
|
||||
inline base_list(bool error) { }
|
||||
inline bool push_back(void *info)
|
||||
@@ -327,6 +375,8 @@ template <class T> class List :public base_list
|
||||
public:
|
||||
inline List() :base_list() {}
|
||||
inline List(const List<T> &tmp) :base_list(tmp) {}
|
||||
inline List(const List<T> &tmp, MEM_ROOT *mem_root) :
|
||||
base_list(tmp, mem_root) {}
|
||||
inline bool push_back(T *a) { return base_list::push_back(a); }
|
||||
inline bool push_front(T *a) { return base_list::push_front(a); }
|
||||
inline T* head() {return (T*) base_list::head(); }
|
||||
|
||||
200
sql/sql_parse.cc
200
sql/sql_parse.cc
@@ -2478,6 +2478,22 @@ mysql_execute_command(THD *thd)
|
||||
}
|
||||
/* Skip first table, which is the table we are creating */
|
||||
TABLE_LIST *create_table, *create_table_local;
|
||||
/*
|
||||
Code below (especially in mysql_create_table() and select_create
|
||||
methods) may modify HA_CREATE_INFO structure in LEX, so we have to
|
||||
use a copy of this structure to make execution prepared statement-
|
||||
safe. A shallow copy is enough as this code won't modify any memory
|
||||
referenced from this structure.
|
||||
*/
|
||||
HA_CREATE_INFO create_info(lex->create_info);
|
||||
Alter_info alter_info(lex->alter_info, thd->mem_root);
|
||||
|
||||
if (thd->is_fatal_error)
|
||||
{
|
||||
/* out of memory when creating a copy of alter_info */
|
||||
res= 1;
|
||||
goto unsent_create_error;
|
||||
}
|
||||
tables= lex->unlink_first_table(tables, &create_table,
|
||||
&create_table_local);
|
||||
|
||||
@@ -2485,12 +2501,12 @@ mysql_execute_command(THD *thd)
|
||||
goto unsent_create_error;
|
||||
|
||||
#ifndef HAVE_READLINK
|
||||
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
|
||||
create_info.data_file_name= create_info.index_file_name= NULL;
|
||||
#else
|
||||
/* Fix names if symlinked tables */
|
||||
if (append_file_to_dir(thd, &lex->create_info.data_file_name,
|
||||
if (append_file_to_dir(thd, &create_info.data_file_name,
|
||||
create_table->real_name) ||
|
||||
append_file_to_dir(thd,&lex->create_info.index_file_name,
|
||||
append_file_to_dir(thd, &create_info.index_file_name,
|
||||
create_table->real_name))
|
||||
{
|
||||
res=-1;
|
||||
@@ -2501,14 +2517,14 @@ mysql_execute_command(THD *thd)
|
||||
If we are using SET CHARSET without DEFAULT, add an implicite
|
||||
DEFAULT to not confuse old users. (This may change).
|
||||
*/
|
||||
if ((lex->create_info.used_fields &
|
||||
if ((create_info.used_fields &
|
||||
(HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
|
||||
HA_CREATE_USED_CHARSET)
|
||||
{
|
||||
lex->create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
|
||||
lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
|
||||
lex->create_info.default_table_charset= lex->create_info.table_charset;
|
||||
lex->create_info.table_charset= 0;
|
||||
create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
|
||||
create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
|
||||
create_info.default_table_charset= create_info.table_charset;
|
||||
create_info.table_charset= 0;
|
||||
}
|
||||
/*
|
||||
The create-select command will open and read-lock the select table
|
||||
@@ -2542,11 +2558,14 @@ mysql_execute_command(THD *thd)
|
||||
if (!(res=open_and_lock_tables(thd,tables)))
|
||||
{
|
||||
res= -1; // If error
|
||||
/*
|
||||
select_create is currently not re-execution friendly and
|
||||
needs to be created for every execution of a PS/SP.
|
||||
*/
|
||||
if ((result=new select_create(create_table->db,
|
||||
create_table->real_name,
|
||||
&lex->create_info,
|
||||
lex->create_list,
|
||||
lex->key_list,
|
||||
&create_info,
|
||||
&alter_info,
|
||||
select_lex->item_list, lex->duplicates,
|
||||
lex->ignore)))
|
||||
{
|
||||
@@ -2558,22 +2577,18 @@ mysql_execute_command(THD *thd)
|
||||
res=handle_select(thd, lex, result);
|
||||
select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
|
||||
}
|
||||
//reset for PS
|
||||
lex->create_list.empty();
|
||||
lex->key_list.empty();
|
||||
}
|
||||
}
|
||||
else // regular create
|
||||
{
|
||||
if (lex->name)
|
||||
res= mysql_create_like_table(thd, create_table, &lex->create_info,
|
||||
res= mysql_create_like_table(thd, create_table, &create_info,
|
||||
(Table_ident *)lex->name);
|
||||
else
|
||||
{
|
||||
res= mysql_create_table(thd, create_table->db,
|
||||
create_table->real_name, &lex->create_info,
|
||||
lex->create_list,
|
||||
lex->key_list,0,0);
|
||||
create_table->real_name, &create_info,
|
||||
&alter_info, 0, 0);
|
||||
}
|
||||
if (!res)
|
||||
send_ok(thd);
|
||||
@@ -2591,15 +2606,48 @@ unsent_create_error:
|
||||
break;
|
||||
}
|
||||
case SQLCOM_CREATE_INDEX:
|
||||
/* Fall through */
|
||||
case SQLCOM_DROP_INDEX:
|
||||
/*
|
||||
CREATE INDEX and DROP INDEX are implemented by calling ALTER
|
||||
TABLE with proper arguments. This isn't very fast but it
|
||||
should work for most cases.
|
||||
|
||||
In the future ALTER TABLE will notice that only added
|
||||
indexes and create these one by one for the existing table
|
||||
without having to do a full rebuild.
|
||||
|
||||
One should normally create all indexes with CREATE TABLE or
|
||||
ALTER TABLE.
|
||||
*/
|
||||
{
|
||||
Alter_info alter_info(lex->alter_info, thd->mem_root);
|
||||
HA_CREATE_INFO create_info;
|
||||
|
||||
if (thd->is_fatal_error) /* out of memory creating a copy of alter_info*/
|
||||
goto error;
|
||||
|
||||
if (check_one_table_access(thd, INDEX_ACL, tables))
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
if (end_active_trans(thd))
|
||||
res= -1;
|
||||
else
|
||||
res = mysql_create_index(thd, tables, lex->key_list);
|
||||
break;
|
||||
goto error;
|
||||
/*
|
||||
Currently CREATE INDEX or DROP INDEX cause a full table rebuild
|
||||
and thus classify as slow administrative statements just like
|
||||
ALTER TABLE.
|
||||
*/
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
|
||||
bzero((char*) &create_info, sizeof(create_info));
|
||||
create_info.db_type= DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
|
||||
res= mysql_alter_table(thd, tables->db, tables->real_name,
|
||||
&create_info, tables, &alter_info,
|
||||
0, (ORDER*)0, DUP_ERROR, 0);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_REPLICATION
|
||||
case SQLCOM_SLAVE_START:
|
||||
{
|
||||
@@ -2642,6 +2690,17 @@ unsent_create_error:
|
||||
#else
|
||||
{
|
||||
ulong priv=0;
|
||||
/*
|
||||
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
|
||||
so we have to use a copy of this structure to make execution
|
||||
prepared statement- safe. A shallow copy is enough as no memory
|
||||
referenced from this structure will be modified.
|
||||
*/
|
||||
HA_CREATE_INFO create_info(lex->create_info);
|
||||
Alter_info alter_info(lex->alter_info, thd->mem_root);
|
||||
|
||||
if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
|
||||
goto error;
|
||||
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
|
||||
{
|
||||
net_printf(thd, ER_WRONG_TABLE_NAME, lex->name);
|
||||
@@ -2655,7 +2714,7 @@ unsent_create_error:
|
||||
default database if the new name is not explicitly qualified
|
||||
by a database. (Bug #11493)
|
||||
*/
|
||||
if (lex->alter_info.flags & ALTER_RENAME)
|
||||
if (alter_info.flags & ALTER_RENAME)
|
||||
{
|
||||
if (! thd->db)
|
||||
{
|
||||
@@ -2671,7 +2730,7 @@ unsent_create_error:
|
||||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
|
||||
check_merge_table_access(thd, tables->db,
|
||||
(TABLE_LIST *)
|
||||
lex->create_info.merge_list.first))
|
||||
create_info.merge_list.first))
|
||||
goto error; /* purecov: inspected */
|
||||
if (grant_option)
|
||||
{
|
||||
@@ -2690,13 +2749,13 @@ unsent_create_error:
|
||||
}
|
||||
}
|
||||
/* Don't yet allow changing of symlinks with ALTER TABLE */
|
||||
if (lex->create_info.data_file_name)
|
||||
if (create_info.data_file_name)
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
|
||||
"DATA DIRECTORY option ignored");
|
||||
if (lex->create_info.index_file_name)
|
||||
if (create_info.index_file_name)
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
|
||||
"INDEX DIRECTORY option ignored");
|
||||
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
|
||||
create_info.data_file_name= create_info.index_file_name= NULL;
|
||||
/* ALTER TABLE ends previous transaction */
|
||||
if (end_active_trans(thd))
|
||||
res= -1;
|
||||
@@ -2704,12 +2763,12 @@ unsent_create_error:
|
||||
{
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= mysql_alter_table(thd, select_lex->db, lex->name,
|
||||
&lex->create_info,
|
||||
tables, lex->create_list,
|
||||
lex->key_list,
|
||||
&create_info,
|
||||
tables,
|
||||
&alter_info,
|
||||
select_lex->order_list.elements,
|
||||
(ORDER *) select_lex->order_list.first,
|
||||
lex->duplicates, lex->ignore, &lex->alter_info);
|
||||
lex->duplicates, lex->ignore);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2846,7 +2905,7 @@ unsent_create_error:
|
||||
goto error; /* purecov: inspected */
|
||||
thd->enable_slow_log= opt_log_slow_admin_statements;
|
||||
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
|
||||
mysql_recreate_table(thd, tables, 1) :
|
||||
mysql_recreate_table(thd, tables) :
|
||||
mysql_optimize_table(thd, tables, &lex->check_opt);
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
@@ -3123,14 +3182,6 @@ unsent_create_error:
|
||||
res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
|
||||
}
|
||||
break;
|
||||
case SQLCOM_DROP_INDEX:
|
||||
if (check_one_table_access(thd, INDEX_ACL, tables))
|
||||
goto error; /* purecov: inspected */
|
||||
if (end_active_trans(thd))
|
||||
res= -1;
|
||||
else
|
||||
res = mysql_drop_index(thd, tables, &lex->alter_info);
|
||||
break;
|
||||
case SQLCOM_SHOW_DATABASES:
|
||||
#if defined(DONT_ALLOW_SHOW_COMMANDS)
|
||||
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
|
||||
@@ -3363,6 +3414,12 @@ purposes internal to the MySQL server", MYF(0));
|
||||
break;
|
||||
case SQLCOM_CREATE_DB:
|
||||
{
|
||||
/*
|
||||
As mysql_create_db() may modify HA_CREATE_INFO structure passed to
|
||||
it, we need to use a copy of LEX::create_info to make execution
|
||||
prepared statement- safe.
|
||||
*/
|
||||
HA_CREATE_INFO create_info(lex->create_info);
|
||||
if (end_active_trans(thd))
|
||||
{
|
||||
res= -1;
|
||||
@@ -3393,7 +3450,7 @@ purposes internal to the MySQL server", MYF(0));
|
||||
if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
|
||||
break;
|
||||
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name),
|
||||
&lex->create_info, 0);
|
||||
&create_info, 0);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DROP_DB:
|
||||
@@ -4443,14 +4500,16 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
||||
if (type_modifier & PRI_KEY_FLAG)
|
||||
{
|
||||
lex->col_list.push_back(new key_part_spec(field_name,0));
|
||||
lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
|
||||
0, lex->col_list));
|
||||
lex->alter_info.key_list.push_back(new Key(Key::PRIMARY, NullS,
|
||||
HA_KEY_ALG_UNDEF, 0,
|
||||
lex->col_list));
|
||||
lex->col_list.empty();
|
||||
}
|
||||
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
|
||||
{
|
||||
lex->col_list.push_back(new key_part_spec(field_name,0));
|
||||
lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, 0,
|
||||
lex->alter_info.key_list.push_back(new Key(Key::UNIQUE, NullS,
|
||||
HA_KEY_ALG_UNDEF, 0,
|
||||
lex->col_list));
|
||||
lex->col_list.empty();
|
||||
}
|
||||
@@ -4778,7 +4837,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
|
||||
new_field->sql_type,
|
||||
new_field->length);
|
||||
new_field->char_length= new_field->length;
|
||||
lex->create_list.push_back(new_field);
|
||||
lex->alter_info.create_list.push_back(new_field);
|
||||
lex->last_field=new_field;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -5458,57 +5517,6 @@ Item * all_any_subquery_creator(Item *left_expr,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
|
||||
the proper arguments. This isn't very fast but it should work for most
|
||||
cases.
|
||||
|
||||
In the future ALTER TABLE will notice that only added indexes
|
||||
and create these one by one for the existing table without having to do
|
||||
a full rebuild.
|
||||
|
||||
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
|
||||
*/
|
||||
|
||||
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
|
||||
{
|
||||
List<create_field> fields;
|
||||
ALTER_INFO alter_info;
|
||||
alter_info.flags= ALTER_ADD_INDEX;
|
||||
alter_info.is_simple= 0;
|
||||
HA_CREATE_INFO create_info;
|
||||
DBUG_ENTER("mysql_create_index");
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
create_info.row_type= ROW_TYPE_NOT_USED;
|
||||
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
|
||||
&create_info, table_list,
|
||||
fields, keys, 0, (ORDER*)0,
|
||||
DUP_ERROR, 0, &alter_info));
|
||||
}
|
||||
|
||||
|
||||
int mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info)
|
||||
{
|
||||
List<create_field> fields;
|
||||
List<Key> keys;
|
||||
HA_CREATE_INFO create_info;
|
||||
DBUG_ENTER("mysql_drop_index");
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
create_info.row_type= ROW_TYPE_NOT_USED;
|
||||
alter_info->clear();
|
||||
alter_info->flags= ALTER_DROP_INDEX;
|
||||
alter_info->is_simple= 0;
|
||||
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
|
||||
&create_info, table_list,
|
||||
fields, keys, 0, (ORDER*)0,
|
||||
DUP_ERROR, 0, alter_info));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Multi update query pre-check
|
||||
|
||||
|
||||
@@ -845,7 +845,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
|
||||
}
|
||||
|
||||
int mysqld_show_create_db(THD *thd, char *dbname,
|
||||
HA_CREATE_INFO *create_info)
|
||||
const HA_CREATE_INFO *create_info)
|
||||
{
|
||||
int length;
|
||||
char path[FN_REFLEN];
|
||||
|
||||
347
sql/sql_table.cc
347
sql/sql_table.cc
@@ -456,8 +456,7 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
|
||||
mysql_prepare_table()
|
||||
thd Thread object
|
||||
create_info Create information (like MAX_ROWS)
|
||||
fields List of fields to create
|
||||
keys List of keys to create
|
||||
alter_info List of columns and indexes to create
|
||||
|
||||
DESCRIPTION
|
||||
Prepares the table and key structures for table creation.
|
||||
@@ -468,8 +467,8 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
|
||||
*/
|
||||
|
||||
int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
List<create_field> &fields,
|
||||
List<Key> &keys, bool tmp_table, uint &db_options,
|
||||
Alter_info *alter_info,
|
||||
bool tmp_table, uint &db_options,
|
||||
handler *file, KEY *&key_info_buffer,
|
||||
uint *key_count, int select_field_count)
|
||||
{
|
||||
@@ -482,10 +481,11 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
int timestamps= 0, timestamps_with_niladic= 0;
|
||||
int field_no,dup_no;
|
||||
int select_field_pos,auto_increment=0;
|
||||
List_iterator<create_field> it(alter_info->create_list);
|
||||
List_iterator<create_field> it2(alter_info->create_list);
|
||||
DBUG_ENTER("mysql_prepare_table");
|
||||
|
||||
List_iterator<create_field> it(fields),it2(fields);
|
||||
select_field_pos=fields.elements - select_field_count;
|
||||
select_field_pos= alter_info->create_list.elements - select_field_count;
|
||||
null_fields=blob_columns=0;
|
||||
|
||||
for (field_no=0; (sql_field=it++) ; field_no++)
|
||||
@@ -883,7 +883,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
|
||||
/* Create keys */
|
||||
|
||||
List_iterator<Key> key_iterator(keys), key_iterator2(keys);
|
||||
List_iterator<Key> key_iterator(alter_info->key_list);
|
||||
List_iterator<Key> key_iterator2(alter_info->key_list);
|
||||
uint key_parts=0, fk_key_count=0;
|
||||
bool primary_key=0,unique_key=0;
|
||||
Key *key, *key2;
|
||||
@@ -1336,20 +1337,24 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
thd Thread object
|
||||
db Database
|
||||
table_name Table name
|
||||
create_info Create information (like MAX_ROWS)
|
||||
fields List of fields to create
|
||||
keys List of keys to create
|
||||
create_info [in/out] Create information (like MAX_ROWS)
|
||||
alter_info [in/out] List of columns and indexes to create
|
||||
tmp_table Set to 1 if this is an internal temporary table
|
||||
(From ALTER TABLE)
|
||||
|
||||
DESCRIPTION
|
||||
If one creates a temporary table, this is automaticly opened
|
||||
If one creates a temporary table, this is automatically opened
|
||||
|
||||
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.
|
||||
|
||||
Note that structures passed as 'create_info' and 'alter_info' parameters
|
||||
may be modified by this function. It is responsibility of the caller to
|
||||
make a copy of create_info in order to provide correct execution in
|
||||
prepared statements/stored routines.
|
||||
|
||||
RETURN VALUES
|
||||
0 ok
|
||||
-1 error
|
||||
@@ -1357,8 +1362,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
|
||||
|
||||
int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
List<create_field> &fields,
|
||||
List<Key> &keys,bool tmp_table,
|
||||
Alter_info *alter_info,
|
||||
bool tmp_table,
|
||||
uint select_field_count)
|
||||
{
|
||||
char path[FN_REFLEN];
|
||||
@@ -1371,7 +1376,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
DBUG_ENTER("mysql_create_table");
|
||||
|
||||
/* Check for duplicate fields and check type of table to create */
|
||||
if (!fields.elements)
|
||||
if (!alter_info->create_list.elements)
|
||||
{
|
||||
my_error(ER_TABLE_MUST_HAVE_COLUMNS,MYF(0));
|
||||
DBUG_RETURN(-1);
|
||||
@@ -1423,8 +1428,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
create_info->default_table_charset= db_info.default_table_charset;
|
||||
}
|
||||
|
||||
if (mysql_prepare_table(thd, create_info, fields,
|
||||
keys, tmp_table, db_options, file,
|
||||
if (mysql_prepare_table(thd, create_info, alter_info, tmp_table,
|
||||
db_options, file,
|
||||
key_info_buffer, &key_count,
|
||||
select_field_count))
|
||||
DBUG_RETURN(-1);
|
||||
@@ -1503,8 +1508,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
create_info->table_options=db_options;
|
||||
|
||||
if (rea_create_table(thd, path, db, table_name,
|
||||
create_info, fields, key_count,
|
||||
key_info_buffer))
|
||||
create_info, alter_info->create_list,
|
||||
key_count, key_info_buffer))
|
||||
goto end;
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
@@ -1592,8 +1597,7 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end)
|
||||
|
||||
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
const char *db, const char *name,
|
||||
List<create_field> *extra_fields,
|
||||
List<Key> *keys,
|
||||
Alter_info *alter_info,
|
||||
List<Item> *items,
|
||||
MYSQL_LOCK **lock)
|
||||
{
|
||||
@@ -1627,7 +1631,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
((Item_field *)item)->field :
|
||||
(Field*) 0))))
|
||||
DBUG_RETURN(0);
|
||||
extra_fields->push_back(cr_field);
|
||||
alter_info->create_list.push_back(cr_field);
|
||||
}
|
||||
/* create and lock table */
|
||||
/* QQ: create and open should be done atomic ! */
|
||||
@@ -1641,8 +1645,8 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
open_table().
|
||||
*/
|
||||
tmp_disable_binlog(thd);
|
||||
if (!mysql_create_table(thd,db,name,create_info,*extra_fields,
|
||||
*keys,0,select_field_count))
|
||||
if (!mysql_create_table(thd, db, name, create_info, alter_info,
|
||||
0, select_field_count))
|
||||
{
|
||||
if (!(table=open_table(thd,db,name,name,(bool*) 0)))
|
||||
quick_rm_table(create_info->db_type,db,table_case_name(create_info,name));
|
||||
@@ -2146,6 +2150,7 @@ send_result_message:
|
||||
|
||||
case HA_ADMIN_TRY_ALTER:
|
||||
{
|
||||
my_bool save_no_send_ok= thd->net.no_send_ok;
|
||||
/*
|
||||
This is currently used only by InnoDB. ha_innobase::optimize() answers
|
||||
"try with alter", so here we close the table, do an ALTER TABLE,
|
||||
@@ -2155,7 +2160,9 @@ send_result_message:
|
||||
TABLE_LIST *save_next= table->next;
|
||||
table->next= 0;
|
||||
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
|
||||
result_code= mysql_recreate_table(thd, table, 0);
|
||||
thd->net.no_send_ok= TRUE;
|
||||
result_code= mysql_recreate_table(thd, table);
|
||||
thd->net.no_send_ok= save_no_send_ok;
|
||||
reenable_binlog(thd);
|
||||
close_thread_tables(thd);
|
||||
if (!result_code) // recreation went ok
|
||||
@@ -2635,206 +2642,6 @@ err:
|
||||
}
|
||||
|
||||
|
||||
#ifdef NOT_USED
|
||||
/*
|
||||
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
|
||||
the proper arguments. This isn't very fast but it should work for most
|
||||
cases.
|
||||
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
|
||||
*/
|
||||
|
||||
int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
|
||||
{
|
||||
List<create_field> fields;
|
||||
List<Alter_drop> drop;
|
||||
List<Alter_column> alter;
|
||||
HA_CREATE_INFO create_info;
|
||||
int rc;
|
||||
uint idx;
|
||||
uint db_options;
|
||||
uint key_count;
|
||||
TABLE *table;
|
||||
Field **f_ptr;
|
||||
KEY *key_info_buffer;
|
||||
char path[FN_REFLEN+1];
|
||||
DBUG_ENTER("mysql_create_index");
|
||||
|
||||
/*
|
||||
Try to use online generation of index.
|
||||
This requires that all indexes can be created online.
|
||||
Otherwise, the old alter table procedure is executed.
|
||||
|
||||
Open the table to have access to the correct table handler.
|
||||
*/
|
||||
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
The add_index method takes an array of KEY structs for the new indexes.
|
||||
Preparing a new table structure generates this array.
|
||||
It needs a list with all fields of the table, which does not need to
|
||||
be correct in every respect. The field names are important.
|
||||
*/
|
||||
for (f_ptr= table->field; *f_ptr; f_ptr++)
|
||||
{
|
||||
create_field *c_fld= new create_field(*f_ptr, *f_ptr);
|
||||
c_fld->unireg_check= Field::NONE; /*avoid multiple auto_increments*/
|
||||
fields.push_back(c_fld);
|
||||
}
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
db_options= 0;
|
||||
if (mysql_prepare_table(thd, &create_info, fields,
|
||||
keys, /*tmp_table*/ 0, db_options, table->file,
|
||||
key_info_buffer, key_count,
|
||||
/*select_field_count*/ 0))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
Check if all keys can be generated with the add_index method.
|
||||
If anyone cannot, then take the old way.
|
||||
*/
|
||||
for (idx=0; idx< key_count; idx++)
|
||||
{
|
||||
DBUG_PRINT("info", ("creating index %s", key_info_buffer[idx].name));
|
||||
if (!(table->file->index_ddl_flags(key_info_buffer+idx)&
|
||||
(HA_DDL_ONLINE| HA_DDL_WITH_LOCK)))
|
||||
break ;
|
||||
}
|
||||
if ((idx < key_count)|| !key_count)
|
||||
{
|
||||
/* Re-initialize the create_info, which was changed by prepare table. */
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
/* Cleanup the fields list. We do not want to create existing fields. */
|
||||
fields.delete_elements();
|
||||
if (real_alter_table(thd, table_list->db, table_list->real_name,
|
||||
&create_info, table_list, table,
|
||||
fields, keys, drop, alter, 0, (ORDER*)0,
|
||||
ALTER_ADD_INDEX, DUP_ERROR))
|
||||
/* Don't need to free((gptr) key_info_buffer);*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (table->file->add_index(table, key_info_buffer, key_count)||
|
||||
build_table_path(path, sizeof(path), table_list->db,
|
||||
(lower_case_table_names == 2) ?
|
||||
table_list->alias : table_list->real_name,
|
||||
reg_ext) == 0 ||
|
||||
mysql_create_frm(thd, path, &create_info,
|
||||
fields, key_count, key_info_buffer, table->file))
|
||||
/* don't need to free((gptr) key_info_buffer);*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
/* don't need to free((gptr) key_info_buffer);*/
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
|
||||
List<Alter_drop> &drop)
|
||||
{
|
||||
List<create_field> fields;
|
||||
List<Key> keys;
|
||||
List<Alter_column> alter;
|
||||
HA_CREATE_INFO create_info;
|
||||
uint idx;
|
||||
uint db_options;
|
||||
uint key_count;
|
||||
uint *key_numbers;
|
||||
TABLE *table;
|
||||
Field **f_ptr;
|
||||
KEY *key_info;
|
||||
KEY *key_info_buffer;
|
||||
char path[FN_REFLEN];
|
||||
DBUG_ENTER("mysql_drop_index");
|
||||
|
||||
/*
|
||||
Try to use online generation of index.
|
||||
This requires that all indexes can be created online.
|
||||
Otherwise, the old alter table procedure is executed.
|
||||
|
||||
Open the table to have access to the correct table handler.
|
||||
*/
|
||||
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/*
|
||||
The drop_index method takes an array of key numbers.
|
||||
It cannot get more entries than keys in the table.
|
||||
*/
|
||||
key_numbers= (uint*) thd->alloc(sizeof(uint*)*table->keys);
|
||||
key_count= 0;
|
||||
|
||||
/*
|
||||
Get the number of each key and check if it can be created online.
|
||||
*/
|
||||
List_iterator<Alter_drop> drop_it(drop);
|
||||
Alter_drop *drop_key;
|
||||
while ((drop_key= drop_it++))
|
||||
{
|
||||
/* Find the key in the table. */
|
||||
key_info=table->key_info;
|
||||
for (idx=0; idx< table->keys; idx++, key_info++)
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info, key_info->name, drop_key->name))
|
||||
break;
|
||||
}
|
||||
if (idx>= table->keys)
|
||||
{
|
||||
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop_key->name);
|
||||
/*don't need to free((gptr) key_numbers);*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
/*
|
||||
Check if the key can be generated with the add_index method.
|
||||
If anyone cannot, then take the old way.
|
||||
*/
|
||||
DBUG_PRINT("info", ("dropping index %s", table->key_info[idx].name));
|
||||
if (!(table->file->index_ddl_flags(table->key_info+idx)&
|
||||
(HA_DDL_ONLINE| HA_DDL_WITH_LOCK)))
|
||||
break ;
|
||||
key_numbers[key_count++]= idx;
|
||||
}
|
||||
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.default_table_charset= thd->variables.collation_database;
|
||||
|
||||
if ((drop_key)|| (drop.elements<= 0))
|
||||
{
|
||||
if (real_alter_table(thd, table_list->db, table_list->real_name,
|
||||
&create_info, table_list, table,
|
||||
fields, keys, drop, alter, 0, (ORDER*)0,
|
||||
ALTER_DROP_INDEX, DUP_ERROR))
|
||||
/*don't need to free((gptr) key_numbers);*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_options= 0;
|
||||
if (table->file->drop_index(table, key_numbers, key_count)||
|
||||
mysql_prepare_table(thd, &create_info, fields,
|
||||
keys, /*tmp_table*/ 0, db_options, table->file,
|
||||
key_info_buffer, key_count,
|
||||
/*select_field_count*/ 0)||
|
||||
build_table_path(path, sizeof(path), table_list->db,
|
||||
(lower_case_table_names == 2) ?
|
||||
table_list->alias : table_list->real_name,
|
||||
reg_ext) == 0 ||
|
||||
mysql_create_frm(thd, path, &create_info,
|
||||
fields, key_count, key_info_buffer, table->file))
|
||||
/*don't need to free((gptr) key_numbers);*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/*don't need to free((gptr) key_numbers);*/
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#endif /* NOT_USED */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2887,15 +2694,21 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
|
||||
|
||||
/*
|
||||
Alter table
|
||||
|
||||
|
||||
NOTE
|
||||
The structures passed as 'create_info' and 'alter_info' parameters may
|
||||
be modified by this function. It is responsibility of the caller to make
|
||||
a copy of create_info in order to provide correct execution in prepared
|
||||
statements/stored routines.
|
||||
*/
|
||||
|
||||
int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
HA_CREATE_INFO *create_info,
|
||||
TABLE_LIST *table_list,
|
||||
List<create_field> &fields, List<Key> &keys,
|
||||
Alter_info *alter_info,
|
||||
uint order_num, ORDER *order,
|
||||
enum enum_duplicates handle_duplicates, bool ignore,
|
||||
ALTER_INFO *alter_info, bool do_send_ok)
|
||||
enum enum_duplicates handle_duplicates, bool ignore)
|
||||
{
|
||||
TABLE *table,*new_table;
|
||||
int error;
|
||||
@@ -3064,7 +2877,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
if (do_send_ok)
|
||||
send_ok(thd);
|
||||
}
|
||||
else if (error > 0)
|
||||
@@ -3091,10 +2903,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
|
||||
restore_record(table,default_values); // Empty record for DEFAULT
|
||||
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
|
||||
List_iterator<create_field> def_it(fields);
|
||||
List_iterator<create_field> def_it(alter_info->create_list);
|
||||
List_iterator<Alter_column> alter_it(alter_info->alter_list);
|
||||
List<create_field> create_list; // Add new fields here
|
||||
List<Key> key_list; // Add new keys here
|
||||
Alter_info new_info; // Add new columns and indexes here
|
||||
create_field *def;
|
||||
|
||||
/*
|
||||
@@ -3140,13 +2951,13 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
def->field=field;
|
||||
if (!def->after)
|
||||
{
|
||||
create_list.push_back(def);
|
||||
new_info.create_list.push_back(def);
|
||||
def_it.remove();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Use old field value
|
||||
create_list.push_back(def=new create_field(field,field));
|
||||
new_info.create_list.push_back(def= new create_field(field, field));
|
||||
alter_it.rewind(); // Change default if ALTER
|
||||
Alter_column *alter;
|
||||
while ((alter=alter_it++))
|
||||
@@ -3167,7 +2978,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
}
|
||||
}
|
||||
def_it.rewind();
|
||||
List_iterator<create_field> find_it(create_list);
|
||||
List_iterator<create_field> find_it(new_info.create_list);
|
||||
while ((def=def_it++)) // Add new columns
|
||||
{
|
||||
if (def->change && ! def->field)
|
||||
@@ -3176,9 +2987,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (!def->after)
|
||||
create_list.push_back(def);
|
||||
new_info.create_list.push_back(def);
|
||||
else if (def->after == first_keyword)
|
||||
create_list.push_front(def);
|
||||
new_info.create_list.push_front(def);
|
||||
else
|
||||
{
|
||||
create_field *find;
|
||||
@@ -3202,7 +3013,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
table_name);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (!create_list.elements)
|
||||
if (!new_info.create_list.elements)
|
||||
{
|
||||
my_error(ER_CANT_REMOVE_ALL_FIELDS,MYF(0));
|
||||
DBUG_RETURN(-1);
|
||||
@@ -3213,8 +3024,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
for which some fields exists.
|
||||
*/
|
||||
|
||||
List_iterator<Key> key_it(keys);
|
||||
List_iterator<create_field> field_it(create_list);
|
||||
List_iterator<Key> key_it(alter_info->key_list);
|
||||
List_iterator<create_field> field_it(new_info.create_list);
|
||||
List<key_part_spec> key_parts;
|
||||
|
||||
KEY *key_info=table->key_info;
|
||||
@@ -3272,24 +3083,37 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
key_part_length));
|
||||
}
|
||||
if (key_parts.elements)
|
||||
key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
|
||||
(key_info->flags & HA_NOSAME ?
|
||||
(!my_strcasecmp(system_charset_info,
|
||||
key_name, primary_key_name) ?
|
||||
Key::PRIMARY : Key::UNIQUE) :
|
||||
(key_info->flags & HA_FULLTEXT ?
|
||||
Key::FULLTEXT : Key::MULTIPLE)),
|
||||
key_name,
|
||||
{
|
||||
Key *key;
|
||||
enum Key::Keytype key_type;
|
||||
|
||||
if (key_info->flags & HA_SPATIAL)
|
||||
key_type= Key::SPATIAL;
|
||||
else if (key_info->flags & HA_NOSAME)
|
||||
{
|
||||
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
|
||||
key_type= Key::PRIMARY;
|
||||
else
|
||||
key_type= Key::UNIQUE;
|
||||
}
|
||||
else if (key_info->flags & HA_FULLTEXT)
|
||||
key_type= Key::FULLTEXT;
|
||||
else
|
||||
key_type= Key::MULTIPLE;
|
||||
|
||||
key= new Key(key_type, key_name,
|
||||
key_info->algorithm,
|
||||
test(key_info->flags & HA_GENERATED_KEY),
|
||||
key_parts));
|
||||
key_parts);
|
||||
new_info.key_list.push_back(key);
|
||||
}
|
||||
}
|
||||
{
|
||||
Key *key;
|
||||
while ((key=key_it++)) // Add new keys
|
||||
{
|
||||
if (key->type != Key::FOREIGN_KEY)
|
||||
key_list.push_back(key);
|
||||
new_info.key_list.push_back(key);
|
||||
if (key->name &&
|
||||
!my_strcasecmp(system_charset_info,key->name,primary_key_name))
|
||||
{
|
||||
@@ -3393,7 +3217,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
/* We don't log the statement, it will be logged later. */
|
||||
tmp_disable_binlog(thd);
|
||||
error= mysql_create_table(thd, new_db, tmp_name,
|
||||
create_info,create_list,key_list,1,0);
|
||||
create_info, &new_info, 1, 0);
|
||||
reenable_binlog(thd);
|
||||
if (error)
|
||||
DBUG_RETURN(error);
|
||||
@@ -3422,7 +3246,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
next_insert_id=thd->next_insert_id; // Remember for loggin
|
||||
copied=deleted=0;
|
||||
if (!new_table->is_view)
|
||||
error=copy_data_between_tables(table,new_table,create_list,
|
||||
error= copy_data_between_tables(table, new_table, new_info.create_list,
|
||||
handle_duplicates, ignore,
|
||||
order_num, order, &copied, &deleted,
|
||||
alter_info->keys_onoff);
|
||||
@@ -3637,7 +3461,6 @@ end_temporary:
|
||||
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
|
||||
(ulong) (copied + deleted), (ulong) deleted,
|
||||
(ulong) thd->cuted_fields);
|
||||
if (do_send_ok)
|
||||
send_ok(thd, copied + deleted, 0L, tmp_name);
|
||||
thd->some_tables_deleted=0;
|
||||
DBUG_RETURN(0);
|
||||
@@ -3828,30 +3651,26 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
||||
mysql_recreate_table()
|
||||
thd Thread handler
|
||||
tables Tables to recreate
|
||||
do_send_ok If we should send_ok() or leave it to caller
|
||||
|
||||
RETURN
|
||||
Like mysql_alter_table().
|
||||
*/
|
||||
int mysql_recreate_table(THD *thd, TABLE_LIST *table_list,
|
||||
bool do_send_ok)
|
||||
int mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
DBUG_ENTER("mysql_recreate_table");
|
||||
LEX *lex= thd->lex;
|
||||
HA_CREATE_INFO create_info;
|
||||
lex->create_list.empty();
|
||||
lex->key_list.empty();
|
||||
lex->col_list.empty();
|
||||
lex->alter_info.reset();
|
||||
lex->alter_info.is_simple= 0; // Force full recreate
|
||||
Alter_info alter_info;
|
||||
|
||||
DBUG_ENTER("mysql_recreate_table");
|
||||
|
||||
bzero((char*) &create_info,sizeof(create_info));
|
||||
create_info.db_type=DB_TYPE_DEFAULT;
|
||||
create_info.row_type=ROW_TYPE_DEFAULT;
|
||||
create_info.default_table_charset=default_charset_info;
|
||||
alter_info.is_simple= 0; // Force full recreate
|
||||
DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
|
||||
table_list, lex->create_list,
|
||||
lex->key_list, 0, (ORDER *) 0,
|
||||
DUP_ERROR, 0, &lex->alter_info, do_send_ok));
|
||||
table_list, &alter_info,
|
||||
0, (ORDER *) 0, DUP_ERROR, 0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1021,8 +1021,7 @@ create:
|
||||
TL_READ_NO_INSERT:
|
||||
TL_READ)))
|
||||
YYABORT;
|
||||
lex->create_list.empty();
|
||||
lex->key_list.empty();
|
||||
lex->alter_info.reset();
|
||||
lex->col_list.empty();
|
||||
lex->change=NullS;
|
||||
bzero((char*) &lex->create_info,sizeof(lex->create_info));
|
||||
@@ -1040,16 +1039,18 @@ create:
|
||||
if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
|
||||
TL_OPTION_UPDATING))
|
||||
YYABORT;
|
||||
lex->create_list.empty();
|
||||
lex->key_list.empty();
|
||||
lex->alter_info.reset();
|
||||
lex->alter_info.is_simple= 0;
|
||||
lex->alter_info.flags= ALTER_ADD_INDEX;
|
||||
lex->col_list.empty();
|
||||
lex->change=NullS;
|
||||
}
|
||||
'(' key_list ')'
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
Key *key= new Key($2, $4.str, $5, 0, lex->col_list);
|
||||
|
||||
lex->key_list.push_back(new Key($2,$4.str, $5, 0, lex->col_list));
|
||||
lex->alter_info.key_list.push_back(key);
|
||||
lex->col_list.empty();
|
||||
}
|
||||
| CREATE DATABASE opt_if_not_exists ident
|
||||
@@ -1305,29 +1306,34 @@ key_def:
|
||||
key_type opt_ident key_alg '(' key_list ')'
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list));
|
||||
Key *key= new Key($1, $2, $3, 0, lex->col_list);
|
||||
lex->alter_info.key_list.push_back(key);
|
||||
|
||||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||||
}
|
||||
| opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')'
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
const char *key_name= $3 ? $3:$1;
|
||||
lex->key_list.push_back(new Key($2, key_name, $4, 0,
|
||||
lex->col_list));
|
||||
Key *key= new Key($2, key_name, $4, 0, lex->col_list);
|
||||
lex->alter_info.key_list.push_back(key);
|
||||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||||
}
|
||||
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list,
|
||||
const char *key_name= $4 ? $4 : $1;
|
||||
Key *key= new foreign_key(key_name, lex->col_list,
|
||||
$8,
|
||||
lex->ref_list,
|
||||
lex->fk_delete_opt,
|
||||
lex->fk_update_opt,
|
||||
lex->fk_match_option));
|
||||
lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
|
||||
lex->fk_match_option);
|
||||
lex->alter_info.key_list.push_back(key);
|
||||
key= new Key(Key::MULTIPLE, key_name,
|
||||
HA_KEY_ALG_UNDEF, 1,
|
||||
lex->col_list));
|
||||
lex->col_list);
|
||||
lex->alter_info.key_list.push_back(key);
|
||||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||||
}
|
||||
| constraint opt_check_constraint
|
||||
@@ -1850,8 +1856,6 @@ alter:
|
||||
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
|
||||
TL_OPTION_UPDATING))
|
||||
YYABORT;
|
||||
lex->create_list.empty();
|
||||
lex->key_list.empty();
|
||||
lex->col_list.empty();
|
||||
lex->select_lex.init_order();
|
||||
lex->select_lex.db=lex->name=0;
|
||||
@@ -1860,8 +1864,6 @@ alter:
|
||||
lex->create_info.default_table_charset= NULL;
|
||||
lex->create_info.row_type= ROW_TYPE_NOT_USED;
|
||||
lex->alter_info.reset();
|
||||
lex->alter_info.is_simple= 1;
|
||||
lex->alter_info.flags= 0;
|
||||
}
|
||||
alter_list
|
||||
{}
|
||||
@@ -4030,7 +4032,9 @@ drop:
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->sql_command= SQLCOM_DROP_INDEX;
|
||||
lex->alter_info.drop_list.empty();
|
||||
lex->alter_info.reset();
|
||||
lex->alter_info.is_simple= 0;
|
||||
lex->alter_info.flags= ALTER_DROP_INDEX;
|
||||
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
|
||||
$3.str));
|
||||
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
|
||||
|
||||
Reference in New Issue
Block a user