diff options
Diffstat (limited to 'sql')
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)); |