summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/des_key_file.cc2
-rw-r--r--sql/field.cc17
-rw-r--r--sql/field.h2
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/gen_lex_hash.cc8
-rw-r--r--sql/ha_blackhole.cc3
-rw-r--r--sql/ha_federated.cc2
-rw-r--r--sql/ha_innodb.cc63
-rw-r--r--sql/ha_innodb.h1
-rw-r--r--sql/ha_myisammrg.h2
-rw-r--r--sql/ha_ndbcluster.cc22
-rw-r--r--sql/handler.cc32
-rw-r--r--sql/handler.h4
-rw-r--r--sql/hostname.cc4
-rw-r--r--sql/item.cc12
-rw-r--r--sql/item.h43
-rw-r--r--sql/item_func.cc105
-rw-r--r--sql/item_strfunc.cc7
-rw-r--r--sql/item_strfunc.h7
-rw-r--r--sql/item_sum.cc9
-rw-r--r--sql/mysql_priv.h10
-rw-r--r--sql/mysqld.cc158
-rw-r--r--sql/opt_range.cc139
-rw-r--r--sql/set_var.cc27
-rw-r--r--sql/set_var.h4
-rw-r--r--sql/sp.cc9
-rw-r--r--sql/sp_head.cc131
-rw-r--r--sql/sp_rcontext.cc63
-rw-r--r--sql/sp_rcontext.h13
-rw-r--r--sql/spatial.cc47
-rw-r--r--sql/spatial.h3
-rw-r--r--sql/sql_acl.cc203
-rw-r--r--sql/sql_acl.h19
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_class.cc8
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_insert.cc3
-rw-r--r--sql/sql_lex.cc9
-rw-r--r--sql/sql_lex.h19
-rw-r--r--sql/sql_list.h48
-rw-r--r--sql/sql_parse.cc60
-rw-r--r--sql/sql_prepare.cc10
-rw-r--r--sql/sql_select.cc84
-rw-r--r--sql/sql_show.cc46
-rw-r--r--sql/sql_table.cc38
-rw-r--r--sql/sql_udf.cc10
-rw-r--r--sql/sql_update.cc1
-rw-r--r--sql/sql_yacc.yy322
-rw-r--r--sql/structs.h2
-rw-r--r--sql/table.cc9
-rw-r--r--sql/unireg.cc78
52 files changed, 1268 insertions, 664 deletions
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index c6b4c5f2c34..a5a3e78d70f 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -14,7 +14,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <mysql_priv.h>
+#include "mysql_priv.h"
#include <m_ctype.h>
#ifdef HAVE_OPENSSL
diff --git a/sql/field.cc b/sql/field.cc
index 34c5210b43c..54ed4044de5 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2365,9 +2365,20 @@ int Field_new_decimal::store(const char *from, uint length,
my_decimal decimal_value;
DBUG_ENTER("Field_new_decimal::store(char*)");
- switch ((err= str2my_decimal(E_DEC_FATAL_ERROR &
- ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
- from, length, charset, &decimal_value))) {
+ if ((err= str2my_decimal(E_DEC_FATAL_ERROR &
+ ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
+ from, length, charset, &decimal_value)) &&
+ table->in_use->abort_on_warning)
+ {
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", from, field_name,
+ (ulong) table->in_use->row_count);
+ DBUG_RETURN(err);
+ }
+
+ switch (err) {
case E_DEC_TRUNCATED:
set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
break;
diff --git a/sql/field.h b/sql/field.h
index edc3286ae8d..f68a2327dff 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -198,7 +198,7 @@ public:
virtual Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
char *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
- virtual void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
+ inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
{
ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
}
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index ae784ae0293..15598e59bb9 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -605,7 +605,11 @@ void field_conv(Field *to,Field *from)
to->type() != FIELD_TYPE_DATE &&
to->type() != FIELD_TYPE_DATETIME))
{ // Identical fields
- memcpy(to->ptr,from->ptr,to->pack_length());
+#ifdef HAVE_purify
+ /* This may happen if one does 'UPDATE ... SET x=x' */
+ if (to->ptr != from->ptr)
+#endif
+ memcpy(to->ptr,from->ptr,to->pack_length());
return;
}
}
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 57b5e006489..7e0b178f7af 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -300,7 +300,7 @@ void print_hash_map(const char *name)
char *cur;
int i;
- printf("uchar %s[%d]= {\n",name,size_hash_map);
+ printf("static uchar %s[%d]= {\n",name,size_hash_map);
for (i=0, cur= hash_map; i<size_hash_map; i++, cur++)
{
switch(i%4){
@@ -459,11 +459,11 @@ int main(int argc,char **argv)
generate_find_structs();
print_find_structs();
- printf("\nunsigned int sql_functions_max_len=%d;\n",max_len);
- printf("\nunsigned int symbols_max_len=%d;\n\n",max_len2);
+ printf("\nstatic unsigned int sql_functions_max_len=%d;\n", max_len);
+ printf("\nstatic unsigned int symbols_max_len=%d;\n\n", max_len2);
printf("\
-inline SYMBOL *get_hash_symbol(const char *s,\n \
+static inline SYMBOL *get_hash_symbol(const char *s,\n\
unsigned int len,bool function)\n\
{\n\
register uchar *hash_map;\n\
diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc
index c5062c4ea81..dcc542a7247 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -132,8 +132,9 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ lock.type=lock_type;
*to++= &lock;
-
return to;
}
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 0ac209d82e0..8cb6dcb7285 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -349,7 +349,7 @@
#pragma implementation // gcc: Class implementation
#endif
-#include <mysql_priv.h>
+#include "mysql_priv.h"
#ifdef HAVE_FEDERATED_DB
#include "ha_federated.h"
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 196c60764c5..381c9c28a79 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2606,7 +2606,7 @@ get_innobase_type_from_mysql_type(
return(DATA_MYSQL);
}
case FIELD_TYPE_NEWDECIMAL:
- return(DATA_BINARY);
+ return(DATA_FIXBINARY);
case FIELD_TYPE_LONG:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_TINY:
@@ -3170,12 +3170,28 @@ no_commit:
prebuilt->sql_stat_start = TRUE;
}
- /*
- We must use the handler code to update the auto-increment
- value to be sure that increment it correctly.
- */
+ /* We have to use the transactional lock mechanism on the
+ auto-inc counter of the table to ensure that replication and
+ roll-forward of the binlog exactly imitates also the given
+ auto-inc values. The lock is released at each SQL statement's
+ end. This lock also prevents a race where two threads would
+ call ::get_auto_increment() simultaneously. */
+
+ error = row_lock_table_autoinc_for_mysql(prebuilt);
+
+ if (error != DB_SUCCESS) {
+ /* Deadlock or lock wait timeout */
+
+ error = convert_error_code_to_mysql(error, user_thd);
+
+ goto func_exit;
+ }
+
+ /* We must use the handler code to update the auto-increment
+ value to be sure that we increment it correctly. */
+
update_auto_increment();
- auto_inc_used= 1;
+ auto_inc_used = 1;
}
@@ -3198,24 +3214,9 @@ no_commit:
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
- /* This call will calculate the max of the current
- value and the value supplied by the user and
- update the counter accordingly */
-
- /* We have to use the transactional lock mechanism
- on the auto-inc counter of the table to ensure
- that replication and roll-forward of the binlog
- exactly imitates also the given auto-inc values.
- The lock is released at each SQL statement's
- end. */
-
- error = row_lock_table_autoinc_for_mysql(prebuilt);
-
- if (error != DB_SUCCESS) {
- error = convert_error_code_to_mysql(error,
- user_thd);
- goto func_exit;
- }
+ /* This call will update the counter according to the
+ value that was inserted in the table */
+
dict_table_autoinc_update(prebuilt->table, auto_inc);
}
}
@@ -5795,7 +5796,6 @@ ha_innobase::start_stmt(
read_view_close_for_mysql(trx);
}
- auto_inc_counter_for_this_stat = 0;
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
@@ -5985,7 +5985,7 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
- auto_inc_counter_for_this_stat = 0;
+
if (trx->n_lock_table_exp) {
row_unlock_tables_for_mysql(trx);
}
@@ -6505,7 +6505,7 @@ ha_innobase::store_lock(
/***********************************************************************
This function initializes the auto-inc counter if it has not been
initialized yet. This function does not change the value of the auto-inc
-counter if it already has been initialized. In paramete ret returns
+counter if it already has been initialized. In parameter ret returns
the value of the auto-inc counter. */
int
@@ -6624,7 +6624,14 @@ ha_innobase::get_auto_increment()
error = innobase_read_and_init_auto_inc(&nr);
if (error) {
-
+ /* This should never happen in the current (5.0.6) code, since
+ we call this function only after the counter has been
+ initialized. */
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: error %lu in ::get_auto_increment()\n",
+ (ulong)error);
return(~(ulonglong) 0);
}
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index bcbc38650b3..4c0f5209af9 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -70,7 +70,6 @@ class ha_innobase: public handler
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */
uint num_write_row; /* number of write_row() calls */
- longlong auto_inc_counter_for_this_stat;
ulong max_supported_row_length(const byte *buf);
uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index 3bc9c11d4be..7348096b695 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -37,7 +37,7 @@ class ha_myisammrg: public handler
{
return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_READ_RND_SAME |
HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
- HA_CAN_INSERT_DELAYED);
+ HA_CAN_INSERT_DELAYED | HA_ANY_INDEX_MAY_BE_UNIQUE);
}
ulong index_flags(uint inx, uint part, bool all_parts) const
{
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 372a178b59a..6ccaa668df9 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -985,16 +985,13 @@ static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
for (unsigned i= 0; key_part != end; key_part++, i++)
{
const char *field_name= key_part->field->field_name;
- unsigned name_sz= strlen(field_name);
- if (name_sz >= NDB_MAX_ATTR_NAME_SIZE)
- name_sz= NDB_MAX_ATTR_NAME_SIZE-1;
#ifndef DBUG_OFF
data.unique_index_attrid_map[i]= 255;
#endif
for (unsigned j= 0; j < sz; j++)
{
const NDBCOL *c= index->getColumn(j);
- if (strncmp(field_name, c->getName(), name_sz) == 0)
+ if (strcmp(field_name, c->getName()) == 0)
{
data.unique_index_attrid_map[i]= j;
break;
@@ -3545,12 +3542,7 @@ static int create_ndb_column(NDBCOL &col,
HA_CREATE_INFO *info)
{
// Set name
- {
- char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE];
- strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name));
- truncated_field_name[sizeof(truncated_field_name)-1]= '\0';
- col.setName(truncated_field_name);
- }
+ col.setName(field->field_name);
// Get char set
CHARSET_INFO *cs= field->charset();
// Set type and sizes
@@ -4040,12 +4032,7 @@ int ha_ndbcluster::create_index(const char *name,
{
Field *field= key_part->field;
DBUG_PRINT("info", ("attr: %s", field->field_name));
- {
- char truncated_field_name[NDB_MAX_ATTR_NAME_SIZE];
- strnmov(truncated_field_name,field->field_name,sizeof(truncated_field_name));
- truncated_field_name[sizeof(truncated_field_name)-1]= '\0';
- ndb_index.addColumnName(truncated_field_name);
- }
+ ndb_index.addColumnName(field->field_name);
}
if (dict->createIndex(ndb_index))
@@ -5507,7 +5494,8 @@ ndb_get_table_statistics(Ndb* ndb, const char * table,
DBUG_RETURN(0);
} while(0);
- ndb->closeTransaction(pTrans);
+ if (pTrans)
+ ndb->closeTransaction(pTrans);
DBUG_PRINT("exit", ("failed"));
DBUG_RETURN(-1);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index a34b3bd8aac..b2ab2003165 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1376,7 +1376,19 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
/*
- Updates columns with type NEXT_NUMBER if:
+ Update the auto_increment field if necessary
+
+ SYNOPSIS
+ update_auto_increment()
+
+ RETURN
+ 0 ok
+ 1 get_auto_increment() was called and returned ~(ulonglong) 0
+
+
+ IMPLEMENTATION
+
+ Updates columns with type NEXT_NUMBER if:
- If column value is set to NULL (in which case
auto_increment_field_not_null is 0)
@@ -1415,11 +1427,13 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
thd->next_insert_id is cleared after it's been used for a statement.
*/
-void handler::update_auto_increment()
+bool handler::update_auto_increment()
{
ulonglong nr;
THD *thd= table->in_use;
struct system_variables *variables= &thd->variables;
+ bool auto_increment_field_not_null;
+ bool result= 0;
DBUG_ENTER("handler::update_auto_increment");
/*
@@ -1427,13 +1441,14 @@ void handler::update_auto_increment()
row was not inserted
*/
thd->prev_insert_id= thd->next_insert_id;
+ auto_increment_field_not_null= table->auto_increment_field_not_null;
+ table->auto_increment_field_not_null= FALSE;
if ((nr= table->next_number_field->val_int()) != 0 ||
- table->auto_increment_field_not_null &&
+ auto_increment_field_not_null &&
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
{
/* Clear flag for next row */
- table->auto_increment_field_not_null= FALSE;
/* Mark that we didn't generate a new value **/
auto_increment_column_changed=0;
@@ -1447,12 +1462,13 @@ void handler::update_auto_increment()
thd->next_insert_id= nr;
DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr));
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
- table->auto_increment_field_not_null= FALSE;
if (!(nr= thd->next_insert_id))
{
- nr= get_auto_increment();
+ if ((nr= get_auto_increment()) == ~(ulonglong) 0)
+ result= 1; // Mark failure
+
if (variables->auto_increment_increment != 1)
nr= next_insert_id(nr-1, variables);
/*
@@ -1492,7 +1508,7 @@ void handler::update_auto_increment()
/* Mark that we generated a new value */
auto_increment_column_changed=1;
- DBUG_VOID_RETURN;
+ DBUG_RETURN(result);
}
/*
diff --git a/sql/handler.h b/sql/handler.h
index 11f8dd0b4d7..3b0b9afe320 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -87,6 +87,7 @@
#define HA_NO_VARCHAR (1 << 27)
#define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */
#define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */
+#define HA_ANY_INDEX_MAY_BE_UNIQUE (1 << 30)
/* bits in index_flags(index_number) for what you can do with index */
@@ -378,6 +379,7 @@ typedef struct st_ha_create_information
SQL_LIST merge_list;
enum db_type db_type;
enum row_type row_type;
+ uint null_bits; /* NULL bits at start of record */
uint options; /* OR of HA_CREATE_ options */
uint raid_type,raid_chunks;
uint merge_insert_method;
@@ -496,7 +498,7 @@ public:
{}
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked);
- void update_auto_increment();
+ bool update_auto_increment();
virtual void print_error(int error, myf errflag);
virtual bool get_error_message(int error, String *buf);
uint get_dup_key(int error);
diff --git a/sql/hostname.cc b/sql/hostname.cc
index ec5c6f29a27..39223556024 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -209,8 +209,8 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors)
DBUG_PRINT("error",("gethostbyaddr returned %d",errno));
if (errno == HOST_NOT_FOUND || errno == NO_DATA)
- add_wrong_ip(in); /* only cache negative responses, not failures */
-
+ goto add_wrong_ip_and_return;
+ /* Failure, don't cache responce */
DBUG_RETURN(0);
}
if (!hp->h_name[0]) // Don't allow empty hostnames
diff --git a/sql/item.cc b/sql/item.cc
index 7f241955ec4..69b1b78a961 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -298,7 +298,7 @@ longlong Item::val_int_from_decimal()
Item::Item():
- name(0), orig_name(0), name_length(0), fixed(0),
+ rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
{
marker= 0;
@@ -330,6 +330,7 @@ Item::Item():
tables
*/
Item::Item(THD *thd, Item *item):
+ rsize(0),
str_value(item->str_value),
name(item->name),
orig_name(item->orig_name),
@@ -740,6 +741,13 @@ Item_splocal::this_item()
return thd->spcont->get_item(m_offset);
}
+
+Item **
+Item_splocal::this_item_addr(THD *thd, Item **addr)
+{
+ return thd->spcont->get_item_addr(m_offset);
+}
+
Item *
Item_splocal::this_const_item() const
{
@@ -3536,7 +3544,7 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const
Item *Item_int_with_ref::new_item()
{
- DBUG_ASSERT(ref->basic_const_item());
+ DBUG_ASSERT(ref->const_item());
/*
We need to evaluate the constant to make sure it works with
parameter markers.
diff --git a/sql/item.h b/sql/item.h
index 7b2344f12d8..f8fe05cfdb2 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -232,6 +232,21 @@ 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); }
+ /* Special for SP local variable assignment - reusing slots */
+ static void *operator new(size_t size, Item *reuse, uint *rsize)
+ {
+ if (reuse && size <= reuse->rsize)
+ {
+ reuse->cleanup();
+ TRASH((void *)reuse, size);
+ if (rsize)
+ (*rsize)= reuse->rsize;
+ return (void *)reuse;
+ }
+ if (rsize)
+ (*rsize)= size;
+ return (void *)sql_alloc((uint)size);
+ }
static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
@@ -247,6 +262,9 @@ public:
enum traverse_order { POSTFIX, PREFIX };
+ /* Reuse size, only used by SP local variable assignment, otherwize 0 */
+ uint rsize;
+
/*
str_values's main purpose is to be used to cache the value in
save_in_field
@@ -525,8 +543,17 @@ public:
virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual Item *set_no_const_sub(byte *arg) { return this; }
virtual Item *replace_equal_field(byte * arg) { return this; }
-
- virtual Item *this_item() { return this; } /* For SPs mostly. */
+
+ /*
+ For SP local variable returns pointer to Item representing its
+ current value and pointer to current Item otherwise.
+ */
+ virtual Item *this_item() { return this; }
+ /*
+ For SP local variable returns address of pointer to Item representing its
+ current value and pointer passed via parameter otherwise.
+ */
+ virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
// Row emulation
@@ -573,6 +600,7 @@ public:
bool is_splocal() { return 1; } /* Needed for error checking */
Item *this_item();
+ Item **this_item_addr(THD *thd, Item **);
Item *this_const_item() const;
bool fix_fields(THD *, struct st_table_list *, Item **);
@@ -1315,6 +1343,7 @@ public:
{
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
+ table_map not_null_tables() const { return (*ref)->not_null_tables(); }
void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return 1; }
void save_in_result_field(bool no_conversions)
@@ -1384,12 +1413,14 @@ public:
void print(String *str);
};
+
/*
The following class is used to optimize comparing of date and bigint columns
- We need to save the original item, to be able to set the field to the
- original value in 'opt_range'.
- An instance of Item_int_with_ref may refer to a signed or an unsigned
- integer.
+ We need to save the original item ('ref') to be able to call
+ ref->save_in_field(). This is used to create index search keys.
+
+ An instance of Item_int_with_ref may have signed or unsigned integer value.
+
*/
class Item_int_with_ref :public Item_int
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 3c87b6ef920..db2aa735b0e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1063,11 +1063,11 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
- if ((null_value= (args[1]->null_value ||
- my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[1]->null_value ||
+ my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return decimal_value;
+ return 0;
}
/*
@@ -1136,11 +1136,11 @@ my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
- if ((null_value= (args[1]->null_value ||
- my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[1]->null_value ||
+ my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return decimal_value;
+ return 0;
}
@@ -1174,11 +1174,11 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
if ((null_value= args[0]->null_value))
return 0;
val2= args[1]->val_decimal(&value2);
- if ((null_value= (args[1]->null_value ||
- my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
- val2) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[1]->null_value ||
+ my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
+ val2) > 1)))
+ return decimal_value;
+ return 0;
}
@@ -1255,8 +1255,8 @@ void Item_func_div::result_precision()
void Item_func_div::fix_length_and_dec()
{
DBUG_ENTER("Item_func_div::fix_length_and_dec");
- Item_num_op::fix_length_and_dec();
prec_increment= current_thd->variables.div_precincrement;
+ Item_num_op::fix_length_and_dec();
switch(hybrid_type) {
case REAL_RESULT:
{
@@ -1396,8 +1396,9 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
{
my_decimal2decimal(value, decimal_value);
my_decimal_neg(decimal_value);
+ return decimal_value;
}
- return decimal_value;
+ return 0;
}
@@ -1460,8 +1461,9 @@ my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
my_decimal2decimal(value, decimal_value);
if (decimal_value->sign())
my_decimal_neg(decimal_value);
+ return decimal_value;
}
- return decimal_value;
+ return 0;
}
@@ -1761,11 +1763,11 @@ double Item_func_ceiling::real_op()
my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
- if ((null_value= (args[0]->null_value ||
- my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
- decimal_value) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[0]->null_value ||
+ my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
+ decimal_value) > 1)))
+ return decimal_value;
+ return 0;
}
@@ -1808,11 +1810,11 @@ double Item_func_floor::real_op()
my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
{
my_decimal val, *value= args[0]->val_decimal(&val);
- if ((null_value= (args[0]->null_value ||
- my_decimal_floor(E_DEC_FATAL_ERROR, value,
- decimal_value) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[0]->null_value ||
+ my_decimal_floor(E_DEC_FATAL_ERROR, value,
+ decimal_value) > 1)))
+ return decimal_value;
+ return 0;
}
@@ -1827,7 +1829,7 @@ void Item_func_round::fix_length_and_dec()
return;
}
- int decimals_to_set= max(args[1]->val_int(), 0);
+ int decimals_to_set= max((int)args[1]->val_int(), 0);
if (args[0]->decimals == NOT_FIXED_DEC)
{
max_length= args[0]->max_length;
@@ -1878,22 +1880,16 @@ void Item_func_round::fix_length_and_dec()
}
}
-double Item_func_round::real_op()
+double my_double_round(double value, int dec, bool truncate)
{
- double value= args[0]->val_real();
- int dec=(int) args[1]->val_int();
- if (dec > 0)
- decimals= dec; // to get correct output
- uint abs_dec=abs(dec);
double tmp;
+ uint abs_dec= abs(dec);
/*
tmp2 is here to avoid return the value with 80 bit precision
This will fix that the test round(0.1,1) = round(0.1,1) is true
*/
volatile double tmp2;
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0.0;
tmp=(abs_dec < array_elements(log_10) ?
log_10[abs_dec] : pow(10.0,(double) abs_dec));
@@ -1910,6 +1906,18 @@ double Item_func_round::real_op()
}
+double Item_func_round::real_op()
+{
+ double value= args[0]->val_real();
+ int dec= (int) args[1]->val_int();
+
+ if (!(null_value= args[0]->null_value || args[1]->null_value))
+ return my_double_round(value, dec, truncate);
+
+ return 0.0;
+}
+
+
longlong Item_func_round::int_op()
{
longlong value= args[0]->val_int();
@@ -1955,11 +1963,11 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
{
decimals= min(dec, DECIMAL_MAX_SCALE); // to get correct output
}
- if ((null_value= (args[0]->null_value || args[1]->null_value ||
- my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
- decimal_value) > 1)))
- return 0;
- return decimal_value;
+ if (!(null_value= (args[0]->null_value || args[1]->null_value ||
+ my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
+ decimal_value) > 1)))
+ return decimal_value;
+ return 0;
}
@@ -4311,6 +4319,11 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
return TRUE;
}
table=((Item_field *)item)->field->table;
+ if (!(table->file->table_flags() & HA_CAN_FULLTEXT))
+ {
+ my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
+ return 1;
+ }
table->fulltext_searched=1;
return agg_arg_collations_for_comparison(cmp_collation, args+1, arg_count-1);
}
@@ -4766,13 +4779,13 @@ Item_func_sp::execute(Item **itp)
#endif
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_procedure_access(thd, EXECUTE_ACL,
- m_sp->m_db.str, m_sp->m_name.str, 0))
+ if (check_routine_access(thd, EXECUTE_ACL,
+ m_sp->m_db.str, m_sp->m_name.str, 0, 0))
DBUG_RETURN(-1);
sp_change_security_context(thd, m_sp, &save_ctx);
if (save_ctx.changed &&
- check_procedure_access(thd, EXECUTE_ACL,
- m_sp->m_db.str, m_sp->m_name.str, 0))
+ check_routine_access(thd, EXECUTE_ACL,
+ m_sp->m_db.str, m_sp->m_name.str, 0, 0))
{
sp_restore_security_context(thd, m_sp, &save_ctx);
thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fb7827ef932..857140dba8f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1673,6 +1673,7 @@ String *Item_func_format::val_str(String *str)
int diff;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
+ nr= my_double_round(nr, decimals, FALSE);
dec= decimals ? decimals+1 : 0;
/* Here default_charset() is right as this is not an automatic conversion */
str->set(nr,decimals, default_charset());
@@ -2906,9 +2907,9 @@ String *Item_func_uuid::val_str(String *str)
ulonglong tv=my_getsystime() + UUID_TIME_OFFSET + nanoseq;
if (unlikely(tv < uuid_time))
set_clock_seq_str();
- else
- if (unlikely(tv == uuid_time))
- { /* special protection from low-res system clocks */
+ else if (unlikely(tv == uuid_time))
+ {
+ /* special protection from low-res system clocks */
nanoseq++;
tv++;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 4c44db49489..95979408ccb 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -726,7 +726,12 @@ public:
Item_func_uuid(): Item_str_func() {}
void fix_length_and_dec() {
collation.set(system_charset_info);
- max_length= UUID_LENGTH;
+ /*
+ NOTE! uuid() should be changed to use 'ascii'
+ charset when hex(), format(), md5(), etc, and implicit
+ number-to-string conversion will use 'ascii'
+ */
+ max_length= UUID_LENGTH * system_charset_info->mbmaxlen;
}
const char *func_name() const{ return "uuid"; }
String *val_str(String *);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index a5694189976..85abb09531b 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -584,13 +584,8 @@ bool Item_sum_distinct::setup(THD *thd)
{
List<create_field> field_list;
create_field field_def; /* field definition */
-
DBUG_ENTER("Item_sum_distinct::setup");
-
- /*
- Setup can be called twice for ROLLUP items. This is a bug.
- Please add DBUG_ASSERT(tree == 0) here when it's fixed.
- */
+ DBUG_ASSERT(tree == 0);
/*
Virtual table and the tree are created anew on each re-execution of
@@ -610,7 +605,7 @@ bool Item_sum_distinct::setup(THD *thd)
args[0]->unsigned_flag);
if (! (table= create_virtual_tmp_table(thd, field_list)))
- return TRUE;
+ return TRUE;
/* XXX: check that the case of CHAR(0) works OK */
tree_key_length= table->s->reclength - table->s->null_bytes;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 82dceb87ed4..5d11a047a8f 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -473,12 +473,12 @@ void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0,
TABLE *stopper= 0);
bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables);
-bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name,
- bool no_errors);
+bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
+ bool is_proc, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
-bool check_some_routine_access(THD *thd, const char *db, const char *name);
+bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool mysql_multi_update_prepare(THD *thd);
@@ -1121,7 +1121,8 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
- LOCK_global_system_variables, LOCK_user_conn;
+ LOCK_global_system_variables, LOCK_user_conn,
+ LOCK_bytes_sent, LOCK_bytes_received;
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_attr_t connection_attrib;
@@ -1258,6 +1259,7 @@ ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
ha_rows max_rows, ha_rows *examined_rows);
void filesort_free_buffers(TABLE *table);
void change_double_for_sort(double nr,byte *to);
+double my_double_round(double value, int dec, bool truncate);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 90d4f9b9a99..8c5ce22f7a6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -39,11 +39,7 @@
#else
#define OPT_INNODB_DEFAULT 0
#endif
-#ifdef HAVE_BERKLEY_DB
-#define OPT_BDB_DEFAULT 1
-#else
#define OPT_BDB_DEFAULT 0
-#endif
#ifdef HAVE_NDBCLUSTER_DB
#define OPT_NDBCLUSTER_DEFAULT 0
#if defined(NOT_ENOUGH_TESTED) \
@@ -223,7 +219,7 @@ extern "C" int gethostname(char *name, int namelen);
/* Constants */
const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
-const char *sql_mode_names[] =
+static const char *sql_mode_names[] =
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
"?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
@@ -237,10 +233,15 @@ const char *sql_mode_names[] =
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
sql_mode_names, NULL };
-const char *tc_heuristic_recover_names[]= { "COMMIT", "ROLLBACK", NullS };
-TYPELIB tc_heuristic_recover_typelib=
- { array_elements(tc_heuristic_recover_names)-1,"",
- tc_heuristic_recover_names, NULL };
+static const char *tc_heuristic_recover_names[]=
+{
+ "COMMIT", "ROLLBACK", NullS
+};
+static TYPELIB tc_heuristic_recover_typelib=
+{
+ array_elements(tc_heuristic_recover_names)-1,"",
+ tc_heuristic_recover_names, NULL
+};
const char *first_keyword= "first", *binary_keyword= "BINARY";
const char *my_localhost= "localhost", *delayed_user= "DELAYED";
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
@@ -254,8 +255,7 @@ bool opt_large_files= sizeof(my_off_t) > 4;
/*
Used with --help for detailed option
*/
-bool opt_help= 0;
-bool opt_verbose= 0;
+static bool opt_help= 0, opt_verbose= 0;
arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
@@ -264,27 +264,55 @@ arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{&Arg_comparator::compare_row, &Arg_comparator::compare_e_row},
{&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}};
+/* static variables */
+
+static bool lower_case_table_names_used= 0;
+static bool volatile select_thread_in_use, signal_thread_in_use;
+static bool volatile ready_to_exit;
+static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
+static my_bool opt_bdb, opt_isam, opt_ndbcluster;
+static my_bool opt_short_log_format= 0;
+static my_bool opt_log_queries_not_using_indexes= 0;
+static uint kill_cached_threads, wake_thread;
+static ulong killed_threads, thread_created;
+static ulong max_used_connections;
+static ulong my_bind_addr; /* the address we bind to */
+static volatile ulong cached_thread_count= 0;
+static const char *sql_mode_str= "OFF";
+static char *mysqld_user, *mysqld_chroot, *log_error_file_ptr;
+static char *opt_init_slave, *language_ptr, *opt_init_connect;
+static char *default_character_set_name;
+static char *my_bind_addr_str;
+static char *default_collation_name;
+static char mysql_data_home_buff[2];
+static struct passwd *user_info;
+static I_List<THD> thread_cache;
+
+static pthread_cond_t COND_thread_cache, COND_flush_thread_cache;
+
+#ifdef HAVE_BERKELEY_DB
+static my_bool opt_sync_bdb_logs;
+#endif
/* Global variables */
bool opt_log, opt_update_log, opt_bin_log, opt_slow_log;
bool opt_error_log= IF_WIN(1,0);
bool opt_disable_networking=0, opt_skip_show_db=0;
-bool lower_case_table_names_used= 0;
bool server_id_supplied = 0;
bool opt_endinfo,using_udf_functions, locked_in_memory;
bool opt_using_transactions, using_update_log;
-bool volatile abort_loop, select_thread_in_use, signal_thread_in_use;
-bool volatile ready_to_exit, shutdown_in_progress, grant_option;
+bool volatile abort_loop;
+bool volatile shutdown_in_progress, grant_option;
my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted
my_bool opt_reckless_slave = 0;
-my_bool opt_enable_named_pipe= 0, opt_debugging= 0;
-my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol;
+my_bool opt_enable_named_pipe= 0;
+my_bool opt_local_infile, opt_slave_compressed_protocol;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
-my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster;
+my_bool opt_innodb;
#ifdef HAVE_NDBCLUSTER_DB
const char *opt_ndbcluster_connectstring= 0;
const char *opt_ndb_connectstring= 0;
@@ -296,10 +324,8 @@ const char *opt_ndb_mgmd;
ulong opt_ndb_nodeid;
#endif
my_bool opt_readonly, use_temp_pool, relay_log_purge;
-my_bool opt_sync_bdb_logs, opt_sync_frm, opt_allow_suspicious_udfs;
+my_bool opt_sync_frm, opt_allow_suspicious_udfs;
my_bool opt_secure_auth= 0;
-my_bool opt_short_log_format= 0;
-my_bool opt_log_queries_not_using_indexes= 0;
my_bool lower_case_file_system= 0;
my_bool opt_large_pages= 0;
uint opt_large_page_size= 0;
@@ -319,7 +345,7 @@ uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint delay_key_write_options, protocol_version;
uint lower_case_table_names;
uint tc_heuristic_recover= 0;
-uint volatile thread_count, thread_running, kill_cached_threads, wake_thread;
+uint volatile thread_count, thread_running;
ulong back_log, connect_timeout, concurrency;
ulong server_id, thd_startup_options;
ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
@@ -330,21 +356,18 @@ ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong refresh_version, flush_version; /* Increments on each reload */
query_id_t query_id;
-ulong aborted_threads, killed_threads, aborted_connects;
+ulong aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
-ulong delayed_insert_errors,flush_time, thread_created;
+ulong delayed_insert_errors,flush_time;
ulong specialflag=0;
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
-ulong max_connections,max_used_connections,
- max_connect_errors;
+ulong max_connections, max_connect_errors;
uint max_user_connections= 0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0, sync_binlog_period;
ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0;
-ulong my_bind_addr; /* the address we bind to */
-volatile ulong cached_thread_count= 0;
double last_query_cost= -1; /* -1 denotes that no query was compiled yet */
double log_10[32]; /* 10 potences */
@@ -353,24 +376,18 @@ time_t start_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
char *default_tz_name;
char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN];
-char* log_error_file_ptr= log_error_file;
char mysql_real_data_home[FN_REFLEN],
language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
- *mysqld_user,*mysqld_chroot, *opt_init_file,
- *opt_init_connect, *opt_init_slave, *opt_tc_log_file,
+ *opt_init_file, *opt_tc_log_file,
def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
const char *opt_date_time_formats[3];
-char *language_ptr, *default_collation_name, *default_character_set_name;
-char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
-struct passwd *user_info;
+char *mysql_data_home= mysql_real_data_home;
char server_version[SERVER_VERSION_LENGTH];
char *mysqld_unix_port, *opt_mysql_tmpdir;
-char *my_bind_addr_str;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
-const char *sql_mode_str="OFF";
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
@@ -392,7 +409,7 @@ I_List<i_string_pair> replicate_rewrite_db;
I_List<i_string> replicate_do_db, replicate_ignore_db;
// allow the user to tell us which db to replicate and which to ignore
I_List<i_string> binlog_do_db, binlog_ignore_db;
-I_List<THD> threads,thread_cache;
+I_List<THD> threads;
I_List<NAMED_LIST> key_caches;
struct system_variables global_system_variables;
@@ -425,9 +442,7 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
-pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped,
- COND_slave_start;
-pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
+pthread_cond_t COND_refresh,COND_thread_count;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
@@ -502,7 +517,7 @@ static const char* default_dbug_option;
char *libwrapName= NULL;
#endif
#ifdef HAVE_QUERY_CACHE
-ulong query_cache_limit= 0;
+static ulong query_cache_limit= 0;
ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
@@ -522,7 +537,7 @@ struct st_VioSSLAcceptorFd *ssl_acceptor_fd;
/* Function declarations */
static void start_signal_handler(void);
-extern "C" pthread_handler_decl(signal_hand, arg);
+static pthread_handler_decl(signal_hand, arg);
static void mysql_init_variables(void);
static void get_options(int argc,char **argv);
static void set_server_version(void);
@@ -558,8 +573,6 @@ static void close_connections(void)
#ifdef EXTRA_DEBUG
int count=0;
#endif
- THD *thd= current_thd;
-
DBUG_ENTER("close_connections");
/* Clear thread cache */
@@ -1916,12 +1929,12 @@ 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) dflt_key_cache->key_cache_mem_size);
- fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_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);
+ fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
+ fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
+ fprintf(stderr, "max_connections=%lu\n", max_connections);
+ fprintf(stderr, "threads_connected=%u\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
-key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
+key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
@@ -1952,7 +1965,7 @@ the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n",
fprintf(stderr, "Trying to get some variables.\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, "thd->thread_id=%lu\n", (ulong) thd->thread_id);
}
fprintf(stderr, "\
The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\
@@ -2098,7 +2111,7 @@ static void start_signal_handler(void)
/* This threads handles all signals and alarms */
/* ARGSUSED */
-extern "C" void *signal_hand(void *arg __attribute__((unused)))
+static void *signal_hand(void *arg __attribute__((unused)))
{
sigset_t set;
int sig;
@@ -2238,7 +2251,7 @@ static void check_data_home(const char *path)
/* ARGSUSED */
-extern "C" int my_message_sql(uint error, const char *str, myf MyFlags)
+static int my_message_sql(uint error, const char *str, myf MyFlags)
{
THD *thd;
DBUG_ENTER("my_message_sql");
@@ -2359,7 +2372,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
#endif
-const char *load_default_groups[]= {
+static const char *load_default_groups[]= {
#ifdef HAVE_NDBCLUSTER_DB
"mysql_cluster",
#endif
@@ -2370,6 +2383,7 @@ static const int load_default_groups_sz=
sizeof(load_default_groups)/sizeof(load_default_groups[0]);
#endif
+
/*
Initialize one of the global date/time format variables
@@ -2387,8 +2401,8 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
1 error
*/
-bool init_global_datetime_format(timestamp_type format_type,
- DATE_TIME_FORMAT **var_ptr)
+static bool init_global_datetime_format(timestamp_type format_type,
+ DATE_TIME_FORMAT **var_ptr)
{
/* Get command line option */
const char *str= opt_date_time_formats[format_type];
@@ -4349,7 +4363,6 @@ Disable with --skip-bdb (will save memory).",
NO_ARG, 0, 0, 0, 0, 0, 0},
{"bdb-no-sync", OPT_BDB_NOSYNC,
"This option is deprecated, use --skip-sync-bdb-logs instead",
- // (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL,
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"bdb-shared-data", OPT_BDB_SHARED,
"Start Berkeley DB in multi-process mode.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
@@ -4389,9 +4402,9 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &max_system_variables.completion_type, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 2, 0, 1, 0},
{"concurrent-insert", OPT_CONCURRENT_INSERT,
- "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
+ "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0",
(gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
- 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+ 0, GET_LONG, OPT_ARG, 1, 0, 2, 0, 0, 0},
{"console", OPT_CONSOLE, "Write error output on screen; Don't remove the console window on windows.",
(gptr*) &opt_console, (gptr*) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
@@ -4571,7 +4584,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
{"isam", OPT_ISAM, "Obsolete. ISAM storage engine is no longer supported.",
(gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
- {"language", 'L',
+ {"language", 'L',
"Client error messages in given language. May be given as a full path.",
(gptr*) &language_ptr, (gptr*) &language_ptr, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
@@ -5332,9 +5345,9 @@ The minimum value for this variable is 4096.",
"Default pointer size to be used for MyISAM tables.",
(gptr*) &myisam_data_pointer_size,
(gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
- 4, 2, 8, 0, 1, 0},
+ 6, 2, 8, 0, 1, 0},
{"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
- "Used to help MySQL to decide when to use the slow but safe key cache index create method.",
+ "Depricated option",
(gptr*) &global_system_variables.myisam_max_extra_sort_file_size,
(gptr*) &max_system_variables.myisam_max_extra_sort_file_size,
0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH,
@@ -5795,11 +5808,6 @@ static void print_version(void)
server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT);
}
-static void use_help(void)
-{
- print_version();
- printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
-}
static void usage(void)
{
@@ -5870,7 +5878,8 @@ static void mysql_init_variables(void)
/* Things reset to zero */
opt_skip_slave_start= opt_reckless_slave = 0;
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
- opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
+ opt_log= opt_update_log= opt_slow_log= 0;
+ opt_bin_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
@@ -6095,7 +6104,7 @@ static void mysql_init_variables(void)
}
-extern "C" my_bool
+static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
{
@@ -6170,7 +6179,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_update_log=1;
break;
case (int) OPT_BIN_LOG:
- opt_bin_log=1;
+ opt_bin_log= test(argument != disabled_my_option);
break;
case (int) OPT_ERROR_LOG_FILE:
opt_error_log= 1;
@@ -6570,6 +6579,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
break;
}
+ case OPT_CONCURRENT_INSERT:
+ /* The following code is mainly here to emulate old behavior */
+ if (!argument) /* --concurrent-insert */
+ myisam_concurrent_insert= 1;
+ else if (argument == disabled_my_option)
+ myisam_concurrent_insert= 0; /* --skip-concurrent-insert */
+ break;
case OPT_TC_HEURISTIC_RECOVER:
{
if ((tc_heuristic_recover=find_type(argument,
@@ -6615,7 +6631,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
/* Initiates DEBUG - but no debugging here ! */
-extern "C" gptr *
+static gptr *
mysql_getopt_value(const char *keyname, uint key_length,
const struct my_option *option)
{
@@ -6644,7 +6660,7 @@ mysql_getopt_value(const char *keyname, uint key_length,
}
-void option_error_reporter(enum loglevel level, const char *format, ...)
+static void option_error_reporter(enum loglevel level, const char *format, ...)
{
va_list args;
va_start(args, format);
@@ -6747,8 +6763,6 @@ static void get_options(int argc,char **argv)
my_default_record_cache_size=global_system_variables.read_buff_size;
myisam_max_temp_length=
(my_off_t) global_system_variables.myisam_max_sort_file_size;
- myisam_max_extra_temp_length=
- (my_off_t) global_system_variables.myisam_max_extra_sort_file_size;
/* Set global variables based on startup options */
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index b81a083d9b3..ca3f5c5af87 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3307,6 +3307,38 @@ QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param,
/*
+ Build a SEL_TREE for <> predicate
+
+ SYNOPSIS
+ get_ne_mm_tree()
+ param PARAM from SQL_SELECT::test_quick_select
+ cond_func item for the predicate
+ field field in the predicate
+ value constant in the predicate
+ cmp_type compare type for the field
+
+ RETURN
+ Pointer to tree built tree
+*/
+
+static SEL_TREE *get_ne_mm_tree(PARAM *param, Item_func *cond_func,
+ Field *field, Item *value,
+ Item_result cmp_type)
+{
+ SEL_TREE *tree= 0;
+ tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ value, cmp_type);
+ if (tree)
+ {
+ tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::GT_FUNC,
+ value, cmp_type));
+ }
+ return tree;
+}
+
+
+/*
Build a SEL_TREE for a simple predicate
SYNOPSIS
@@ -3316,55 +3348,86 @@ QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param,
field field in the predicate
value constant in the predicate
cmp_type compare type for the field
+ inv TRUE <> NOT cond_func is considered
+ (makes sense only when cond_func is BETWEEN or IN)
RETURN
- Pointer to thre built tree
+ Pointer to the tree built tree
*/
static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
Field *field, Item *value,
- Item_result cmp_type)
+ Item_result cmp_type, bool inv)
{
SEL_TREE *tree= 0;
DBUG_ENTER("get_func_mm_tree");
switch (cond_func->functype()) {
+
case Item_func::NE_FUNC:
- tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
- value, cmp_type);
- if (tree)
- {
- tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
- Item_func::GT_FUNC,
- value, cmp_type));
- }
+ tree= get_ne_mm_tree(param, cond_func, field, value, cmp_type);
break;
+
case Item_func::BETWEEN:
- tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC,
- cond_func->arguments()[1],cmp_type);
- if (tree)
+ if (inv)
{
- tree= tree_and(param, tree, get_mm_parts(param, cond_func, field,
- Item_func::LE_FUNC,
- cond_func->arguments()[2],
- cmp_type));
+ tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ cond_func->arguments()[1],cmp_type);
+ if (tree)
+ {
+ tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::GT_FUNC,
+ cond_func->arguments()[2],
+ cmp_type));
+ }
+ }
+ else
+ {
+ tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC,
+ cond_func->arguments()[1],cmp_type);
+ if (tree)
+ {
+ tree= tree_and(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::LE_FUNC,
+ cond_func->arguments()[2],
+ cmp_type));
+ }
}
break;
+
case Item_func::IN_FUNC:
{
Item_func_in *func=(Item_func_in*) cond_func;
- tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC,
- func->arguments()[1], cmp_type);
- if (tree)
+
+ if (inv)
{
- Item **arg, **end;
- for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
- arg < end ; arg++)
+ tree= get_ne_mm_tree(param, cond_func, field,
+ func->arguments()[1], cmp_type);
+ if (tree)
{
- tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
- Item_func::EQ_FUNC,
- *arg,
- cmp_type));
+ Item **arg, **end;
+ for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
+ arg < end ; arg++)
+ {
+ tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field,
+ *arg, cmp_type));
+ }
+ }
+ }
+ else
+ {
+ tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC,
+ func->arguments()[1], cmp_type);
+ if (tree)
+ {
+ Item **arg, **end;
+ for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
+ arg < end ; arg++)
+ {
+ tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
+ Item_func::EQ_FUNC,
+ *arg, cmp_type));
+ }
}
}
break;
@@ -3396,6 +3459,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
SEL_TREE *tree=0;
SEL_TREE *ftree= 0;
Item_field *field_item= 0;
+ bool inv= FALSE;
Item *value;
DBUG_ENTER("get_mm_tree");
@@ -3457,8 +3521,21 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
}
Item_func *cond_func= (Item_func*) cond;
- if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
- DBUG_RETURN(0); // Can't be calculated
+ if (cond_func->functype() == Item_func::NOT_FUNC)
+ {
+ Item *arg= cond_func->arguments()[0];
+ if (arg->type() == Item::FUNC_ITEM)
+ {
+ cond_func= (Item_func*) arg;
+ if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
+ DBUG_RETURN(0);
+ inv= TRUE;
+ }
+ else
+ DBUG_RETURN(0);
+ }
+ else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
+ DBUG_RETURN(0);
param->cond= cond;
@@ -3536,7 +3613,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
Field *field= field_item->field;
Item_result cmp_type= field->cmp_type();
if (!((ref_tables | field->table->map) & param_comp))
- ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type);
+ ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type, inv);
Item_equal *item_equal= field_item->item_equal;
if (item_equal)
{
@@ -3549,7 +3626,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
continue;
if (!((ref_tables | f->table->map) & param_comp))
{
- tree= get_func_mm_tree(param, cond_func, f, value, cmp_type);
+ tree= get_func_mm_tree(param, cond_func, f, value, cmp_type, inv);
ftree= !ftree ? tree : tree_and(param, ftree, tree);
}
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 4add5d6b39b..b8059779a2a 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -108,7 +108,6 @@ static void fix_net_retry_count(THD *thd, enum_var_type type);
static void fix_max_join_size(THD *thd, enum_var_type type);
static void fix_query_cache_size(THD *thd, enum_var_type type);
static void fix_query_cache_min_res_unit(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);
static void fix_max_binlog_size(THD *thd, enum_var_type type);
static void fix_max_relay_log_size(THD *thd, enum_var_type type);
@@ -158,8 +157,8 @@ sys_var_thd_ulong sys_completion_type("completion_type",
sys_var_collation_connection sys_collation_connection("collation_connection");
sys_var_collation_database sys_collation_database("collation_database");
sys_var_collation_server sys_collation_server("collation_server");
-sys_var_bool_ptr sys_concurrent_insert("concurrent_insert",
- &myisam_concurrent_insert);
+sys_var_long_ptr sys_concurrent_insert("concurrent_insert",
+ &myisam_concurrent_insert);
sys_var_long_ptr sys_connect_timeout("connect_timeout",
&connect_timeout);
sys_var_enum sys_delay_key_write("delay_key_write",
@@ -270,7 +269,6 @@ sys_var_thd_ulong sys_multi_range_count("multi_range_count",
&SV::multi_range_count);
sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size",
&myisam_data_pointer_size);
-sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1);
sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1);
sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads);
sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size);
@@ -623,7 +621,6 @@ sys_var *sys_variables[]=
&sys_max_write_lock_count,
&sys_multi_range_count,
&sys_myisam_data_pointer_size,
- &sys_myisam_max_extra_sort_file_size,
&sys_myisam_max_sort_file_size,
&sys_myisam_repair_threads,
&sys_myisam_sort_buffer_size,
@@ -882,9 +879,6 @@ struct show_var_st init_vars[]= {
{sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS},
{sys_multi_range_count.name, (char*) &sys_multi_range_count, SHOW_SYS},
{sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS},
- {sys_myisam_max_extra_sort_file_size.name,
- (char*) &sys_myisam_max_extra_sort_file_size,
- SHOW_SYS},
{sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size,
SHOW_SYS},
{"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR},
@@ -951,7 +945,11 @@ struct show_var_st init_vars[]= {
{"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL},
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
#ifdef HAVE_REPLICATION
+ {sys_slave_compressed_protocol.name,
+ (char*) &sys_slave_compressed_protocol, SHOW_SYS},
+ {"slave_load_tmpdir", (char*) &slave_load_tmpdir, SHOW_CHAR_PTR},
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
+ {"slave_skip_errors", (char*) &slave_error_mask, SHOW_SLAVE_SKIP_ERRORS},
{sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS},
#endif
{sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
@@ -1141,14 +1139,6 @@ static void fix_low_priority_updates(THD *thd, enum_var_type type)
static void
-fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type)
-{
- myisam_max_extra_temp_length=
- (my_off_t) global_system_variables.myisam_max_extra_sort_file_size;
-}
-
-
-static void
fix_myisam_max_sort_file_size(THD *thd, enum_var_type type)
{
myisam_max_temp_length=
@@ -2964,6 +2954,11 @@ bool not_all_support_one_shot(List<set_var_base> *var_list)
int set_var::check(THD *thd)
{
+ if (var->is_readonly())
+ {
+ my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name, "read only");
+ return -1;
+ }
if (var->check_type(type))
{
int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
diff --git a/sql/set_var.h b/sql/set_var.h
index 32f45187124..56690c46131 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -32,7 +32,7 @@ extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
enum enum_var_type
{
- OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL
+ OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
};
typedef int (*sys_check_func)(THD *, set_var *);
@@ -75,6 +75,7 @@ public:
{ return option_limits == 0; }
Item *item(THD *thd, enum_var_type type, LEX_STRING *base);
virtual bool is_struct() { return 0; }
+ virtual bool is_readonly() const { return 0; }
};
@@ -699,6 +700,7 @@ public:
return (*value_ptr_func)(thd);
}
SHOW_TYPE type() { return show_type; }
+ bool is_readonly() const { return 1; }
};
class sys_var_thd_time_zone :public sys_var_thd
diff --git a/sql/sp.cc b/sql/sp.cc
index 81513cb3198..9a816f277ed 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -72,6 +72,9 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
DBUG_PRINT("enter", ("type: %d name: %*s",
type, name->m_name.length, name->m_name.str));
+ *opened= FALSE;
+ *tablep= 0;
+
/*
Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
is set when we create or read stored procedure or on flush privileges.
@@ -88,9 +91,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
strcmp(table->s->table_name, "proc") == 0)
break;
}
- if (table)
- *opened= FALSE;
- else
+ if (!table)
{
TABLE_LIST tables;
@@ -99,7 +100,6 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
tables.table_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, ltype)))
{
- *tablep= NULL;
/*
Under explicit LOCK TABLES or in prelocked mode we should not
say that mysql.proc table does not exist if we are unable to
@@ -131,7 +131,6 @@ db_find_routine_aux(THD *thd, int type, sp_name *name,
key, table->key_info->key_length,
HA_READ_KEY_EXACT))
{
- *tablep= NULL;
DBUG_RETURN(SP_KEY_NOT_FOUND);
}
*tablep= table;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 0be93c3e41c..988345694b2 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -97,25 +97,56 @@ sp_multi_results_command(enum enum_sql_command cmd)
}
}
+
+/*
+ Prepare Item for execution (call of fix_fields)
+
+ SYNOPSIS
+ sp_prepare_func_item()
+ thd thread handler
+ it_addr pointer on item refernce
+
+ RETURN
+ NULL error
+ prepared item
+*/
+
+static Item *
+sp_prepare_func_item(THD* thd, Item **it_addr)
+{
+ Item *it= *it_addr;
+ DBUG_ENTER("sp_prepare_func_item");
+ it_addr= it->this_item_addr(thd, it_addr);
+
+ if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr))
+ {
+ DBUG_PRINT("info", ("fix_fields() failed"));
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(*it_addr);
+}
+
+
/* Evaluate a (presumed) func item. Always returns an item, the parameter
** if nothing else.
*/
Item *
-sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
+sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type,
+ Item *reuse)
{
DBUG_ENTER("sp_eval_func_item");
- it= it->this_item();
+ Item *it= sp_prepare_func_item(thd, it_addr);
+ uint rsize;
DBUG_PRINT("info", ("type: %d", type));
- if (!it->fixed && it->fix_fields(thd, 0, &it))
+ if (!it)
{
- DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(NULL);
}
/* QQ How do we do this? Is there some better way? */
if (type == MYSQL_TYPE_NULL)
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
else
{
switch (sp_map_result_type(type)) {
@@ -126,12 +157,12 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
if (it->null_value)
{
DBUG_PRINT("info", ("INT_RESULT: null"));
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
}
else
{
DBUG_PRINT("info", ("INT_RESULT: %d", i));
- it= new Item_int(i);
+ it= new(reuse, &rsize) Item_int(i);
}
break;
}
@@ -142,7 +173,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
if (it->null_value)
{
DBUG_PRINT("info", ("REAL_RESULT: null"));
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
}
else
{
@@ -151,7 +182,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
uint8 decimals= it->decimals;
uint32 max_length= it->max_length;
DBUG_PRINT("info", ("REAL_RESULT: %g", d));
- it= new Item_float(d);
+ it= new(reuse, &rsize) Item_float(d);
it->decimals= decimals;
it->max_length= max_length;
}
@@ -161,9 +192,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
{
my_decimal value, *val= it->val_decimal(&value);
if (it->null_value)
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
else
- it= new Item_decimal(val);
+ it= new(reuse, &rsize) Item_decimal(val);
#ifndef DBUG_OFF
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
@@ -179,14 +210,16 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
if (it->null_value)
{
DBUG_PRINT("info", ("default result: null"));
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
}
else
{
DBUG_PRINT("info",("default result: %*s",
s->length(), s->c_ptr_quick()));
- it= new Item_string(thd->strmake(s->ptr(), s->length()),
- s->length(), it->collation.collation);
+ it= new(reuse, &rsize) Item_string(thd->strmake(s->ptr(),
+ s->length()),
+ s->length(),
+ it->collation.collation);
}
break;
}
@@ -195,6 +228,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
DBUG_ASSERT(0);
}
}
+ it->rsize= rsize;
DBUG_RETURN(it);
}
@@ -679,7 +713,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
for (i= 0 ; i < params && i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
- Item *it= sp_eval_func_item(thd, *argp++, pvar->type);
+ Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL);
if (it)
nctx->push_item(it);
@@ -761,7 +795,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
{
Item_null *nit= NULL; // Re-use this, and only create if needed
uint i;
- List_iterator_fast<Item> li(*args);
+ List_iterator<Item> li(*args);
Item *it;
nctx= new sp_rcontext(csize, hmax, cmax);
@@ -794,7 +828,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
}
else
{
- Item *it2= sp_eval_func_item(thd, it, pvar->type);
+ Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type, NULL);
if (it2)
nctx->push_item(it2); // IN or INOUT
@@ -1082,7 +1116,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
(!strcmp(sp->m_definer_user.str, thd->priv_user) &&
!strcmp(sp->m_definer_host.str, thd->priv_host)));
if (!*full_access)
- return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str);
+ return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
+ sp->m_type == TYPE_ENUM_PROCEDURE);
return 0;
}
@@ -1436,19 +1471,9 @@ sp_instr_set::execute(THD *thd, uint *nextp)
int
sp_instr_set::exec_core(THD *thd, uint *nextp)
{
- Item *it;
- int res;
+ int res= thd->spcont->set_item_eval(thd, m_offset, &m_value, m_type);
- it= sp_eval_func_item(thd, m_value, m_type);
- if (! it)
- res= -1;
- else
- {
- res= 0;
- thd->spcont->set_item(m_offset, it);
- }
*nextp = m_ip+1;
-
return res;
}
@@ -1569,13 +1594,13 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+ it= sp_prepare_func_item(thd, &m_expr);
if (!it)
res= -1;
else
{
res= 0;
- if (it->val_int())
+ if (it->val_bool())
*nextp = m_dest;
else
*nextp = m_ip+1;
@@ -1627,13 +1652,13 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+ it= sp_prepare_func_item(thd, &m_expr);
if (! it)
res= -1;
else
{
res= 0;
- if (! it->val_int())
+ if (! it->val_bool())
*nextp = m_dest;
else
*nextp = m_ip+1;
@@ -1685,7 +1710,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp)
Item *it;
int res;
- it= sp_eval_func_item(thd, m_value, m_type);
+ it= sp_eval_func_item(thd, &m_value, m_type, NULL);
if (! it)
res= -1;
else
@@ -2061,15 +2086,10 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
typedef struct st_sp_table
{
- LEX_STRING qname;
- bool temp;
- TABLE_LIST *table;
- /*
- We can't use table->lock_type as lock type for table
- in multi-set since it can be changed by statement during
- its execution (e.g. as this happens for multi-update).
- */
- thr_lock_type lock_type;
+ LEX_STRING qname; /* Multi-set key: db_name\0table_name\0alias\0 */
+ uint db_length, table_name_length;
+ bool temp; /* true if corresponds to a temporary table */
+ thr_lock_type lock_type; /* lock type used for prelocking */
uint lock_count;
uint query_lock_count;
} SP_TABLE;
@@ -2121,15 +2141,15 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
for (; table ; table= table->next_global)
if (!table->derived && !table->schema_table)
{
- char tname[64+1+64+1+64+1]; // db.table.alias\0
+ char tname[(NAME_LEN + 1) * 3]; // db\0table\0alias\0
uint tlen, alen;
tlen= table->db_length;
memcpy(tname, table->db, tlen);
- tname[tlen++]= '.';
+ tname[tlen++]= '\0';
memcpy(tname+tlen, table->table_name, table->table_name_length);
tlen+= table->table_name_length;
- tname[tlen++]= '.';
+ tname[tlen++]= '\0';
alen= strlen(table->alias);
memcpy(tname+tlen, table->alias, alen);
tlen+= alen;
@@ -2152,14 +2172,15 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
return FALSE;
tab->qname.length= tlen;
- tab->qname.str= (char *)thd->strmake(tname, tab->qname.length);
+ tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1);
if (!tab->qname.str)
return FALSE;
if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
lex_for_tmp_check->query_tables == table &&
lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
tab->temp= TRUE;
- tab->table= table;
+ tab->table_name_length= table->table_name_length;
+ tab->db_length= table->db_length;
tab->lock_type= table->lock_type;
tab->lock_count= tab->query_lock_count= 1;
my_hash_insert(&m_sptabs, (byte *)tab);
@@ -2207,13 +2228,11 @@ sp_head::add_used_tables_to_table_list(THD *thd,
for (i=0 ; i < m_sptabs.records ; i++)
{
char *tab_buff;
- TABLE_LIST *table, *otable;
+ TABLE_LIST *table;
SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i);
if (stab->temp)
continue;
- otable= stab->table;
-
if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) *
stab->lock_count)))
DBUG_RETURN(FALSE);
@@ -2228,11 +2247,11 @@ sp_head::add_used_tables_to_table_list(THD *thd,
that the PS will be invalidated if the functions is deleted or
changed.
*/
- table->db= otable->db;
- table->db_length= otable->db_length;
- table->alias= otable->alias;
- table->table_name= otable->table_name;
- table->table_name_length= otable->table_name_length;
+ table->db= stab->qname.str;
+ table->db_length= stab->db_length;
+ table->table_name= table->db + table->db_length + 1;
+ table->table_name_length= stab->table_name_length;
+ table->alias= table->table_name + table->table_name_length + 1;
table->lock_type= stab->lock_type;
table->cacheable_table= 1;
table->prelocking_placeholder= 1;
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index def38009eee..49ead5d1585 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -40,19 +40,39 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
m_saved.empty();
}
+
int
-sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type)
+sp_rcontext::set_item_eval(THD *thd, uint idx, Item **item_addr,
+ enum_field_types type)
{
- extern Item *sp_eval_func_item(THD *thd, Item *it, enum_field_types type);
- Item *it= sp_eval_func_item(current_thd, i, type);
+ extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type,
+ Item *reuse);
+ Item *it;
+ Item *reuse_it;
+ Item *old_item_next;
+ Item *old_free_list= thd->free_list;
+ int res;
+ LINT_INIT(old_item_next);
+ if ((reuse_it= get_item(idx)))
+ old_item_next= reuse_it->next;
+ it= sp_eval_func_item(thd, item_addr, type, reuse_it);
if (! it)
- return -1;
+ res= -1;
else
{
+ res= 0;
+ if (reuse_it && it == reuse_it)
+ {
+ // A reused item slot, where the constructor put it in the free_list,
+ // so we have to restore the list.
+ thd->free_list= old_free_list;
+ it->next= old_item_next;
+ }
set_item(idx, it);
- return 0;
}
+
+ return res;
}
bool
@@ -111,7 +131,10 @@ void
sp_rcontext::save_variables(uint fp)
{
while (fp < m_count)
- m_saved.push_front(m_frame[fp++]);
+ {
+ m_saved.push_front(m_frame[fp]);
+ m_frame[fp++]= NULL; // Prevent reuse
+ }
}
void
@@ -230,7 +253,12 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
for (fldcount= 0 ; (pv= li++) ; fldcount++)
{
Item *it;
+ Item *reuse;
+ uint rsize;
+ Item *old_item_next;
+ Item *old_free_list= thd->free_list;
const char *s;
+ LINT_INIT(old_item_next);
if (fldcount >= m_prot->get_field_count())
{
@@ -238,9 +266,13 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0));
return -1;
}
+
+ if ((reuse= thd->spcont->get_item(pv->offset)))
+ old_item_next= reuse->next;
+
s= row[fldcount];
if (!s)
- it= new Item_null();
+ it= new(reuse, &rsize) Item_null();
else
{
/*
@@ -255,23 +287,32 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
len= (*next -s)-1;
switch (sp_map_result_type(pv->type)) {
case INT_RESULT:
- it= new Item_int(s);
+ it= new(reuse, &rsize) Item_int(s);
break;
case REAL_RESULT:
- it= new Item_float(s, len);
+ it= new(reuse, &rsize) Item_float(s, len);
break;
case DECIMAL_RESULT:
- it= new Item_decimal(s, len, thd->db_charset);
+ it= new(reuse, &rsize) Item_decimal(s, len, thd->db_charset);
break;
case STRING_RESULT:
/* TODO: Document why we do an extra copy of the string 's' here */
- it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
+ it= new(reuse, &rsize) Item_string(thd->strmake(s, len), len,
+ thd->db_charset);
break;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
}
}
+ it->rsize= rsize;
+ if (reuse && it == reuse)
+ {
+ // A reused item slot, where the constructor put it in the free_list,
+ // so we have to restore the list.
+ thd->free_list= old_free_list;
+ it->next= old_item_next;
+ }
thd->spcont->set_item(pv->offset, it);
}
if (fldcount < m_prot->get_field_count())
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index afcd937a369..417c50d0f0f 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -62,19 +62,19 @@ class sp_rcontext : public Sql_alloc
push_item(Item *i)
{
if (m_count < m_fsize)
- m_frame[m_count++] = i;
+ m_frame[m_count++]= i;
}
inline void
set_item(uint idx, Item *i)
{
if (idx < m_count)
- m_frame[idx] = i;
+ m_frame[idx]= i;
}
/* Returns 0 on success, -1 on (eval) failure */
int
- set_item_eval(uint idx, Item *i, enum_field_types type);
+ set_item_eval(THD *thd, uint idx, Item **i, enum_field_types type);
inline Item *
get_item(uint idx)
@@ -82,6 +82,13 @@ class sp_rcontext : public Sql_alloc
return m_frame[idx];
}
+ inline Item **
+ get_item_addr(uint idx)
+ {
+ return m_frame + idx;
+ }
+
+
inline void
set_result(Item *it)
{
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 427648850e4..176f1f2fbfe 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -98,6 +98,12 @@ static Geometry::Class_info
geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollection,
create_geometrycollection);
+static void get_point(double *x, double *y, const char *data)
+{
+ float8get(*x, data);
+ float8get(*y, data + SIZEOF_STORED_DOUBLE);
+}
+
/***************************** Geometry *******************************/
Geometry::Class_info *Geometry::find_class(const char *name, uint32 len)
@@ -268,14 +274,13 @@ const char *Geometry::append_points(String *txt, uint32 n_points,
{
while (n_points--)
{
- double d;
+ double x,y;
data+= offset;
- float8get(d, data);
- txt->qs_append(d);
- txt->qs_append(' ');
- float8get(d, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
- txt->qs_append(d);
+ txt->qs_append(x);
+ txt->qs_append(' ');
+ txt->qs_append(y);
txt->qs_append(',');
}
return data;
@@ -428,8 +433,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
while (n_points--)
{
double x, y;
- float8get(x, data);
- float8get(y, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
txt->qs_append(x);
txt->qs_append(' ');
@@ -462,15 +466,13 @@ int Gis_line_string::length(double *len) const
if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points))
return 1;
- float8get(prev_x, data);
- float8get(prev_y, data + SIZEOF_STORED_DOUBLE);
+ get_point(&prev_x, &prev_y, data);
data+= SIZEOF_STORED_DOUBLE*2;
while (--n_points)
{
double x, y;
- float8get(x, data);
- float8get(y, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x, &y, data);
data+= SIZEOF_STORED_DOUBLE * 2;
*len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
prev_x= x;
@@ -499,13 +501,11 @@ int Gis_line_string::is_closed(int *closed) const
return 1;
/* Get first point */
- float8get(x1, data);
- float8get(y1, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x1, &y1, data);
/* get last point */
data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE;
- float8get(x2, data);
- float8get(y2, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x2, &y2, data);
*closed= (x1==x2) && (y1==y2);
return 0;
@@ -683,15 +683,13 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const
n_points= uint4korr(data);
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
return 1;
- float8get(prev_x, data+4);
- float8get(prev_y, data+(4+SIZEOF_STORED_DOUBLE));
+ get_point(&prev_x, &prev_y, data+4);
data+= (4+SIZEOF_STORED_DOUBLE*2);
while (--n_points) // One point is already read
{
double x, y;
- float8get(x, data);
- float8get(y, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x, &y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
/* QQ: Is the following prev_x+x right ? */
lr_area+= (prev_x + x)* (prev_y - y);
@@ -781,7 +779,8 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const
int Gis_polygon::centroid_xy(double *x, double *y) const
{
uint32 n_linear_rings;
- double res_area, res_cx, res_cy;
+ double res_area;
+ double res_cx, res_cy;
const char *data= m_data;
bool first_loop= 1;
LINT_INIT(res_area);
@@ -807,15 +806,13 @@ int Gis_polygon::centroid_xy(double *x, double *y) const
data+= 4;
if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points))
return 1;
- float8get(prev_x, data);
- float8get(prev_y, data+SIZEOF_STORED_DOUBLE);
+ get_point(&prev_x, &prev_y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
while (--n_points) // One point is already read
{
double x, y;
- float8get(x, data);
- float8get(y, data + SIZEOF_STORED_DOUBLE);
+ get_point(&x, &y, data);
data+= (SIZEOF_STORED_DOUBLE*2);
/* QQ: Is the following prev_x+x right ? */
cur_area+= (prev_x + x) * (prev_y - y);
diff --git a/sql/spatial.h b/sql/spatial.h
index 438ec171a72..b5ea7d641d1 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -173,6 +173,9 @@ public:
static void operator delete(void *ptr, void *buffer)
{}
+ static void operator delete(void *buffer)
+ {}
+
static String bad_geometry_data;
enum wkbType
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ca9ba7611e6..7caece67599 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -60,7 +60,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
-static HASH acl_check_hosts, column_priv_hash, proc_priv_hash;
+static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_init */
@@ -2136,11 +2136,12 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
inline GRANT_NAME *
-proc_hash_search(const char *host, const char *ip, const char *db,
- const char *user, const char *tname, bool exact)
+routine_hash_search(const char *host, const char *ip, const char *db,
+ const char *user, const char *tname, bool proc, bool exact)
{
- return (GRANT_TABLE*) name_hash_search(&proc_priv_hash, host, ip, db,
- user, tname, exact);
+ return (GRANT_TABLE*)
+ name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
+ host, ip, db, user, tname, exact);
}
@@ -2466,16 +2467,17 @@ table_error:
}
-static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
+static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo,
- const char *db, const char *proc_name,
- ulong rights, bool revoke_grant)
+ const char *db, const char *routine_name,
+ bool is_proc, ulong rights, bool revoke_grant)
{
char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
int old_row_exists= 1;
int error=0;
ulong store_proc_rights;
- DBUG_ENTER("replace_proc_table");
+ byte *key;
+ DBUG_ENTER("replace_routine_table");
if (!initialized)
{
@@ -2499,7 +2501,10 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[3]->store(proc_name,(uint) strlen(proc_name), &my_charset_latin1);
+ table->field[3]->store(routine_name,(uint) strlen(routine_name),
+ &my_charset_latin1);
+ table->field[4]->store((longlong)(is_proc ?
+ TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION));
store_record(table,record[1]); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
@@ -2514,7 +2519,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
if (revoke_grant)
{ // no row, no revoke
my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
- combo.user.str, combo.host.str, proc_name);
+ combo.user.str, combo.host.str, routine_name);
DBUG_RETURN(-1);
}
old_row_exists= 0;
@@ -2539,7 +2544,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
}
}
- table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
+ table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
table->field[6]->store((longlong) store_proc_rights);
rights=fix_rights_for_procedure(store_proc_rights);
@@ -2566,7 +2571,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
}
else
{
- hash_delete(&proc_priv_hash,(byte*) grant_name);
+ hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
}
DBUG_RETURN(0);
@@ -2841,12 +2846,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/*
- Store procedure level grants in the privilege tables
+ Store routine level grants in the privilege tables
SYNOPSIS
- mysql_procedure_grant()
+ mysql_routine_grant()
thd Thread handle
- table_list List of procedures to give grant
+ table_list List of routines to give grant
+ is_proc true indicates routine list are procedures
user_list List of users to give grant
rights Table level grant
revoke_grant Set to 1 if this is a REVOKE command
@@ -2856,16 +2862,16 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
1 error
*/
-bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
- List <LEX_USER> &user_list, ulong rights,
- bool revoke_grant, bool no_error)
+bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
+ List <LEX_USER> &user_list, ulong rights,
+ bool revoke_grant, bool no_error)
{
List_iterator <LEX_USER> str_list (user_list);
LEX_USER *Str;
TABLE_LIST tables[2];
bool create_new_users=0, result=0;
char *db_name, *table_name;
- DBUG_ENTER("mysql_procedure_grant");
+ DBUG_ENTER("mysql_routine_grant");
if (!initialized)
{
@@ -2884,7 +2890,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
if (!revoke_grant)
{
- if (sp_exists_routine(thd, table_list, 0, no_error)<0)
+ if (sp_exists_routine(thd, table_list, is_proc, no_error)<0)
DBUG_RETURN(TRUE);
}
@@ -2957,8 +2963,8 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
db_name= table_list->db;
table_name= table_list->table_name;
- grant_name= proc_hash_search(Str->host.str, NullS, db_name,
- Str->user.str, table_name, 1);
+ grant_name= routine_hash_search(Str->host.str, NullS, db_name,
+ Str->user.str, table_name, is_proc, 1);
if (!grant_name)
{
if (revoke_grant)
@@ -2977,11 +2983,11 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
result= TRUE;
continue;
}
- my_hash_insert(&proc_priv_hash,(byte*) grant_name);
+ my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
}
- if (replace_proc_table(thd, grant_name, tables[1].table, *Str,
- db_name, table_name, rights, revoke_grant))
+ if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
+ db_name, table_name, is_proc, rights, revoke_grant))
{
result= TRUE;
continue;
@@ -3109,6 +3115,7 @@ void grant_free(void)
grant_option = FALSE;
hash_free(&column_priv_hash);
hash_free(&proc_priv_hash);
+ hash_free(&func_priv_hash);
free_root(&memex,MYF(0));
DBUG_VOID_RETURN;
}
@@ -3133,6 +3140,9 @@ my_bool grant_init(THD *org_thd)
(void) hash_init(&proc_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table,
0,0);
+ (void) hash_init(&func_priv_hash,system_charset_info,
+ 0,0,0, (hash_get_key) get_grant_table,
+ 0,0);
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
/* Don't do anything if running with --skip-grant */
@@ -3206,6 +3216,8 @@ my_bool grant_init(THD *org_thd)
do
{
GRANT_NAME *mem_check;
+ longlong proc_type;
+ HASH *hash;
if (!(mem_check=new GRANT_NAME(p_table)))
{
/* This could only happen if we are out memory */
@@ -3224,11 +3236,27 @@ my_bool grant_init(THD *org_thd)
continue;
}
}
+ if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
+ {
+ hash= &proc_priv_hash;
+ }
+ else
+ if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
+ {
+ hash= &func_priv_hash;
+ }
+ else
+ {
+ sql_print_warning("'procs_priv' entry '%s' "
+ "ignored, bad routine type",
+ mem_check->tname);
+ continue;
+ }
mem_check->privs= fix_rights_for_procedure(mem_check->privs);
if (! mem_check->ok())
delete mem_check;
- else if (my_hash_insert(&proc_priv_hash,(byte*) mem_check))
+ else if (my_hash_insert(hash, (byte*) mem_check))
{
delete mem_check;
grant_option= FALSE;
@@ -3272,7 +3300,7 @@ end:
void grant_reload(THD *thd)
{
- HASH old_column_priv_hash, old_proc_priv_hash;
+ HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
bool old_grant_option;
MEM_ROOT old_mem;
DBUG_ENTER("grant_reload");
@@ -3281,6 +3309,7 @@ void grant_reload(THD *thd)
grant_version++;
old_column_priv_hash= column_priv_hash;
old_proc_priv_hash= proc_priv_hash;
+ old_func_priv_hash= func_priv_hash;
old_grant_option= grant_option;
old_mem= memex;
@@ -3290,6 +3319,7 @@ void grant_reload(THD *thd)
grant_free(); /* purecov: deadcode */
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
proc_priv_hash= old_proc_priv_hash;
+ func_priv_hash= old_func_priv_hash;
grant_option= old_grant_option; /* purecov: deadcode */
memex= old_mem; /* purecov: deadcode */
}
@@ -3297,6 +3327,7 @@ void grant_reload(THD *thd)
{
hash_free(&old_column_priv_hash);
hash_free(&old_proc_priv_hash);
+ hash_free(&old_func_priv_hash);
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
@@ -3540,13 +3571,14 @@ bool check_grant_db(THD *thd,const char *db)
/****************************************************************************
- Check procedure level grants
+ Check routine level grants
SYNPOSIS
- bool check_grant_procedure()
+ bool check_grant_routine()
thd Thread handler
want_access Bits of privileges user needs to have
- procs List of procedures to check. The user should have 'want_access'
+ procs List of routines to check. The user should have 'want_access'
+ is_proc True if the list is all procedures, else functions
no_errors If 0 then we write an error. The error is sent directly to
the client
@@ -3555,13 +3587,13 @@ bool check_grant_db(THD *thd,const char *db)
1 Error: User did not have the requested privielges
****************************************************************************/
-bool check_grant_procedure(THD *thd, ulong want_access,
- TABLE_LIST *procs, bool no_errors)
+bool check_grant_routine(THD *thd, ulong want_access,
+ TABLE_LIST *procs, bool is_proc, bool no_errors)
{
TABLE_LIST *table;
char *user= thd->priv_user;
char *host= thd->priv_host;
- DBUG_ENTER("check_grant_procedure");
+ DBUG_ENTER("check_grant_routine");
want_access&= ~thd->master_access;
if (!want_access)
@@ -3571,8 +3603,8 @@ bool check_grant_procedure(THD *thd, ulong want_access,
for (table= procs; table; table= table->next_global)
{
GRANT_NAME *grant_proc;
- if ((grant_proc= proc_hash_search(host,thd->ip,
- table->db, user, table->table_name, 0)))
+ if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user,
+ table->table_name, is_proc, 0)))
table->grant.privilege|= grant_proc->privs;
if (want_access & ~table->grant.privilege)
@@ -3594,7 +3626,7 @@ err:
if (want_access & EXECUTE_ACL)
command= "execute";
else if (want_access & ALTER_PROC_ACL)
- command= "alter procedure";
+ command= "alter routine";
else if (want_access & GRANT_ACL)
command= "grant";
my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0),
@@ -3606,7 +3638,7 @@ err:
/*
Check if routine has any of the
- procedure level grants
+ routine level grants
SYNPOSIS
bool check_routine_level_acl()
@@ -3619,15 +3651,16 @@ err:
1 error
*/
-bool check_routine_level_acl(THD *thd, const char *db, const char *name)
+bool check_routine_level_acl(THD *thd, const char *db, const char *name,
+ bool is_proc)
{
bool no_routine_acl= 1;
if (grant_option)
{
GRANT_NAME *grant_proc;
rw_rdlock(&LOCK_grant);
- if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db,
- thd->priv_user, name, 0)))
+ if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db,
+ thd->priv_user, name, is_proc, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
rw_unlock(&LOCK_grant);
}
@@ -3730,6 +3763,11 @@ static uint command_lengths[]=
};
+static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash,
+ const char *type, int typelen,
+ char *buff, int buffsize);
+
+
/*
SHOW GRANTS; Send grants for a user to the client
@@ -4076,12 +4114,40 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
- /* Add procedure access */
- for (index=0 ; index < proc_priv_hash.records ; index++)
+ if (show_routine_grants(thd, lex_user, &proc_priv_hash,
+ "PROCEDURE", 9, buff, sizeof(buff)))
+ {
+ error= -1;
+ goto end;
+ }
+
+ if (show_routine_grants(thd, lex_user, &func_priv_hash,
+ "FUNCTION", 8, buff, sizeof(buff)))
+ {
+ error= -1;
+ goto end;
+ }
+
+end:
+ VOID(pthread_mutex_unlock(&acl_cache->lock));
+ rw_unlock(&LOCK_grant);
+
+ send_eof(thd);
+ DBUG_RETURN(error);
+}
+
+static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
+ const char *type, int typelen,
+ char *buff, int buffsize)
+{
+ uint counter, index;
+ int error= 0;
+ Protocol *protocol= thd->protocol;
+ /* Add routine access */
+ for (index=0 ; index < hash->records ; index++)
{
const char *user;
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
- index);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index);
if (!(user=grant_proc->user))
user= "";
@@ -4093,7 +4159,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
ulong proc_access= grant_proc->privs;
if (proc_access != 0)
{
- String global(buff, sizeof(buff), system_charset_info);
+ String global(buff, buffsize, system_charset_info);
ulong test_access= proc_access & ~GRANT_ACL;
global.length(0);
@@ -4119,6 +4185,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
global.append(" ON ",4);
+ global.append(type,typelen);
+ global.append(' ');
append_identifier(thd, &global, grant_proc->db,
strlen(grant_proc->db));
global.append('.');
@@ -4143,15 +4211,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
}
-end:
- VOID(pthread_mutex_unlock(&acl_cache->lock));
- rw_unlock(&LOCK_grant);
-
- send_eof(thd);
- DBUG_RETURN(error);
+ return error;
}
-
/*
Make a clear-text version of the requested privilege.
*/
@@ -4977,7 +5039,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{
- uint counter, revoked;
+ uint counter, revoked, is_proc;
int result;
ACL_DB *acl_db;
TABLE_LIST tables[GRANT_TABLES];
@@ -5092,12 +5154,12 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} while (revoked);
/* Remove procedure access */
- do {
- for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; )
+ for (is_proc=0; is_proc<2; is_proc++) do {
+ HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
+ for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
const char *user,*host;
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
- counter);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
if (!(user=grant_proc->user))
user= "";
if (!(host=grant_proc->host.hostname))
@@ -5106,9 +5168,10 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
- if (!replace_proc_table(thd,grant_proc,tables[4].table,*lex_user,
+ if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
grant_proc->db,
grant_proc->tname,
+ is_proc,
~0, 1))
{
revoked= 1;
@@ -5146,11 +5209,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
< 0 Error. Error message not yet sent.
*/
-bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
+bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
+ bool is_proc)
{
uint counter, revoked;
int result;
TABLE_LIST tables[GRANT_TABLES];
+ HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
DBUG_ENTER("sp_revoke_privileges");
if ((result= open_grant_tables(thd, tables)))
@@ -5162,10 +5227,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
/* Remove procedure access */
do
{
- for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; )
+ for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
- GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash,
- counter);
+ GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) &&
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
{
@@ -5174,8 +5238,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
lex_user.user.length= strlen(grant_proc->user);
lex_user.host.str= grant_proc->host.hostname;
lex_user.host.length= strlen(grant_proc->host.hostname);
- if (!replace_proc_table(thd,grant_proc,tables[4].table,lex_user,
- grant_proc->db, grant_proc->tname, ~0, 1))
+ if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
+ grant_proc->db, grant_proc->tname,
+ is_proc, ~0, 1))
{
revoked= 1;
continue;
@@ -5211,7 +5276,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
< 0 Error. Error message not yet sent.
*/
-bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name)
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+ bool is_proc)
{
LEX_USER *combo;
TABLE_LIST tables[1];
@@ -5249,7 +5315,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name)
thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
- result= mysql_procedure_grant(thd, tables, user_list,
+ result= mysql_routine_grant(thd, tables, is_proc, user_list,
DEFAULT_CREATE_PROC_ACLS, 0, 1);
DBUG_RETURN(result);
}
@@ -5598,7 +5664,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
Dummy wrappers when we don't have any access checks
****************************************************************************/
-bool check_routine_level_acl(THD *thd, const char *db, const char *name)
+bool check_routine_level_acl(THD *thd, const char *db, const char *name,
+ bool is_proc)
{
return FALSE;
}
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 18eb123d402..f2896889669 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -185,9 +185,9 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights,
bool revoke);
-bool mysql_procedure_grant(THD *thd, TABLE_LIST *table,
- List <LEX_USER> &user_list, ulong rights,
- bool revoke, bool no_error);
+bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
+ List <LEX_USER> &user_list, ulong rights,
+ bool revoke, bool no_error);
ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx);
my_bool grant_init(THD *thd);
void grant_free(void);
@@ -200,8 +200,8 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant,
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name,
Field_iterator *fields);
-bool check_grant_procedure(THD *thd, ulong want_access,
- TABLE_LIST *procs, bool no_error);
+bool check_grant_routine(THD *thd, ulong want_access,
+ TABLE_LIST *procs, bool is_proc, bool no_error);
bool check_grant_db(THD *thd,const char *db);
ulong get_table_grant(THD *thd, TABLE_LIST *table);
ulong get_column_grant(THD *thd, GRANT_INFO *grant,
@@ -216,9 +216,12 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
-bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name);
-bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name);
-bool check_routine_level_acl(THD *thd, const char *db, const char *name);
+bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
+ bool is_proc);
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+ bool is_proc);
+bool check_routine_level_acl(THD *thd, const char *db, const char *name,
+ bool is_proc);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d431bb7ddca..2e9cf1ae40d 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3306,8 +3306,8 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
name->length(), 1)) <=
0)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0),
- name->c_ptr(), table->s->table_name);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
+ table->s->table_name);
map->set_all();
return 1;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a6a1f4d60ef..2a500610479 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1719,10 +1719,9 @@ bool select_dumpvar::send_data(List<Item> &items)
List_iterator_fast<Item_func_set_user_var> li(vars);
List_iterator_fast<Item_splocal> var_li(local_vars);
List_iterator_fast<my_var> my_li(var_list);
- List_iterator_fast<Item> it(items);
+ List_iterator<Item> it(items);
Item_func_set_user_var *xx;
Item_splocal *yy;
- Item *item;
my_var *zz;
DBUG_ENTER("send_data");
if (unit->offset_limit_cnt)
@@ -1741,13 +1740,14 @@ bool select_dumpvar::send_data(List<Item> &items)
my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
DBUG_RETURN(1);
}
- while ((zz=my_li++) && (item=it++))
+ while ((zz=my_li++) && (it++))
{
if (zz->local)
{
if ((yy=var_li++))
{
- if (thd->spcont->set_item_eval(yy->get_offset(), item, zz->type))
+ if (thd->spcont->set_item_eval(current_thd,
+ yy->get_offset(), it.ref(), zz->type))
DBUG_RETURN(1);
}
}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3bdd800cd2f..d110ff6f778 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1076,7 +1076,7 @@ bool mysql_change_db(THD *thd, const char *name)
length=unpack_dirname(path,path); // Convert if not unix
if (length && path[length-1] == FN_LIBCHAR)
path[length-1]=0; // remove ending '\'
- if (access(path,F_OK))
+ if (my_access(path,F_OK))
{
my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
my_free(dbname,MYF(0));
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 19e9866597a..97830f7ec8f 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -48,7 +48,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
}
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ce90b4ad3e0..6db7e6a6b18 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1030,7 +1030,8 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry)
for (Field **field=entry->field ; *field ; field++)
{
if ((*field)->query_id != thd->query_id &&
- ((*field)->flags & NO_DEFAULT_VALUE_FLAG))
+ ((*field)->flags & NO_DEFAULT_VALUE_FLAG) &&
+ ((*field)->real_type() != FIELD_TYPE_ENUM))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_FIELD,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 61f710a2fe5..7c7939eaf60 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -50,7 +50,8 @@ pthread_key(LEX*,THR_LEX);
used when comparing keywords
*/
-uchar to_upper_lex[] = {
+static uchar to_upper_lex[]=
+{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
@@ -1100,7 +1101,7 @@ void st_select_lex::init_query()
embedding= leaf_tables= 0;
item_list.empty();
join= 0;
- where= prep_where= 0;
+ having= where= prep_where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
resolve_mode= NOMATTER_MODE;
@@ -1530,8 +1531,8 @@ void st_select_lex::print_order(String *str, ORDER *order)
if (order->counter_used)
{
char buffer[20];
- my_snprintf(buffer, 20, "%u", order->counter);
- str->append(buffer);
+ uint length= my_snprintf(buffer, 20, "%d", order->counter);
+ str->append(buffer, length);
}
else
(*order->item)->print(str);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 94f1a8e0df4..3e463cb35ce 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -296,7 +296,7 @@ protected:
*link_next, **link_prev; /* list of whole SELECT_LEX */
public:
- ulong options;
+ ulonglong options;
/*
result of this query can't be cached, bit field, can be :
UNCACHEABLE_DEPENDENT
@@ -757,7 +757,13 @@ typedef struct st_lex
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog;
bool tx_chain, tx_release;
- /* special JOIN::prepare mode: changing of query is prohibited */
+ /*
+ Special JOIN::prepare mode: changing of query is prohibited.
+ When creating a view, we need to just check its syntax omitting
+ any optimizations: afterwards definition of the view will be
+ reconstructed by means of ::print() methods and written to
+ to an .frm file. We need this definition to stay untouched.
+ */
bool view_prepare_mode;
bool safe_to_cache_query;
bool subqueries, ignore;
@@ -898,10 +904,11 @@ struct st_lex_local: public st_lex
{ /* Never called */ }
};
-void lex_init(void);
-void lex_free(void);
-void lex_start(THD *thd, uchar *buf,uint length);
-void lex_end(LEX *lex);
+extern void lex_init(void);
+extern void lex_free(void);
+extern void lex_start(THD *thd, uchar *buf,uint length);
+extern void lex_end(LEX *lex);
+extern int yylex(void *arg, void *yythd);
extern pthread_key(LEX*,THR_LEX);
diff --git a/sql/sql_list.h b/sql/sql_list.h
index ac0f7f7012a..09c01931c38 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -192,6 +192,54 @@ public:
friend class error_list;
friend class error_list_iterator;
+#ifdef LIST_EXTRA_DEBUG
+ /*
+ Check list invariants and print results into trace. Invariants are:
+ - (*last) points to end_of_list
+ - There are no NULLs in the list.
+ - base_list::elements is the number of elements in the list.
+
+ SYNOPSIS
+ check_list()
+ name Name to print to trace file
+
+ RETURN
+ 1 The list is Ok.
+ 0 List invariants are not met.
+ */
+
+ bool check_list(const char *name)
+ {
+ base_list *list= this;
+ list_node *node= first;
+ uint cnt= 0;
+
+ while (node->next != &end_of_list)
+ {
+ if (!node->info)
+ {
+ DBUG_PRINT("list_invariants",("%s: error: NULL element in the list",
+ name));
+ return FALSE;
+ }
+ node= node->next;
+ cnt++;
+ }
+ if (last != &(node->next))
+ {
+ DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name));
+ return FALSE;
+ }
+ if (cnt+1 != elements)
+ {
+ DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name));
+ return FALSE;
+ }
+ DBUG_PRINT("list_invariants", ("%s: list is ok", name));
+ return TRUE;
+ }
+#endif // LIST_EXTRA_DEBUG
+
protected:
void after(void *info,list_node *node)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 47ac8d3afc1..0e8f7746f0f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1270,8 +1270,10 @@ void free_items(Item *item)
void cleanup_items(Item *item)
{
+ DBUG_ENTER("cleanup_items");
for (; item ; item=item->next)
item->cleanup();
+ DBUG_VOID_RETURN;
}
int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
@@ -3669,17 +3671,20 @@ unsent_create_error:
}
if (first_table)
{
- if (!lex->columns.elements &&
- sp_exists_routine(thd, all_tables, 1, 1))
+ if (lex->type == TYPE_ENUM_PROCEDURE ||
+ lex->type == TYPE_ENUM_FUNCTION)
{
uint grants= lex->all_privileges
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
: lex->grant;
if (grant_option &&
- check_grant_procedure(thd, grants | GRANT_ACL, all_tables, 0))
+ check_grant_routine(thd, grants | GRANT_ACL, all_tables,
+ lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error;
- res= mysql_procedure_grant(thd, all_tables, lex->users_list,
- grants, lex->sql_command == SQLCOM_REVOKE,0);
+ res= mysql_routine_grant(thd, all_tables,
+ lex->type == TYPE_ENUM_PROCEDURE,
+ lex->users_list, grants,
+ lex->sql_command == SQLCOM_REVOKE, 0);
}
else
{
@@ -3701,7 +3706,7 @@ unsent_create_error:
}
else
{
- if (lex->columns.elements)
+ if (lex->columns.elements || lex->type)
{
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
MYF(0));
@@ -3983,11 +3988,13 @@ unsent_create_error:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */
if (sp_automatic_privileges &&
- check_procedure_access(thd, DEFAULT_CREATE_PROC_ACLS,
- db, name, 1))
+ check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
+ db, name,
+ lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
{
close_thread_tables(thd);
- if (sp_grant_privileges(thd, db, name))
+ if (sp_grant_privileges(thd, db, name,
+ lex->sql_command == SQLCOM_CREATE_PROCEDURE))
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL,
ER(ER_PROC_AUTO_GRANT_FAIL));
@@ -4072,8 +4079,8 @@ unsent_create_error:
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_procedure_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, 0))
+ if (check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0))
{
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok;
@@ -4082,8 +4089,8 @@ unsent_create_error:
}
sp_change_security_context(thd, sp, &save_ctx);
if (save_ctx.changed &&
- check_procedure_access(thd, EXECUTE_ACL,
- sp->m_db.str, sp->m_name.str, 0))
+ check_routine_access(thd, EXECUTE_ACL,
+ sp->m_db.str, sp->m_name.str, TRUE, 0))
{
#ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok;
@@ -4185,8 +4192,9 @@ unsent_create_error:
}
else
{
- if (check_procedure_access(thd, ALTER_PROC_ACL, sp->m_db.str,
- sp->m_name.str, 0))
+ if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
+ sp->m_name.str,
+ lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
goto error;
memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
if (!trust_routine_creators && mysql_bin_log.is_open() &&
@@ -4244,11 +4252,13 @@ unsent_create_error:
{
db= thd->strdup(sp->m_db.str);
name= thd->strdup(sp->m_name.str);
- if (check_procedure_access(thd, ALTER_PROC_ACL, db, name, 0))
+ if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges &&
- sp_revoke_privileges(thd, db, name))
+ sp_revoke_privileges(thd, db, name,
+ lex->sql_command == SQLCOM_DROP_PROCEDURE))
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_REVOKE_FAIL,
@@ -4832,8 +4842,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
bool
-check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
- bool no_errors)
+check_routine_access(THD *thd, ulong want_access,char *db, char *name,
+ bool is_proc, bool no_errors)
{
TABLE_LIST tables[1];
@@ -4849,7 +4859,7 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
- return check_grant_procedure(thd, want_access, tables, no_errors);
+ return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
#endif
return FALSE;
@@ -4870,7 +4880,8 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
1 error
*/
-bool check_some_routine_access(THD *thd, const char *db, const char *name)
+bool check_some_routine_access(THD *thd, const char *db, const char *name,
+ bool is_proc)
{
ulong save_priv;
if (thd->master_access & SHOW_PROC_ACLS)
@@ -4878,7 +4889,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name)
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
(save_priv & SHOW_PROC_ACLS))
return FALSE;
- return check_routine_level_acl(thd, db, name);
+ return check_routine_level_acl(thd, db, name, is_proc);
}
@@ -5423,12 +5434,9 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
new_field->comment=*comment;
/*
Set flag if this field doesn't have a default value
- Enum values has always the first value as a default (set in
- make_empty_rec().
*/
if (!default_value && !(type_modifier & AUTO_INCREMENT_FLAG) &&
- (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP &&
- type != FIELD_TYPE_ENUM)
+ (type_modifier & NOT_NULL_FLAG) && type != FIELD_TYPE_TIMESTAMP)
new_field->flags|= NO_DEFAULT_VALUE_FLAG;
if (length && !(new_field->length= (uint) atoi(length)))
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index b36d835a80a..1521b206e0d 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1934,12 +1934,12 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
}
-/*
- Clears parameters from data left from previous execution or long data
+/*
+ Clears parameters from data left from previous execution or long data
SYNOPSIS
reset_stmt_params()
- stmt - prepared statement for which parameters should be reset
+ stmt prepared statement for which parameters should be reset
*/
static void reset_stmt_params(Prepared_statement *stmt)
@@ -1955,6 +1955,7 @@ static void reset_stmt_params(Prepared_statement *stmt)
Executes previously prepared query.
If there is any parameters, then replace markers with the data supplied
from client, and then execute the query.
+
SYNOPSIS
mysql_stmt_execute()
thd Current thread
@@ -2208,7 +2209,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
{
/* assume there is always place for 8-16 bytes */
ulong stmt_id= uint4korr(packet);
- ulong num_rows= uint4korr(packet+=4);
+ ulong num_rows= uint4korr(packet+4);
Statement *stmt;
DBUG_ENTER("mysql_stmt_fetch");
@@ -2266,7 +2267,6 @@ void mysql_stmt_reset(THD *thd, char *packet)
/* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
-
DBUG_ENTER("mysql_stmt_reset");
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5ba157cb608..26e8b398844 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1320,7 +1320,7 @@ JOIN::exec()
}
curr_all_fields= &tmp_all_fields1;
curr_fields_list= &tmp_fields_list1;
- set_items_ref_array(items1);
+ curr_join->set_items_ref_array(items1);
if (sort_and_group || curr_tmp_table->group)
{
@@ -1455,7 +1455,7 @@ JOIN::exec()
}
curr_fields_list= &curr_join->tmp_fields_list2;
curr_all_fields= &curr_join->tmp_all_fields2;
- set_items_ref_array(items2);
+ curr_join->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;
@@ -1516,7 +1516,7 @@ JOIN::exec()
}
curr_fields_list= &tmp_fields_list3;
curr_all_fields= &tmp_all_fields3;
- set_items_ref_array(items3);
+ curr_join->set_items_ref_array(items3);
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1, TRUE) ||
@@ -1834,13 +1834,14 @@ Cursor::fetch(ulong num_rows)
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
enum_nested_loop_state error= NESTED_LOOP_OK;
+ DBUG_ENTER("Cursor::fetch");
+ DBUG_PRINT("enter",("rows: %lu", num_rows));
/* save references to memory, allocated during fetch */
thd->set_n_backup_item_arena(this, &thd->stmt_backup);
join->fetch_limit+= num_rows;
-
error= sub_select(join, join_tab, 0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
@@ -1873,6 +1874,7 @@ Cursor::fetch(ulong num_rows)
else if (error != NESTED_LOOP_KILLED)
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
}
+ DBUG_VOID_RETURN;
}
@@ -1930,6 +1932,50 @@ Cursor::~Cursor()
/*********************************************************************/
+/*
+ An entry point to single-unit select (a select without UNION).
+
+ SYNOPSIS
+ mysql_select()
+
+ thd thread handler
+ rref_pointer_array a reference to ref_pointer_array of
+ the top-level select_lex for this query
+ tables list of all tables used in this query.
+ The tables have been pre-opened.
+ wild_num number of wildcards used in the top level
+ select of this query.
+ For example statement
+ SELECT *, t1.*, catalog.t2.* FROM t0, t1, t2;
+ has 3 wildcards.
+ fields list of items in SELECT list of the top-level
+ select
+ e.g. SELECT a, b, c FROM t1 will have Item_field
+ for a, b and c in this list.
+ conds top level item of an expression representing
+ WHERE clause of the top level select
+ og_num total number of ORDER BY and GROUP BY clauses
+ arguments
+ order linked list of ORDER BY agruments
+ group linked list of GROUP BY arguments
+ having top level item of HAVING expression
+ proc_param list of PROCEDUREs
+ select_options select options (BIG_RESULT, etc)
+ result an instance of result set handling class.
+ This object is responsible for send result
+ set rows to the client or inserting them
+ into a table.
+ select_lex the only SELECT_LEX of this query
+ unit top-level UNIT of this query
+ UNIT is an artificial object created by the parser
+ for every SELECT clause.
+ e.g. SELECT * FROM t1 WHERE a1 IN (SELECT * FROM t2)
+ has 2 unions.
+
+ RETURN VALUE
+ FALSE success
+ TRUE an error
+*/
bool
mysql_select(THD *thd, Item ***rref_pointer_array,
@@ -2776,6 +2822,22 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level,
if (cond->type() != Item::FUNC_ITEM)
return;
Item_func *cond_func= (Item_func*) cond;
+ if (cond_func->functype() == Item_func::NOT_FUNC)
+ {
+ Item *item= cond_func->arguments()[0];
+ /*
+ At this moment all NOT before simple comparison predicates
+ are eliminated. NOT IN and NOT BETWEEN are treated similar
+ IN and BETWEEN respectively.
+ */
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->select_optimize() == Item_func::OPTIMIZE_KEY)
+ {
+ add_key_fields(key_fields,and_level,item,usable_tables);
+ return;
+ }
+ return;
+ }
switch (cond_func->select_optimize()) {
case Item_func::OPTIMIZE_NONE:
break;
@@ -6335,7 +6397,9 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
Item *left_item= ((Item_func*) item)->arguments()[0];
Item *right_item= ((Item_func*) item)->arguments()[1];
if (left_item->type() == Item::FIELD_ITEM &&
- right_item->type() == Item::FIELD_ITEM)
+ right_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)left_item)->depended_from &&
+ !((Item_field*)right_item)->depended_from)
{
/* The predicate the form field1=field2 is processed */
@@ -6414,13 +6478,15 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
/* The predicate of the form field=const/const=field is processed */
Item *const_item= 0;
Item_field *field_item= 0;
- if (left_item->type() == Item::FIELD_ITEM &&
+ if (left_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)left_item)->depended_from &&
right_item->const_item())
{
field_item= (Item_field*) left_item;
const_item= right_item;
}
- else if (right_item->type() == Item::FIELD_ITEM &&
+ else if (right_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)right_item)->depended_from &&
left_item->const_item())
{
field_item= (Item_field*) right_item;
@@ -12609,8 +12675,10 @@ static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
Item_sum *func;
DBUG_ENTER("setup_sum_funcs");
while ((func= *(func_ptr++)))
+ {
if (func->setup(thd))
DBUG_RETURN(TRUE);
+ }
DBUG_RETURN(FALSE);
}
@@ -12897,8 +12965,6 @@ bool JOIN::rollup_make_fields(List<Item> &fields_arg, List<Item> &sel_fields,
*/
item= item->copy_or_same(thd);
((Item_sum*) item)->make_unique();
- if (((Item_sum*) item)->setup(thd))
- return 1;
*(*func)= (Item_sum*) item;
(*func)++;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index dfdff8ae914..267d584d9eb 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1345,6 +1345,32 @@ static bool show_status_array(THD *thd, const char *wild,
pthread_mutex_unlock(&LOCK_active_mi);
break;
}
+ case SHOW_SLAVE_SKIP_ERRORS:
+ {
+ MY_BITMAP *bitmap= (MY_BITMAP *)value;
+ if (!use_slave_mask || bitmap_is_clear_all(bitmap))
+ {
+ end= strmov(buff, "OFF");
+ }
+ else if (bitmap_is_set_all(bitmap))
+ {
+ end= strmov(buff, "ALL");
+ }
+ else
+ {
+ for (int i= 1; i < MAX_SLAVE_ERROR; i++)
+ {
+ if (bitmap_is_set(bitmap, i))
+ {
+ end= int10_to_str(i, (char*) end, 10);
+ *(char*) end++= ',';
+ }
+ }
+ if (end != buff)
+ end--; // Remove last ','
+ }
+ break;
+ }
#endif /* HAVE_REPLICATION */
case SHOW_OPENTABLES:
end= int10_to_str((long) cached_tables(), buff, 10);
@@ -2599,7 +2625,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
definer= get_field(thd->mem_root, proc_table->field[11]);
if (!full_access)
full_access= !strcmp(sp_user, definer);
- if (!full_access && check_some_routine_access(thd, sp_db, sp_name))
+ if (!full_access && check_some_routine_access(thd, sp_db, sp_name,
+ proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE))
return 0;
if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
@@ -2982,12 +3009,13 @@ static int get_schema_key_column_usage_record(THD *thd,
while ((f_key_info= it++))
{
LEX_STRING *f_info;
+ LEX_STRING *r_info;
List_iterator_fast<LEX_STRING> it(f_key_info->foreign_fields),
it1(f_key_info->referenced_fields);
uint f_idx= 0;
while ((f_info= it++))
{
- it1++; // Ignore r_info
+ r_info= it1++;
f_idx++;
restore_record(table, s->default_values);
store_key_column_usage(table, base_name, file_name,
@@ -2997,6 +3025,17 @@ static int get_schema_key_column_usage_record(THD *thd,
(longlong) f_idx);
table->field[8]->store((longlong) f_idx);
table->field[8]->set_notnull();
+ table->field[9]->store(f_key_info->referenced_db->str,
+ f_key_info->referenced_db->length,
+ system_charset_info);
+ table->field[9]->set_notnull();
+ table->field[10]->store(f_key_info->referenced_table->str,
+ f_key_info->referenced_table->length,
+ system_charset_info);
+ table->field[10]->set_notnull();
+ table->field[11]->store(r_info->str, r_info->length,
+ system_charset_info);
+ table->field[11]->set_notnull();
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
}
@@ -3744,6 +3783,9 @@ ST_FIELD_INFO key_column_usage_fields_info[]=
{"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONG, 0, 0, 0},
{"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONG, 0, 1, 0},
+ {"REFERENCED_TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"REFERENCED_TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"REFERENCED_COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ad0a0baae2d..4ddef3fc653 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -640,9 +640,8 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
const char *key_name;
create_field *sql_field,*dup_field;
- uint field,null_fields,blob_columns;
- uint max_key_length= file->max_key_length();
- ulong pos;
+ uint field,null_fields,blob_columns,max_key_length;
+ ulong record_offset= 0;
KEY *key_info;
KEY_PART_INFO *key_part_info;
int timestamps= 0, timestamps_with_niladic= 0;
@@ -655,6 +654,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
select_field_pos= fields->elements - select_field_count;
null_fields=blob_columns=0;
create_info->varchar= 0;
+ max_key_length= file->max_key_length();
for (field_no=0; (sql_field=it++) ; field_no++)
{
@@ -836,10 +836,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
(*db_options)|= HA_OPTION_PACK_RECORD;
it2.rewind();
}
- /* If fixed row records, we need one bit to check for deleted rows */
- if (!((*db_options) & HA_OPTION_PACK_RECORD))
- null_fields++;
- pos= (null_fields + total_uneven_bit_length + 7) / 8;
+
+ /* record_offset will be increased with 'length-of-null-bits' later */
+ record_offset= 0;
+ null_fields+= total_uneven_bit_length;
it.rewind();
while ((sql_field=it++))
@@ -852,10 +852,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
create_info->varchar= 1;
- sql_field->offset= pos;
+ sql_field->offset= record_offset;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
- pos+=sql_field->pack_length;
+ record_offset+= sql_field->pack_length;
}
if (timestamps_with_niladic > 1)
{
@@ -1159,6 +1159,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* Implicitly set primary key fields to NOT NULL for ISO conf. */
sql_field->flags|= NOT_NULL_FLAG;
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
+ null_fields--;
}
else
key_info->flags|= HA_NULL_PART_KEY;
@@ -1190,10 +1191,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (f_is_blob(sql_field->pack_flag))
{
- if ((length=column->length) > file->max_key_length() ||
+ if ((length=column->length) > max_key_length ||
length > file->max_key_part_length())
{
- length=min(file->max_key_length(), file->max_key_part_length());
+ length=min(max_key_length, file->max_key_part_length());
if (key->type == Key::MULTIPLE)
{
/* not a critical problem */
@@ -1317,6 +1318,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
/* Sort keys in optimized order */
qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY),
(qsort_cmp) sort_keys);
+ create_info->null_bits= null_fields;
DBUG_RETURN(0);
}
@@ -3417,12 +3419,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/*
better have a negative test here, instead of positive, like
- alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
+ alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
so that ALTER TABLE won't break when somebody will add new flag
*/
- need_copy_table=(alter_info->flags & ~(ALTER_CHANGE_COLUMN_DEFAULT|ALTER_OPTIONS) ||
- create_info->used_fields & ~(HA_CREATE_USED_COMMENT|HA_CREATE_USED_PASSWORD) ||
- table->s->tmp_table);
+ need_copy_table= (alter_info->flags &
+ ~(ALTER_CHANGE_COLUMN_DEFAULT|ALTER_OPTIONS) ||
+ (create_info->used_fields &
+ ~(HA_CREATE_USED_COMMENT|HA_CREATE_USED_PASSWORD)) ||
+ table->s->tmp_table);
create_info->frm_only= !need_copy_table;
/*
@@ -3827,8 +3831,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
!(sortorder=make_unireg_sortorder(order, &length)) ||
(from->sort.found_records = filesort(thd, from, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
- &examined_rows))
- == HA_POS_ERROR)
+ &examined_rows)) ==
+ HA_POS_ERROR)
goto err;
};
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index f5d64efb5e9..1e1a5683d09 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -194,7 +194,9 @@ void udf_init()
This is done to ensure that only approved dll from the system
directories are used (to make this even remotely secure).
*/
- if (strchr(dl_name, '/') || name.length > NAME_LEN)
+ if (strchr(dl_name, '/') ||
+ IF_WIN(strchr(dl_name, '\\'),0) ||
+ strlen(name.str) > NAME_LEN)
{
sql_print_error("Invalid row in mysql.func table for function '%.64s'",
name.str);
@@ -223,7 +225,7 @@ void udf_init()
}
tmp->dlhandle = dl;
{
- char buf[MAX_FIELD_NAME+16], *missing;
+ char buf[NAME_LEN+16], *missing;
if ((missing= init_syms(tmp, buf)))
{
sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
@@ -410,7 +412,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
This is done to ensure that only approved dll from the system
directories are used (to make this even remotely secure).
*/
- if (strchr(udf->dl, '/'))
+ if (strchr(udf->dl, '/') || IF_WIN(strchr(udf->dl, '\\'),0))
{
my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
DBUG_RETURN(1);
@@ -441,7 +443,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
}
udf->dlhandle=dl;
{
- char buf[MAX_FIELD_NAME+16], *missing;
+ char buf[NAME_LEN+16], *missing;
if ((missing= init_syms(udf, buf)))
{
my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), missing);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 291f829a4e3..a19a3e46798 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1107,6 +1107,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case JT_EQ_REF:
return TRUE; // At most one matching row
case JT_REF:
+ case JT_REF_OR_NULL:
return !check_if_key_used(table, join_tab->ref.key, *fields) &&
!(table->triggers &&
table->triggers->has_before_update_triggers());
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 25a78178995..99b0f43db2d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -698,7 +698,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option
start_transaction_opts opt_chain opt_release
- union_opt select_derived_init
+ union_opt select_derived_init option_type option_type2
%type <ulong_num>
ulong_num raid_types merge_insert_types
@@ -804,7 +804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
- opt_column_list grant_privileges opt_table grant_list grant_option
+ opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
@@ -3986,7 +3986,15 @@ select_from:
select_options:
/* empty*/
- | select_option_list;
+ | select_option_list
+ {
+ if (test_all_bits(Select->options, SELECT_ALL | SELECT_DISTINCT))
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT");
+ YYABORT;
+ }
+ }
+ ;
select_option_list:
select_option_list select_option
@@ -4000,15 +4008,7 @@ select_option:
YYABORT;
Lex->lock_option= TL_READ_HIGH_PRIORITY;
}
- | DISTINCT
- {
- if (Select->options & SELECT_ALL)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
- Select->options|= SELECT_DISTINCT;
- }
+ | DISTINCT { Select->options|= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
| SQL_BUFFER_RESULT
@@ -4028,15 +4028,7 @@ select_option:
{
Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
}
- | ALL
- {
- if (Select->options & SELECT_DISTINCT)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
- Select->options|= SELECT_ALL;
- }
+ | ALL { Select->options|= SELECT_ALL; }
;
select_lock_type:
@@ -6619,6 +6611,11 @@ use: USE_SYM ident
load: LOAD DATA_SYM
{
LEX *lex=Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
+ YYABORT;
+ }
lex->fname_start= lex->ptr;
}
load_data
@@ -6626,7 +6623,13 @@ load: LOAD DATA_SYM
|
LOAD TABLE_SYM table_ident FROM MASTER_SYM
{
- Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
+ LEX *lex=Lex;
+ if (lex->sphead)
+ {
+ my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD TABLE");
+ YYABORT;
+ }
+ lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
YYABORT;
};
@@ -7463,8 +7466,8 @@ option_type_value:
/*
If we are in SP we want have own LEX for each assignment.
This is mostly because it is hard for several sp_instr_set
- and sp_instr_set_trigger instructions share one LEX.
- (Well, it is theoretically possible but adds some extra
+ and sp_instr_set_trigger instructions share one LEX.
+ (Well, it is theoretically possible but adds some extra
overhead on preparation for execution stage and IMO less
robust).
@@ -7473,7 +7476,7 @@ option_type_value:
LEX *lex;
Lex->sphead->reset_lex(YYTHD);
lex= Lex;
-
+
/* Set new LEX as if we at start of set rule. */
lex->sql_command= SQLCOM_SET_OPTION;
mysql_init_select(lex);
@@ -7483,14 +7486,14 @@ option_type_value:
lex->sphead->m_tmp_query= lex->tok_start;
}
}
- option_type option_value
+ ext_option_value
{
LEX *lex= Lex;
-
+
if (lex->sphead)
{
sp_head *sp= lex->sphead;
-
+
if (!lex->var_list.is_empty())
{
/*
@@ -7500,19 +7503,19 @@ option_type_value:
*/
LEX_STRING qbuff;
sp_instr_stmt *i;
-
+
if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
lex)))
YYABORT;
-
+
if (lex->ptr - lex->tok_end > 1)
qbuff.length= lex->ptr - sp->m_tmp_query;
else
qbuff.length= lex->tok_end - sp->m_tmp_query;
-
+
if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
YYABORT;
-
+
strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
qbuff.length);
qbuff.length+= 4;
@@ -7524,11 +7527,15 @@ option_type_value:
};
option_type:
- /* empty */ {}
- | GLOBAL_SYM { Lex->option_type= OPT_GLOBAL; }
- | LOCAL_SYM { Lex->option_type= OPT_SESSION; }
- | SESSION_SYM { Lex->option_type= OPT_SESSION; }
- | ONE_SHOT_SYM { Lex->option_type= OPT_SESSION; Lex->one_shot_set= 1; }
+ option_type2 {}
+ | GLOBAL_SYM { $$=OPT_GLOBAL; }
+ | LOCAL_SYM { $$=OPT_SESSION; }
+ | SESSION_SYM { $$=OPT_SESSION; }
+ ;
+
+option_type2:
+ /* empty */ { $$= OPT_DEFAULT; }
+ | ONE_SHOT_SYM { Lex->one_shot_set= 1; $$= OPT_SESSION; }
;
opt_var_type:
@@ -7545,89 +7552,110 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-option_value:
- '@' ident_or_text equal expr
- {
- Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
- }
- | internal_variable_name equal set_expr_or_default
- {
- LEX *lex=Lex;
+ext_option_value:
+ sys_option_value
+ | option_type2 option_value;
- if ($1.var == &trg_new_row_fake_var)
- {
- /* We are in trigger and assigning value to field of new row */
- Item *it;
- sp_instr_set_trigger_field *i;
- if (lex->query_tables)
- {
- my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
- MYF(0));
- YYABORT;
- }
- if ($3)
- it= $3;
- else
- {
- /* QQ: Shouldn't this be field's default value ? */
- it= new Item_null();
- }
-
- if (!(i= new sp_instr_set_trigger_field(
- lex->sphead->instructions(), lex->spcont,
- $1.base_name, it)))
- YYABORT;
-
- /*
- Let us add this item to list of all Item_trigger_field
- objects in trigger.
- */
- lex->trg_table_fields.link_in_list((byte *)&i->trigger_field,
- (byte **)&i->trigger_field.next_trg_field);
+sys_option_value:
+ option_type internal_variable_name equal set_expr_or_default
+ {
+ LEX *lex=Lex;
- lex->sphead->add_instr(i);
+ if ($2.var == &trg_new_row_fake_var)
+ {
+ /* We are in trigger and assigning value to field of new row */
+ Item *it;
+ sp_instr_set_trigger_field *i;
+ if ($1)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
}
- else if ($1.var)
- { /* System variable */
- lex->var_list.push_back(new set_var(lex->option_type, $1.var,
- &$1.base_name, $3));
- }
+ if (lex->query_tables)
+ {
+ my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI),
+ MYF(0));
+ YYABORT;
+ }
+ if ($4)
+ it= $4;
else
- {
- /* An SP local variable */
- sp_pcontext *ctx= lex->spcont;
- sp_pvar_t *spv;
- sp_instr_set *i;
- Item *it;
+ {
+ /* QQ: Shouldn't this be field's default value ? */
+ it= new Item_null();
+ }
- spv= ctx->find_pvar(&$1.base_name);
+ if (!(i= new sp_instr_set_trigger_field(
+ lex->sphead->instructions(), lex->spcont,
+ $2.base_name, it)))
+ YYABORT;
- if ($3)
- it= $3;
- else if (spv->dflt)
- it= spv->dflt;
- else
- it= new Item_null();
- i= new sp_instr_set(lex->sphead->instructions(), ctx,
- spv->offset, it, spv->type, lex, TRUE);
- lex->sphead->add_instr(i);
- spv->isset= TRUE;
- }
- }
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ lex->trg_table_fields.link_in_list((byte *)&i->trigger_field,
+ (byte **)&i->trigger_field.next_trg_field);
+
+ lex->sphead->add_instr(i);
+ }
+ else if ($2.var)
+ { /* System variable */
+ if ($1)
+ lex->option_type= (enum_var_type)$1;
+ lex->var_list.push_back(new set_var(lex->option_type, $2.var,
+ &$2.base_name, $4));
+ }
+ else
+ {
+ /* An SP local variable */
+ sp_pcontext *ctx= lex->spcont;
+ sp_pvar_t *spv;
+ sp_instr_set *i;
+ Item *it;
+ if ($1)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+
+ spv= ctx->find_pvar(&$2.base_name);
+
+ if ($4)
+ it= $4;
+ else if (spv->dflt)
+ it= spv->dflt;
+ else
+ it= new Item_null();
+ i= new sp_instr_set(lex->sphead->instructions(), ctx,
+ spv->offset, it, spv->type, lex, TRUE);
+ lex->sphead->add_instr(i);
+ spv->isset= TRUE;
+ }
+ }
+ | option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
+ {
+ LEX *lex=Lex;
+ if (!$1)
+ lex->option_type= (enum_var_type)$1;
+ lex->var_list.push_back(new set_var(lex->option_type,
+ find_sys_var("tx_isolation"),
+ &null_lex_str,
+ new Item_int((int32) $5)));
+ }
+ ;
+
+option_value:
+ '@' ident_or_text equal expr
+ {
+ Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
+ }
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
LEX *lex=Lex;
lex->var_list.push_back(new set_var((enum_var_type) $3, $4.var,
&$4.base_name, $6));
}
- | TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
- {
- LEX *lex=Lex;
- lex->var_list.push_back(new set_var(lex->option_type,
- find_sys_var("tx_isolation"),
- &null_lex_str,
- new Item_int((int32) $4)));
- }
| charset old_or_new_charset_name_or_default
{
THD *thd= YYTHD;
@@ -7915,9 +7943,36 @@ revoke:
;
revoke_command:
- grant_privileges ON opt_table FROM grant_list
+ grant_privileges ON opt_table grant_ident FROM grant_list
{
- Lex->sql_command = SQLCOM_REVOKE;
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_REVOKE;
+ lex->type= 0;
+ }
+ |
+ grant_privileges ON FUNCTION_SYM grant_ident FROM grant_list
+ {
+ LEX *lex= Lex;
+ if (lex->columns.elements)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_REVOKE;
+ lex->type= TYPE_ENUM_FUNCTION;
+
+ }
+ |
+ grant_privileges ON PROCEDURE grant_ident FROM grant_list
+ {
+ LEX *lex= Lex;
+ if (lex->columns.elements)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_REVOKE;
+ lex->type= TYPE_ENUM_PROCEDURE;
}
|
ALL opt_privileges ',' GRANT OPTION FROM grant_list
@@ -7927,11 +7982,50 @@ revoke_command:
;
grant:
- GRANT clear_privileges grant_privileges ON opt_table TO_SYM grant_list
+ GRANT clear_privileges grant_command
+ {}
+ ;
+
+grant_command:
+ grant_privileges ON opt_table grant_ident TO_SYM grant_list
require_clause grant_options
- { Lex->sql_command= SQLCOM_GRANT; }
- ;
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_GRANT;
+ lex->type= 0;
+ }
+ |
+ grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
+ require_clause grant_options
+ {
+ LEX *lex= Lex;
+ if (lex->columns.elements)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_GRANT;
+ lex->type= TYPE_ENUM_FUNCTION;
+ }
+ |
+ grant_privileges ON PROCEDURE grant_ident TO_SYM grant_list
+ require_clause grant_options
+ {
+ LEX *lex= Lex;
+ if (lex->columns.elements)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_GRANT;
+ lex->type= TYPE_ENUM_PROCEDURE;
+ }
+ ;
+opt_table:
+ /* Empty */
+ | TABLE_SYM ;
+
grant_privileges:
object_privilege_list { }
| ALL opt_privileges
@@ -8024,7 +8118,7 @@ require_list_element:
}
;
-opt_table:
+grant_ident:
'*'
{
LEX *lex= Lex;
diff --git a/sql/structs.h b/sql/structs.h
index 7a70bfc0f4f..14c0100f5be 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -184,7 +184,7 @@ enum SHOW_TYPE
#endif /* HAVE_OPENSSL */
SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS,
SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG,
- SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS
+ SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS, SHOW_SLAVE_SKIP_ERRORS
};
enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
diff --git a/sql/table.cc b/sql/table.cc
index 82a8afd826b..d3ba4056571 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -739,8 +739,13 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
set_if_bigger(share->max_key_length,keyinfo->key_length+
keyinfo->key_parts);
share->total_key_length+= keyinfo->key_length;
- if (keyinfo->flags & HA_NOSAME)
- set_if_bigger(share->max_unique_length, keyinfo->key_length);
+ /*
+ MERGE tables do not have unique indexes. But every key could be
+ an unique index on the underlying MyISAM table. (Bug #10400)
+ */
+ if ((keyinfo->flags & HA_NOSAME) ||
+ (ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE))
+ set_if_bigger(share->max_unique_length,keyinfo->key_length);
}
if (primary_key < MAX_KEY &&
(share->keys_in_use.is_set(primary_key)))
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 00fc80a25fe..57d9fd07e51 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -27,23 +27,26 @@
#define USES_TYPES
#include "mysql_priv.h"
#include <m_ctype.h>
+#include <assert.h>
#define FCOMP 17 /* Bytes for a packed field */
static uchar * pack_screens(List<create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
-static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info);
+static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
+ ulong data_offset);
static bool pack_header(uchar *forminfo,enum db_type table_type,
List<create_field> &create_fields,
uint info_length, uint screens, uint table_options,
- handler *file);
+ ulong data_offset, handler *file);
static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
create_field *last_field);
-static bool pack_fields(File file, List<create_field> &create_fields);
+static bool pack_fields(File file, List<create_field> &create_fields,
+ ulong data_offset);
static bool make_empty_rec(THD *thd, int file, enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
- uint reclength,uint null_fields);
+ uint reclength, ulong data_offset);
/*
Create a frm (table definition) file
@@ -69,9 +72,9 @@ bool mysql_create_frm(THD *thd, my_string file_name,
uint keys, KEY *key_info,
handler *db_file)
{
- uint reclength,info_length,screens,key_info_length,maxlength,null_fields;
+ uint reclength,info_length,screens,key_info_length,maxlength;
File file;
- ulong filepos;
+ ulong filepos, data_offset;
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
@@ -81,9 +84,16 @@ bool mysql_create_frm(THD *thd, my_string file_name,
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
DBUG_RETURN(1);
if (db_file == NULL)
- db_file=get_new_handler((TABLE*) 0, create_info->db_type);
+ db_file= get_new_handler((TABLE*) 0, create_info->db_type);
+
+ /* If fixed row records, we need one bit to check for deleted rows */
+ if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
+ create_info->null_bits++;
+ data_offset= (create_info->null_bits + 7) / 8;
+
if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
- screens, create_info->table_options, db_file))
+ screens, create_info->table_options,
+ data_offset, db_file))
{
my_free((gptr) screen_buff,MYF(0));
if (thd->net.last_errno != ER_TOO_MANY_FIELDS)
@@ -94,14 +104,13 @@ bool mysql_create_frm(THD *thd, my_string file_name,
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
DBUG_RETURN(1);
if (pack_header(forminfo, create_info->db_type, create_fields,info_length,
- screens, create_info->table_options, db_file))
+ screens, create_info->table_options, data_offset, db_file))
{
my_free((gptr) screen_buff,MYF(0));
DBUG_RETURN(1);
}
}
reclength=uint2korr(forminfo+266);
- null_fields=uint2korr(forminfo+282);
if ((file=create_frm(file_name, reclength, fileinfo,
create_info, keys)) < 0)
@@ -112,7 +121,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
uint key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
- key_info_length=pack_keys(keybuff,keys,key_info);
+ key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
VOID(get_form_pos(file,fileinfo,&formnames));
if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
goto err;
@@ -135,13 +144,13 @@ bool mysql_create_frm(THD *thd, my_string file_name,
(ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
MY_SEEK_SET,MYF(0)));
if (make_empty_rec(thd,file,create_info->db_type,create_info->table_options,
- create_fields,reclength,null_fields))
+ create_fields,reclength, data_offset))
goto err;
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
- pack_fields(file,create_fields))
+ pack_fields(file, create_fields, data_offset))
goto err;
#ifdef HAVE_CRYPTED_FRM
@@ -313,7 +322,8 @@ static uchar * pack_screens(List<create_field> &create_fields,
/* Pack keyinfo and keynames to keybuff for save in form-file. */
-static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
+static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
+ ulong data_offset)
{
uint key_parts,length;
uchar *pos, *keyname_pos;
@@ -340,10 +350,13 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
key_part++)
{
- DBUG_PRINT("loop",("field: %d startpos: %ld length: %ld",
- key_part->fieldnr,key_part->offset,key_part->length));
+ uint offset;
+ DBUG_PRINT("loop",("field: %d startpos: %lu length: %ld",
+ key_part->fieldnr, key_part->offset + data_offset,
+ key_part->length));
int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
- int2store(pos+2,key_part->offset+1);
+ offset= (uint) (key_part->offset+data_offset+1);
+ int2store(pos+2, offset);
pos[4]=0; // Sort order
int2store(pos+5,key_part->key_type);
int2store(pos+7,key_part->length);
@@ -384,8 +397,8 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
static bool pack_header(uchar *forminfo, enum db_type table_type,
List<create_field> &create_fields,
- uint info_length, uint screens,uint table_options,
- handler *file)
+ uint info_length, uint screens, uint table_options,
+ ulong data_offset, handler *file)
{
uint length,int_count,int_length,no_empty, int_parts;
uint time_stamp_pos,null_fields;
@@ -425,10 +438,10 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
if (field->sql_type == FIELD_TYPE_TIMESTAMP &&
MTYP_TYPENR(field->unireg_check) != Field::NONE &&
!time_stamp_pos)
- time_stamp_pos=(int) field->offset+1;
+ time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
length=field->pack_length;
- if ((int) field->offset+length > reclength)
- reclength=(int) field->offset+length;
+ if ((uint) field->offset+ (uint) data_offset+ length > reclength)
+ reclength=(uint) (field->offset+ data_offset + length);
n_length+= (ulong) strlen(field->field_name)+1;
field->interval_id=0;
if (field->interval)
@@ -539,7 +552,8 @@ static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
/* Save fields, fieldnames and intervals */
-static bool pack_fields(File file,List<create_field> &create_fields)
+static bool pack_fields(File file, List<create_field> &create_fields,
+ ulong data_offset)
{
reg2 uint i;
uint int_count, comment_length=0;
@@ -554,11 +568,13 @@ static bool pack_fields(File file,List<create_field> &create_fields)
int_count=0;
while ((field=it++))
{
+ uint recpos;
buff[0]= (uchar) field->row;
buff[1]= (uchar) field->col;
buff[2]= (uchar) field->sc_length;
int2store(buff+3, field->length);
- uint recpos=(uint) field->offset+1;
+ /* The +1 is here becasue the col offset in .frm file have offset 1 */
+ recpos= field->offset+1 + (uint) data_offset;
int3store(buff+5,recpos);
int2store(buff+8,field->pack_flag);
int2store(buff+10,field->unireg_check);
@@ -644,11 +660,12 @@ static bool pack_fields(File file,List<create_field> &create_fields)
static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
- uint reclength, uint null_fields)
+ uint reclength,
+ ulong data_offset)
{
int error;
Field::utype type;
- uint null_count;
+ uint firstpos, null_count;
uchar *buff,*null_pos;
TABLE table;
create_field *field;
@@ -675,8 +692,7 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
null_count=0;
if (!(table_options & HA_OPTION_PACK_RECORD))
{
- null_fields++; // Need one bit for delete mark
- null_count++;
+ null_count++; // Need one bit for delete mark
*buff|= 1;
}
null_pos= buff;
@@ -688,7 +704,8 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
/*
regfield don't have to be deleted as it's allocated with sql_alloc()
*/
- Field *regfield=make_field((char*) buff+field->offset,field->length,
+ Field *regfield=make_field((char*) buff+field->offset + data_offset,
+ field->length,
null_pos + null_count / 8,
null_count & 7,
field->pack_flag,
@@ -737,12 +754,13 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type,
else
regfield->reset();
}
+ DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
/* Fill not used startpos */
if (null_count)
*(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
- error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
+ error=(int) my_write(file,(byte*) buff, (uint) reclength,MYF_RW);
err:
my_free((gptr) buff,MYF(MY_FAE));