summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <hf@deer.(none)>2003-06-09 14:51:40 +0500
committerunknown <hf@deer.(none)>2003-06-09 14:51:40 +0500
commit5551e0df2a5208ead3ca7d024083e572e21f8845 (patch)
treec4c3d3834aeb10d9d1a1125f7259c7d0e1ff6bed /sql
parentf6722eac25d7ef63f31e8470d8f2cbde98931026 (diff)
parent0bb5b9eadddfc911bfaa7c6ee69db92fc7785c94 (diff)
downloadmariadb-git-5551e0df2a5208ead3ca7d024083e572e21f8845.tar.gz
Merge abotchkov@bk-internal.mysql.com:/home/bk/mysql-4.1
into deer.(none):/home/hf/work/mysql-4.1.2way BitKeeper/etc/logging_ok: auto-union include/mysql.h: Auto merged include/mysql_com.h: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am3
-rw-r--r--sql/field.cc3
-rw-r--r--sql/ha_innodb.cc222
-rw-r--r--sql/handler.cc8
-rw-r--r--sql/item.cc34
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/item_sum.cc160
-rw-r--r--sql/item_sum.h79
-rw-r--r--sql/item_uniq.h2
-rw-r--r--sql/lex.h2
-rw-r--r--sql/log.cc51
-rw-r--r--sql/log_event.cc39
-rw-r--r--sql/mysql_priv.h14
-rw-r--r--sql/mysqld.cc137
-rw-r--r--sql/net_serv.cc20
-rw-r--r--sql/protocol.cc7
-rw-r--r--sql/set_var.cc136
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/share/czech/errmsg.txt2
-rw-r--r--sql/share/danish/errmsg.txt2
-rw-r--r--sql/share/dutch/errmsg.txt2
-rw-r--r--sql/share/english/errmsg.txt2
-rw-r--r--sql/share/estonian/errmsg.txt2
-rw-r--r--sql/share/french/errmsg.txt2
-rw-r--r--sql/share/german/errmsg.txt2
-rw-r--r--sql/share/greek/errmsg.txt2
-rw-r--r--sql/share/hungarian/errmsg.txt2
-rw-r--r--sql/share/italian/errmsg.txt2
-rw-r--r--sql/share/japanese/errmsg.txt2
-rw-r--r--sql/share/korean/errmsg.txt2
-rw-r--r--sql/share/norwegian-ny/errmsg.txt2
-rw-r--r--sql/share/norwegian/errmsg.txt2
-rw-r--r--sql/share/polish/errmsg.txt2
-rw-r--r--sql/share/portuguese/errmsg.txt2
-rw-r--r--sql/share/romanian/errmsg.txt2
-rw-r--r--sql/share/russian/errmsg.txt2
-rw-r--r--sql/share/serbian/errmsg.txt2
-rw-r--r--sql/share/slovak/errmsg.txt2
-rw-r--r--sql/share/spanish/errmsg.txt2
-rw-r--r--sql/share/swedish/errmsg.txt2
-rw-r--r--sql/share/ukrainian/errmsg.txt2
-rw-r--r--sql/slave.cc38
-rw-r--r--sql/sql_acl.cc288
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_base.cc27
-rw-r--r--sql/sql_cache.cc19
-rw-r--r--sql/sql_help.cc6
-rw-r--r--sql/sql_insert.cc24
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_list.h3
-rw-r--r--sql/sql_parse.cc41
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_repl.cc8
-rw-r--r--sql/sql_select.cc489
-rw-r--r--sql/sql_select.h49
-rw-r--r--sql/sql_show.cc27
-rw-r--r--sql/sql_state.c53
-rw-r--r--sql/sql_string.cc4
-rw-r--r--sql/sql_string.h5
-rw-r--r--sql/sql_table.cc138
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc1
-rw-r--r--sql/sql_yacc.yy66
-rw-r--r--sql/time.cc56
-rw-r--r--sql/unireg.h13
66 files changed, 1771 insertions, 571 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index c3b7c77e252..7c98f1a9315 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -64,7 +64,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
thr_malloc.cc item_create.cc item_subselect.cc \
item_row.cc item_geofunc.cc \
field.cc key.cc sql_class.cc sql_list.cc \
- net_serv.cc protocol.cc lock.cc my_lock.c \
+ net_serv.cc protocol.cc sql_state.c \
+ lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
set_var.cc sql_parse.cc sql_yacc.yy \
diff --git a/sql/field.cc b/sql/field.cc
index 044684b2675..484eab5e130 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2755,6 +2755,7 @@ int Field_timestamp::store(longlong nr)
if ((nr=fix_datetime(nr)))
{
+ long not_used;
part1=(long) (nr/LL(1000000));
part2=(long) (nr - (longlong) part1*LL(1000000));
l_time.year= (int) (part1/10000L); part1%=10000L;
@@ -2763,7 +2764,7 @@ int Field_timestamp::store(longlong nr)
l_time.hour= (int) (part2/10000L); part2%=10000L;
l_time.minute=(int) part2 / 100;
l_time.second=(int) part2 % 100;
- timestamp=my_gmt_sec(&l_time);
+ timestamp=my_gmt_sec(&l_time, &not_used);
}
else
timestamp=0;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index bf4dc7e5066..1cf123dbec6 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -131,9 +131,11 @@ static void innobase_print_error(const char* db_errpfx, char* buffer);
/**********************************************************************
Releases possible search latch and InnoDB thread FIFO ticket. These should
-be released at each SQL statement end. It does no harm to release these
-also in the middle of an SQL statement. */
+be released at each SQL statement end, and also when mysqld passes the
+control to the client. It does no harm to release these also in the middle
+of an SQL statement. */
static
+inline
void
innobase_release_stat_resources(
/*============================*/
@@ -914,6 +916,11 @@ innobase_commit_low(
trx_t* trx) /* in: transaction handle */
{
#ifdef HAVE_REPLICATION
+ if (trx->conc_state == TRX_NOT_STARTED) {
+
+ return;
+ }
+
/* TODO: Guilhem should check if master_log_name, pending
etc. are right if the master log gets rotated! Possible bug here.
Comment by Heikki March 4, 2003. */
@@ -929,11 +936,13 @@ innobase_commit_low(
));
}
#endif /* HAVE_REPLICATION */
+
trx_commit_for_mysql(trx);
}
/*********************************************************************
-Commits a transaction in an InnoDB database. */
+Commits a transaction in an InnoDB database or marks an SQL statement
+ended. */
int
innobase_commit(
@@ -951,29 +960,45 @@ innobase_commit(
DBUG_ENTER("innobase_commit");
DBUG_PRINT("trans", ("ending transaction"));
- trx = check_trx_exists(thd);
+ /* The flag thd->transaction.all.innodb_active_trans is set to 1
+ in ::external_lock and ::start_stmt, and it is only set to 0 in
+ a commit or a rollback. If it is 0 we know there cannot be resources
+ to be freed and we can return immediately. */
- if (trx->auto_inc_lock) {
-
- /* If we had reserved the auto-inc lock for
- some table in this SQL statement, we release it now */
-
- srv_conc_enter_innodb(trx);
- row_unlock_table_autoinc_for_mysql(trx);
- srv_conc_exit_innodb(trx);
+ if (thd->transaction.all.innodb_active_trans == 0) {
+
+ DBUG_RETURN(0);
}
- if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
+ trx = check_trx_exists(thd);
+
+ if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
+
innobase_commit_low(trx);
- thd->transaction.all.innodb_active_trans=0;
+
+ thd->transaction.all.innodb_active_trans = 0;
+ } else {
+ if (trx->auto_inc_lock) {
+ /* If we had reserved the auto-inc lock for some
+ table in this SQL statement we release it now */
+
+ srv_conc_enter_innodb(trx);
+ row_unlock_table_autoinc_for_mysql(trx);
+ srv_conc_exit_innodb(trx);
+ }
+ /* Store the current undo_no of the transaction so that we
+ know where to roll back if we have to roll back the next
+ SQL statement */
+
+ trx_mark_sql_stat_end(trx);
}
- /* Release possible statement level resources */
+ /* Release a possible FIFO ticket and search latch */
innobase_release_stat_resources(trx);
- trx_mark_sql_stat_end(trx);
- /* Tell InnoDB server that there might be work for
- utility threads: */
+ /* Tell the InnoDB server that there might be work for utility
+ threads: */
srv_active_wake_master_thread();
@@ -1044,7 +1069,7 @@ innobase_commit_complete(
}
/*********************************************************************
-Rolls back a transaction in an InnoDB database. */
+Rolls back a transaction or the latest SQL statement in an InnoDB database. */
int
innobase_rollback(
@@ -1085,11 +1110,9 @@ innobase_rollback(
srv_conc_exit_innodb(trx);
- /* Release possible statement level resources */
+ /* Release a possible FIFO ticket and search latch */
innobase_release_stat_resources(trx);
- trx_mark_sql_stat_end(trx);
-
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
@@ -3032,6 +3055,8 @@ create_index(
KEY* key;
KEY_PART_INFO* key_part;
ulint ind_type;
+ ulint col_type;
+ ulint prefix_len;
ulint i;
DBUG_ENTER("create_index");
@@ -3059,6 +3084,27 @@ create_index(
for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i;
+ if (key_part->length != key_part->field->pack_length()) {
+ prefix_len = key_part->length;
+
+ col_type = get_innobase_type_from_mysql_type(
+ key_part->field);
+ if (col_type == DATA_INT
+ || col_type == DATA_FLOAT
+ || col_type == DATA_DOUBLE
+ || col_type == DATA_DECIMAL) {
+ fprintf(stderr,
+"InnoDB: error: MySQL is trying to create a column prefix index field\n"
+"InnoDB: on an inappropriate data type %lu. Table name %s, column name %s.\n",
+ col_type, table_name,
+ key_part->field->field_name);
+
+ prefix_len = 0;
+ }
+ } else {
+ prefix_len = 0;
+ }
+
/* We assume all fields should be sorted in ascending
order, hence the '0': */
dict_mem_index_add_field(index,
@@ -3600,8 +3646,7 @@ ha_innobase::records_in_range(
/*************************************************************************
Gives an UPPER BOUND to the number of rows in a table. This is used in
-filesort.cc and its better if the upper bound hold.
-*/
+filesort.cc. */
ha_rows
ha_innobase::estimate_number_of_rows(void)
@@ -3636,11 +3681,11 @@ ha_innobase::estimate_number_of_rows(void)
/* Calculate a minimum length for a clustered index record and from
that an upper bound for the number of rows. Since we only calculate
- new statistics in row0mysql.c when a tablehas grown
- by a threshold factor, we must add a safety factor 2 in front
- of the formula below. */
+ new statistics in row0mysql.c when a table has grown by a threshold
+ factor, we must add a safety factor 2 in front of the formula below. */
- estimate = 2 * local_data_file_length / dict_index_calc_min_rec_len(index);
+ estimate = 2 * local_data_file_length /
+ dict_index_calc_min_rec_len(index);
prebuilt->trx->op_info = (char*)"";
@@ -3667,27 +3712,36 @@ ha_innobase::scan_time()
return((double) (prebuilt->table->stat_clustered_index_size));
}
-/*
- Calculate the time it takes to read a set of ranges through and index
- This enables us to optimise reads for clustered indexes.
-*/
+/**********************************************************************
+Calculate the time it takes to read a set of ranges through an index
+This enables us to optimise reads for clustered indexes. */
-double ha_innobase::read_time(uint index, uint ranges, ha_rows rows)
+double
+ha_innobase::read_time(
+/*===================*/
+ /* out: estimated time measured in disk seeks */
+ uint index, /* in: key number */
+ uint ranges, /* in: how many ranges */
+ ha_rows rows) /* in: estimated number of rows in the ranges */
{
- ha_rows total_rows;
- double time_for_scan;
- if (index != table->primary_key)
- return handler::read_time(index, ranges, rows); // Not clustered
- if (rows <= 2)
- return (double) rows;
- /*
- Assume that the read is proportional to scan time for all rows + one
- seek per range.
- */
- time_for_scan= scan_time();
- if ((total_rows= estimate_number_of_rows()) < rows)
- return time_for_scan;
- return (ranges + (double) rows / (double) total_rows * time_for_scan);
+ ha_rows total_rows;
+ double time_for_scan;
+
+ if (index != table->primary_key)
+ return handler::read_time(index, ranges, rows); // Not clustered
+
+ if (rows <= 2)
+ return (double) rows;
+
+ /* Assume that the read time is proportional to the scan time for all
+ rows + at most one seek per range. */
+
+ time_for_scan= scan_time();
+
+ if ((total_rows= estimate_number_of_rows()) < rows)
+ return time_for_scan;
+
+ return (ranges + (double) rows / (double) total_rows * time_for_scan);
}
/*************************************************************************
@@ -4040,10 +4094,10 @@ ha_innobase::reset(void)
}
/**********************************************************************
-Inside LOCK TABLES MySQL will not call external_lock() between SQL
-statements. It will call this function at the start of each SQL statement.
-Note also a spacial case: if a temporary table is created inside LOCK
-TABLES, MySQL has not called external_lock() at all on that table. */
+MySQL calls this function at the start of each SQL statement. Inside LOCK
+TABLES the ::external_lock method does not work to mark SQL statement
+borders. Note also a special case: if a temporary table is created inside
+LOCK TABLES, MySQL has not called external_lock() at all on that table. */
int
ha_innobase::start_stmt(
@@ -4058,8 +4112,14 @@ ha_innobase::start_stmt(
trx = prebuilt->trx;
+ /* Here we release the search latch and the InnoDB thread FIFO ticket
+ if they were reserved. They should have been released already at the
+ end of the previous statement, but because inside LOCK TABLES the
+ lock count method does not work to mark the end of a SELECT statement,
+ that may not be the case. We MUST release the search latch before an
+ INSERT, for example. */
+
innobase_release_stat_resources(trx);
- trx_mark_sql_stat_end(trx);
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& trx->read_view) {
@@ -4082,7 +4142,8 @@ ha_innobase::start_stmt(
prebuilt->select_lock_type = LOCK_X;
}
-
+
+ /* Set the MySQL flag to mark that there is an active transaction */
thd->transaction.all.innodb_active_trans = 1;
return(0);
@@ -4146,17 +4207,20 @@ ha_innobase::external_lock(
}
if (lock_type != F_UNLCK) {
- if (trx->n_mysql_tables_in_use == 0) {
- trx_mark_sql_stat_end(trx);
- }
+ /* MySQL is setting a new table lock */
+ /* Set the MySQL flag to mark that there is an active
+ transaction */
thd->transaction.all.innodb_active_trans = 1;
+
trx->n_mysql_tables_in_use++;
prebuilt->mysql_has_locked = TRUE;
- trx->isolation_level = innobase_map_isolation_level(
+ if (trx->n_mysql_tables_in_use == 1) {
+ trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
+ }
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE) {
@@ -4172,37 +4236,44 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked++;
}
- } else {
- trx->n_mysql_tables_in_use--;
- prebuilt->mysql_has_locked = FALSE;
- auto_inc_counter_for_this_stat = 0;
- if (trx->n_mysql_tables_in_use == 0) {
+ DBUG_RETURN(error);
+ }
- trx->mysql_n_tables_locked = 0;
+ /* MySQL is releasing a table lock */
- prebuilt->used_in_HANDLER = FALSE;
+ trx->n_mysql_tables_in_use--;
+ prebuilt->mysql_has_locked = FALSE;
+ auto_inc_counter_for_this_stat = 0;
- /* Here we release the search latch and InnoDB
- thread FIFO ticket if they were reserved. */
+ /* If the MySQL lock count drops to zero we know that the current SQL
+ statement has ended */
- innobase_release_stat_resources(trx);
+ if (trx->n_mysql_tables_in_use == 0) {
+ trx->mysql_n_tables_locked = 0;
+ prebuilt->used_in_HANDLER = FALSE;
+
+ if (!(thd->options
+ & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
+ if (thd->transaction.all.innodb_active_trans != 0) {
+ innobase_commit(thd, trx);
+ }
+ } else {
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& trx->read_view) {
- /* At low transaction isolation levels we let
+ /* At low transaction isolation levels we let
each consistent read set its own snapshot */
- read_view_close_for_mysql(trx);
+ read_view_close_for_mysql(trx);
}
-
- if (!(thd->options
- & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
-
- innobase_commit(thd, trx);
- }
}
+
+ /* Here we release the search latch and the InnoDB thread FIFO
+ ticket if they were reserved. */
+
+ innobase_release_stat_resources(trx);
}
DBUG_RETURN(error);
@@ -4513,4 +4584,3 @@ ha_innobase::get_auto_increment()
}
#endif /* HAVE_INNOBASE_DB */
-
diff --git a/sql/handler.cc b/sql/handler.cc
index db1857e938c..493959f0473 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -218,8 +218,12 @@ void ha_close_connection(THD* thd)
}
/*
- This is used to commit or rollback a single statement depending
- on the value of error
+ This is used to commit or rollback a single statement depending on the value
+ of error. Note that if the autocommit is on, then the following call inside
+ InnoDB will commit or rollback the whole transaction (= the statement). The
+ autocommit mechanism built into InnoDB is based on counting locks, but if
+ the user has used LOCK TABLES then that mechanism does not know to do the
+ commit.
*/
int ha_autocommit_or_rollback(THD *thd, int error)
diff --git a/sql/item.cc b/sql/item.cc
index 42a949287e5..cdd78572a0a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -117,7 +117,9 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
/*
- This function is only called when comparing items in the WHERE clause
+ This function is called when:
+ - Comparing items in the WHERE clause (when doing where optimization)
+ - When trying to find an ORDER BY/GROUP BY item in the SELECT part
*/
bool Item::eq(const Item *item, bool binary_cmp) const
@@ -243,6 +245,7 @@ void Item_field::set_field(Field *field_par)
decimals= field->decimals();
table_name=field_par->table_name;
field_name=field_par->field_name;
+ db_name=field_par->table->table_cache_key;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
set_charset(field_par->charset(), COER_IMPLICIT);
}
@@ -344,9 +347,34 @@ longlong Item_field::val_int_result()
return result_field->val_int();
}
+
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
- return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field;
+ if (item->type() != FIELD_ITEM)
+ return 0;
+
+ Item_field *item_field= (Item_field*) item;
+ if (item_field->field)
+ return item_field->field == field;
+ /*
+ We may come here when we are trying to find a function in a GROUP BY
+ clause from the select list.
+ In this case the '100 % correct' way to do this would be to first
+ run fix_fields() on the GROUP BY item and then retry this function, but
+ I think it's better to relax the checking a bit as we will in
+ most cases do the correct thing by just checking the field name.
+ (In cases where we would choose wrong we would have to generate a
+ ER_NON_UNIQ_ERROR).
+ */
+ return (!my_strcasecmp(system_charset_info, item_field->name,
+ field_name) &&
+ (!item_field->table_name ||
+ (!my_strcasecmp(table_alias_charset, item_field->table_name,
+ table_name) &&
+ (!item_field->db_name ||
+ (item_field->db_name && !my_strcasecmp(table_alias_charset,
+ item_field->db_name,
+ db_name))))));
}
table_map Item_field::used_tables() const
@@ -837,7 +865,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
}
}
- }
+ }
else if (!tmp)
return -1;
diff --git a/sql/item.h b/sql/item.h
index 2d285bbe434..5cfe8eb3907 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -29,6 +29,8 @@ class Item {
void operator=(Item &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr,size_t size) {} /*lint -e715 */
enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2a4f4e0c410..e5b73e7670f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -515,18 +515,18 @@ String *Item_func_concat_ws::val_str(String *str)
str->length(0); // QQ; Should be removed
res=str;
- // Skip until non-null and non-empty argument is found.
+ // Skip until non-null argument is found.
// If not, return the empty string
for (i=0; i < arg_count; i++)
- if ((res= args[i]->val_str(str)) && res->length())
+ if ((res= args[i]->val_str(str)))
break;
if (i == arg_count)
return &empty_string;
for (i++; i < arg_count ; i++)
{
- if (!(res2= args[i]->val_str(use_as_buff)) || !res2->length())
- continue; // Skip NULL and empty string
+ if (!(res2= args[i]->val_str(use_as_buff)))
+ continue; // Skip NULL
if (res->length() + sep_str->length() + res2->length() >
current_thd->variables.max_allowed_packet)
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index fa8bf7e6e0f..a57291702bc 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -217,11 +217,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
** reset and add of sum_func
***********************************************************************/
-void Item_sum_sum::reset()
+Item *Item_sum_sum::copy_or_same(THD* thd)
{
- null_value=1; sum=0.0; Item_sum_sum::add();
+ return new (&thd->mem_root) Item_sum_sum(thd, *this);
}
+
+bool Item_sum_sum::reset()
+{
+ null_value=1; sum=0.0;
+ return Item_sum_sum::add();
+}
+
+
bool Item_sum_sum::add()
{
sum+=args[0]->val();
@@ -230,17 +238,26 @@ bool Item_sum_sum::add()
return 0;
}
+
double Item_sum_sum::val()
{
return sum;
}
-void Item_sum_count::reset()
+Item *Item_sum_count::copy_or_same(THD* thd)
{
- count=0; add();
+ return new (&thd->mem_root) Item_sum_count(thd, *this);
}
+
+bool Item_sum_count::reset()
+{
+ count=0;
+ return add();
+}
+
+
bool Item_sum_count::add()
{
if (!args[0]->maybe_null)
@@ -260,14 +277,22 @@ longlong Item_sum_count::val_int()
}
/*
-** Avgerage
+ Avgerage
*/
-void Item_sum_avg::reset()
+Item *Item_sum_avg::copy_or_same(THD* thd)
{
- sum=0.0; count=0; Item_sum_avg::add();
+ return new (&thd->mem_root) Item_sum_avg(thd, *this);
}
+
+bool Item_sum_avg::reset()
+{
+ sum=0.0; count=0;
+ return Item_sum_avg::add();
+}
+
+
bool Item_sum_avg::add()
{
double nr=args[0]->val();
@@ -292,7 +317,7 @@ double Item_sum_avg::val()
/*
-** Standard deviation
+ Standard deviation
*/
double Item_sum_std::val()
@@ -301,15 +326,27 @@ double Item_sum_std::val()
return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
+Item *Item_sum_std::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_std(thd, *this);
+}
+
+
/*
-** variance
+ Variance
*/
-void Item_sum_variance::reset()
+Item *Item_sum_variance::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_variance(thd, *this);
+}
+
+
+bool Item_sum_variance::reset()
{
sum=sum_sqr=0.0;
count=0;
- (void) Item_sum_variance::add();
+ return Item_sum_variance::add();
}
bool Item_sum_variance::add()
@@ -440,6 +477,13 @@ Item_sum_hybrid::val_str(String *str)
return str; // Keep compiler happy
}
+
+Item *Item_sum_min::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_min(thd, *this);
+}
+
+
bool Item_sum_min::add()
{
switch (hybrid_type) {
@@ -487,6 +531,12 @@ bool Item_sum_min::add()
}
+Item *Item_sum_max::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_max(thd, *this);
+}
+
+
bool Item_sum_max::add()
{
switch (hybrid_type) {
@@ -541,11 +591,19 @@ longlong Item_sum_bit::val_int()
return (longlong) bits;
}
-void Item_sum_bit::reset()
+
+bool Item_sum_bit::reset()
+{
+ bits=reset_bits;
+ return add();
+}
+
+Item *Item_sum_or::copy_or_same(THD* thd)
{
- bits=reset_bits; add();
+ return new (&thd->mem_root) Item_sum_or(thd, *this);
}
+
bool Item_sum_or::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
@@ -554,6 +612,12 @@ bool Item_sum_or::add()
return 0;
}
+Item *Item_sum_and::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_and(thd, *this);
+}
+
+
bool Item_sum_and::add()
{
ulonglong value= (ulonglong) args[0]->val_int();
@@ -1032,12 +1096,21 @@ Item_sum_count_distinct::~Item_sum_count_distinct()
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref)
{
- if (Item_sum_num::fix_fields(thd, tables, ref) ||
- !(tmp_table_param= new TMP_TABLE_PARAM))
+ if (Item_sum_num::fix_fields(thd, tables, ref))
return 1;
return 0;
}
+/* This is used by rollup to create a separate usable copy of the function */
+
+void Item_sum_count_distinct::make_unique()
+{
+ table=0;
+ original= 0;
+ tree= &tree_base;
+}
+
+
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
@@ -1045,6 +1118,9 @@ bool Item_sum_count_distinct::setup(THD *thd)
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
return 1;
+ if (!(tmp_table_param= new TMP_TABLE_PARAM))
+ return 1;
+
/* Create a table with an unique key over all parameters */
for (uint i=0; i < arg_count ; i++)
{
@@ -1192,7 +1268,14 @@ int Item_sum_count_distinct::tree_to_myisam()
return 0;
}
-void Item_sum_count_distinct::reset()
+
+Item *Item_sum_count_distinct::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_count_distinct(thd, *this);
+}
+
+
+bool Item_sum_count_distinct::reset()
{
if (use_tree)
reset_tree(tree);
@@ -1202,7 +1285,7 @@ void Item_sum_count_distinct::reset()
table->file->delete_all_rows();
table->file->extra(HA_EXTRA_WRITE_CACHE);
}
- (void) add();
+ return add();
}
bool Item_sum_count_distinct::add()
@@ -1265,11 +1348,11 @@ longlong Item_sum_count_distinct::val_int()
#ifdef HAVE_DLOPEN
-void Item_udf_sum::reset()
+bool Item_udf_sum::reset()
{
DBUG_ENTER("Item_udf_sum::reset");
udf.reset(&null_value);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
bool Item_udf_sum::add()
@@ -1279,6 +1362,11 @@ bool Item_udf_sum::add()
DBUG_RETURN(0);
}
+Item *Item_sum_udf_float::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_float(thd, *this);
+}
+
double Item_sum_udf_float::val()
{
DBUG_ENTER("Item_sum_udf_float::val");
@@ -1298,6 +1386,12 @@ String *Item_sum_udf_float::val_str(String *str)
}
+Item *Item_sum_udf_int::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_int(thd, *this);
+}
+
+
longlong Item_sum_udf_int::val_int()
{
DBUG_ENTER("Item_sum_udf_int::val_int");
@@ -1306,6 +1400,7 @@ longlong Item_sum_udf_int::val_int()
DBUG_RETURN(udf.val_int(&null_value));
}
+
String *Item_sum_udf_int::val_str(String *str)
{
longlong nr=val_int();
@@ -1327,6 +1422,13 @@ void Item_sum_udf_str::fix_length_and_dec()
DBUG_VOID_RETURN;
}
+
+Item *Item_sum_udf_str::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_sum_udf_str(thd, *this);
+}
+
+
String *Item_sum_udf_str::val_str(String *str)
{
DBUG_ENTER("Item_sum_udf_str::str");
@@ -1568,7 +1670,13 @@ Item_func_group_concat::~Item_func_group_concat()
}
-void Item_func_group_concat::reset()
+Item *Item_func_group_concat::copy_or_same(THD* thd)
+{
+ return new (&thd->mem_root) Item_func_group_concat(thd, *this);
+}
+
+
+bool Item_func_group_concat::reset()
{
result.length(0);
result.copy();
@@ -1582,7 +1690,7 @@ void Item_func_group_concat::reset()
}
if (tree_mode)
reset_tree(tree);
- add();
+ return add();
}
@@ -1768,6 +1876,16 @@ bool Item_func_group_concat::setup(THD *thd)
return 0;
}
+/* This is used by rollup to create a separate usable copy of the function */
+
+void Item_func_group_concat::make_unique()
+{
+ table=0;
+ original= 0;
+ tree= &tree_base;
+}
+
+
String* Item_func_group_concat::val_str(String* str)
{
if (null_value)
diff --git a/sql/item_sum.h b/sql/item_sum.h
index f996f980fff..c8614dda679 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -26,9 +26,11 @@
class Item_sum :public Item_result_field
{
public:
- enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
- MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
- UDF_SUM_FUNC, GROUP_CONCAT_FUNC };
+ enum Sumfunctype
+ { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
+ MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
+ UDF_SUM_FUNC, GROUP_CONCAT_FUNC
+ };
Item **args,*tmp_args[2];
uint arg_count;
@@ -60,7 +62,7 @@ public:
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
- virtual void reset()=0;
+ virtual bool reset()=0;
virtual bool add()=0;
virtual void reset_field()=0;
virtual void update_field(int offset)=0;
@@ -78,6 +80,7 @@ public:
void fix_num_length_and_dec();
void no_rows_in_result() { reset(); }
virtual bool setup(THD *thd) {return 0;}
+ virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
};
@@ -121,14 +124,14 @@ class Item_sum_sum :public Item_sum_num
Item_sum_sum(THD *thd, Item_sum_sum &item)
:Item_sum_num(thd, item), sum(item.sum) {}
enum Sumfunctype sum_func () const {return SUM_FUNC;}
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
void update_field(int offset);
void no_rows_in_result() {}
const char *func_name() const { return "sum"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -148,7 +151,7 @@ class Item_sum_count :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
- void reset();
+ bool reset();
void no_rows_in_result() { count=0; }
bool add();
void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
@@ -156,7 +159,7 @@ class Item_sum_count :public Item_sum_int
void reset_field();
void update_field(int offset);
const char *func_name() const { return "count"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_count(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -222,17 +225,15 @@ class Item_sum_count_distinct :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
- void reset();
+ bool reset();
bool add();
longlong val_int();
void reset_field() { return ;} // Never called
void update_field(int offset) { return ; } // Never called
const char *func_name() const { return "count_distinct"; }
bool setup(THD *thd);
- Item *copy_or_same(THD* thd)
- {
- return new Item_sum_count_distinct(thd, *this);
- }
+ void make_unique();
+ Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
};
@@ -268,7 +269,7 @@ class Item_sum_avg :public Item_sum_num
Item_sum_avg(THD *thd, Item_sum_avg &item)
:Item_sum_num(thd, item), sum(item.sum), count(item.count) {}
enum Sumfunctype sum_func () const {return AVG_FUNC;}
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
@@ -276,7 +277,7 @@ class Item_sum_avg :public Item_sum_num
Item *result_item(Field *field)
{ return new Item_avg_field(this); }
const char *func_name() const { return "avg"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_avg(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
class Item_sum_variance;
@@ -321,7 +322,7 @@ class Item_sum_variance : public Item_sum_num
Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr),
count(item.count) {}
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
- void reset();
+ bool reset();
bool add();
double val();
void reset_field();
@@ -329,7 +330,7 @@ class Item_sum_variance : public Item_sum_num
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
const char *func_name() const { return "variance"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_variance(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
class Item_sum_std;
@@ -349,12 +350,16 @@ public:
class Item_sum_std :public Item_sum_variance
{
public:
- Item_sum_std(Item *item_par) :Item_sum_variance(item_par){}
+ Item_sum_std(Item *item_par) :Item_sum_variance(item_par) {}
+ Item_sum_std(THD *thd, Item_sum_std &item)
+ :Item_sum_variance(thd, item)
+ {}
enum Sumfunctype sum_func () const { return STD_FUNC; }
double val();
Item *result_item(Field *field)
{ return new Item_std_field(this); }
const char *func_name() const { return "std"; }
+ Item *copy_or_same(THD* thd);
};
// This class is a string or number function depending on num_func
@@ -386,13 +391,13 @@ class Item_sum_hybrid :public Item_sum
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
- void reset()
+ bool reset()
{
sum=0.0;
sum_int=0;
value.length(0);
null_value=1;
- add();
+ return add();
}
double val();
longlong val_int();
@@ -418,7 +423,7 @@ public:
bool add();
const char *func_name() const { return "min"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_min(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -431,7 +436,7 @@ public:
bool add();
const char *func_name() const { return "max"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_max(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -446,7 +451,7 @@ class Item_sum_bit :public Item_sum_int
Item_sum_bit(THD *thd, Item_sum_bit &item):
Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {}
enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;}
- void reset();
+ bool reset();
longlong val_int();
void reset_field();
void fix_length_and_dec()
@@ -462,7 +467,7 @@ class Item_sum_or :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_or"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_or(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -474,7 +479,7 @@ class Item_sum_and :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_and"; }
- Item *copy_or_same(THD* thd) { return new Item_sum_and(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
/*
@@ -504,7 +509,7 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
virtual bool have_field_update(void) const { return 0; }
- void reset();
+ bool reset();
bool add();
void reset_field() {};
void update_field(int offset_arg) {};
@@ -524,7 +529,7 @@ class Item_sum_udf_float :public Item_udf_sum
double val();
String *val_str(String*str);
void fix_length_and_dec() { fix_num_length_and_dec(); }
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -542,7 +547,7 @@ public:
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; }
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
@@ -571,7 +576,7 @@ public:
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
#else /* Dummy functions to get sql_yacc.cc compiled */
@@ -586,10 +591,9 @@ class Item_sum_udf_float :public Item_sum_num
~Item_sum_udf_float() {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
double val() { return 0.0; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
};
@@ -604,10 +608,9 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
longlong val_int() { return 0; }
double val() { return 0; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
};
@@ -625,10 +628,9 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec() { maybe_null=1; max_length=0; }
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
- void reset() {}
+ bool reset() { return 0; }
bool add() { return 0; }
void update_field(int offset) {}
- Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
};
#endif /* HAVE_DLOPEN */
@@ -676,7 +678,7 @@ class Item_func_group_concat : public Item_sum
warning(item.warning),
warning_available(item.warning_available),
separator(item.separator),
- tree(item.tree),
+ tree(item.tree),
table(item.table),
expr(item.expr),
order(item.order),
@@ -700,11 +702,12 @@ class Item_func_group_concat : public Item_sum
enum Type type() const { return SUM_FUNC_ITEM; }
void fix_length_and_dec() { max_length=group_concat_max_len; }
virtual Item_result result_type () const { return STRING_RESULT; }
- void reset();
+ bool reset();
bool add();
void reset_field();
bool fix_fields(THD *, TABLE_LIST *, Item **);
bool setup(THD *thd);
+ void make_unique();
virtual void update_field(int offset) {};
double val()
{
@@ -717,5 +720,5 @@ class Item_func_group_concat : public Item_sum
return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
}
String* val_str(String* str);
- Item *copy_or_same(THD* thd) { return new Item_func_group_concat(thd, *this); }
+ Item *copy_or_same(THD* thd);
};
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 5ffd10be7a5..f2c64c4bde9 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -41,7 +41,7 @@ public:
:Item_sum_num(thd, item) {}
double val() { return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
- void reset() {}
+ bool reset() { return 0;}
bool add() { return 0; }
void reset_field() {}
void update_field(int offset) {}
diff --git a/sql/lex.h b/sql/lex.h
index e89c9f51520..064bab8acbb 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -396,6 +396,7 @@ static SYMBOL symbols[] = {
{ "UNSIGNED", SYM(UNSIGNED),0,0},
{ "USE", SYM(USE_SYM),0,0},
{ "USE_FRM", SYM(USE_FRM),0,0},
+ { "USER", SYM(USER),0,0},
{ "USING", SYM(USING),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
@@ -632,7 +633,6 @@ static SYMBOL sql_functions[] = {
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
{ "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0},
{ "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
- { "USER", SYM(USER),0,0},
{ "VARIANCE", SYM(VARIANCE_SYM),0,0},
{ "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
{ "WEEK", SYM(WEEK_SYM),0,0},
diff --git a/sql/log.cc b/sql/log.cc
index c05d52bdc5d..0ccb40c5246 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1200,6 +1200,12 @@ bool MYSQL_LOG::write(Log_event* event_info)
No check for auto events flag here - this write method should
never be called if auto-events are enabled
*/
+
+ /*
+ 1. Write first log events which describe the 'run environment'
+ of the SQL command
+ */
+
if (thd)
{
if (thd->last_insert_id_used)
@@ -1245,7 +1251,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
goto err;
}
}
-#if 0
+#ifdef TO_BE_REMOVED
if (thd->variables.convert_set)
{
char buf[256], *p;
@@ -1257,12 +1263,39 @@ bool MYSQL_LOG::write(Log_event* event_info)
goto err;
}
#endif
+
+ /*
+ If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL
+ command in the binlog inside:
+ SET FOREIGN_KEY_CHECKS=0;
+ <command>;
+ SET FOREIGN_KEY_CHECKS=1;
+ */
+
+ if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ {
+ Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
}
+
+ /* Write the SQL command */
+
event_info->set_log_pos(this);
- if (event_info->write(file) ||
- file == &log_file && flush_io_cache(file))
+ if (event_info->write(file))
goto err;
- error=0;
+
+ /* Write log events to reset the 'run environment' of the SQL command */
+
+ if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
+ {
+ Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
/*
Tell for transactional table handlers up to which position in the
@@ -1283,6 +1316,9 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (file == &log_file) // we are writing to the real log (disk)
{
+ if (flush_io_cache(file))
+ goto err;
+
if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log))
{
/*
@@ -1292,8 +1328,8 @@ bool MYSQL_LOG::write(Log_event* event_info)
handler if the log event type is appropriate.
*/
- if (event_info->get_type_code() == QUERY_EVENT
- || event_info->get_type_code() == EXEC_LOAD_EVENT)
+ if (event_info->get_type_code() == QUERY_EVENT ||
+ event_info->get_type_code() == EXEC_LOAD_EVENT)
{
error = ha_report_binlog_offset_and_commit(thd, log_file_name,
file->pos_in_file);
@@ -1303,6 +1339,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
/* we wrote to the real log, check automatic rotation */
should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size);
}
+ error=0;
err:
if (error)
@@ -1329,7 +1366,7 @@ err:
Flush the transactional handler log file now that we have released
LOCK_log; the flush is placed here to eliminate the bottleneck on the
group commit
- */
+ */
if (called_handler_commit)
ha_commit_complete(thd);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index fb690efc364..3d500ede462 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1573,9 +1573,27 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
else
{
char llbuff[22];
- enum enum_duplicates handle_dup = DUP_IGNORE;
+ enum enum_duplicates handle_dup;
if (sql_ex.opt_flags & REPLACE_FLAG)
handle_dup= DUP_REPLACE;
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ handle_dup= DUP_IGNORE;
+ else
+ /*
+ Note that when replication is running fine, if it was DUP_ERROR on the
+ master then we could choose DUP_IGNORE here, because if DUP_ERROR
+ suceeded on master, and data is identical on the master and slave,
+ then there should be no uniqueness errors on slave, so DUP_IGNORE is
+ the same as DUP_ERROR. But in the unlikely case of uniqueness errors
+ (because the data on the master and slave happen to be different (user
+ error or bug), we want LOAD DATA to print an error message on the
+ slave to discover the problem.
+
+ If reading from net (a 3.23 master), mysql_load() will change this
+ to DUP_IGNORE.
+ */
+ handle_dup= DUP_ERROR;
+
sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
@@ -1637,12 +1655,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
close_thread_tables(thd);
if (thd->query_error)
{
- int sql_error= thd->net.last_errno;
- if (!sql_error)
- sql_error= ER_UNKNOWN_ERROR;
- slave_print_error(rli,sql_error,
- "Error '%s' running LOAD DATA INFILE",
- ER_SAFE(sql_error));
+ /* this err/sql_errno code is copy-paste from send_error() */
+ const char *err;
+ int sql_errno;
+ if ((err=thd->net.last_error)[0])
+ sql_errno=thd->net.last_errno;
+ else
+ {
+ sql_errno=ER_UNKNOWN_ERROR;
+ err=ER(sql_errno);
+ }
+ slave_print_error(rli,sql_errno,
+ "Error '%s' running load data infile",
+ err);
free_root(&thd->mem_root,0);
return 1;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a59f1d4b81a..0508d0aa986 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -66,9 +66,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#endif
#endif
-extern CHARSET_INFO *system_charset_info;
-extern CHARSET_INFO *files_charset_info;
-extern CHARSET_INFO *national_charset_info;
+extern CHARSET_INFO *system_charset_info, *files_charset_info ;
+extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/***************************************************************************
Configuration parameters
@@ -208,7 +207,7 @@ extern CHARSET_INFO *national_charset_info;
#define MODE_PIPES_AS_CONCAT 2
#define MODE_ANSI_QUOTES 4
#define MODE_IGNORE_SPACE 8
-#define MODE_SERIALIZABLE 16
+#define MODE_NOT_USED 16
#define MODE_ONLY_FULL_GROUP_BY 32
#define MODE_NO_UNSIGNED_SUBTRACTION 64
#define MODE_POSTGRESQL 128
@@ -221,6 +220,7 @@ extern CHARSET_INFO *national_charset_info;
#define MODE_NO_FIELD_OPTIONS 16384
#define MODE_MYSQL323 32768
#define MODE_MYSQL40 65536
+#define MODE_ANSI (MODE_MYSQL40*2)
#define RAID_BLOCK_SIZE 1024
@@ -461,7 +461,6 @@ bool mysql_rename_table(enum db_type base,
const char * old_name,
const char *new_db,
const char * new_name);
-bool close_cached_table(THD *thd,TABLE *table);
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
@@ -501,6 +500,7 @@ Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL
+#include <openssl/des.h>
struct st_des_keyblock
{
des_cblock key1, key2, key3;
@@ -723,7 +723,7 @@ extern ulong ha_read_rnd_count, ha_read_rnd_next_count;
extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong max_insert_delayed_threads, max_user_connections;
-extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode;
+extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
@@ -837,7 +837,7 @@ uint calc_days_in_year(uint year);
void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
void init_time(void);
-long my_gmt_sec(TIME *);
+long my_gmt_sec(TIME *, long *current_timezone);
time_t str_to_timestamp(const char *str,uint length);
bool str_to_time(const char *str,uint length,TIME *l_time);
longlong str_to_datetime(const char *str,uint length,bool fuzzy_date);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 1a595c46e81..3f3b2ee7c9f 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -208,9 +208,9 @@ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
const char *sql_mode_names[] =
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
- "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
+ "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS",
- "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40",
+ "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
@@ -267,7 +267,7 @@ ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong com_stat[(uint) SQLCOM_END], com_other;
-ulong bytes_sent, bytes_received;
+ulong bytes_sent, bytes_received, net_big_packet_count;
ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */
ulong query_id, long_query_count, aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
@@ -324,6 +324,9 @@ MY_TMPDIR mysql_tmpdir_list;
DATE_FORMAT dayord;
MY_BITMAP temp_pool;
+CHARSET_INFO *system_charset_info, *files_charset_info ;
+CHARSET_INFO *national_charset_info, *table_alias_charset;
+
SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam;
SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache;
SHOW_COMP_OPTION have_crypt, have_compress;
@@ -562,7 +565,7 @@ static void close_connections(void)
unix_sock= INVALID_SOCKET;
}
#endif
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(0); // Abort old alarms.
end_slave();
/* First signal all threads that it's time to die */
@@ -871,6 +874,7 @@ void clean_up(bool print_message)
#endif
(void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */
end_key_cache();
+ end_thr_alarm(1); /* Free allocated memory */
#ifdef USE_RAID
end_raid();
#endif
@@ -936,7 +940,6 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_crypt);
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
- (void) pthread_mutex_destroy(&LOCK_timezone);
(void) pthread_mutex_destroy(&LOCK_user_conn);
#ifdef HAVE_REPLICATION
(void) pthread_mutex_destroy(&LOCK_rpl_status);
@@ -984,14 +987,21 @@ static void set_ports()
static void set_user(const char *user)
{
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
- struct passwd *ent;
+ struct passwd *ent;
+ uid_t user_id= geteuid();
// don't bother if we aren't superuser
- if (geteuid())
+ if (user_id)
{
if (user)
- fprintf(stderr,
- "Warning: One can only use the --user switch if running as root\n");
+ {
+ /* Don't give a warning, if real user is same as given with --user */
+ struct passwd *user_info= getpwnam(user);
+
+ if (!user_info || user_id != user_info->pw_uid)
+ fprintf(stderr,
+ "Warning: One can only use the --user switch if running as root\n");
+ }
return;
}
else if (!user)
@@ -1497,7 +1507,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size);
fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size);
- fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size);
fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
fprintf(stderr, "max_connections=%ld\n", max_connections);
fprintf(stderr, "threads_connected=%d\n", thread_count);
@@ -1505,7 +1514,7 @@ and this may fail.\n\n");
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
bytes of memory\n", ((ulong) keybuff_size +
(global_system_variables.read_buff_size +
- thd->variables.sortbuff_size) *
+ global_system_variables.sortbuff_size) *
max_connections)/ 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
@@ -1534,14 +1543,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
Some pointers may be invalid and cause the dump to abort...\n");
safe_print_str("thd->query", thd->query, 1024);
fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id);
- fprintf(stderr, "\n\
-Successfully dumped variables, if you ran with --log, take a look at the\n\
-details of what thread %ld did to cause the crash. In some cases of really\n\
-bad corruption, the values shown above may be invalid.\n\n",
- thd->thread_id);
}
fprintf(stderr, "\
-The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\
+The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
@@ -1565,6 +1569,7 @@ information that should help you find out what is causing the crash.\n");
static void init_signals(void)
{
sigset_t set;
+ struct sigaction sa;
DBUG_ENTER("init_signals");
sigset(THR_KILL_SIGNAL,end_thread_signal);
@@ -1572,7 +1577,6 @@ static void init_signals(void)
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
{
- struct sigaction sa;
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
sigemptyset(&sa.sa_mask);
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
@@ -1614,15 +1618,23 @@ static void init_signals(void)
sigaddset(&set,SIGQUIT);
sigaddset(&set,SIGTERM);
sigaddset(&set,SIGHUP);
- sigset(SIGTERM, print_signal_warning); // If it's blocked by parent
- sigset(SIGHUP, print_signal_warning); // If it's blocked by parent
+
+ /* Fix signals if blocked by parents (can happen on Mac OS X) */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = print_signal_warning;
+ sigaction(SIGTERM, &sa, (struct sigaction*) 0);
+ sa.sa_flags = 0;
+ sa.sa_handler = print_signal_warning;
+ sigaction(SIGHUP, &sa, (struct sigaction*) 0);
#ifdef SIGTSTP
sigaddset(&set,SIGTSTP);
#endif
sigaddset(&set,THR_SERVER_ALARM);
sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
sigdelset(&set,THR_CLIENT_ALARM); // For alarms
- (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
+ sigprocmask(SIG_SETMASK,&set,NULL);
+ pthread_sigmask(SIG_SETMASK,&set,NULL);
DBUG_VOID_RETURN;
}
@@ -1890,7 +1902,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
#endif
-const char *load_default_groups[]= { "mysqld","server",0 };
+const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 };
bool open_log(MYSQL_LOG *log, const char *hostname,
const char *opt_name, const char *extension,
@@ -1947,19 +1959,11 @@ static int init_common_variables(const char *conf_file_name, int argc,
}
#endif
#ifdef HAVE_TZNAME
-#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
{
struct tm tm_tmp;
localtime_r(&start_time,&tm_tmp);
strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]);
}
-#else
- {
- struct tm *start_tm;
- start_tm=localtime(&start_time);
- strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]);
- }
-#endif
#endif
if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
@@ -2073,7 +2077,6 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
@@ -2282,9 +2285,7 @@ static void handle_connections_methods()
#endif /* __NT__ */
if (have_tcpip && !opt_disable_networking)
{
-#ifdef __NT__
handler_count++;
-#endif
if (pthread_create(&hThread,&connection_attrib,
handle_connections_sockets, 0))
{
@@ -2295,9 +2296,7 @@ static void handle_connections_methods()
#ifdef HAVE_SMEM
if (opt_enable_shared_memory)
{
-#ifdef __NT__
handler_count++;
-#endif
if (pthread_create(&hThread,&connection_attrib,
handle_connections_shared_memory, 0))
{
@@ -2312,6 +2311,16 @@ static void handle_connections_methods()
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
+
+void decrement_handler_count()
+{
+ pthread_mutex_lock(&LOCK_thread_count);
+ handler_count--;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_cond_signal(&COND_handler_count);
+}
+#else
+#define decrement_handler_count()
#endif /* defined(__NT__) || defined(HAVE_SMEM) */
@@ -2429,18 +2438,18 @@ The server will not act as a slave.");
#endif
/* init_slave() must be called after the thread keys are created */
init_slave();
-
+
if (opt_bootstrap)
{
int error=bootstrap(stdin);
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(1); // Don't allow alarms
unireg_abort(error ? 1 : 0);
}
if (opt_init_file)
{
if (read_init_file(opt_init_file))
{
- end_thr_alarm(); // Don't allow alarms
+ end_thr_alarm(1); // Don't allow alarms
unireg_abort(1);
}
}
@@ -2612,9 +2621,12 @@ int main(int argc, char **argv)
return 0;
if (Service.IsService(argv[2]))
{
- /* start an optional service */
+ /*
+ mysqld was started as
+ mysqld --defaults-file=my_path\my.ini service-name
+ */
use_opt_args=1;
- opt_argc=argc;
+ opt_argc= 2; // Skip service-name
opt_argv=argv;
start_mode= 1;
Service.Init(argv[2], mysql_service);
@@ -3020,13 +3032,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
// kill server must be invoked from thread 1!
kill_server(MYSQL_KILL_SIGNAL);
#endif
-
-#ifdef __NT__
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
-#endif
+ decrement_handler_count();
DBUG_RETURN(0);
}
@@ -3106,10 +3112,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
create_new_thread(thd);
}
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
+ decrement_handler_count();
DBUG_RETURN(0);
}
#endif /* __NT__ */
@@ -3323,12 +3326,8 @@ error:
if (!handle_connect_file_map) CloseHandle(handle_connect_file_map);
if (!event_connect_answer) CloseHandle(event_connect_answer);
if (!event_connect_request) CloseHandle(event_connect_request);
-#ifdef __NT__
- pthread_mutex_lock(&LOCK_thread_count);
- handler_count--;
- pthread_mutex_unlock(&LOCK_thread_count);
- pthread_cond_signal(&COND_handler_count);
-#endif
+
+ decrement_handler_count();
DBUG_RETURN(0);
}
#endif /* HAVE_SMEM */
@@ -3922,7 +3921,7 @@ replicating a LOAD DATA INFILE command",
(gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
- "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
+ "Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
#ifdef HAVE_OPENSSL
@@ -4635,6 +4634,12 @@ static void mysql_init_variables(void)
bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
bzero((gptr) &com_stat, sizeof(com_stat));
+ /* Character sets */
+ system_charset_info= &my_charset_utf8_general_ci;
+ files_charset_info= &my_charset_utf8_general_ci;
+ national_charset_info= &my_charset_utf8_general_ci;
+ table_alias_charset= &my_charset_bin;
+
/* Things with default values that are not zero */
delay_key_write_options= (uint) DELAY_KEY_WRITE_ON;
opt_specialflag= SPECIAL_ENGLISH;
@@ -4685,6 +4690,7 @@ static void mysql_init_variables(void)
default_collation_name= (char*) MYSQL_DEFAULT_COLLATION_NAME;
sys_charset_system.value= (char*) system_charset_info->csname;
+
/* Set default values for some option variables */
global_system_variables.character_set_server= default_charset_info;
global_system_variables.character_set_database= default_charset_info;
@@ -4792,10 +4798,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_endinfo=1; /* unireg: memory allocation */
break;
case 'a':
- global_system_variables.sql_mode=
- (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT |
- MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE |
- MODE_ONLY_FULL_GROUP_BY);
+ global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
@@ -5273,11 +5276,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
fprintf(stderr, "Unknown option to sql-mode: %s\n", argument);
exit(1);
}
- global_system_variables.tx_isolation=
- ((global_system_variables.sql_mode & MODE_SERIALIZABLE) ?
- ISO_SERIALIZABLE :
- ISO_REPEATABLE_READ);
- break;
+ global_system_variables.sql_mode= fix_sql_mode(global_system_variables.
+ sql_mode);
}
case OPT_MASTER_PASSWORD:
master_password=argument;
@@ -5335,6 +5335,9 @@ static void get_options(int argc,char **argv)
/* Set global variables based on startup options */
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
+ table_alias_charset= (lower_case_table_names ?
+ files_charset_info :
+ &my_charset_bin);
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 8271d971782..eb4d76bbf6e 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -15,6 +15,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
+ This file is the net layer API for the MySQL client/server protocol,
+ which is a tightly coupled, proprietary protocol owned by MySQL AB.
+ Any re-implementations of this protocol must also be under GPL
+ unless one has got an license from MySQL AB stating otherwise.
+*/
+
+/*
Write and read of logical packets to/from socket
Writes are cached into net_buffer_length big packets.
@@ -66,11 +73,13 @@ void sql_print_error(const char *format,...);
#define USE_QUERY_CACHE
extern uint test_flags;
extern void query_cache_insert(NET *net, const char *packet, ulong length);
-extern ulong bytes_sent, bytes_received;
+extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
+#undef statistic_increment
#define statistic_add(A,B,C)
+#define statistic_increment(A,B)
#endif
#define TEST_BLOCKING 8
@@ -555,7 +564,7 @@ static my_bool net_safe_read(NET *net, char *buff, uint32 length,
if ((tmp=vio_read(net->vio,(char*) net->buff, length)) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
- if (!thr_got_alarm(&alarmed) && interrupted)
+ if (!thr_got_alarm(alarmed) && interrupted)
{ /* Probably in MIT threads */
if (retry_count++ < net->retry_count)
continue;
@@ -589,10 +598,13 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
DBUG_ENTER("my_net_skip_rest");
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
- if (!thr_alarm_in_use(&alarmed))
+ /* The following is good for debugging */
+ statistic_increment(net_big_packet_count,&LOCK_bytes_received);
+
+ if (!thr_alarm_in_use(alarmed))
{
my_bool old_mode;
- if (!thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
+ if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
vio_blocking(net->vio, TRUE, &old_mode) < 0)
DBUG_RETURN(1); /* Can't setup, abort */
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 7abbf3ce85b..10fe2c1725e 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -102,7 +102,8 @@ void send_error(THD *thd, uint sql_errno, const char *err)
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
/* The first # is to make the protocol backward compatible */
- strmov(buff+2, "#000000");
+ buff[2]= '#';
+ strmov(buff+3, mysql_errno_to_sqlstate(sql_errno));
pos= buff + 2 + SQLSTATE_LENGTH +1;
}
length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff);
@@ -222,8 +223,8 @@ net_printf(THD *thd, uint errcode, ...)
int2store(pos, errcode);
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- /* The first # is to make the protocol backward compatible */
- memcpy(pos+2, "#000000", SQLSTATE_LENGTH +1);
+ pos[2]= '#'; /* To make the protocol backward compatible */
+ memcpy(pos+3, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
}
}
VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 60b0d24430d..ad3966f76f9 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -89,6 +89,7 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
static void fix_key_buffer_size(THD *thd, enum_var_type type);
static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type);
static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type);
+void fix_sql_mode_var(THD *thd, enum_var_type type);
static byte *get_error_count(THD *thd);
static byte *get_warning_count(THD *thd);
@@ -207,6 +208,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
&SV::read_buff_size);
+sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size);
#ifdef HAVE_REPLICATION
@@ -235,7 +237,6 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
#endif
-sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
&slow_launch_time);
sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
@@ -599,6 +600,7 @@ struct show_var_st init_vars[]= {
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
{sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
+ {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
#ifdef HAVE_REPLICATION
{sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
@@ -1168,40 +1170,6 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type)
}
-byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type)
-{
- ulong val;
- char buff[256];
- String tmp(buff, sizeof(buff), &my_charset_latin1);
- my_bool found= 0;
-
- tmp.length(0);
- val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
- thd->variables.*offset);
- for (uint i= 0; val; val>>= 1, i++)
- {
- if (val & 1)
- {
- tmp.append(enum_names->type_names[i]);
- tmp.append(',');
- }
- }
- if (tmp.length())
- tmp.length(tmp.length() - 1);
- return (byte*) thd->strmake(tmp.ptr(), tmp.length());
-}
-
-
-void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
-{
- if (type == OPT_GLOBAL)
- global_system_variables.*offset= 0;
- else
- thd->variables.*offset= global_system_variables.*offset;
-}
-
-
-
bool sys_var_thd_bit::update(THD *thd, set_var *var)
{
int res= (*update_func)(thd, var);
@@ -1857,7 +1825,105 @@ int set_var_password::update(THD *thd)
1 : 0);
}
+/****************************************************************************
+ Functions to handle sql_mode
+****************************************************************************/
+
+byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type)
+{
+ ulong val;
+ char buff[256];
+ String tmp(buff, sizeof(buff), &my_charset_latin1);
+ my_bool found= 0;
+
+ tmp.length(0);
+ val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+ thd->variables.*offset);
+ for (uint i= 0; val; val>>= 1, i++)
+ {
+ if (val & 1)
+ {
+ tmp.append(enum_names->type_names[i]);
+ tmp.append(',');
+ }
+ }
+ if (tmp.length())
+ tmp.length(tmp.length() - 1);
+ return (byte*) thd->strmake(tmp.ptr(), tmp.length());
+}
+
+
+void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.*offset= 0;
+ else
+ thd->variables.*offset= global_system_variables.*offset;
+}
+
+void fix_sql_mode_var(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.sql_mode=
+ fix_sql_mode(global_system_variables.sql_mode);
+ else
+ thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode);
+}
+
+/* Map database specific bits to function bits */
+ulong fix_sql_mode(ulong sql_mode)
+{
+ /*
+ Note that we dont set
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS
+ to allow one to get full use of MySQL in this mode.
+ */
+
+ if (sql_mode & MODE_ANSI)
+ sql_mode|= (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE | MODE_ONLY_FULL_GROUP_BY);
+ if (sql_mode & MODE_ORACLE)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MSSQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MSSQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_POSTGRESQL)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_DB2)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_DB2)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_SAPDB)
+ sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
+ MODE_IGNORE_SPACE |
+ MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS |
+ MODE_NO_FIELD_OPTIONS);
+ if (sql_mode & MODE_MYSQL40)
+ sql_mode|= MODE_NO_FIELD_OPTIONS;
+ if (sql_mode & MODE_MYSQL323)
+ sql_mode|= MODE_NO_FIELD_OPTIONS;
+ return sql_mode;
+}
diff --git a/sql/set_var.h b/sql/set_var.h
index d016c3a7085..998d61ff2d1 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -309,11 +309,14 @@ public:
};
+extern void fix_sql_mode_var(THD *thd, enum_var_type type);
+
class sys_var_thd_sql_mode :public sys_var_thd_enum
{
public:
sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg)
- :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib)
+ :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib,
+ fix_sql_mode_var)
{}
bool check(THD *thd, set_var *var)
{
@@ -636,6 +639,7 @@ void set_var_free();
sys_var *find_sys_var(const char *str, uint length=0);
int sql_set_variables(THD *thd, List<set_var_base> *var_list);
void fix_delay_key_write(THD *thd, enum_var_type type);
+ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index e277c19e26f..273dfa0fcf5 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -271,3 +271,5 @@ v/*
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 01856ffed01..1d39a328154 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -265,3 +265,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 4b9b0b9f710..5b79f06b621 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -273,3 +273,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 89045b13985..ad15d55405f 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -267,3 +267,5 @@
"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index d5064b53790..506b5fc0188 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -267,3 +267,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index eb936243332..8882e4dceda 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -262,3 +262,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 2ac25216b8e..1e8f5bb2c05 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -271,3 +271,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 8e82559db5c..d322f3fbd6a 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -262,3 +262,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index de0e7da614e..162bfc5509c 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -264,3 +264,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index d9308faf8a6..26d916a968d 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -262,3 +262,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 45e78941906..a01a2b7ff6f 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -264,3 +264,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 43d291ae3a5..5f5526be04b 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -262,3 +262,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index c0c045438ec..bf1019d3d87 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -264,3 +264,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 03430ae546b..68c95bbf22b 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -264,3 +264,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 997ee08e66a..5b93403c757 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -266,3 +266,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index ef051d957cb..edd3e3b813f 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -262,3 +262,5 @@
"%d linha(s) foi(foram) cortada(s) por group_concat()",
"Usando engine de armazenamento %s para tabela '%s'",
"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 89c00b4bf15..873a708fa7b 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -266,3 +266,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index fac4dedb3ee..a05ecde6808 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -264,3 +264,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index d954e7998a2..c1c0de779c7 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -258,3 +258,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 8f7747c6bf6..26d673b847c 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -270,3 +270,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 4a7989ce7be..99a92f63c4e 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -263,3 +263,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 6734369d3ac..c613d205947 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -262,3 +262,5 @@
"%d rad(er) kapades av group_concat()",
"Använder handler %s för tabell '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 67c52dc8fee..6505c3c9cac 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -267,3 +267,5 @@
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
+"Can't drop one or more of the requested users"
+"Can't revoke all privileges, grant for one or more of the requested users"
diff --git a/sql/slave.cc b/sql/slave.cc
index 22c47bbdd05..cc27bb96ab7 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -287,7 +287,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
goto err;
rli->cur_log = &rli->cache_buf;
}
- if (pos > BIN_LOG_HEADER_SIZE)
+ if (pos >= BIN_LOG_HEADER_SIZE)
my_b_seek(rli->cur_log,(off_t)pos);
err:
@@ -1388,9 +1388,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
- {
pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
- }
thd->proc_info = save_proc_info;
pthread_mutex_unlock(&rli->log_space_lock);
DBUG_RETURN(slave_killed);
@@ -2101,7 +2099,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
Log_event * ev = next_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
if (sql_slave_killed(thd,rli))
+ {
+ /* do not forget to free ev ! */
+ if (ev) delete ev;
return 1;
+ }
if (ev)
{
int type_code = ev->get_type_code();
@@ -2152,8 +2154,13 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
else
{
sql_print_error("\
-Could not parse log event entry, check the master for binlog corruption\n\
-This may also be a network problem, or just a bug in the master or slave code.\
+Could not parse relay log event entry. The possible reasons are: the master's \
+binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
+binary log), the slave's relay log is corrupted (you can check this by running \
+'mysqlbinlog' on the relay log), a network problem, or a bug in the master's \
+or slave's MySQL code. If you want to check the master's binary log or slave's \
+relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' \
+on this slave.\
");
return 1;
}
@@ -2376,6 +2383,18 @@ reconnect done to recover from failed read");
goto err;
}
flush_master_info(mi);
+ /*
+ See if the relay logs take too much space.
+ We don't lock mi->rli.log_space_lock here; this dirty read saves time
+ and does not introduce any problem:
+ - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so
+ the clean value is 0), then we are reading only one more event as we
+ should, and we'll block only at the next event. No big deal.
+ - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so
+ the clean value is 1), then we are going into wait_for_relay_log_space()
+ for no reason, but this function will do a clean read, notice the clean
+ value and exit immediately.
+ */
if (mi->rli.log_space_limit && mi->rli.log_space_limit <
mi->rli.log_space_total &&
!mi->rli.ignore_log_space_limit)
@@ -2489,7 +2508,9 @@ slave_begin:
pthread_cond_broadcast(&rli->start_cond);
//tell the I/O thread to take relay_log_space_limit into account from now on
+ pthread_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
+ pthread_mutex_unlock(&rli->log_space_lock);
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@@ -3223,7 +3244,12 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
pthread_mutex_lock(&rli->log_space_lock);
// prevent the I/O thread from blocking next times
rli->ignore_log_space_limit= 1;
- // If the I/O thread is blocked, unblock it
+ /*
+ If the I/O thread is blocked, unblock it.
+ Ok to broadcast after unlock, because the mutex is only destroyed in
+ ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be
+ destroyed before we exit the present function.
+ */
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ec6db64ea73..49aad321702 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2179,11 +2179,6 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
int error;
GRANT_TABLE *grant_table;
- if (!Str->host.str)
- {
- Str->host.str=(char*) "%";
- Str->host.length=1;
- }
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
@@ -2350,11 +2345,6 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
int result=0;
while ((Str = str_list++))
{
- if (!Str->host.str)
- {
- Str->host.str=(char*) "%";
- Str->host.length=1;
- }
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
@@ -2855,11 +2845,6 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
send_error(thd, ER_UNKNOWN_COM_ERROR);
DBUG_RETURN(-1);
}
- if (!lex_user->host.str)
- {
- lex_user->host.str=(char*) "%";
- lex_user->host.length=1;
- }
if (lex_user->host.length > HOSTNAME_LENGTH ||
lex_user->user.length > USERNAME_LENGTH)
{
@@ -3202,6 +3187,279 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
}
+int open_grant_tables(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("open_grant_tables");
+
+ if (!initialized)
+ {
+ send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ DBUG_RETURN(-1);
+ }
+
+ bzero((char*) tables, 4*sizeof(*tables));
+ tables->alias= tables->real_name= (char*) "user";
+ (tables+1)->alias= (tables+1)->real_name= (char*) "db";
+ (tables+2)->alias= (tables+2)->real_name= (char*) "tables_priv";
+ (tables+3)->alias= (tables+3)->real_name= (char*) "columns_priv";
+ tables->next= tables+1;
+ (tables+1)->next= tables+2;
+ (tables+2)->next= tables+3;
+ (tables+3)->next= 0;
+ tables->lock_type= (tables+1)->lock_type=
+ (tables+2)->lock_type= (tables+3)->lock_type= TL_WRITE;
+ tables->db= (tables+1)->db= (tables+2)->db= (tables+3)->db=(char*) "mysql";
+
+#ifdef HAVE_REPLICATION
+ /*
+ GRANT and REVOKE are applied the slave in/exclusion rules as they are
+ some kind of updates to the mysql.% tables.
+ */
+ if (thd->slave_thread && table_rules_on && !tables_ok(0, tables))
+ DBUG_RETURN(1);
+#endif
+
+ if (open_and_lock_tables(thd, tables))
+ { // This should never happen
+ close_thread_tables(thd);
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+ACL_USER *check_acl_user(LEX_USER *user_name,
+ uint *acl_user_idx)
+{
+ ACL_USER *acl_user= 0;
+ uint counter;
+
+ for (counter= 0 ; counter < acl_users.elements ; counter++)
+ {
+ const char *user,*host;
+ acl_user= dynamic_element(&acl_users, counter, ACL_USER*);
+ if (!(user=acl_user->user))
+ user="";
+ if (!(host=acl_user->host.hostname))
+ host="%";
+ if (!strcmp(user_name->user.str,user) &&
+ !my_strcasecmp(system_charset_info, user_name->host.str, host))
+ break;
+ }
+ if (counter == acl_users.elements)
+ return 0;
+
+ *acl_user_idx= counter;
+ return acl_user;
+}
+
+int mysql_drop_user(THD *thd, List <LEX_USER> &list)
+{
+ uint counter, user_id;
+ int result;
+ ACL_USER *acl_user;
+ ACL_DB *acl_db;
+ TABLE_LIST tables[4];
+
+ DBUG_ENTER("mysql_drop_user");
+
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result == 1 ? 0 : -1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ LEX_USER *user_name;
+ List_iterator <LEX_USER> user_list(list);
+ while ((user_name=user_list++))
+ {
+ if (!(acl_user= check_acl_user(user_name, &counter)))
+ {
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ user_name->user.str,
+ user_name->host.str);
+ result= -1;
+ continue;
+ }
+ if ((acl_user->access & ~0))
+ {
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ user_name->user.str,
+ user_name->host.str);
+ result= -1;
+ continue;
+ }
+ user_id= counter;
+
+ for (counter= 0 ; counter < acl_dbs.elements ; counter++)
+ {
+ const char *user,*host;
+ acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ if (!(user= acl_db->user))
+ user="";
+ if (!(host= acl_db->host.hostname))
+ host="";
+
+ if (!strcmp(user_name->user.str,user) &&
+ !my_strcasecmp(system_charset_info, user_name->host.str, host))
+ break;
+ }
+ if (counter != acl_dbs.elements)
+ {
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ user_name->user.str,
+ user_name->host.str);
+ result= -1;
+ continue;
+ }
+
+ for (counter= 0 ; counter < column_priv_hash.records ; counter++)
+ {
+ const char *user,*host;
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ counter);
+ if (!(user=grant_table->user))
+ user="";
+ if (!(host=grant_table->host))
+ host="";
+
+ if (!strcmp(user_name->user.str,user) &&
+ !my_strcasecmp(system_charset_info, user_name->host.str, host))
+ break;
+ }
+ if (counter != column_priv_hash.records)
+ {
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ user_name->user.str,
+ user_name->host.str);
+ result= -1;
+ continue;
+ }
+
+ tables[0].table->field[0]->store(user_name->host.str,(uint)
+ user_name->host.length, system_charset_info);
+ tables[0].table->field[1]->store(user_name->user.str,(uint)
+ user_name->user.length, system_charset_info);
+ if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0,
+ (byte*) tables[0].table->field[0]->ptr,0,
+ HA_READ_KEY_EXACT))
+ {
+ int error;
+ if ((error = tables[0].table->file->delete_row(tables[0].table->record[0])))
+ {
+ tables[0].table->file->print_error(error, MYF(0));
+ tables[0].table->file->index_end();
+ DBUG_RETURN(-1);
+ }
+ delete_dynamic_element(&acl_users, user_id);
+ }
+ tables[0].table->file->index_end();
+ }
+err:
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_DROP_USER, MYF(0));
+ DBUG_RETURN(result);
+}
+
+int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
+{
+ uint counter;
+ int result;
+ ACL_USER *acl_user; ACL_DB *acl_db;
+ TABLE_LIST tables[4];
+ DBUG_ENTER("mysql_revoke_all");
+
+ if ((result= open_grant_tables(thd, tables)))
+ DBUG_RETURN(result == 1 ? 0 : -1);
+
+ rw_wrlock(&LOCK_grant);
+ VOID(pthread_mutex_lock(&acl_cache->lock));
+
+ LEX_USER *lex_user;
+ List_iterator <LEX_USER> user_list(list);
+ while ((lex_user=user_list++))
+ {
+ if (!(acl_user= check_acl_user(lex_user, &counter)))
+ {
+ sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' not exists",
+ lex_user->user.str,
+ lex_user->host.str);
+ result= -1;
+ continue;
+ }
+
+ if (replace_user_table(thd, tables[0].table,
+ *lex_user, ~0, 1, 0))
+ {
+ result= -1;
+ continue;
+ }
+
+ /* Remove db access privileges */
+ for (counter= 0 ; counter < acl_dbs.elements ; counter++)
+ {
+ const char *user,*host;
+
+ acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ if (!(user=acl_db->user))
+ user="";
+ if (!(host=acl_db->host.hostname))
+ host="";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ {
+ if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
+ result= -1;
+ }
+ }
+
+ /* Remove column access */
+ for (counter= 0 ; counter < column_priv_hash.records ; counter++)
+ {
+ const char *user,*host;
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ counter);
+ if (!(user=grant_table->user))
+ user="";
+ if (!(host=grant_table->host))
+ host="";
+
+ if (!strcmp(lex_user->user.str,user) &&
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ {
+ if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
+ grant_table->db,
+ grant_table->tname,
+ ~0, 0, 1))
+ {
+ result= -1;
+ continue;
+ }
+ if (grant_table->cols)
+ {
+ List<LEX_COLUMN> columns;
+ if (replace_column_table(grant_table,tables[3].table, *lex_user,
+ columns,
+ grant_table->db,
+ grant_table->tname,
+ ~0, 1))
+ result= -1;
+ }
+ }
+ }
+ }
+
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+ close_thread_tables(thd);
+ if (result)
+ my_error(ER_REVOKE_GRANTS, MYF(0));
+ DBUG_RETURN(result);
+}
/*****************************************************************************
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index d85a281cbb5..e6c6771253c 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -163,3 +163,5 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field);
int mysql_show_grants(THD *thd, LEX_USER *user);
void get_privilege_desc(char *to, uint max_length, ulong access);
void get_mqh(const char *user, const char *host, USER_CONN *uc);
+int mysql_drop_user(THD *thd, List <LEX_USER> &list);
+int mysql_revoke_all(THD *thd, List <LEX_USER> &list);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 81c620fdaf4..1ef4e9df020 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -544,7 +544,8 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table,
{
for (; table; table= table->next)
if ((!db_name || !strcmp(table->db, db_name)) &&
- (!table_name || !strcmp(table->alias, table_name)))
+ (!table_name || !my_strcasecmp(table_alias_charset,
+ table->alias, table_name)))
break;
return table;
}
@@ -1739,7 +1740,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
bool found_table=0;
for (; tables ; tables=tables->next)
{
- if (!strcmp(tables->alias,table_name) &&
+ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
(!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
{
found_table=1;
@@ -1868,20 +1869,22 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
List_iterator<Item> li(items);
Item **found=0,*item;
+ const char *db_name=0;
const char *field_name=0;
const char *table_name=0;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
{
field_name= ((Item_ident*) find)->field_name;
table_name= ((Item_ident*) find)->table_name;
+ db_name= ((Item_ident*) find)->db_name;
}
for (uint i= 0; (item=li++); i++)
{
if (field_name && item->type() == Item::FIELD_ITEM)
{
- if (!my_strcasecmp(system_charset_info,
- ((Item_field*) item)->name,field_name))
+ Item_field *item_field= (Item_field*) item;
+ if (!my_strcasecmp(system_charset_info, item_field->name, field_name))
{
if (!table_name)
{
@@ -1897,11 +1900,16 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
found= li.ref();
*counter= i;
}
- else if (!strcmp(((Item_field*) item)->table_name,table_name))
+ else
{
- found= li.ref();
- *counter= i;
- break;
+ if (!strcmp(item_field->table_name,table_name) &&
+ (!db_name || (db_name && item_field->db_name &&
+ !strcmp(item_field->table_name,table_name))))
+ {
+ found= li.ref();
+ *counter= i;
+ break;
+ }
}
}
}
@@ -2094,7 +2102,8 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
for (; tables ; tables=tables->next)
{
TABLE *table=tables->table;
- if (!table_name || (!strcmp(table_name,tables->alias) &&
+ if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
+ tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
{
/* Ensure that we have access right to all columns */
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index adc3d177fdf..ac6471e794c 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -739,7 +739,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size_arg));
free_cache(0);
query_cache_size= query_cache_size_arg;
- DBUG_RETURN(init_cache());
+ DBUG_RETURN(::query_cache_size= init_cache());
}
@@ -1318,6 +1318,12 @@ ulong Query_cache::init_cache()
mem_bin_steps = 1;
mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
prev_size = 0;
+ if (mem_bin_size <= min_allocation_unit)
+ {
+ DBUG_PRINT("qcache", ("too small query cache => query cache disabled"));
+ // TODO here (and above) should be warning in 4.1
+ goto err;
+ }
while (mem_bin_size > min_allocation_unit)
{
mem_bin_num += mem_bin_count;
@@ -1344,14 +1350,6 @@ ulong Query_cache::init_cache()
query_cache_size -= additional_data_size;
STRUCT_LOCK(&structure_guard_mutex);
- if (max_mem_bin_size <= min_allocation_unit)
- {
- DBUG_PRINT("qcache",
- (" max bin size (%lu) <= min_allocation_unit => cache disabled",
- max_mem_bin_size));
- STRUCT_UNLOCK(&structure_guard_mutex);
- goto err;
- }
if (!(cache = (byte *)
my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
@@ -1432,7 +1430,8 @@ ulong Query_cache::init_cache()
#else
// windows, OS/2 or other case insensitive file names work around
VOID(hash_init(&tables,
- lower_case_table_names ? &my_charset_bin : system_charset_info,
+ lower_case_table_names ? &my_charset_bin :
+ system_charset_info,
def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0));
#endif
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 9003d4b36cd..ba7c08ff15f 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -553,14 +553,14 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
String **pointers= (String**)alloc_root(mem_root,
sizeof(String*)*names->elements);
- String **pos= pointers;
+ String **pos;
+ String **end= pointers + names->elements;
List_iterator<String> it(*names);
- while ((*pos++= it++));
+ for ( pos= pointers; pos!=end; (*pos++= it++));
qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp);
- String **end= pointers + names->elements;
for (pos= pointers; pos!=end; pos++)
{
protocol->prepare_for_resend();
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c3a399cd5a7..f65ef4b968a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1421,6 +1421,24 @@ void select_insert::send_error(uint errcode,const char *err)
::send_error(thd,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
+ /*
+ If at least one row has been inserted/modified and will stay in the table
+ (the table doesn't have transactions) (example: we got a duplicate key
+ error while inserting into a MyISAM table) we must write to the binlog (and
+ the error code will make the slave stop).
+ */
+ if ((info.copied || info.deleted) && !table->file->has_transactions())
+ {
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For binary log
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ table->file->has_transactions());
+ mysql_bin_log.write(&qinfo);
+ }
+ }
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
ha_rollback_stmt(thd);
@@ -1442,7 +1460,10 @@ bool select_insert::send_eof()
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
+ if (last_insert_id)
+ thd->insert_id(last_insert_id); // For binary log
/* Write to binlog before commiting transaction */
+ mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -1467,10 +1488,7 @@ bool select_insert::send_eof()
else
sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
thd->cuted_fields);
- if (last_insert_id)
- thd->insert_id(last_insert_id); // For update log
::send_ok(thd,info.copied+info.deleted,last_insert_id,buff);
- mysql_update_log.write(thd,thd->query,thd->query_length);
return 0;
}
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f31b3305e07..a01c98bb283 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -71,7 +71,7 @@ enum enum_sql_command {
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
- SQLCOM_HELP,
+ SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL,
/* This should be the last !!! */
SQLCOM_END
diff --git a/sql/sql_list.h b/sql/sql_list.h
index ff21663576a..2450b2051f2 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -33,6 +33,8 @@ public:
{
return (void*) sql_alloc((uint) size);
}
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size) {} /*lint -e715 */
static void operator delete[](void *ptr, size_t size) {}
#ifdef HAVE_purify
@@ -190,6 +192,7 @@ public:
inline void *replace(void *element)
{ // Return old element
void *tmp=current->info;
+ DBUG_ASSERT(current->info != 0);
current->info=element;
return tmp;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f098ce0d0b6..a9a29904b60 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -891,7 +891,11 @@ pthread_handler_decl(handle_one_connection,arg)
send_error(thd,net->last_errno,NullS);
statistic_increment(aborted_threads,&LOCK_status);
}
-
+ else if (thd->killed)
+ {
+ statistic_increment(aborted_threads,&LOCK_status);
+ }
+
end_thread:
close_connection(thd, 0, 1);
end_thread(thd,1);
@@ -1068,7 +1072,10 @@ bool do_command(THD *thd)
vio_description(net->vio)));
/* Check if we can continue without closing the connection */
if (net->error != 3)
+ {
+ statistic_increment(aborted_threads,&LOCK_status);
DBUG_RETURN(TRUE); // We have to close it.
+ }
send_error(thd,net->last_errno,NullS);
net->error= 0;
DBUG_RETURN(FALSE);
@@ -2897,6 +2904,38 @@ mysql_execute_command(THD *thd)
res= -1;
#endif
break;
+ case SQLCOM_DROP_USER:
+ {
+ if (check_access(thd, GRANT_ACL,"mysql",0,1))
+ break;
+ if (!(res= mysql_drop_user(thd, lex->users_list)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_REVOKE_ALL:
+ {
+ if (check_access(thd, GRANT_ACL ,"mysql",0,1))
+ break;
+ if (!(res = mysql_revoke_all(thd, lex->users_list)))
+ {
+ mysql_update_log.write(thd, thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+ send_ok(thd);
+ }
+ break;
+ }
case SQLCOM_REVOKE:
case SQLCOM_GRANT:
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 95ac57013da..fcddc2d2252 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -663,7 +663,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
thd->protocol_simple.send_fields(&fields, 0) ||
send_item_params(stmt))
DBUG_RETURN(1);
- join->cleanup(thd);
+ join->cleanup();
}
DBUG_RETURN(0);
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index fe47e553cf3..121411379f8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -997,7 +997,7 @@ int show_binlog_events(THD* thd)
{
LEX_MASTER_INFO *lex_mi = &thd->lex.mi;
ha_rows event_count, limit_start, limit_end;
- my_off_t pos = lex_mi->pos;
+ my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
@@ -1025,12 +1025,6 @@ int show_binlog_events(THD* thd)
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
goto err;
- if (pos < 4)
- {
- errmsg = "Invalid log position";
- goto err;
- }
-
pthread_mutex_lock(log_lock);
my_b_seek(&log, pos);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4167da5802a..61a64573eaa 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -138,7 +138,6 @@ static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool alloc_group_fields(JOIN *join,ORDER *group);
-static bool make_sum_func_list(JOIN *join,List<Item> &fields);
// Create list for using with tempory table
static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
List<Item> &new_list1,
@@ -153,7 +152,7 @@ static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
-static void init_sum_functions(Item_sum **func);
+static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct, const char *message=NullS);
@@ -313,9 +312,11 @@ JOIN::prepare(Item ***rref_pointer_array,
if (having->with_sum_func)
having->split_sum_func(ref_pointer_array, all_fields);
}
-
+
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
+
+
/*
Check if one one uses a not constant column with group functions
and no GROUP BY.
@@ -345,45 +346,47 @@ JOIN::prepare(Item ***rref_pointer_array,
for (table=tables_list ; table ; table=table->next)
tables++;
}
+ {
+ /* Caclulate the number of groups */
+ send_group_parts= 0;
+ for (ORDER *group= group_list ; group ; group= group->next)
+ send_group_parts++;
+ }
+
procedure= setup_procedure(thd, proc_param, result, fields_list, &error);
if (error)
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (procedure)
{
if (setup_new_fields(thd, tables_list, fields_list, all_fields,
procedure->param_fields))
- { /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
- }
+ goto err; /* purecov: inspected */
if (procedure->group)
{
if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
}
#ifdef NOT_NEEDED
else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
- delete procedure;
- DBUG_RETURN(-1);
+ goto err;
}
#endif
if (order && (procedure->flags & PROC_NO_SORT))
- { /* purecov: inspected */
+ { /* purecov: inspected */
my_message(0,"Can't use order with this procedure",MYF(0)); /* purecov: inspected */
- delete procedure; /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
}
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
+ ref_pointer_array_size= all_fields.elements*sizeof(Item*);
this->group= group_list != 0;
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
@@ -398,15 +401,23 @@ JOIN::prepare(Item ***rref_pointer_array,
if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
- delete procedure;
- DBUG_RETURN(-1);
+ goto err;
}
#endif
if (!procedure && result->prepare(fields_list, unit))
- { /* purecov: inspected */
- DBUG_RETURN(-1); /* purecov: inspected */
- }
+ goto err; /* purecov: inspected */
+
+ if (select_lex->olap == ROLLUP_TYPE && rollup_init())
+ goto err;
+ if (alloc_func_list())
+ goto err;
+
DBUG_RETURN(0); // All OK
+
+err:
+ delete procedure; /* purecov: inspected */
+ procedure= 0;
+ DBUG_RETURN(-1); /* purecov: inspected */
}
/*
@@ -638,7 +649,9 @@ JOIN::optimize()
else if (thd->is_fatal_error) // End of memory
DBUG_RETURN(1);
}
- group_list= remove_const(this, group_list, conds, &simple_group);
+ simple_group= 0;
+ if (rollup.state == ROLLUP::STATE_NONE)
+ group_list= remove_const(this, group_list, conds, &simple_group);
if (!group_list && group)
{
order=0; // The output has only one row
@@ -788,14 +801,14 @@ JOIN::optimize()
thd->proc_info="Sorting for group";
if (create_sort_index(thd, &join_tab[const_tables], group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
- make_sum_func_list(this, all_fields) ||
- alloc_group_fields(this, group_list))
+ alloc_group_fields(this, group_list) ||
+ make_sum_func_list(all_fields, fields_list, 1))
DBUG_RETURN(1);
group_list=0;
}
else
{
- if (make_sum_func_list(this, all_fields))
+ if (make_sum_func_list(all_fields, fields_list, 0))
DBUG_RETURN(1);
if (!group_list && ! exec_tmp_table1->distinct && order && simple_order)
{
@@ -862,7 +875,7 @@ int
JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
- //TODO move to unit reinit
+ /* TODO move to unit reinit */
unit->offset_limit_cnt =select_lex->offset_limit;
unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
if (unit->select_limit_cnt < select_lex->select_limit)
@@ -873,7 +886,7 @@ JOIN::reinit()
if (setup_tables(tables_list))
DBUG_RETURN(1);
- // Reset of sum functions
+ /* Reset of sum functions */
first_record= 0;
if (sum_funcs)
{
@@ -897,7 +910,7 @@ JOIN::reinit()
filesort_free_buffers(exec_tmp_table2);
}
if (items0)
- memcpy(ref_pointer_array, items0, ref_pointer_array_size);
+ set_items_ref_array(items0);
if (tmp_join)
restore_tmp();
@@ -977,9 +990,6 @@ JOIN::exec()
DBUG_VOID_RETURN;
}
- /* Perform FULLTEXT search before all regular searches */
- //init_ftfuncs(thd, select_lex, test(order));
-
JOIN *curr_join= this;
List<Item> *curr_all_fields= &all_fields;
List<Item> *curr_fields_list= &fields_list;
@@ -1030,7 +1040,7 @@ JOIN::exec()
}
curr_all_fields= &tmp_all_fields1;
curr_fields_list= &tmp_fields_list1;
- memcpy(ref_pointer_array, items1, ref_pointer_array_size);
+ set_items_ref_array(items1);
if (sort_and_group || curr_tmp_table->group)
{
@@ -1079,7 +1089,8 @@ JOIN::exec()
if (make_simple_join(curr_join, curr_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(curr_join, group_list);
- count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1,
+ count_field_types(&curr_join->tmp_table_param,
+ curr_join->tmp_all_fields1,
curr_join->select_distinct && !curr_join->group_list);
curr_join->tmp_table_param.hidden_field_count=
(curr_join->tmp_all_fields1.elements-
@@ -1117,7 +1128,8 @@ JOIN::exec()
thd->proc_info="Copying to group table";
tmp_error= -1;
- if (make_sum_func_list(curr_join, *curr_all_fields) ||
+ if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
+ 1) ||
(tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
0)))
{
@@ -1141,7 +1153,7 @@ JOIN::exec()
}
curr_fields_list= &curr_join->tmp_fields_list2;
curr_all_fields= &curr_join->tmp_all_fields2;
- memcpy(ref_pointer_array, items2, ref_pointer_array_size);
+ set_items_ref_array(items2);
curr_join->tmp_table_param.field_count+=
curr_join->tmp_table_param.sum_func_count;
curr_join->tmp_table_param.sum_func_count= 0;
@@ -1169,9 +1181,7 @@ JOIN::exec()
}
if (procedure)
- {
count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0);
- }
if (curr_join->group || curr_join->tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
@@ -1201,10 +1211,10 @@ JOIN::exec()
}
curr_fields_list= &tmp_fields_list3;
curr_all_fields= &tmp_all_fields3;
- memcpy(ref_pointer_array, items3, ref_pointer_array_size);
+ set_items_ref_array(items3);
- if (make_sum_func_list(curr_join, *curr_all_fields) ||
- thd->is_fatal_error)
+ if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
+ 1) || thd->is_fatal_error)
DBUG_VOID_RETURN;
}
if (curr_join->group_list || curr_join->order)
@@ -1291,7 +1301,7 @@ JOIN::exec()
*/
int
-JOIN::cleanup(THD *thd)
+JOIN::cleanup()
{
DBUG_ENTER("JOIN::cleanup");
select_lex->join= 0;
@@ -1312,7 +1322,7 @@ JOIN::cleanup(THD *thd)
}
}
tmp_join->tmp_join= 0;
- DBUG_RETURN(tmp_join->cleanup(thd));
+ DBUG_RETURN(tmp_join->cleanup());
}
lock=0; // It's faster to unlock later
@@ -1396,7 +1406,7 @@ err:
thd->limit_found_rows= curr_join->send_records;
thd->examined_row_count= curr_join->examined_rows;
thd->proc_info="end";
- err= join->cleanup(thd);
+ err= join->cleanup();
if (thd->net.report_error)
err= -1;
delete join;
@@ -2916,7 +2926,6 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->tmp_table_param.func_count=0;
join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
join->first_record=join->sort_and_group=0;
- join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
join->row_limit=join->unit->select_limit_cnt;
@@ -5715,8 +5724,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
- else if (join->do_send_rows)
- error=join->procedure->send_row(*join->fields) ? 1 : 0;
+ else
+ {
+ if (join->do_send_rows)
+ error=join->procedure->send_row(*join->fields) ? 1 : 0;
+ join->send_records++;
+ }
if (end_of_records && join->procedure->end_of_records())
error= 1; // Fatal error
}
@@ -5730,17 +5743,23 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
- else if (join->do_send_rows)
- error=join->result->send_data(*join->fields) ? 1 : 0;
+ else
+ {
+ if (join->do_send_rows)
+ error=join->result->send_data(*join->fields) ? 1 : 0;
+ join->send_records++;
+ }
+ if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0)
+ {
+ if (join->rollup_send_data((uint) (idx+1)))
+ error= 1;
+ }
}
if (error > 0)
DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
- {
- join->send_records++;
DBUG_RETURN(0);
- }
- if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
+ if (join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
@@ -5760,7 +5779,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (idx < (int) join->send_group_parts)
{
copy_fields(&join->tmp_table_param);
- init_sum_functions(join->sum_funcs);
+ if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
+ DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@@ -6016,7 +6036,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.items_to_copy);
- init_sum_functions(join->sum_funcs);
+ if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1]))
+ DBUG_RETURN(-1);
if (join->procedure)
join->procedure->add();
DBUG_RETURN(0);
@@ -7674,7 +7695,10 @@ err2:
/*
- Copy fields and null values between two tables
+ Make a copy of all simple SELECT'ed items
+
+ This is done at the start of a new group so that we can retrieve
+ these later when the group changes.
*/
void
@@ -7694,33 +7718,76 @@ copy_fields(TMP_TABLE_PARAM *param)
}
-/*****************************************************************************
- Make an array of pointer to sum_functions to speed up sum_func calculation
-*****************************************************************************/
+/*
+ Make an array of pointers to sum_functions to speed up sum_func calculation
-static bool
-make_sum_func_list(JOIN *join,List<Item> &fields)
+ SYNOPSIS
+ alloc_func_list()
+
+ RETURN
+ 0 ok
+ 1 Error
+*/
+
+bool JOIN::alloc_func_list()
{
+ uint func_count, group_parts;
+ DBUG_ENTER("alloc_func_list");
+
+ func_count= tmp_table_param.sum_func_count;
+ /*
+ If we are using rollup, we need a copy of the summary functions for
+ each level
+ */
+ if (rollup.state != ROLLUP::STATE_NONE)
+ func_count*= (send_group_parts+1);
+
+ group_parts= send_group_parts;
+ /*
+ If distinct, reserve memory for possible
+ disctinct->group_by optimization
+ */
+ if (select_distinct)
+ group_parts+= fields_list.elements;
+
+ /* This must use calloc() as rollup_make_fields depends on this */
+ sum_funcs= (Item_sum**) thd->calloc(sizeof(Item_sum**) * (func_count+1) +
+ sizeof(Item_sum***) * (group_parts+1));
+ sum_funcs_end= (Item_sum***) (sum_funcs+func_count+1);
+ DBUG_RETURN(sum_funcs == 0);
+}
+
+
+bool JOIN::make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
+ bool before_group_by)
+{
+ List_iterator_fast<Item> it(all_fields);
+ Item_sum **func;
+ Item *item;
DBUG_ENTER("make_sum_func_list");
- Item_sum **func =
- (Item_sum**) sql_alloc(sizeof(Item_sum*)*
- (join->tmp_table_param.sum_func_count+1));
- if (!func)
- DBUG_RETURN(TRUE);
- List_iterator<Item> it(fields);
- join->sum_funcs=func;
- Item *field;
- while ((field=it++))
+ func= sum_funcs;
+ while ((item=it++))
{
- if (field->type() == Item::SUM_FUNC_ITEM && !field->const_item())
+ if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
{
- *func++=(Item_sum*) field;
+ *func++= (Item_sum*) item;
/* let COUNT(DISTINCT) create the temporary table */
- if (((Item_sum*) field)->setup(join->thd))
+ if (((Item_sum*) item)->setup(thd))
DBUG_RETURN(TRUE);
}
}
+ if (before_group_by && rollup.state == ROLLUP::STATE_INITED)
+ {
+ rollup.state= ROLLUP::STATE_READY;
+ if (rollup_make_fields(all_fields, send_fields, &func))
+ DBUG_RETURN(TRUE); // Should never happen
+ }
+ else if (rollup.state == ROLLUP::STATE_NONE)
+ {
+ for (uint i=0 ; i <= send_group_parts ;i++)
+ sum_funcs_end[i]= func;
+ }
*func=0; // End marker
DBUG_RETURN(FALSE);
}
@@ -7816,8 +7883,8 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
all_fields - all fields list
RETURN
- 0 - ok
- !=0 - error
+ 0 ok
+ 1 error
*/
static bool
@@ -7886,12 +7953,21 @@ copy_sum_funcs(Item_sum **func_ptr)
}
-static void
-init_sum_functions(Item_sum **func_ptr)
+static bool
+init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
{
- Item_sum *func;
- for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
- func->reset();
+ for (; func_ptr != end_ptr ;func_ptr++)
+ {
+ if ((*func_ptr)->reset())
+ return 1;
+ }
+ /* If rollup, calculate the upper sum levels */
+ for ( ; *func_ptr ; func_ptr++)
+ {
+ if ((*func_ptr)->add())
+ return 1;
+ }
+ return 0;
}
@@ -7916,10 +7992,10 @@ copy_funcs(Item **func_ptr)
}
-/*****************************************************************************
+/*
Create a condition for a const reference and add this to the
currenct select for the table
-*****************************************************************************/
+*/
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
{
@@ -7935,7 +8011,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
for (uint i=0 ; i < join_tab->ref.key_parts ; i++)
{
- Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].fieldnr-1];
+ Field *field=table->field[table->key_info[join_tab->ref.key].key_part[i].
+ fieldnr-1];
Item *value=join_tab->ref.items[i];
cond->add(new Item_func_equal(new Item_field(field),value));
}
@@ -7958,7 +8035,241 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
DBUG_RETURN(error ? TRUE : FALSE);
}
+
+/*
+ Free joins of subselect of this select.
+
+ free_underlaid_joins()
+ thd - THD pointer
+ select - pointer to st_select_lex which subselects joins we will free
+*/
+
+void free_underlaid_joins(THD *thd, SELECT_LEX *select)
+{
+ for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ unit->cleanup();
+}
+
+/****************************************************************************
+ ROLLUP handling
+****************************************************************************/
+
+/* Allocate memory needed for other rollup functions */
+
+bool JOIN::rollup_init()
+{
+ uint i,j;
+ ORDER *group;
+ Item **ref_array;
+
+ tmp_table_param.quick_group= 0; // Can't create groups in tmp table
+ rollup.state= ROLLUP::STATE_INITED;
+
+ /*
+ Create pointers to the different sum function groups
+ These are updated by rollup_make_fields()
+ */
+ tmp_table_param.group_parts= send_group_parts;
+
+ if (!(rollup.fields= (List<Item>*) thd->alloc((sizeof(Item*) +
+ sizeof(List<Item>) +
+ ref_pointer_array_size)
+ * send_group_parts)))
+ return 1;
+ rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
+ ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
+ rollup.item_null= new (&thd->mem_root) Item_null();
+
+ /*
+ Prepare space for field list for the different levels
+ These will be filled up in rollup_make_fields()
+ */
+ for (i= 0 ; i < send_group_parts ; i++)
+ {
+ List<Item> *fields= &rollup.fields[i];
+ fields->empty();
+ rollup.ref_pointer_arrays[i]= ref_array;
+ ref_array+= all_fields.elements;
+ for (j=0 ; j < fields_list.elements ; j++)
+ fields->push_back(rollup.item_null);
+ }
+ return 0;
+}
+
+
+/*
+ Fill up rollup structures with pointers to fields to use
+
+ SYNOPSIS
+ rollup_make_fields()
+ all_fields List of all fields (hidden and real ones)
+ fields Pointer to selected fields
+ func Store here a pointer to all fields
+
+ IMPLEMENTATION:
+ Creates copies of item_sum items for each sum level
+
+ RETURN
+ 0 if ok
+ In this case func is pointing to next not used element.
+ 1 on error
+*/
+
+bool JOIN::rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
+ Item_sum ***func)
+{
+ List_iterator_fast<Item> it(all_fields);
+ Item *first_field= fields.head();
+ uint level;
+
+ /*
+ Create field lists for the different levels
+
+ The idea here is to have a separate field list for each rollup level to
+ avoid all runtime checks of which columns should be NULL.
+
+ The list is stored in reverse order to get sum function in such an order
+ in func that it makes it easy to reset them with init_sum_functions()
+
+ Assuming: SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
+
+ rollup.fields[0] will contain list where a,b,c is NULL
+ rollup.fields[1] will contain list where b,c is NULL
+ ...
+ rollup.ref_pointer_array[#] points to fields for rollup.fields[#]
+ ...
+ sum_funcs_end[0] points to all sum functions
+ sum_funcs_end[1] points to all sum functions, except grand totals
+ ...
+ */
+
+ for (level=0 ; level < send_group_parts > 0 ; level++)
+ {
+ uint i;
+ uint pos= send_group_parts - level -1;
+ bool real_fields= 0;
+ Item *item;
+ List_iterator<Item> new_it(rollup.fields[pos]);
+ Item **ref_array_start= rollup.ref_pointer_arrays[pos];
+ ORDER *start_group;
+
+ /* Point to first hidden field */
+ Item **ref_array= ref_array_start + all_fields.elements-1;
+
+ /* Remember where the sum functions ends for the previous level */
+ sum_funcs_end[pos+1]= *func;
+
+ /* Find the start of the group for this level */
+ for (i= 0, start_group= group_list ;
+ i++ < pos ;
+ start_group= start_group->next)
+ ;
+
+ it.rewind();
+ while ((item= it++))
+ {
+ if (item == first_field)
+ {
+ real_fields= 1; // End of hidden fields
+ ref_array= ref_array_start;
+ }
+
+ if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item())
+ {
+ /*
+ This is a top level summary function that must be replaced with
+ a sum function that is reset for this level.
+
+ NOTE: This code creates an object which is not that nice in a
+ sub select. Fortunately it's not common to have rollup in
+ sub selects.
+ */
+ item= item->copy_or_same(thd);
+ ((Item_sum*) item)->make_unique();
+ if (((Item_sum*) item)->setup(thd))
+ return 1;
+ *(*func)= (Item_sum*) item;
+ (*func)++;
+ }
+ else if (real_fields)
+ {
+ /* Check if this is something that is part of this group by */
+ ORDER *group;
+ for (group= start_group ; group ; group= group->next)
+ {
+ if (*group->item == item)
+ {
+ /*
+ This is an element that is used by the GROUP BY and should be
+ set to NULL in this level
+ */
+ item->maybe_null= 1; // Value will be null sometimes
+ item= rollup.item_null;
+ break;
+ }
+ }
+ }
+ *ref_array= item;
+ if (real_fields)
+ {
+ (void) new_it++; // Point to next item
+ new_it.replace(item); // Replace previous
+ ref_array++;
+ }
+ else
+ ref_array--;
+ }
+ }
+ sum_funcs_end[0]= *func; // Point to last function
+ return 0;
+}
+
+/*
+ Send all rollup levels higher than the current one to the client
+
+ SYNOPSIS:
+ rollup_send_data()
+ idx Level we are on:
+ 0 = Total sum level
+ 1 = First group changed (a)
+ 2 = Second group changed (a,b)
+
+ SAMPLE
+ SELECT a, b, c SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP
+
+ RETURN
+ 0 ok
+ 1 If send_data_failed()
+*/
+
+int JOIN::rollup_send_data(uint idx)
+{
+ uint i;
+ for (i= send_group_parts ; i-- > idx ; )
+ {
+ /* Get reference pointers to sum functions in place */
+ memcpy((char*) ref_pointer_array,
+ (char*) rollup.ref_pointer_arrays[i],
+ ref_pointer_array_size);
+ if ((!having || having->val_int()))
+ {
+ if (send_records < unit->select_limit_cnt &&
+ result->send_data(rollup.fields[i]))
+ return 1;
+ send_records++;
+ }
+ }
+ /* Restore ref_pointer_array */
+ set_items_ref_array(current_ref_pointer_array);
+ return 0;
+}
+
+
/****************************************************************************
+ EXPLAIN handling
+
Send a description about what how the select will be done to stdout
****************************************************************************/
@@ -8198,19 +8509,3 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
result, unit, select_lex, 0);
DBUG_RETURN(res);
}
-
-/*
- Free joins of subselect of this select.
-
- free_underlaid_joins()
- thd - THD pointer
- select - pointer to st_select_lex which subselects joins we will free
-*/
-
-void free_underlaid_joins(THD *thd, SELECT_LEX *select)
-{
- for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
- unit;
- unit= unit->next_unit())
- unit->cleanup();
-}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 7f3669f7478..df21d337b54 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -106,12 +106,22 @@ typedef struct st_join_table {
} JOIN_TAB;
-typedef struct st_position { /* Used in find_best */
+typedef struct st_position /* Used in find_best */
+{
double records_read;
JOIN_TAB *table;
KEYUSE *key;
} POSITION;
+typedef struct st_rollup
+{
+ enum State { STATE_NONE, STATE_INITED, STATE_READY };
+ State state;
+ Item *item_null;
+ Item ***ref_pointer_arrays;
+ List<Item> *fields;
+} ROLLUP;
+
class JOIN :public Sql_alloc
{
@@ -132,7 +142,7 @@ class JOIN :public Sql_alloc
// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
- Item_sum **sum_funcs;
+ Item_sum **sum_funcs, ***sum_funcs_end;
Procedure *procedure;
Item *having;
Item *tmp_having; // To store Having when processed temporary table
@@ -146,6 +156,7 @@ class JOIN :public Sql_alloc
SELECT_LEX *select_lex;
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
+ ROLLUP rollup; // Used with rollup
bool select_distinct, //Is select distinct?
no_order, simple_order, simple_group,
@@ -159,7 +170,7 @@ class JOIN :public Sql_alloc
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
//Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
- List<Item> & fields_list; // hold field list passed to mysql_select
+ List<Item> &fields_list; // hold field list passed to mysql_select
int error;
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
@@ -168,15 +179,15 @@ class JOIN :public Sql_alloc
SQL_SELECT *select; //created in optimisation phase
Item **ref_pointer_array; //used pointer reference for this select
// Copy of above to be used with different lists
- Item **items0, **items1, **items2, **items3;
+ Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
uint ref_pointer_array_size; // size of above in bytes
const char *zero_result_cause; // not 0 if exec must return zero result
bool union_part; // this subselect is part of union
bool optimized; // flag to avoid double optimization in EXPLAIN
- JOIN(THD *thd, List<Item> &fields,
- ulong select_options, select_result *result):
+ JOIN(THD *thd_arg, List<Item> &fields, ulong select_options_arg,
+ select_result *result_arg):
join_tab(0),
table(0),
tables(0), const_tables(0),
@@ -184,13 +195,13 @@ class JOIN :public Sql_alloc
do_send_rows(1),
send_records(0), found_records(0), examined_rows(0),
exec_tmp_table1(0), exec_tmp_table2(0),
- thd(thd),
+ thd(thd_arg),
sum_funcs(0),
procedure(0),
having(0), tmp_having(0),
- select_options(select_options),
- result(result),
- lock(thd->lock),
+ select_options(select_options_arg),
+ result(result_arg),
+ lock(thd_arg->lock),
select_lex(0), //for safety
tmp_join(0),
select_distinct(test(select_options & SELECT_DISTINCT)),
@@ -212,6 +223,7 @@ class JOIN :public Sql_alloc
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.copy_field=0;
tmp_table_param.end_write_records= HA_POS_ERROR;
+ rollup.state= ROLLUP::STATE_NONE;
}
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
@@ -221,15 +233,28 @@ class JOIN :public Sql_alloc
int optimize();
int reinit();
void exec();
- int cleanup(THD *thd);
+ int cleanup();
void restore_tmp();
+ bool alloc_func_list();
+ bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
+ bool before_group_by);
+ inline void set_items_ref_array(Item **ptr)
+ {
+ memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
+ current_ref_pointer_array= ptr;
+ }
inline void init_items_ref_array()
{
items0= ref_pointer_array + all_fields.elements;
- ref_pointer_array_size= all_fields.elements*sizeof(Item*);
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
+ current_ref_pointer_array= items0;
}
+
+ bool rollup_init();
+ bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
+ Item_sum ***func);
+ int JOIN::rollup_send_data(uint idx);
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 277bc5d8337..1c4954e0276 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1006,12 +1006,7 @@ static void
append_identifier(THD *thd, String *packet, const char *name)
{
char qtype;
- if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) ||
- (thd->variables.sql_mode & MODE_POSTGRESQL) ||
- (thd->variables.sql_mode & MODE_ORACLE) ||
- (thd->variables.sql_mode & MODE_MSSQL) ||
- (thd->variables.sql_mode & MODE_DB2) ||
- (thd->variables.sql_mode & MODE_SAPDB))
+ if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
qtype= '\"';
else
qtype= '`';
@@ -1033,16 +1028,16 @@ append_identifier(THD *thd, String *packet, const char *name)
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
- my_bool foreign_db_mode= ((thd->variables.sql_mode & MODE_POSTGRESQL) ||
- (thd->variables.sql_mode & MODE_ORACLE) ||
- (thd->variables.sql_mode & MODE_MSSQL) ||
- (thd->variables.sql_mode & MODE_DB2) ||
- (thd->variables.sql_mode & MODE_SAPDB));
- my_bool limited_mysql_mode= ((thd->variables.sql_mode &
- MODE_NO_FIELD_OPTIONS) ||
- (thd->variables.sql_mode & MODE_MYSQL323) ||
- (thd->variables.sql_mode & MODE_MYSQL40));
-
+ my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
+ MODE_ORACLE |
+ MODE_MSSQL |
+ MODE_DB2 |
+ MODE_SAPDB |
+ MODE_ANSI)) != 0;
+ my_bool limited_mysql_mode= (thd->variables.sql_mode &
+ (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
+ MODE_MYSQL40)) != 0;
+
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
diff --git a/sql/sql_state.c b/sql/sql_state.c
new file mode 100644
index 00000000000..355b847f239
--- /dev/null
+++ b/sql/sql_state.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to map mysqld errno to sql_state */
+
+#include <my_global.h>
+#include <mysqld_error.h>
+
+struct st_map_errno_to_sqlstate
+{
+ uint mysql_errno;
+ const char *odbc_state;
+ const char *jdbc_state;
+};
+
+struct st_map_errno_to_sqlstate sqlstate_map[]=
+{
+#include <sql_state.h>
+};
+
+const char *mysql_errno_to_sqlstate(uint mysql_errno)
+{
+ uint first=0, end= array_elements(sqlstate_map)-1;
+ struct st_map_errno_to_sqlstate *map;
+
+ /* Do binary search in the sorted array */
+ while (first != end)
+ {
+ uint mid= (first+end)/2;
+ map= sqlstate_map+mid;
+ if (map->mysql_errno < mysql_errno)
+ first= mid+1;
+ else
+ end= mid;
+ }
+ map= sqlstate_map+first;
+ if (map->mysql_errno == mysql_errno)
+ return map->odbc_state;
+ return "HY000"; /* General error */
+}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index cf6645fa23e..0a3e8d0db9f 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -28,10 +28,6 @@
#include <floatingpoint.h>
#endif
-CHARSET_INFO *system_charset_info= &my_charset_utf8_general_ci;
-CHARSET_INFO *files_charset_info= &my_charset_utf8_general_ci;
-CHARSET_INFO *national_charset_info= &my_charset_utf8_general_ci;
-
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
diff --git a/sql/sql_string.h b/sql/sql_string.h
index ee38853a2d3..e88c9389589 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -69,7 +69,10 @@ public:
Alloced_length=str.Alloced_length; alloced=0;
str_charset=str.str_charset;
}
- static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size)
+ { return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
{ sql_element_free(ptr_arg); }
~String() { free(); }
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index c53ca0b68a8..2b329aac305 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1082,58 +1082,76 @@ mysql_rename_table(enum db_type base,
}
/*
- close table in this thread and force close + reopen in other threads
- This assumes that the calling thread has lock on LOCK_open
- Win32 clients must also have a WRITE LOCK on the table !
+ Force all other threads to stop using the table
+
+ SYNOPSIS
+ wait_while_table_is_used()
+ thd Thread handler
+ table Table to remove from cache
+
+ NOTES
+ When returning, the table will be unusable for other threads until
+ the table is closed.
+
+ PREREQUISITES
+ Lock on LOCK_open
+ Win32 clients must also have a WRITE LOCK on the table !
*/
-static void safe_remove_from_cache(THD *thd,TABLE *table)
+static void wait_while_table_is_used(THD *thd,TABLE *table)
{
- DBUG_ENTER("safe_remove_from_cache");
- if (table)
- {
- DBUG_PRINT("enter",("table: %s", table->real_name));
- VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
- /* Mark all tables that are in use as 'old' */
- mysql_lock_abort(thd,table); // end threads waiting on lock
+ DBUG_PRINT("enter",("table: %s", table->real_name));
+ DBUG_ENTER("wait_while_table_is_used");
+ safe_mutex_assert_owner(&LOCK_open);
-#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2)
- /* Wait until all there are no other threads that has this table open */
- while (remove_table_from_cache(thd,table->table_cache_key,
- table->real_name))
- {
- dropping_tables++;
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- dropping_tables--;
- }
-#else
- (void) remove_table_from_cache(thd,table->table_cache_key,
- table->real_name);
-#endif
- /* When lock on LOCK_open is freed other threads can continue */
- pthread_cond_broadcast(&COND_refresh);
+ VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
+ /* Mark all tables that are in use as 'old' */
+ mysql_lock_abort(thd, table); // end threads waiting on lock
+
+ /* Wait until all there are no other threads that has this table open */
+ while (remove_table_from_cache(thd,table->table_cache_key,
+ table->real_name))
+ {
+ dropping_tables++;
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ dropping_tables--;
}
DBUG_VOID_RETURN;
}
+/*
+ Close a cached table
-bool close_cached_table(THD *thd,TABLE *table)
+ SYNOPSIS
+ clsoe_cached_table()
+ thd Thread handler
+ table Table to remove from cache
+
+ NOTES
+ Function ends by signaling threads waiting for the table to try to
+ reopen the table.
+
+ PREREQUISITES
+ Lock on LOCK_open
+ Win32 clients must also have a WRITE LOCK on the table !
+*/
+
+static bool close_cached_table(THD *thd, TABLE *table)
{
DBUG_ENTER("close_cached_table");
- safe_mutex_assert_owner(&LOCK_open);
-
- if (table)
+
+ wait_while_table_is_used(thd,table);
+ /* Close lock if this is not got with LOCK TABLES */
+ if (thd->lock)
{
- safe_remove_from_cache(thd,table);
- /* Close lock if this is not got with LOCK TABLES */
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0; // Start locked threads
- }
- /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
- thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0; // Start locked threads
}
+ /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
+ thd->open_tables=unlink_open_table(thd,thd->open_tables,table);
+
+ /* When lock on LOCK_open is freed other threads can continue */
+ pthread_cond_broadcast(&COND_refresh);
DBUG_RETURN(0);
}
@@ -1262,10 +1280,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id);
- pthread_mutex_lock(&LOCK_open);
- close_cached_table(thd,table_list->table);
- pthread_mutex_unlock(&LOCK_open);
-
+ /* If we could open the table, close it */
+ if (table_list->table)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ close_cached_table(thd, table);
+ pthread_mutex_unlock(&LOCK_open);
+ }
if (lock_and_wait_for_table_name(thd,table_list))
{
error= -1;
@@ -1732,10 +1753,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
fn_same(new_name_buff,table_name,3);
if (lower_case_table_names)
my_casedn_str(system_charset_info,new_name);
- if ((lower_case_table_names &&
- !my_strcasecmp(system_charset_info, new_name_buff,table_name)) ||
- (!lower_case_table_names &&
- !strcmp(new_name_buff,table_name)))
+ if (!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
new_name=table_name; // No. Make later check easier
else
{
@@ -1798,11 +1816,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
else
{
*fn_ext(new_name)=0;
- close_cached_table(thd,table);
+ close_cached_table(thd, table);
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name))
error= -1;
}
- VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
}
if (!error)
@@ -1811,12 +1828,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
case LEAVE_AS_IS:
break;
case ENABLE:
- safe_remove_from_cache(thd,table);
- error= table->file->activate_all_index(thd);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ error= table->file->activate_all_index(thd);
+ /* COND_refresh will be signaled in close_thread_tables() */
break;
case DISABLE:
- safe_remove_from_cache(thd,table);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
table->file->deactivate_non_unique_index(HA_POS_ERROR);
+ /* COND_refresh will be signaled in close_thread_tables() */
break;
}
}
@@ -2251,7 +2274,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
close the original table at before doing the rename
*/
table_name=thd->strdup(table_name); // must be saved
- if (close_cached_table(thd,table))
+ if (close_cached_table(thd, table))
{ // Aborted
VOID(quick_rm_table(new_db_type,new_db,tmp_name));
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -2285,7 +2308,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
This shouldn't happen. We solve this the safe way by
closing the locked table.
*/
- close_cached_table(thd,table);
+ if (table)
+ close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
@@ -2295,7 +2319,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Not table locking or alter table with rename
free locks and remove old table
*/
- close_cached_table(thd,table);
+ if (table)
+ close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name));
}
else
@@ -2315,7 +2340,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (close_data_tables(thd,db,table_name) ||
reopen_tables(thd,1,0))
{ // This shouldn't happen
- close_cached_table(thd,table); // Remove lock for table
+ if (table)
+ close_cached_table(thd,table); // Remove lock for table
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1d0f37f0042..f47900d8276 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -389,7 +389,7 @@ int st_select_lex_unit::cleanup()
JOIN *join;
if ((join= sl->join))
{
- error|= sl->join->cleanup(thd);
+ error|= sl->join->cleanup();
delete join;
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1f6364ec427..989d17b006b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -200,7 +200,6 @@ int mysql_update(THD *thd,
*/
uint length;
SORT_FIELD *sortorder;
- List<Item> fields;
ha_rows examined_rows;
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9b2808f93a8..91bd5a77d27 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -804,6 +804,18 @@ master_def:
MASTER_LOG_POS_SYM EQ ulonglong_num
{
Lex->mi.pos = $3;
+ /*
+ If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
+ instead of causing subsequent errors.
+ We need to do it in this file, because only there we know that
+ MASTER_LOG_POS has been explicitely specified. On the contrary
+ in change_master() (sql_repl.cc) we cannot distinguish between 0
+ (MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified),
+ whereas we want to distinguish (specified 0 means "read the binlog
+ from 0" (4 in fact), unspecified means "don't change the position
+ (keep the preceding value)").
+ */
+ Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos);
}
|
MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM
@@ -819,6 +831,8 @@ master_def:
RELAY_LOG_POS_SYM EQ ULONG_NUM
{
Lex->mi.relay_log_pos = $3;
+ /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
+ Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
}
;
@@ -2975,7 +2989,7 @@ olap_opt:
}
lex->current_select->select_lex()->olap= CUBE_TYPE;
net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE");
- YYABORT; /* To be deleted in 4.1 */
+ YYABORT; /* To be deleted in 5.1 */
}
| WITH ROLLUP_SYM
{
@@ -2987,8 +3001,6 @@ olap_opt:
YYABORT;
}
lex->current_select->select_lex()->olap= ROLLUP_TYPE;
- net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP");
- YYABORT; /* To be deleted in 4.1 */
}
;
@@ -3043,20 +3055,7 @@ opt_limit_clause:
;
limit_clause:
- LIMIT
- {
- LEX *lex= Lex;
- if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- lex->current_select->select_lex()->olap !=
- UNSPECIFIED_OLAP_TYPE)
- {
- net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP",
- "LIMIT");
- YYABORT;
- }
- }
- limit_options
- {}
+ LIMIT limit_options {}
;
limit_options:
@@ -3217,7 +3216,7 @@ do: DO_SYM
;
/*
- Drop : delete tables or index
+ Drop : delete tables or index or user
*/
drop:
@@ -3251,7 +3250,16 @@ drop:
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->udf.name = $3;
- };
+ }
+ | DROP USER
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_DROP_USER;
+ lex->users_list.empty();
+ }
+ user_list
+ {}
+ ;
table_list:
@@ -4179,8 +4187,10 @@ user:
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
- $$->user = $1; $$->host.str=NullS;
- }
+ $$->user = $1;
+ $$->host.str= (char *) "%";
+ $$->host.length= 1;
+ }
| ident_or_text '@' ident_or_text
{
THD *thd= YYTHD;
@@ -4343,6 +4353,7 @@ keyword:
| SHARE_SYM {}
| SHUTDOWN {}
| SLAVE {}
+ | SOUNDS_SYM {}
| SQL_CACHE_SYM {}
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
@@ -4363,12 +4374,13 @@ keyword:
| UDF_SYM {}
| UNCOMMITTED_SYM {}
| UNICODE_SYM {}
+ | USER {}
| USE_FRM {}
| VARIABLES {}
| VALUE_SYM {}
| WORK_SYM {}
+ | X509_SYM {}
| YEAR_SYM {}
- | SOUNDS_SYM {}
;
/* Option functions */
@@ -4634,8 +4646,18 @@ revoke:
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char*) &lex->mqh, sizeof(lex->mqh));
}
+ revoke_command
+ {}
+ ;
+
+revoke_command:
grant_privileges ON opt_table FROM user_list
{}
+ |
+ ALL PRIVILEGES ',' GRANT FROM user_list
+ {
+ Lex->sql_command = SQLCOM_REVOKE_ALL;
+ }
;
grant:
diff --git a/sql/time.cc b/sql/time.cc
index eba664a690d..b6ca306e523 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -28,7 +28,6 @@ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037
/* Currently only my_time_zone is inited */
static long my_time_zone=0;
-pthread_mutex_t LOCK_timezone;
void init_time(void)
{
@@ -39,14 +38,14 @@ void init_time(void)
seconds= (time_t) time((time_t*) 0);
localtime_r(&seconds,&tm_tmp);
l_time= &tm_tmp;
- my_time_zone=0;
+ my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */
my_time.year= (uint) l_time->tm_year+1900;
my_time.month= (uint) l_time->tm_mon+1;
my_time.day= (uint) l_time->tm_mday;
my_time.hour= (uint) l_time->tm_hour;
my_time.minute= (uint) l_time->tm_min;
- my_time.second= (uint) l_time->tm_sec;
- VOID(my_gmt_sec(&my_time)); /* Init my_time_zone */
+ my_time.second= (uint) l_time->tm_sec;
+ my_gmt_sec(&my_time, &my_time_zone); /* Init my_time_zone */
}
/*
@@ -57,26 +56,39 @@ void init_time(void)
*/
-long my_gmt_sec(TIME *t)
+long my_gmt_sec(TIME *t, long *my_timezone)
{
uint loop;
time_t tmp;
struct tm *l_time,tm_tmp;
- long diff;
+ long diff, current_timezone;
if (t->hour >= 24)
{ /* Fix for time-loop */
t->day+=t->hour/24;
t->hour%=24;
}
- pthread_mutex_lock(&LOCK_timezone);
- tmp=(time_t) ((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
- (long) days_at_timestart)*86400L + (long) t->hour*3600L +
- (long) (t->minute*60 + t->second)) + (time_t) my_time_zone;
+
+ /*
+ Calculate the gmt time based on current time and timezone
+ The -1 on the end is to ensure that if have a date that exists twice
+ (like 2002-10-27 02:00:0 MET), we will find the initial date.
+
+ By doing -3600 we will have to call localtime_r() several times, but
+ I couldn't come up with a better way to get a repeatable result :(
+
+ We can't use mktime() as it's buggy on many platforms and not thread safe.
+ */
+ tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
+ (long) days_at_timestart)*86400L + (long) t->hour*3600L +
+ (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
+ 3600);
+ current_timezone= my_time_zone;
+
localtime_r(&tmp,&tm_tmp);
l_time=&tm_tmp;
for (loop=0;
- loop < 3 &&
+ loop < 2 &&
(t->hour != (uint) l_time->tm_hour ||
t->minute != (uint) l_time->tm_min);
loop++)
@@ -89,14 +101,16 @@ long my_gmt_sec(TIME *t)
days= -1;
diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
(long) (60*((int) t->minute - (int) l_time->tm_min)));
- my_time_zone+=diff;
- tmp+=(time_t) diff;
+ current_timezone+= diff+3600; // Compensate for -3600 above
+ tmp+= (time_t) diff;
localtime_r(&tmp,&tm_tmp);
l_time=&tm_tmp;
}
- /* Fix that if we are in the not existing daylight saving time hour
- we move the start of the next real hour */
- if (loop == 3 && t->hour != (uint) l_time->tm_hour)
+ /*
+ Fix that if we are in the not existing daylight saving time hour
+ we move the start of the next real hour
+ */
+ if (loop == 2 && t->hour != (uint) l_time->tm_hour)
{
int days= t->day - l_time->tm_mday;
if (days < -1)
@@ -108,11 +122,9 @@ long my_gmt_sec(TIME *t)
if (diff == 3600)
tmp+=3600 - t->minute*60 - t->second; // Move to next hour
else if (diff == -3600)
- tmp-=t->minute*60 + t->second; // Move to next hour
+ tmp-=t->minute*60 + t->second; // Move to previous hour
}
- if ((my_time_zone >=0 ? my_time_zone: -my_time_zone) > 3600L*12)
- my_time_zone=0; /* Wrong date */
- pthread_mutex_unlock(&LOCK_timezone);
+ *my_timezone= current_timezone;
return (long) tmp;
} /* my_gmt_sec */
@@ -428,6 +440,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
time_t str_to_timestamp(const char *str,uint length)
{
TIME l_time;
+ long not_used;
+
if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE)
return(0);
if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR)
@@ -435,7 +449,7 @@ time_t str_to_timestamp(const char *str,uint length)
current_thd->cuted_fields++;
return(0);
}
- return(my_gmt_sec(&l_time));
+ return(my_gmt_sec(&l_time, &not_used));
}
diff --git a/sql/unireg.h b/sql/unireg.h
index 6ddd9856724..4bbfa8b0fae 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -106,8 +106,8 @@
#define SPECIAL_SAFE_MODE 2048
/* Extern defines */
-#define store_record(A,B) bmove_allign((A)->B,(A)->record[0],(size_t) (A)->reclength)
-#define restore_record(A,B) bmove_allign((A)->record[0],(A)->B,(size_t) (A)->reclength)
+#define store_record(A,B) bmove_align((A)->B,(A)->record[0],(size_t) (A)->reclength)
+#define restore_record(A,B) bmove_align((A)->record[0],(A)->B,(size_t) (A)->reclength)
#define cmp_record(A,B) memcmp((A)->record[0],(A)->B,(size_t) (A)->reclength)
#define empty_record(A) { \
restore_record((A),default_values); \
@@ -141,10 +141,13 @@
*/
#define MIN_TURBOBM_PATTERN_LEN 3
-/* Defines for binary logging */
-
-#define BIN_LOG_HEADER_SIZE 4
+/*
+ Defines for binary logging.
+ Do not decrease the value of BIN_LOG_HEADER_SIZE.
+ Do not even increase it before checking code.
+*/
+#define BIN_LOG_HEADER_SIZE 4
#define FLOATING_POINT_BUFFER 331
/* Include prototypes for unireg */