diff options
Diffstat (limited to 'sql')
79 files changed, 2131 insertions, 1727 deletions
diff --git a/sql/field.h b/sql/field.h index 794b4a89542..10d3e671867 100644 --- a/sql/field.h +++ b/sql/field.h @@ -305,6 +305,11 @@ public: unireg_check_arg, field_name_arg, table_arg, dec_arg, zero_arg,unsigned_arg) {} + Field_decimal(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } @@ -334,6 +339,11 @@ public: unireg_check_arg, field_name_arg, table_arg, 0, zero_arg,unsigned_arg) {} + Field_tiny(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum Item_result result_type () const { return INT_RESULT; } enum_field_types type() const { return FIELD_TYPE_TINY;} enum ha_base_keytype key_type() const @@ -364,6 +374,11 @@ public: unireg_check_arg, field_name_arg, table_arg, 0, zero_arg,unsigned_arg) {} + Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum Item_result result_type () const { return INT_RESULT; } enum_field_types type() const { return FIELD_TYPE_SHORT;} enum ha_base_keytype key_type() const @@ -497,6 +512,11 @@ public: unireg_check_arg, field_name_arg, table_arg, dec_arg, zero_arg,unsigned_arg) {} + Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, uint8 dec_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg,dec_arg,0,0) + {} enum_field_types type() const { return FIELD_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -558,6 +578,11 @@ public: :Field_str(ptr_arg, len_arg, null, 1, unireg_check_arg, field_name_arg, table_arg, cs) {} + Field_null(uint32 len_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0, len_arg, null, 1, + NONE, field_name_arg, table_arg, cs) + {} enum_field_types type() const { return FIELD_TYPE_NULL;} int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; } int store(double nr) { null[0]=1; return 0; } @@ -627,6 +652,10 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, 1, 1) {} + Field_year(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg) + :Field_tiny(len_arg,maybe_null_arg,field_name_arg,table_arg,1) + {} enum_field_types type() const { return FIELD_TYPE_YEAR;} int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index e8e4798c2b2..a87bed94484 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -236,6 +236,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0)); if (!table->db_record_offset) int_table_flags|=HA_REC_NOT_IN_SEQ; + if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) + int_table_flags|=HA_HAS_CHECKSUM; return (0); } @@ -1414,3 +1416,9 @@ int ha_myisam::ft_read(byte * buf) table->status=error ? STATUS_NOT_FOUND: 0; return error; } + +uint ha_myisam::checksum() const +{ + return (uint)file->s->state.checksum; +} + diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 8486e25556b..e4e3192af10 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -64,6 +64,7 @@ class ha_myisam: public handler uint max_keys() const { return MI_MAX_KEY; } uint max_key_parts() const { return MAX_REF_PARTS; } uint max_key_length() const { return MI_MAX_KEY_LENGTH; } + uint checksum() const; int open(const char *name, int mode, uint test_if_locked); int close(void); diff --git a/sql/handler.cc b/sql/handler.cc index b4d370491bb..851e73f15d2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -359,7 +359,10 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { + if (wait_if_global_read_lock(thd, 0)) + DBUG_RETURN(1); mysql_bin_log.write(thd, &thd->transaction.trans_log); + start_waiting_global_read_lock(thd); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); thd->transaction.trans_log.end_of_file= max_binlog_cache_size; diff --git a/sql/handler.h b/sql/handler.h index b1b5cfb02b0..b74e06c6edf 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -42,38 +42,39 @@ #define HA_ADMIN_INVALID -5 /* Bits in table_flags() to show what database can do */ -#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record - (To update with RND-read) */ -#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */ -#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */ -#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber; - It returns a position to ha_r_rnd */ -#define HA_HAS_GEOMETRY 16 -#define HA_NO_INDEX 32 /* No index needed for next/prev */ -#define HA_KEY_READ_WRONG_STR 64 /* keyread returns converted strings */ -#define HA_NULL_KEY 128 /* One can have keys with NULL */ -#define HA_DUPP_POS 256 /* ha_position() gives dupp row */ -#define HA_NO_BLOBS 512 /* Doesn't support blobs */ -#define HA_BLOB_KEY (HA_NO_BLOBS*2) /* key on blob */ -#define HA_AUTO_PART_KEY (HA_BLOB_KEY*2) -#define HA_REQUIRE_PRIMARY_KEY (HA_AUTO_PART_KEY*2) -#define HA_NOT_EXACT_COUNT (HA_REQUIRE_PRIMARY_KEY*2) -#define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2) -#define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2) -#define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2) -#define HA_NOT_READ_AFTER_KEY (HA_DROP_BEFORE_CREATE*2) -#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2) -#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2) -#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2) -#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2) -#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2) -#define HA_NO_AUTO_INCREMENT (HA_CAN_SQL_HANDLER*2) +#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record + (To update with RND-read) */ +#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */ +#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */ +#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber; + It returns a position to ha_r_rnd */ +#define HA_HAS_GEOMETRY (1 << 4) +#define HA_NO_INDEX (1 << 5) /* No index needed for next/prev */ +#define HA_KEY_READ_WRONG_STR (1 << 6) /* keyread returns converted strings */ +#define HA_NULL_KEY (1 << 7) /* One can have keys with NULL */ +#define HA_DUPP_POS (1 << 8) /* ha_position() gives dupp row */ +#define HA_NO_BLOBS (1 << 9) /* Doesn't support blobs */ +#define HA_BLOB_KEY (1 << 10) /* key on blob */ +#define HA_AUTO_PART_KEY (1 << 11) +#define HA_REQUIRE_PRIMARY_KEY (1 << 12) +#define HA_NOT_EXACT_COUNT (1 << 13) +#define HA_NO_WRITE_DELAYED (1 << 14) +#define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15) +#define HA_DROP_BEFORE_CREATE (1 << 16) +#define HA_NOT_READ_AFTER_KEY (1 << 17) +#define HA_NOT_DELETE_WITH_CACHE (1 << 18) +#define HA_NO_TEMP_TABLES (1 << 19) +#define HA_NO_PREFIX_CHAR_KEYS (1 << 20) +#define HA_CAN_FULLTEXT (1 << 21) +#define HA_CAN_SQL_HANDLER (1 << 22) +#define HA_NO_AUTO_INCREMENT (1 << 23) +#define HA_HAS_CHECKSUM (1 << 24) /* Next record gives next record according last record read (even if database is updated after read). Not used at this point. */ -#define HA_LASTKEY_ORDER (HA_NO_AUTO_INCREMENT*2) +#define HA_LASTKEY_ORDER (1 << 25) /* bits in index_flags(index_number) for what you can do with index */ @@ -306,8 +307,8 @@ public: virtual bool check_and_repair(THD *thd) {return 1;} virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt); virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt); - virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); + virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); /* restore assumes .frm file must exist, and that generate_table() has been called; It will just copy the data file and run repair. @@ -325,8 +326,8 @@ public: virtual char* get_foreign_key_create_info() { return(NULL);} /* gets foreign key create string from InnoDB */ virtual void init_table_handle_for_HANDLER() - { return; } /* prepare InnoDB for HANDLER */ - virtual void free_foreign_key_create_info(char* str) {} + { return; } /* prepare InnoDB for HANDLER */ + virtual void free_foreign_key_create_info(char* str) {} /* The following can be called without an open handler */ virtual const char *table_type() const =0; virtual const char **bas_ext() const =0; @@ -342,6 +343,7 @@ public: virtual uint max_key_part_length() { return 255; } virtual uint min_record_length(uint options) const { return 1; } virtual bool low_byte_first() const { return 1; } + virtual uint checksum() const { return 0; } virtual bool is_crashed() const { return 0; } virtual bool auto_repair() const { return 0; } @@ -355,13 +357,12 @@ public: /* Type of table for caching query */ virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } - /* - Is query with this cable cachable (have sense only for ASKTRANSACT + /* + Is query with this table cachable (have sense only for ASKTRANSACT tables) */ - static bool caching_allowed(THD* thd, char* table_key, + static bool caching_allowed(THD* thd, char* table_key, uint key_length, uint8 cahe_type); - }; /* Some extern variables used with handlers */ @@ -390,7 +391,7 @@ int ha_delete_table(enum db_type db_type, const char *path); void ha_drop_database(char* path); void ha_key_cache(void); void ha_resize_key_cache(void); -int ha_start_stmt(THD *thd); +int ha_start_stmt(THD *thd); int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, my_off_t end_offset); int ha_commit_complete(THD *thd); diff --git a/sql/item.cc b/sql/item.cc index 17b9e1b508f..0f799184559 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -490,27 +490,38 @@ String *Item_null::val_str(String *str) /* Item_param related */ void Item_param::set_null() -{ - maybe_null=null_value=1; +{ + DBUG_ENTER("Item_param::set_null"); + maybe_null= null_value= 1; + DBUG_VOID_RETURN; } void Item_param::set_int(longlong i) -{ - int_value=(longlong)i; - item_type = INT_ITEM; +{ + DBUG_ENTER("Item_param::set_int"); + int_value= (longlong)i; + item_type= INT_ITEM; + DBUG_PRINT("info", ("integer: %lld", int_value)); + DBUG_VOID_RETURN; } void Item_param::set_double(double value) -{ +{ + DBUG_ENTER("Item_param::set_double"); real_value=value; - item_type = REAL_ITEM; + item_type= REAL_ITEM; + DBUG_PRINT("info", ("double: %lg", real_value)); + DBUG_VOID_RETURN; } void Item_param::set_value(const char *str, uint length) -{ - str_value.set(str,length,default_charset()); - item_type = STRING_ITEM; +{ + DBUG_ENTER("Item_param::set_value"); + str_value.copy(str,length,default_charset()); + item_type= STRING_ITEM; + DBUG_PRINT("info", ("string: %s", str_value.ptr())); + DBUG_VOID_RETURN; } @@ -923,6 +934,73 @@ enum_field_types Item::field_type() const FIELD_TYPE_DOUBLE); } +Field *Item::tmp_table_field_from_field_type(TABLE *table) +{ + switch (field_type()) + { + case MYSQL_TYPE_DECIMAL: + return new Field_decimal(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_TINY: + return new Field_tiny(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_SHORT: + return new Field_short(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_LONG: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_FLOAT: + return new Field_float(max_length, maybe_null, name, table, decimals); + case MYSQL_TYPE_DOUBLE: + return new Field_double(max_length, maybe_null, name, table, decimals); + case MYSQL_TYPE_NULL: + return new Field_null(max_length, name, table, &my_charset_bin); +#ifdef HAVE_LONG_LONG + case MYSQL_TYPE_LONGLONG: + return new Field_longlong(max_length, maybe_null, name, table, + unsigned_flag); +#endif + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_INT24: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_DATE: + return new Field_date(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_TIME: + return new Field_time(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return new Field_datetime(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_YEAR: + return new Field_year(max_length, maybe_null, name, table); + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + case MYSQL_TYPE_VAR_STRING: + if (max_length > 255) + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + else + return new Field_varstring(max_length, maybe_null, name, table, collation.collation); + case MYSQL_TYPE_STRING: + if (max_length > 255) + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + else + return new Field_string(max_length, maybe_null, name, table, collation.collation); + default: + // This case should never be choosen + DBUG_ASSERT(0); + return 0; + } +} + /* ARGSUSED */ void Item_field::make_field(Send_field *tmp_field) { diff --git a/sql/item.h b/sql/item.h index 296ad18b1f1..147c350878e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -120,6 +120,9 @@ public: Constructor used by Item_field, Item_ref & agregate (sum) functions. Used for duplicating lists in processing queries with temporary tables + Also it used for Item_cond_and/Item_cond_or for creating + top AND/OR ctructure of WHERE clause to protect it of + optimisation changes in prepared statements */ Item(THD *thd, Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ @@ -140,7 +143,7 @@ public: virtual double val()=0; virtual longlong val_int()=0; virtual String *val_str(String*)=0; - virtual Field *tmp_table_field() { return 0; } + virtual Field *get_tmp_table_field() { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } virtual double val_result() { return val(); } @@ -184,6 +187,7 @@ public: virtual void save_in_result_field(bool no_conversions) {} virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } + virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } @@ -205,6 +209,8 @@ public: virtual bool null_inside() { return 0; } // used in row subselects to get value of elements virtual void bring_value() {} + + Field *tmp_table_field_from_field_type(TABLE *table); }; @@ -265,7 +271,7 @@ public: { return field->type(); } - Field *tmp_table_field() { return result_field; } + Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } bool get_date(TIME *ltime,bool fuzzydate); bool get_date_result(TIME *ltime,bool fuzzydate); @@ -539,12 +545,12 @@ class Item_result_field :public Item /* Item with result field */ public: Field *result_field; /* Save result here */ Item_result_field() :result_field(0) {} - // Constructor used for Item_sum (see Item comment) + // Constructor used for Item_sum/Item_cond_and/or (see Item comment) Item_result_field(THD *thd, Item_result_field &item): Item(thd, item), result_field(item.result_field) {} ~Item_result_field() {} /* Required with gcc 2.95 */ - Field *tmp_table_field() { return result_field; } + Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } table_map used_tables() const { return 1; } virtual void fix_length_and_dec()=0; @@ -862,6 +868,7 @@ public: { value= item->val_int_result(); null_value= item->null_value; + collation.set(item->collation); } double val() { return (double) value; } longlong val_int() { return value; } @@ -879,6 +886,7 @@ public: { value= item->val_result(); null_value= item->null_value; + collation.set(item->collation); } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 053eb9e6fef..7460c103550 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -698,8 +698,21 @@ Item_func_ifnull::fix_length_and_dec() agg_arg_collations(collation, args, arg_count); else if (cached_result_type != REAL_RESULT) decimals= 0; + + cached_field_type= args[0]->field_type(); + if (cached_field_type != args[1]->field_type()) + cached_field_type= Item_func::field_type(); +} + +enum_field_types Item_func_ifnull::field_type() const +{ + return cached_field_type; } +Field *Item_func_ifnull::tmp_table_field(TABLE *table) +{ + return tmp_table_field_from_field_type(table); +} double Item_func_ifnull::val() @@ -1536,6 +1549,31 @@ longlong Item_func_bit_and::val_int() return (longlong) (arg1 & arg2); } +Item_cond::Item_cond(THD *thd, Item_cond &item) + :Item_bool_func(thd, item), + abort_on_null(item.abort_on_null), + and_tables_cache(item.and_tables_cache) +{ + /* + here should be following text: + + List_iterator_fast<Item*> li(item.list); + while(Item *it= li++) + list.push_back(it); + + but it do not need, + because this constructor used only for AND/OR and + argument list will be copied by copy_andor_arguments call + */ + +} + +void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) +{ + List_iterator_fast<Item> li(item->list); + while(Item *it= li++) + list.push_back(it->copy_andor_structure(thd)); +} bool Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 5c06f4fa1df..f8104491978 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -82,6 +82,7 @@ public: Item_bool_func() :Item_int_func() {} Item_bool_func(Item *a) :Item_int_func(a) {} Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} + Item_bool_func(THD *thd, Item_bool_func &item) :Item_int_func(thd, item) {} void fix_length_and_dec() { decimals=0; max_length=1; } }; @@ -115,8 +116,8 @@ protected: String tmp_value1,tmp_value2; public: - Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} + Item_bool_func2(Item *a,Item *b) + :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} void fix_length_and_dec(); void set_cmp_func() { @@ -158,7 +159,7 @@ public: class Item_func_eq :public Item_bool_rowready_func2 { public: - Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; + Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {} longlong val_int(); enum Functype functype() const { return EQ_FUNC; } enum Functype rev_functype() const { return EQ_FUNC; } @@ -280,6 +281,8 @@ public: class Item_func_ifnull :public Item_func { enum Item_result cached_result_type; + enum_field_types cached_field_type; + bool field_type_defined; public: Item_func_ifnull(Item *a,Item *b) :Item_func(a,b), cached_result_type(INT_RESULT) @@ -288,8 +291,10 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } + enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } + Field *tmp_table_field(TABLE *table); table_map not_null_tables() const { return 0; } }; @@ -787,8 +792,13 @@ protected: public: /* Item_cond() is only used to create top level items */ Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; } - Item_cond(Item *i1,Item *i2) :Item_bool_func(), abort_on_null(0) - { list.push_back(i1); list.push_back(i2); } + Item_cond(Item *i1,Item *i2) + :Item_bool_func(), abort_on_null(0) + { + list.push_back(i1); + list.push_back(i2); + } + Item_cond(THD *thd, Item_cond &item); ~Item_cond() { list.delete_elements(); } bool add(Item *item) { return list.push_back(item); } bool fix_fields(THD *, struct st_table_list *, Item **ref); @@ -801,6 +811,7 @@ public: void split_sum_func(Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); void top_level_item() { abort_on_null=1; } + void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); }; @@ -811,9 +822,17 @@ class Item_cond_and :public Item_cond public: Item_cond_and() :Item_cond() {} Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {} + Item_cond_and(THD *thd, Item_cond_and &item) :Item_cond(thd, item) {} enum Functype functype() const { return COND_AND_FUNC; } longlong val_int(); const char *func_name() const { return "and"; } + Item* copy_andor_structure(THD *thd) + { + Item_cond_and *item; + if((item= new Item_cond_and(thd, *this))) + item->copy_andor_arguments(thd, this); + return item; + } }; class Item_cond_or :public Item_cond @@ -821,10 +840,18 @@ class Item_cond_or :public Item_cond public: Item_cond_or() :Item_cond() {} Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {} + Item_cond_or(THD *thd, Item_cond_or &item) :Item_cond(thd, item) {} enum Functype functype() const { return COND_OR_FUNC; } longlong val_int(); const char *func_name() const { return "or"; } table_map not_null_tables() const { return and_tables_cache; } + Item* copy_andor_structure(THD *thd) + { + Item_cond_or *item; + if((item= new Item_cond_or(thd, *this))) + item->copy_andor_arguments(thd, this); + return item; + } }; diff --git a/sql/item_create.cc b/sql/item_create.cc index e3e3c021a1e..b1173b9c7b8 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -52,13 +52,6 @@ Item *create_func_ord(Item* a) return new Item_func_ord(a); } -Item *create_func_old_password(Item* a) -{ - return new Item_func_old_password(a); -} - - - Item *create_func_asin(Item* a) { return new Item_func_asin(a); @@ -107,14 +100,6 @@ Item *create_func_cot(Item* a) new Item_func_tan(a)); } - -#ifdef HAVE_COMPRESS -Item *create_func_crc32(Item* a) -{ - return new Item_func_crc32(a); -} -#endif - Item *create_func_date_format(Item* a,Item *b) { return new Item_func_date_format(a,b,0); @@ -332,11 +317,6 @@ Item *create_func_quarter(Item* a) return new Item_func_quarter(a); } -Item *create_func_password(Item* a) -{ - return new Item_func_password(a); -} - Item *create_func_radians(Item *a) { return new Item_func_units((char*) "radians",a,M_PI/180,0.0); @@ -666,13 +646,10 @@ Item *create_func_point(Item *a, Item *b) return new Item_func_point(a, b); } -#if !defined(HAVE_COMPRESS) - -Item *create_func_compress (Item*a __attribute__((unused))){return 0;} -Item *create_func_uncompress (Item*a __attribute__((unused))){return 0;} -Item *create_func_uncompressed_length(Item*a __attribute__((unused))){return 0;} - -#else +Item *create_func_crc32(Item* a) +{ + return new Item_func_crc32(a); +} Item *create_func_compress(Item* a) { @@ -689,8 +666,6 @@ Item *create_func_uncompressed_length(Item* a) return new Item_func_uncompressed_length(a); } -#endif - Item *create_func_datediff(Item *a, Item *b) { return new Item_func_minus(new Item_func_to_days(a), diff --git a/sql/item_create.h b/sql/item_create.h index 16c4fccf709..c75f4404bad 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -33,9 +33,7 @@ Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); Item *create_func_cot(Item* a); -#ifdef HAVE_COMPRESS Item *create_func_crc32(Item* a); -#endif Item *create_func_date_format(Item* a,Item *b); Item *create_func_dayname(Item* a); Item *create_func_dayofmonth(Item* a); @@ -69,14 +67,12 @@ Item *create_func_monthname(Item* a); Item *create_func_nullif(Item* a, Item *b); Item *create_func_oct(Item *); Item *create_func_ord(Item* a); -Item *create_func_old_password(Item* a); Item *create_func_period_add(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b); Item *create_func_pi(void); Item *create_func_pow(Item* a, Item *b); Item *create_func_current_user(void); Item *create_func_quarter(Item* a); -Item *create_func_password(Item* a); Item *create_func_radians(Item *a); Item *create_func_release_lock(Item* a); Item *create_func_repeat(Item* a, Item *b); diff --git a/sql/item_func.cc b/sql/item_func.cc index 4bda8ae78cd..5ebc4e82f13 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -27,22 +27,18 @@ #include <hash.h> #include <time.h> #include <ft_global.h> -#ifdef HAVE_COMPRESS -#include <zlib.h> -#endif static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), + c1.collation->name,c1.derivation_name(), c2.collation->name,c2.derivation_name(), fname); } - -static void my_coll_agg_error(DTCollation &c1, +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, DTCollation &c3, const char *fname) @@ -134,6 +130,27 @@ Item_func::Item_func(List<Item> &list) set_arguments(list); } +Item_func::Item_func(THD *thd, Item_func &item) + :Item_result_field(thd, item), + allowed_arg_cols(item.allowed_arg_cols), + arg_count(item.arg_count), + used_tables_cache(item.used_tables_cache), + not_null_tables_cache(item.not_null_tables_cache), + const_item_cache(item.const_item_cache) +{ + if (arg_count) + { + if (arg_count <=2) + args= tmp_arg; + else + { + if (!(args=(Item**) thd->alloc(sizeof(Item*)*arg_count))) + return; + } + memcpy((char*) args, (char*) item.args, sizeof(Item*)*arg_count); + } +} + /* Resolve references to table column for a function and it's argument @@ -1085,36 +1102,6 @@ longlong Item_func_min_max::val_int() return value; } - -#ifdef HAVE_COMPRESS -longlong Item_func_crc32::val_int() -{ - String *res=args[0]->val_str(&value); - if (!res) - { - null_value=1; - return 0; /* purecov: inspected */ - } - null_value=0; - return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length()); -} - - -longlong Item_func_uncompressed_length::val_int() -{ - String *res= args[0]->val_str(&value); - if (!res) - { - null_value=1; - return 0; /* purecov: inspected */ - } - null_value=0; - if (res->is_empty()) return 0; - return uint4korr(res->c_ptr()) & 0x3FFFFFFF; -} -#endif /* HAVE_COMPRESS */ - - longlong Item_func_length::val_int() { String *res=args[0]->val_str(&value); diff --git a/sql/item_func.h b/sql/item_func.h index 7fedbcf48ee..cf554f613d4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -104,6 +104,8 @@ public: } } Item_func(List<Item> &list); + // Constructor used for Item_cond_and/or (see Item comment) + Item_func(THD *thd, Item_func &item); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ bool fix_fields(THD *,struct st_table_list *, Item **ref); table_map used_tables() const; @@ -196,6 +198,7 @@ public: Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; } Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; } + Item_int_func(THD *thd, Item_int_func &item) :Item_func(thd, item) {} double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } @@ -555,27 +558,6 @@ public: }; -#ifdef HAVE_COMPRESS -class Item_func_crc32 :public Item_int_func -{ - String value; -public: - Item_func_crc32(Item *a) :Item_int_func(a) {} - longlong val_int(); - const char *func_name() const { return "crc32"; } - void fix_length_and_dec() { max_length=10; } -}; -class Item_func_uncompressed_length : public Item_int_func -{ - String value; -public: - Item_func_uncompressed_length(Item *a):Item_int_func(a){} - longlong val_int(); - const char *func_name() const{return "uncompressed_length";} - void fix_length_and_dec() { max_length=10; } -}; -#endif - class Item_func_length :public Item_int_func { String value; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index d86914eb6c5..79e45cca26f 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -167,30 +167,6 @@ public: const char *func_name() const { return "multipoint"; } }; -#ifdef HAVE_COMPRESS - -class Item_func_compress: public Item_str_func -{ - String buffer; -public: - Item_func_compress(Item *a):Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} - const char *func_name() const{return "compress";} -}; - -class Item_func_uncompress: public Item_str_func -{ - String buffer; -public: - Item_func_uncompress(Item *a): Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} - const char *func_name() const{return "uncompress";} -}; - -#endif - /* Spatial relations */ diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b0b9cc01bf1..f8cc602129f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1327,95 +1327,49 @@ void Item_func_trim::fix_length_and_dec() } - - -void Item_func_password::fix_length_and_dec() -{ - /* - If PASSWORD() was called with only one argument, it depends on a random - number so we need to save this random number into the binary log. - If called with two arguments, it is repeatable. - */ - if (arg_count == 1) - { - THD *thd= current_thd; - thd->rand_used= 1; - thd->rand_saved_seed1= thd->rand.seed1; - thd->rand_saved_seed2= thd->rand.seed2; - } - max_length= get_password_length(use_old_passwords); -} - -/* - Password() function has 2 arguments. Second argument can be used - to make results repeatable -*/ +/* Item_func_password */ String *Item_func_password::val_str(String *str) { - struct rand_struct rand_st; // local structure for 2 param version - ulong seed=0; // seed to initialise random generator to - - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; - - if (arg_count == 1) - { - if (res->length() == 0) - return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords, - ¤t_thd->rand); - str->set(tmp_value,get_password_length(use_old_passwords),res->charset()); - return str; - } - else - { - /* We'll need the buffer to get second parameter */ - char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); - String *key =args[1]->val_str(&tmp_key_value); - - /* Check second argument for NULL value. First one is already checked */ - if ((null_value=args[1]->null_value)) - return 0; - - /* This shall be done after checking for null for proper results */ - if (res->length() == 0) - return &empty_string; - - /* Generate the seed first this allows to avoid double allocation */ - char* seed_ptr=key->c_ptr(); - while (*seed_ptr) - { - seed=(seed*211+*seed_ptr) & 0xffffffffL; /* Use simple hashing */ - seed_ptr++; - } - - /* Use constants which allow nice random values even with small seed */ - randominit(&rand_st, - (ulong) ((ulonglong) seed*111111+33333333L) & (ulong) 0xffffffff, - (ulong) ((ulonglong) seed*1111+55555555L) & (ulong) 0xffffffff); - - make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords, - &rand_st); - str->set(tmp_value,get_password_length(use_old_passwords),res->charset()); - return str; - } + if (res->length() == 0) + return &empty_string; + make_scrambled_password(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset()); + return str; +} + +char *Item_func_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, password); + return buff; } +/* Item_func_old_password */ + String *Item_func_old_password::val_str(String *str) { - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr(),1,¤t_thd->rand); - str->set(tmp_value,16,res->charset()); + make_scrambled_password_323(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset()); return str; } +char *Item_func_old_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, password); + return buff; +} #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') @@ -2554,6 +2508,31 @@ null: return 0; } +longlong Item_func_uncompressed_length::val_int() +{ + String *res= args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + if (res->is_empty()) return 0; + return uint4korr(res->c_ptr()) & 0x3FFFFFFF; +} + +longlong Item_func_crc32::val_int() +{ + String *res=args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + return (longlong) crc32(0L, (uchar*)res->ptr(), res->length()); +} + #ifdef HAVE_COMPRESS #include "zlib.h" @@ -2581,7 +2560,7 @@ String *Item_func_compress::val_str(String *str) buffer.realloc((uint32)new_size + 4 + 1); Byte *body= ((Byte*)buffer.c_ptr()) + 4; - + if ((err= compress(body, &new_size, (const Bytef*)res->c_ptr(), res->length())) != Z_OK) { @@ -2603,7 +2582,7 @@ String *Item_func_compress::val_str(String *str) } buffer.length((uint32)new_size + 4); - + return &buffer; } @@ -2615,7 +2594,7 @@ String *Item_func_uncompress::val_str(String *str) ulong new_size= uint4korr(res->c_ptr()) & 0x3FFFFFFF; int err= Z_OK; uint code; - + if (new_size > MAX_BLOB_WIDTH) { push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, @@ -2624,21 +2603,20 @@ String *Item_func_uncompress::val_str(String *str) null_value= 0; return 0; } - + buffer.realloc((uint32)new_size); - - if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size, + + if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size, ((const Bytef*)res->c_ptr())+4,res->length())) == Z_OK) { buffer.length((uint32)new_size); return &buffer; } - - code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR : + + code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR : err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR; push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); null_value= 1; return 0; } - #endif diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index f64a145b136..b82dacb4fe0 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -254,30 +254,45 @@ public: }; +/* + Item_func_password -- new (4.1.1) PASSWORD() function implementation. + Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new + password format, sha1(sha1(password) is so-called hash_stage2 value. + Length of returned string is always 41 byte. To find out how entire + authentification procedure works, see comments in password.c. +*/ + class Item_func_password :public Item_str_func { - char tmp_value[64]; /* This should be enough for new password format */ + char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; public: Item_func_password(Item *a) :Item_str_func(a) {} - Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {} - String *val_str(String *); - void fix_length_and_dec(); + String *val_str(String *str); + void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } const char *func_name() const { return "password"; } + static char *alloc(THD *thd, const char *password); }; +/* + Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0 + compatibility mode. This item is created in sql_yacc.yy when + 'old_passwords' session variable is set, and to handle OLD_PASSWORD() + function. +*/ + class Item_func_old_password :public Item_str_func { - char tmp_value[17]; /* old password length +1 */ + char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1]; public: Item_func_old_password(Item *a) :Item_str_func(a) {} - String *val_str(String *); - void fix_length_and_dec() { max_length = get_password_length(1); } + String *val_str(String *str); + void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } const char *func_name() const { return "old_password"; } + static char *alloc(THD *thd, const char *password); }; - class Item_func_des_encrypt :public Item_str_func { String tmp_value; @@ -624,9 +639,56 @@ public: Item_func_collation(Item *a) :Item_str_func(a) {} String *val_str(String *); const char *func_name() const { return "collation"; } - void fix_length_and_dec() + void fix_length_and_dec() { max_length=40; // should be enough collation.set(system_charset_info); }; }; + +class Item_func_crc32 :public Item_int_func +{ + String value; +public: + Item_func_crc32(Item *a) :Item_int_func(a) {} + const char *func_name() const { return "crc32"; } + void fix_length_and_dec() { max_length=10; } + longlong val_int(); +}; + +class Item_func_uncompressed_length : public Item_int_func +{ + String value; +public: + Item_func_uncompressed_length(Item *a):Item_int_func(a){} + const char *func_name() const{return "uncompressed_length";} + void fix_length_and_dec() { max_length=10; } + longlong val_int(); +}; + +#ifdef HAVE_COMPRESS +#define ZLIB_DEPENDED_FUNCTION ; +#else +#define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; } +#endif + +class Item_func_compress: public Item_str_func +{ + String buffer; +public: + Item_func_compress(Item *a):Item_str_func(a){} + void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} + const char *func_name() const{return "compress";} + String *val_str(String *) ZLIB_DEPENDED_FUNCTION +}; + +class Item_func_uncompress: public Item_str_func +{ + String buffer; +public: + Item_func_uncompress(Item *a): Item_str_func(a){} + void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} + const char *func_name() const{return "uncompress";} + String *val_str(String *) ZLIB_DEPENDED_FUNCTION +}; + diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index cbda995504c..79366086a8d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -72,7 +72,7 @@ Item_subselect::trans_res Item_subselect::select_transformer(JOIN *join) { DBUG_ENTER("Item_subselect::select_transformer"); - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } @@ -214,14 +214,14 @@ Item_singlerow_subselect::select_transformer(JOIN *join) cond= join->having; else if (!(cond= new Item_cond_and(join->conds, join->having))) - return ERROR; + return RES_ERROR; if (!(substitution= new Item_func_if(cond, substitution, new Item_null()))) - return ERROR; + return RES_ERROR; } - return REDUCE; + return RES_REDUCE; } - return OK; + return RES_OK; } void Item_singlerow_subselect::store(uint i, Item *item) @@ -508,7 +508,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { thd->lex.current_select= current; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } thd->lex.current_select= current; @@ -528,7 +528,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (select_lex->item_list.elements > 1) { my_error(ER_CARDINALITY_COL, MYF(0), 1); - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } item= (Item*) select_lex->item_list.head(); @@ -546,7 +546,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -570,7 +570,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; item= new Item_cond_or(item, @@ -578,7 +578,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, } join->conds= and_items(join->conds, item); if (join->conds->fix_fields(thd, join->tables_list, &join->conds)) - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } else { @@ -592,7 +592,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -610,11 +610,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SELECT_REDUCED, warn_buff); } - DBUG_RETURN(REDUCE); + DBUG_RETURN(RES_REDUCE); } } } - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } Item_subselect::trans_res @@ -640,7 +640,7 @@ Item_in_subselect::row_value_transformer(JOIN *join, if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { thd->lex.current_select= current; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } thd->lex.current_select= current; @@ -679,7 +679,7 @@ Item_in_subselect::row_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -687,9 +687,9 @@ Item_in_subselect::row_value_transformer(JOIN *join, { join->conds= and_items(join->conds, item); if (join->conds->fix_fields(thd, join->tables_list, &join->having)) - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } Item_subselect::trans_res @@ -846,7 +846,7 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) SELECT_LEX *sl= unit->first_select(); bool fake= 0; res_type= set_row(sl, item, row, &fake); - for (sl= sl->next_select(); sl; sl->next_select()) + for (sl= sl->next_select(); sl; sl= sl->next_select()) { List_iterator_fast<Item> li(sl->item_list); Item *sel_item; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ddb53ab616a..174e8809688 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -51,7 +51,7 @@ public: /* changed engine indicator */ bool engine_changed; - enum trans_res {OK, REDUCE, ERROR}; + enum trans_res {RES_OK, RES_REDUCE, RES_ERROR}; enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, EXISTS_SUBS, IN_SUBS, ALLANY_SUBS}; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0d05d05f0af..814612cfca8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -223,10 +223,9 @@ Item *Item_sum_sum::copy_or_same(THD* thd) } -bool Item_sum_sum::reset() +void Item_sum_sum::clear() { null_value=1; sum=0.0; - return Item_sum_sum::add(); } @@ -251,10 +250,9 @@ Item *Item_sum_count::copy_or_same(THD* thd) } -bool Item_sum_count::reset() +void Item_sum_count::clear() { - count=0; - return add(); + count= 0; } @@ -286,10 +284,9 @@ Item *Item_sum_avg::copy_or_same(THD* thd) } -bool Item_sum_avg::reset() +void Item_sum_avg::clear() { sum=0.0; count=0; - return Item_sum_avg::add(); } @@ -342,11 +339,10 @@ Item *Item_sum_variance::copy_or_same(THD* thd) } -bool Item_sum_variance::reset() +void Item_sum_variance::clear() { sum=sum_sqr=0.0; count=0; - return Item_sum_variance::add(); } bool Item_sum_variance::add() @@ -592,10 +588,9 @@ longlong Item_sum_bit::val_int() } -bool Item_sum_bit::reset() +void Item_sum_bit::clear() { - bits=reset_bits; - return add(); + bits= reset_bits; } Item *Item_sum_or::copy_or_same(THD* thd) @@ -1280,7 +1275,7 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd) } -bool Item_sum_count_distinct::reset() +void Item_sum_count_distinct::clear() { if (use_tree) reset_tree(tree); @@ -1290,7 +1285,6 @@ bool Item_sum_count_distinct::reset() table->file->delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); } - return add(); } bool Item_sum_count_distinct::add() @@ -1353,11 +1347,11 @@ longlong Item_sum_count_distinct::val_int() #ifdef HAVE_DLOPEN -bool Item_udf_sum::reset() +void Item_udf_sum::clear() { - DBUG_ENTER("Item_udf_sum::reset"); - udf.reset(&null_value); - DBUG_RETURN(0); + DBUG_ENTER("Item_udf_sum::clear"); + udf.clear(); + DBUG_VOID_RETURN; } bool Item_udf_sum::add() @@ -1466,7 +1460,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1, for (uint i= 0; i < item->arg_count_field; i++) { Item *field_item= item->args[i]; - Field *field= field_item->tmp_table_field(); + Field *field= field_item->real_item()->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1497,7 +1491,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2) { ORDER *order_item= item->order[i]; Item *item= *order_item->item; - Field *field= item->tmp_table_field(); + Field *field= item->real_item()->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1548,7 +1542,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), Item *show_item= group_concat_item->args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->real_item()->get_tmp_table_field(); char *sv= f->ptr; f->ptr= (char *)key + f->abs_offset; String *res= f->val_str(&tmp,&tmp2); @@ -1685,7 +1679,7 @@ Item *Item_func_group_concat::copy_or_same(THD* thd) } -bool Item_func_group_concat::reset() +void Item_func_group_concat::clear() { result.length(0); result.copy(); @@ -1699,7 +1693,6 @@ bool Item_func_group_concat::reset() } if (tree_mode) reset_tree(tree); - return add(); } @@ -1716,7 +1709,7 @@ bool Item_func_group_concat::add() Item *show_item= args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->real_item()->get_tmp_table_field(); if (!f->is_null()) { record_is_null= FALSE; diff --git a/sql/item_sum.h b/sql/item_sum.h index ebb90c05215..b2377a96833 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -62,7 +62,8 @@ public: enum Type type() const { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; - virtual bool reset()=0; + inline bool reset() { clear(); return add(); }; + virtual void clear()= 0; virtual bool add()=0; virtual void reset_field()=0; virtual void update_field(int offset)=0; @@ -124,7 +125,7 @@ class Item_sum_sum :public Item_sum_num Item_sum_sum(THD *thd, Item_sum_sum &item) :Item_sum_num(thd, item), sum(item.sum) {} enum Sumfunctype sum_func () const {return SUM_FUNC;} - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -151,7 +152,7 @@ class Item_sum_count :public Item_sum_int table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_FUNC; } - bool reset(); + void clear(); void no_rows_in_result() { count=0; } bool add(); void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; } @@ -225,7 +226,7 @@ class Item_sum_count_distinct :public Item_sum_int table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } - bool reset(); + void clear(); bool add(); longlong val_int(); void reset_field() { return ;} // Never called @@ -269,7 +270,7 @@ class Item_sum_avg :public Item_sum_num Item_sum_avg(THD *thd, Item_sum_avg &item) :Item_sum_num(thd, item), sum(item.sum), count(item.count) {} enum Sumfunctype sum_func () const {return AVG_FUNC;} - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -322,7 +323,7 @@ class Item_sum_variance : public Item_sum_num Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr), count(item.count) {} enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -385,19 +386,18 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(THD *thd, Item_sum_hybrid &item): Item_sum(thd, item), value(item.value), tmp_value(item.tmp_value), sum(item.sum), sum_int(item.sum_int), hybrid_type(item.hybrid_type), - cmp_sign(item.cmp_sign), used_table_cache(used_table_cache), - cmp_charset(item.cmp_charset) {} + hybrid_field_type(item.hybrid_field_type),cmp_sign(item.cmp_sign), + used_table_cache(used_table_cache), cmp_charset(item.cmp_charset) {} bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } - bool reset() + void clear() { sum=0.0; sum_int=0; value.length(0); null_value=1; - return add(); } double val(); longlong val_int(); @@ -451,7 +451,7 @@ class Item_sum_bit :public Item_sum_int Item_sum_bit(THD *thd, Item_sum_bit &item): Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {} enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} - bool reset(); + void clear(); longlong val_int(); void reset_field(); void fix_length_and_dec() @@ -509,7 +509,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } - bool reset(); + void clear(); bool add(); void reset_field() {}; void update_field(int offset_arg) {}; @@ -591,7 +591,7 @@ class Item_sum_udf_float :public Item_sum_num ~Item_sum_udf_float() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val() { return 0.0; } - bool reset() { return 0; } + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -608,7 +608,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { return 0; } double val() { return 0; } - bool reset() { return 0; } + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -628,7 +628,7 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { maybe_null=1; max_length=0; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - bool reset() { return 0; } + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -714,7 +714,7 @@ class Item_func_group_concat : public Item_sum const char *func_name() const { return "group_concat"; } enum Type type() const { return SUM_FUNC_ITEM; } virtual Item_result result_type () const { return STRING_RESULT; } - bool reset(); + void clear(); bool add(); void reset_field(); bool fix_fields(THD *, TABLE_LIST *, Item **); @@ -733,4 +733,5 @@ class Item_func_group_concat : public Item_sum } String* val_str(String* str); Item *copy_or_same(THD* thd); + void no_rows_in_result() {} }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index d84267a5066..6dcf7d00ce1 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -327,7 +327,6 @@ public: max_length=10*default_charset()->mbmaxlen; } int save_in_field(Field *to, bool no_conversions); - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, default_charset())); @@ -342,7 +341,6 @@ public: Item_date_func(Item *a) :Item_str_func(a) {} Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {} enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_datetime(maybe_null, name, t_arg, default_charset())); @@ -366,7 +364,6 @@ public: longlong val_int() { return value; } String *val_str(String *str); void fix_length_and_dec(); - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -533,7 +530,6 @@ public: } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -634,7 +630,6 @@ public: bool get_date(TIME *ltime, bool fuzzy_date); const char *func_name() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, default_charset())); @@ -650,7 +645,6 @@ public: bool get_time(TIME *ltime); const char *func_name() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -665,7 +659,6 @@ public: String *val_str(String *str); const char *func_name() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_datetime(maybe_null, name, t_arg, default_charset())); @@ -684,7 +677,6 @@ public: decimals=0; max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); @@ -711,7 +703,6 @@ public: Change this when we support microseconds in TIME/DATETIME */ - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { if (cached_field_type == MYSQL_TYPE_TIME) @@ -735,7 +726,6 @@ public: decimals=0; max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); @@ -755,7 +745,6 @@ public: decimals=0; max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index f2c64c4bde9..e41397dac44 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -41,7 +41,7 @@ public: :Item_sum_num(thd, item) {} double val() { return 0.0; } enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;} - bool reset() { return 0;} + void clear() {} bool add() { return 0; } void reset_field() {} void update_field(int offset) {} diff --git a/sql/lex.h b/sql/lex.h index 24bfe796cc0..aa6d96d4029 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -249,6 +249,12 @@ static SYMBOL symbols[] = { { "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0}, { "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0}, { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0}, + { "MASTER_SSL", SYM(MASTER_SSL_SYM),0,0}, + { "MASTER_SSL_CA", SYM(MASTER_SSL_CA_SYM),0,0}, + { "MASTER_SSL_CAPATH",SYM(MASTER_SSL_CAPATH_SYM),0,0}, + { "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM),0,0}, + { "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM),0,0}, + { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM),0,0}, { "MASTER_USER", SYM(MASTER_USER_SYM),0,0}, { "MAX_ROWS", SYM(MAX_ROWS),0,0}, { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR), 0,0}, @@ -288,6 +294,7 @@ static SYMBOL symbols[] = { { "NULL", SYM(NULL_SYM),0,0}, { "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "OFFSET", SYM(OFFSET_SYM),0,0}, + { "OLD_PASSWORD", SYM(OLD_PASSWORD),0,0}, { "ON", SYM(ON),0,0}, { "OPEN", SYM(OPEN_SYM),0,0}, { "OPTIMIZE", SYM(OPTIMIZE),0,0}, @@ -473,9 +480,7 @@ static SYMBOL sql_functions[] = { { "COUNT", SYM(COUNT_SYM),0,0}, { "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)}, { "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)}, -#ifdef HAVE_COMPRESS { "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)}, -#endif { "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)}, { "CURDATE", SYM(CURDATE),0,0}, { "CURTIME", SYM(CURTIME),0,0}, @@ -590,7 +595,6 @@ static SYMBOL sql_functions[] = { { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)}, { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)}, { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, - { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)}, { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a5d9ce5bce3..ea5dc909f74 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -74,9 +74,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; ****************************************************************************/ #define ACL_CACHE_SIZE 256 -/* Password lengh for 4.1 version previous versions had 16 bytes password hash */ -#define HASH_PASSWORD_LENGTH 45 -#define HASH_OLD_PASSWORD_LENGTH 16 #define MAX_PASSWORD_LENGTH 32 #define HOST_CACHE_SIZE 128 #define MAX_ACCEPT_RETRY 10 // Test accept this many times @@ -411,6 +408,8 @@ bool check_global_access(THD *thd, ulong want_access); int mysql_backup_table(THD* thd, TABLE_LIST* table_list); int mysql_restore_table(THD* thd, TABLE_LIST* table_list); +int mysql_checksum_table(THD* thd, TABLE_LIST* table_list, + HA_CHECK_OPT* check_opt); int mysql_check_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); int mysql_repair_table(THD* thd, TABLE_LIST* table_list, @@ -771,7 +770,7 @@ extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern my_bool opt_readonly; extern my_bool opt_enable_named_pipe; -extern my_bool opt_old_passwords, use_old_passwords; +extern my_bool opt_secure_auth; extern char *shared_memory_base_name, *mysqld_unix_port; extern bool opt_enable_shared_memory; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 41bd9706fc3..45c1fdc82d1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -257,9 +257,10 @@ my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool lower_case_table_names, opt_old_rpl_compat; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; -my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0; +my_bool opt_log_slave_updates= 0; my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam; my_bool opt_readonly, use_temp_pool, relay_log_purge; +my_bool opt_secure_auth= 0; volatile bool mqh_used = 0; uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; @@ -362,15 +363,15 @@ pthread_t signal_thread; pthread_attr_t connection_attrib; /* replication parameters, if master_host is not NULL, we are a slave */ -my_bool master_ssl; uint master_port= MYSQL_PORT, master_connect_retry = 60; uint report_port= MYSQL_PORT; ulong master_retry_count=0; char *master_user, *master_password, *master_host, *master_info_file; -char *relay_log_info_file, *master_ssl_key, *master_ssl_cert; -char *master_ssl_capath, *master_ssl_cipher, *report_user; -char *report_password, *report_host; +char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; +my_bool master_ssl; +char *master_ssl_key, *master_ssl_cert; +char *master_ssl_ca, *master_ssl_capath, *master_ssl_cipher; /* Static variables */ @@ -2819,12 +2820,6 @@ static void create_new_thread(THD *thd) if (thread_count-delayed_insert_threads > max_used_connections) max_used_connections=thread_count-delayed_insert_threads; thd->thread_id=thread_id++; - for (uint i=0; i < 8 ; i++) // Generate password teststring - thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33); - thd->scramble[8]=0; - // Back it up as old clients may need it - memcpy(thd->old_scramble,thd->scramble,9); - thd->real_id=pthread_self(); // Keep purify happy @@ -3445,7 +3440,7 @@ enum options OPT_MASTER_RETRY_COUNT, OPT_MASTER_SSL, OPT_MASTER_SSL_KEY, OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH, - OPT_MASTER_SSL_CIPHER, + OPT_MASTER_SSL_CIPHER, OPT_MASTER_SSL_CA, OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB, OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES, OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB, @@ -3535,7 +3530,8 @@ enum options OPT_EXPIRE_LOGS_DAYS, OPT_DEFAULT_WEEK_FORMAT, OPT_GROUP_CONCAT_MAX_LEN, - OPT_DEFAULT_COLLATION + OPT_DEFAULT_COLLATION, + OPT_SECURE_AUTH }; @@ -3783,27 +3779,28 @@ thread is in the master's binlogs.", (gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl", OPT_MASTER_SSL, - "Planned to enable the slave to connect to the master using SSL. Does nothing yet.", + "Enable the slave to connect to the master using SSL.", (gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-key", OPT_MASTER_SSL_KEY, - "Master SSL keyfile name. Only applies if you have enabled master-ssl. Does \ -nothing yet.", + "Master SSL keyfile name. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, "Master SSL certificate file name. Only applies if you have enabled \ -master-ssl. Does nothing yet.", +master-ssl", (gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"master-ssl-ca", OPT_MASTER_SSL_CA, + "Master SSL CA file. Only applies if you have enabled master-ssl.", + (gptr*) &master_ssl_ca, (gptr*) &master_ssl_ca, 0, GET_STR, OPT_ARG, + 0, 0, 0, 0, 0, 0}, {"master-ssl-capath", OPT_MASTER_SSL_CAPATH, - "Master SSL CA path. Only applies if you have enabled master-ssl. \ -Does nothing yet.", + "Master SSL CA path. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, - "Master SSL cipher. Only applies if you have enabled master-ssl. \ -Does nothing yet.", + "Master SSL cipher. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"myisam-recover", OPT_MYISAM_RECOVER, @@ -3844,9 +3841,10 @@ Does nothing yet.", (gptr*) &opt_no_mix_types, (gptr*) &opt_no_mix_types, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"old-protocol", 'o', "Use the old (3.20) protocol client/server protocol.", - (gptr*) &protocol_version, (gptr*) &protocol_version, 0, GET_UINT, NO_ARG, - PROTOCOL_VERSION, 0, 0, 0, 0, 0}, + {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).", + (gptr*) &global_system_variables.old_passwords, + (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"old-rpl-compat", OPT_OLD_RPL_COMPAT, "Use old LOAD DATA format in the binary log (don't save data in file).", (gptr*) &opt_old_rpl_compat, (gptr*) &opt_old_rpl_compat, 0, GET_BOOL, @@ -3913,8 +3911,6 @@ relay logs.", GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).", - (gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_DELETED {"safe-show-database", OPT_SAFE_SHOW_DB, "Deprecated option; One should use GRANT SHOW DATABASES instead...", @@ -3924,6 +3920,9 @@ relay logs.", "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", (gptr*) &opt_safe_user_create, (gptr*) &opt_safe_user_create, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.", + (gptr*) &opt_secure_auth, (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, + my_bool(0), 0, 0, 0, 0, 0}, {"server-id", OPT_SERVER_ID, "Uniquely identifies the server instance in the community of replication partners.", (gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, @@ -4452,14 +4451,15 @@ struct show_var_st status_vars[]= { {"Bytes_received", (char*) &bytes_received, SHOW_LONG}, {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG}, {"Com_admin_commands", (char*) &com_other, SHOW_LONG}, - {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG}, {"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG}, + {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG}, {"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG}, {"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG}, {"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG}, {"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG}, {"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG}, {"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG}, + {"Com_checksum", (char*) (com_stat+(uint) SQLCOM_CHECKSUM),SHOW_LONG}, {"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG}, {"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG}, {"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG}, @@ -4472,6 +4472,7 @@ struct show_var_st status_vars[]= { {"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG}, {"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG}, {"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG}, + {"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG}, {"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG}, {"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG}, {"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG}, @@ -4486,6 +4487,7 @@ struct show_var_st status_vars[]= { {"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG}, {"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG}, {"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG}, + {"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG}, {"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG}, {"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG}, {"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG}, @@ -4495,13 +4497,15 @@ struct show_var_st status_vars[]= { {"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG}, {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG}, {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG}, + {"Com_revoke_all", (char*) (com_stat+(uint) SQLCOM_REVOKE_ALL),SHOW_LONG}, {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG}, {"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG}, {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG}, {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG}, - {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG}, {"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG}, + {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG}, {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG}, + {"Com_show_collations", (char*) (com_stat+(uint) SQLCOM_SHOW_COLLATIONS),SHOW_LONG}, {"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG}, {"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG}, {"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG}, @@ -4509,6 +4513,7 @@ struct show_var_st status_vars[]= { {"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG}, {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG}, {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG}, + {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG}, {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG}, {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG}, @@ -4519,7 +4524,6 @@ struct show_var_st status_vars[]= { {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG}, {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG}, {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG}, - {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG}, {"Com_show_table_types", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLE_TYPES),SHOW_LONG}, {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG}, @@ -4708,7 +4712,8 @@ static void mysql_init_variables(void) opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0; opt_disable_networking= opt_skip_show_db=0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0; - opt_bootstrap= opt_myisam_log= use_old_passwords= 0; + opt_secure_auth= 0; + opt_bootstrap= opt_myisam_log= 0; mqh_used= 0; segfaulted= kill_in_progress= 0; cleanup_done= 0; @@ -4787,8 +4792,9 @@ static void mysql_init_variables(void) master_user= (char*) "test"; master_password= master_host= 0; master_info_file= (char*) "master.info", - relay_log_info_file= (char*) "relay-log.info", - master_ssl_key= master_ssl_cert= master_ssl_capath= master_ssl_cipher= 0; + relay_log_info_file= (char*) "relay-log.info"; + master_ssl_key= master_ssl_cert= master_ssl_ca= + master_ssl_capath= master_ssl_cipher= 0; report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; @@ -4811,6 +4817,7 @@ static void mysql_init_variables(void) max_system_variables.select_limit= (ulonglong) HA_POS_ERROR; global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + global_system_variables.old_passwords= 0; /* Variables that depends on compile options */ #ifndef DBUG_OFF @@ -4932,9 +4939,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'L': strmake(language, argument, sizeof(language)-1); break; - case 'o': - protocol_version=PROTOCOL_VERSION-1; - break; #ifdef HAVE_REPLICATION case OPT_SLAVE_SKIP_ERRORS: init_slave_skip_errors(argument); diff --git a/sql/password.c b/sql/password.c index 257547671e5..9f4910d8c60 100644 --- a/sql/password.c +++ b/sql/password.c @@ -29,28 +29,33 @@ The password is saved (in user.password) by using the PASSWORD() function in mysql. + This is .c file because it's used in libmysqlclient, which is entirely in C. + (we need it to be portable to a variety of systems). Example: update user set password=PASSWORD("hello") where user="test" This saves a hashed number as a string in the password field. + The new autentication is performed in following manner: - New in MySQL 4.1 authentication works even more secure way. - At the first step client sends user name to the sever, and password if - it is empty. So in case of empty password authentication is as fast as before. - At the second stap servers sends scramble to client, which is encoded with - password stage2 hash stored in the password database as well as salt, needed - for client to build stage2 password to decrypt scramble. - Client decrypts the scramble and encrypts it once again with stage1 password. - This information is sent to server. - Server decrypts the scramble to get stage1 password and hashes it to get - stage2 hash. This hash is when compared to hash stored in the database. + SERVER: public_seed=create_random_string() + send(public_seed) - This authentication needs 2 packet round trips instead of one but it is much - stronger. Now if one will steal mysql database content he will not be able - to break into MySQL. + CLIENT: recv(public_seed) + hash_stage1=sha1("password") + hash_stage2=sha1(hash_stage1) + reply=xor(hash_stage1, sha1(public_seed,hash_stage2) - New Password handling functions by Peter Zaitsev + // this three steps are done in scramble() + send(reply) + + + SERVER: recv(reply) + hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) + candidate_hash2=sha1(hash_stage1) + check(candidate_hash2==hash_stage2) + + // this three steps are done in check_scramble() *****************************************************************************/ @@ -60,31 +65,21 @@ #include <sha1.h> #include "mysql.h" - - -/* Character to use as version identifier for version 4.1 */ -#define PVERSION41_CHAR '*' - -/* Scramble length for new password version */ - +/************ MySQL 3.23-4.0 authentification routines: untouched ***********/ /* New (MySQL 3.21+) random generation structure initialization - SYNOPSIS randominit() rand_st OUT Structure to initialize seed1 IN First initialization parameter seed2 IN Second initialization parameter - - RETURN - none */ -void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) -{ /* For mysql 3.21.# */ +void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) +{ /* For mysql 3.21.# */ #ifdef HAVE_purify - bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ + bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ #endif rand_st->max_value= 0x3FFFFFFFL; rand_st->max_value_dbl=(double) rand_st->max_value; @@ -94,35 +89,12 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) /* - Old (MySQL 3.20) random generation structure initialization - - SYNOPSIS - old_randominit() - rand_st OUT Structure to initialize - seed1 IN First initialization parameter - - RETURN - none -*/ - -static void old_randominit(struct rand_struct *rand_st,ulong seed1) -{ /* For mysql 3.20.# */ - rand_st->max_value= 0x01FFFFFFL; - rand_st->max_value_dbl=(double) rand_st->max_value; - seed1%=rand_st->max_value; - rand_st->seed1=seed1 ; rand_st->seed2=seed1/2; -} - - -/* - Generate Random number - + Generate random number. SYNOPSIS my_rnd() rand_st INOUT Structure used for number generation - - RETURN - Generated pseudo random number + RETURN VALUE + generated pseudo random number */ double my_rnd(struct rand_struct *rand_st) @@ -134,73 +106,24 @@ double my_rnd(struct rand_struct *rand_st) /* - Generate String of printable random characters of requested length - String will not be zero terminated. - + Generate binary hash from raw text string + Used for Pre-4.1 password handling SYNOPSIS - create_random_string() - length IN Lenght of - rand_st INOUT Structure used for number generation - target OUT Buffer for generation - - RETURN - none + hash_password() + result OUT store hash in this location + password IN plain text password to build hash + password_len IN password length (password may be not null-terminated) */ -void create_random_string(int length,struct rand_struct *rand_st,char *target) -{ - char *end=target+length; - /* Use pointer arithmetics as it is faster way to do so. */ - for (; target<end ; target++) - *target= (char) (my_rnd(rand_st)*94+33); -} - - -/* - Encrypt/Decrypt function used for password encryption in authentication - Simple XOR is used here but it is OK as we crypt random strings - - SYNOPSIS - password_crypt() - from IN Data for encryption - to OUT Encrypt data to the buffer (may be the same) - password IN Password used for encryption (same length) - length IN Length of data to encrypt - - RETURN - none -*/ - -void password_crypt(const char *from,char *to, const char *password,int length) -{ - const char *from_end=from+length; - - while (from < from_end) - *to++= *(from++) ^* (password++); -} - - -/* - Generate binary hash from raw text password - Used for Pre-4.1 Password handling - - SYNOPSIS - hash_pasword() - result OUT Store hash in this location - password IN Plain text password to build hash - - RETURN - none -*/ - -void hash_password(ulong *result, const char *password) +void hash_password(ulong *result, const char *password, uint password_len) { register ulong nr=1345345333L, add=7, nr2=0x12345671L; ulong tmp; - for (; *password ; password++) + const char *password_end= password + password_len; + for (; password < password_end; password++) { if (*password == ' ' || *password == '\t') - continue; /* skipp space in password */ + continue; /* skip space in password */ tmp= (ulong) (uchar) *password; nr^= (((nr & 63)+add)*tmp)+ (nr << 8); nr2+=(nr2 << 8) ^ nr; @@ -208,519 +131,388 @@ void hash_password(ulong *result, const char *password) } result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */; result[1]=nr2 & (((ulong) 1L << 31) -1L); - return; } /* - Stage one password hashing. - Used in MySQL 4.1 password handling - + Create password to be stored in user database from raw string + Used for pre-4.1 password handling SYNOPSIS - password_hash_stage1() - to OUT Store stage one hash to this location - password IN Plain text password to build hash - - RETURN - none + make_scrambled_password_323() + to OUT store scrambled password here + password IN user-supplied password */ -void password_hash_stage1(char *to, const char *password) +void make_scrambled_password_323(char *to, const char *password) { - SHA1_CONTEXT context; - sha1_reset(&context); - for (; *password ; password++) - { - if (*password == ' ' || *password == '\t') - continue;/* skip space in password */ - sha1_input(&context,(uint8*) &password[0],1); - } - sha1_result(&context,(uint8*)to); + ulong hash_res[2]; + hash_password(hash_res, password, strlen(password)); + sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]); } /* - Stage two password hashing. - Used in MySQL 4.1 password handling - + Scramble string with password. + Used in pre 4.1 authentication phase. SYNOPSIS - password_hash_stage2() - to INOUT Use this as stage one hash and store stage two hash here - salt IN Salt used for stage two hashing - - RETURN - none + scramble_323() + to OUT Store scrambled message here. Buffer must be at least + SCRAMBLE_LENGTH_323+1 bytes long + message IN Message to scramble. Message must be at least + SRAMBLE_LENGTH_323 bytes long. + password IN Password to use while scrambling */ -void password_hash_stage2(char *to, const char *salt) +void scramble_323(char *to, const char *message, const char *password) { - SHA1_CONTEXT context; - sha1_reset(&context); - sha1_input(&context,(uint8*) salt, 4); - sha1_input(&context,(uint8*) to, SHA1_HASH_SIZE); - sha1_result(&context,(uint8*) to); + struct rand_struct rand_st; + ulong hash_pass[2], hash_message[2]; + + if (password && password[0]) + { + char extra, *to_start=to; + const char *message_end= message + SCRAMBLE_LENGTH_323; + hash_password(hash_pass,password, strlen(password)); + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); + for (; message < message_end; message++) + *to++= (char) (floor(my_rnd(&rand_st)*31)+64); + extra=(char) (floor(my_rnd(&rand_st)*31)); + while (to_start != to) + *(to_start++)^=extra; + } + *to= 0; } /* - Create password to be stored in user database from raw string - Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords - + Check scrambled message + Used in pre 4.1 password handling SYNOPSIS - make_scramble_password() - to OUT Store scrambled password here - password IN Raw string password - force_old_scramle - IN Force generation of old scramble variant - rand_st INOUT Structure for temporary number generation. - RETURN - none + check_scramble_323() + scrambled scrambled message to check. + message original random message which was used for scrambling; must + be exactly SCRAMBLED_LENGTH_323 bytes long and + NULL-terminated. + hash_pass password which should be used for scrambling + All params are IN. + + RETURN VALUE + 0 - password correct + !0 - password invalid */ -void make_scrambled_password(char *to,const char *password, - my_bool force_old_scramble, - struct rand_struct *rand_st) +my_bool +check_scramble_323(const char *scrambled, const char *message, + ulong *hash_pass) { - ulong hash_res[2]; /* Used for pre 4.1 password hashing */ - unsigned short salt; /* Salt for 4.1 version password */ - uint8 digest[SHA1_HASH_SIZE]; - if (force_old_scramble) /* Pre 4.1 password encryption */ - { - hash_password(hash_res,password); - sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); - } - else /* New password 4.1 password scrambling */ + struct rand_struct rand_st; + ulong hash_message[2]; + char buff[16],*to,extra; /* Big enough for check */ + const char *pos; + + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); + to=buff; + for (pos=scrambled ; *pos ; pos++) + *to++=(char) (floor(my_rnd(&rand_st)*31)+64); + extra=(char) (floor(my_rnd(&rand_st)*31)); + to=buff; + while (*scrambled) { - to[0]=PVERSION41_CHAR; /* New passwords have version prefix */ - /* Rnd returns number from 0 to 1 so this would be good salt generation.*/ - salt=(unsigned short) (my_rnd(rand_st)*65535+1); - /* Use only 2 first bytes from it */ - sprintf(to+1,"%04x",salt); - /* First hasing is done without salt */ - password_hash_stage1((char*) digest, password); - /* Second stage is done with salt */ - password_hash_stage2((char*) digest,(char*)to+1), - /* Print resulting hash into the password*/ - sprintf(to+5, - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6], - digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13], - digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]); + if (*scrambled++ != (char) (*to++ ^ extra)) + return 1; /* Wrong password */ } + return 0; } +static inline uint8 char_val(uint8 X) +{ + return (uint) (X >= '0' && X <= '9' ? X-'0' : + X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10); +} -/* - Convert password from binary string form to salt form - Used for MySQL 4.1 password handling +/* + Convert password from hex string (as stored in mysql.user) to binary form. SYNOPSIS - get_salt_from_bin_password() - res OUT Store salt form password here - password IN Binary password to be converted - salt IN hashing-salt to be used for salt form generation - - RETURN - none + get_salt_from_password_323() + res OUT store salt here + password IN password string as stored in mysql.user + NOTE + This function does not have length check for passwords. It will just crash + Password hashes in old format must have length divisible by 8 */ -void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt) +void get_salt_from_password_323(ulong *res, const char *password) { - unsigned char *password_end=password+SCRAMBLE41_LENGTH; - *res=salt; - res++; - - /* Process password of known length*/ - while (password<password_end) + res[0]= res[1]= 0; + if (password) { - ulong val=0; - uint i; - for (i=0 ; i < 4 ; i++) - val=(val << 8)+(*password++); - *res++=val; + while (*password) + { + ulong val=0; + uint i; + for (i=0 ; i < 8 ; i++) + val=(val << 4)+char_val(*password++); + *res++=val; + } } } /* - Validate password for MySQL 4.1 password handling. - + Convert scrambled password from binary form to asciiz hex string. SYNOPSIS - validate_password() - password IN Encrypted Scramble which we got from the client - message IN Original scramble which we have sent to the client before - salt IN Password in the salted form to match to - - RETURN - 0 for correct password - !0 for invalid password + make_password_from_salt_323() + to OUT store resulting string password here, at least 17 bytes + salt IN password in salt format, 2 ulongs */ -my_bool validate_password(const char *password, const char *message, - ulong *salt) +void make_password_from_salt_323(char *to, const ulong *salt) { - char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */ - char tmpsalt[8]; /* Temporary value to convert salt to string form */ - ulong salt_candidate[6]; /* Computed candidate salt */ - ulong *sc=salt_candidate; /* we need to be able to increment */ - ulong *salt_end; - - /* Now we shall get stage1 encrypted password in buffer*/ - password_crypt(password,buffer,message,SCRAMBLE41_LENGTH); - - /* For compatibility reasons we use ulong to store salt while we need char */ - sprintf(tmpsalt,"%04x",(unsigned short)salt[0]); - - password_hash_stage2(buffer,tmpsalt); - /* Convert password to salt to compare */ - get_salt_from_bin_password(salt_candidate,(uchar*) buffer,salt[0]); - - /* Now we shall get exactly the same password as we have stored for user */ - for (salt_end=salt+5 ; salt < salt_end; ) - if (*++salt != *++sc) - return 1; - - /* Or password correct*/ - return 0; + sprintf(to,"%08lx%08lx", salt[0], salt[1]); } /* - Get length of password string which is stored in mysql.user table + **************** MySQL 4.1.1 authentification routines ************* +*/ +/* + Generate string of printable random characters of requested length SYNOPSIS - get_password_length() - force_old_scramble IN If we wish to use pre 4.1 scramble format - - RETURN - password length >0 + create_random_string() + to OUT buffer for generation; must be at least length+1 bytes + long; result string is always null-terminated + length IN how many random characters to put in buffer + rand_st INOUT structure used for number generation */ -int get_password_length(my_bool force_old_scramble) +void create_random_string(char *to, uint length, struct rand_struct *rand_st) { - return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1; + char *end= to + length; + /* Use pointer arithmetics as it is faster way to do so. */ + for (; to < end; to++) + *to= (char) (my_rnd(rand_st)*94+33); + *to= '\0'; } -/* - Get version of the password based on mysql.user password string - - SYNOPSIS - get_password_version() - password IN Password string as stored in mysql.user - - RETURN - 0 for pre 4.1 passwords - !0 password version char for newer passwords -*/ +/* Character to use as version identifier for version 4.1 */ -char get_password_version(const char *password) -{ - if (password==NULL) return 0; - if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR; - return 0; -} +#define PVERSION41_CHAR '*' /* - Get integer value of Hex character - + Convert given octet sequence to asciiz string of hex characters; + str..str+len and 'to' may not overlap. SYNOPSIS - char_val() - X IN Character to find value for - - RETURN - Appropriate integer value + octet2hex() + buf OUT output buffer. Must be at least 2*len+1 bytes + str, len IN the beginning and the length of the input string */ - - -static inline unsigned int char_val(char X) +static void +octet2hex(char *to, const uint8 *str, uint len) { - return (uint) (X >= '0' && X <= '9' ? X-'0' : - X >= 'A' && X <= 'Z' ? X-'A'+10 : - X-'a'+10); + const uint8 *str_end= str + len; + for (; str != str_end; ++str) + { + *to++= _dig_vec[(*str & 0xF0) >> 4]; + *to++= _dig_vec[*str & 0x0F]; + } + *to= '\0'; } /* - Get Binary salt from password as in mysql.user format - + Convert given asciiz string of hex (0..9 a..f) characters to octet + sequence. SYNOPSIS - get_salt_from_password() - res OUT Store binary salt here - password IN Password string as stored in mysql.user - - RETURN - none - - NOTE - This function does not have length check for passwords. It will just crash - Password hashes in old format must have length divisible by 8 -*/ - -void get_salt_from_password(ulong *res,const char *password) + hex2octet() + to OUT buffer to place result; must be at least len/2 bytes + str, len IN begin, length for character string; str and to may not + overlap; len % 2 == 0 +*/ + +static void +hex2octet(uint8 *to, const char *str, uint len) { - if (password) /* zero salt corresponds to empty password */ + const char *str_end= str + len; + while (str < str_end) { - if (password[0]==PVERSION41_CHAR) /* if new password */ - { - uint val=0; - uint i; - password++; /* skip version identifier */ - - /*get hashing salt from password and store in in the start of array */ - for (i=0 ; i < 4 ; i++) - val=(val << 4)+char_val(*password++); - *res++=val; - } - /* We process old passwords the same way as new ones in other case */ -#ifdef EXTRA_DEBUG - if (strlen(password)%8!=0) - fprintf(stderr,"Warning: Incorrect password length for salting: %d\n", - strlen(password)); -#endif - while (*password) - { - ulong val=0; - uint i; - for (i=0 ; i < 8 ; i++) - val=(val << 4)+char_val(*password++); - *res++=val; - } + register char tmp= char_val(*str++); + *to++= (tmp << 4) | char_val(*str++); } - return; } /* - Get string version as stored in mysql.user from salt form - + Encrypt/Decrypt function used for password encryption in authentication. + Simple XOR is used here but it is OK as we crypt random strings. Note, + that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1) SYNOPSIS - make_password_from_salt() - to OUT Store resulting string password here - hash_res IN Password in salt format - password_version - IN According to which version salt should be treated - - RETURN - none + my_crypt() + to OUT buffer to hold crypted string; must be at least len bytes + long; to and s1 (or s2) may be the same. + s1, s2 IN input strings (of equal length) + len IN length of s1 and s2 */ -void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version) +static void +my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) { - if (!password_version) /* Handling of old passwords. */ - sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); - else - if (password_version==PVERSION41_CHAR) - sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1], - hash_res[2],hash_res[3],hash_res[4],hash_res[5]); - else /* Just use empty password if we can't handle it. This should not happen */ - to[0]='\0'; + const uint8 *s1_end= s1 + len; + while (s1 < s1_end) + *to++= *s1++ ^ *s2++; } /* - Convert password in salted form to binary string password and hash-salt - For old password this involes one more hashing - + MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice + applied to the password string, and then produced octet sequence is + converted to hex string. + The result of this function is used as return value from PASSWORD() and + is stored in the database. SYNOPSIS - get_hash_and_password() - salt IN Salt to convert from - pversion IN Password version to use - hash OUT Store zero ended hash here - bin_password OUT Store binary password here (no zero at the end) - - RETURN - 0 for pre 4.1 passwords - !0 password version char for newer passwords + make_scrambled_password() + buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string + password IN NULL-terminated password string */ -void get_hash_and_password(ulong *salt, uint8 pversion, char *hash, - unsigned char *bin_password) +void +make_scrambled_password(char *to, const char *password) { - int t; - ulong* salt_end; - ulong val; - SHA1_CONTEXT context; - - if (pversion) /* New password version assumed */ - { - salt_end=salt+5; - sprintf(hash,"%04x",(unsigned short)salt[0]); - while (salt<salt_end) - { - val=*(++salt); - for (t=3; t>=0; t--) - { - bin_password[t]= (char) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ - } - bin_password+=4; /* Get to next 4 chars*/ - } - } - else - { - unsigned char *bp= bin_password; /* Binary password loop pointer */ - - /* Use zero starting hash as an indication of old password */ - hash[0]=0; - salt_end=salt+2; - /* Encode salt using SHA1 here */ - sha1_reset(&context); - while (salt<salt_end) /* Iterate over these elements*/ - { - val= *salt; - for (t=3;t>=0;t--) - { - bp[t]= (uchar) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ - } - bp+= 4; /* Get to next 4 chars*/ - salt++; - } - /* Use 8 bytes of binary password for hash */ - sha1_input(&context,(uint8*)bin_password,8); - sha1_result(&context,(uint8*)bin_password); - } + SHA1_CONTEXT sha1_context; + uint8 hash_stage2[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* stage 1: hash password */ + sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_result(&sha1_context, (uint8 *) to); + /* stage 2: hash stage1 output */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); + /* separate buffer is used to pass 'to' in octet2hex */ + sha1_result(&sha1_context, hash_stage2); + /* convert hash_stage2 to hex string */ + *to++= PVERSION41_CHAR; + octet2hex(to, hash_stage2, SHA1_HASH_SIZE); } - + /* - Create key from old password to decode scramble - Used in 4.1 authentication with passwords stored old way - + Produce an obscure octet sequence from password and random + string, recieved from the server. This sequence corresponds to the + password, but password can not be easily restored from it. The sequence + is then sent to the server for validation. Trailing zero is not stored + in the buf as it is not needed. + This function is used by client to create authenticated reply to the + server's greeting. SYNOPSIS - create_key_from_old_password() - passwd IN Password used for key generation - key OUT Created 20 bytes key - - RETURN - None + scramble() + buf OUT store scrambled string here. The buf must be at least + SHA1_HASH_SIZE bytes long. + message IN random message, must be exactly SCRAMBLE_LENGTH long and + NULL-terminated. + password IN users' password */ - -void create_key_from_old_password(const char *passwd, char *key) +void +scramble(char *to, const char *message, const char *password) { - char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */ - ulong salt[6]; /* Salt (large for safety) */ - /* At first hash password to the string stored in password */ - make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL); - /* Now convert it to the salt form */ - get_salt_from_password(salt,buffer); - /* Finally get hash and bin password from salt */ - get_hash_and_password(salt,0,buffer,(unsigned char*) key); + SHA1_CONTEXT sha1_context; + uint8 hash_stage1[SHA1_HASH_SIZE]; + uint8 hash_stage2[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* stage 1: hash password */ + sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_result(&sha1_context, hash_stage1); + /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE); + sha1_result(&sha1_context, hash_stage2); + /* create crypt string as sha1(message, hash_stage2) */; + sha1_reset(&sha1_context); + sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + /* xor allows 'from' and 'to' overlap: lets take advantage of it */ + sha1_result(&sha1_context, (uint8 *) to); + my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH); } /* - Scramble string with password - Used at pre 4.1 authentication phase. - + Check that scrambled message corresponds to the password; the function + is used by server to check that recieved reply is authentic. + This function does not check lengths of given strings: message must be + null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE + long (if not, something fishy is going on). SYNOPSIS - scramble() - to OUT Store scrambled message here - message IN Message to scramble - password IN Password to use while scrambling - old_ver IN Forse old version random number generator - - RETURN - End of scrambled string + check_scramble() + scramble clients' reply, presumably produced by scramble() + message original random string, previously sent to client + (presumably second argument of scramble()), must be + exactly SCRAMBLE_LENGTH long and NULL-terminated. + hash_stage2 hex2octet-decoded database entry + All params are IN. + + RETURN VALUE + 0 password is correct + !0 password is invalid */ -char *scramble(char *to,const char *message,const char *password, - my_bool old_ver) +my_bool +check_scramble(const char *scramble, const char *message, + const uint8 *hash_stage2) { - struct rand_struct rand_st; - ulong hash_pass[2],hash_message[2]; - char message_buffer[9]; /* Real message buffer */ - char *msg=message_buffer; - - /* We use special message buffer now as new server can provide longer hash */ - - memcpy(message_buffer,message,8); - message_buffer[8]=0; - - if (password && password[0]) - { - char *to_start=to; - hash_password(hash_pass,password); - hash_password(hash_message,message_buffer); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); - while (*msg++) - *to++= (char) (floor(my_rnd(&rand_st)*31)+64); - if (!old_ver) - { /* Make it harder to break */ - char extra=(char) (floor(my_rnd(&rand_st)*31)); - while (to_start != to) - *(to_start++)^=extra; - } - } - *to=0; - return to; + SHA1_CONTEXT sha1_context; + uint8 buf[SHA1_HASH_SIZE]; + uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* create key to encrypt scramble */ + sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + sha1_result(&sha1_context, buf); + /* encrypt scramble */ + my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH); + /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); + sha1_result(&sha1_context, hash_stage2_reassured); + return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE); } /* - Check scrambled message - Used for pre 4.1 password handling + Convert scrambled password from asciiz hex string to binary form. + SYNOPSIS + get_salt_from_password() + res OUT buf to hold password. Must be at least SHA1_HASH_SIZE + bytes long. + password IN 4.1.1 version value of user.password +*/ + +void get_salt_from_password(uint8 *hash_stage2, const char *password) +{ + hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2); +} +/* + Convert scrambled password from binary form to asciiz hex string. SYNOPSIS - scramble() - scrambled IN Scrambled message to check - message IN Original message which was scramble - hash_pass IN Password which should be used for scrambling - old_ver IN Forse old version random number generator - - RETURN - 0 Password correct - !0 Password invalid + make_password_from_salt() + to OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes + salt IN password in salt format */ -my_bool check_scramble(const char *scrambled, const char *message, - ulong *hash_pass, my_bool old_ver) +void make_password_from_salt(char *to, const uint8 *hash_stage2) { - struct rand_struct rand_st; - ulong hash_message[2]; - char buff[16],*to,extra; /* Big enough for check */ - const char *pos; - char message_buffer[SCRAMBLE_LENGTH+1]; /* Copy of message */ - - /* We need to copy the message as this function can be called for MySQL 4.1 - scramble which is not zero ended and can have zeroes inside - We could just write zero to proper place in original message but - this would make it harder to understand code for next generations - */ - - memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */ - message_buffer[SCRAMBLE_LENGTH]=0; - - /* Check if this exactly N bytes. Overwise this is something fishy */ - if (strlen(message_buffer)!=SCRAMBLE_LENGTH) - return 1; /* Wrong password */ - - hash_password(hash_message,message_buffer); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); - to=buff; - for (pos=scrambled ; *pos ; pos++) - *to++=(char) (floor(my_rnd(&rand_st)*31)+64); - if (old_ver) - extra=0; - else - extra=(char) (floor(my_rnd(&rand_st)*31)); - to=buff; - while (*scrambled) - { - if (*scrambled++ != (char) (*to++ ^ extra)) - return 1; /* Wrong password */ - } - return 0; + *to++= PVERSION41_CHAR; + octet2hex(to, hash_stage2, SHA1_HASH_SIZE); } diff --git a/sql/protocol.cc b/sql/protocol.cc index e90aa7585e2..d1eb3460fc8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -349,10 +349,35 @@ send_eof(THD *thd, bool no_flush) } DBUG_VOID_RETURN; } + +/* + Please client to send scrambled_password in old format. + SYNOPSYS + send_old_password_request() + thd thread handle + + RETURN VALUE + 0 ok + !0 error +*/ + +bool send_old_password_request(THD *thd) +{ + static char buff[1]= { (char) 254 }; + NET *net= &thd->net; + return my_net_write(net, buff, 1) || net_flush(net); +} + #endif /* EMBEDDED_LIBRARY */ /* - Faster net_store_length when we know length is a 32 bit integer + Faster net_store_length when we know that length is less than 65536. + We keep a separate version for that range because it's widely used in + libmysql. + uint is used as agrument type because of MySQL type conventions: + uint for 0..65536 + ulong for 0..4294967296 + ulonglong for bigger numbers. */ char *net_store_length(char *pkg, uint length) diff --git a/sql/protocol.h b/sql/protocol.h index 05aee12d3d9..f32c135ab3c 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -164,6 +164,7 @@ void net_printf(THD *thd,uint sql_errno, ...); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); void send_eof(THD *thd, bool no_flush=0); +bool send_old_password_request(THD *thd); char *net_store_length(char *packet,ulonglong length); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index e9c3b1ed0b0..d9c09c88f0d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -670,6 +670,17 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) } mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); + +#ifdef HAVE_OPENSSL + if (mi->ssl) + mysql_ssl_set(mysql, + mi->ssl_key[0]?mi->ssl_key:0, + mi->ssl_cert[0]?mi->ssl_cert:0, + mi->ssl_ca[0]?mi->ssl_ca:0, + mi->ssl_capath[0]?mi->ssl_capath:0, + mi->ssl_cipher[0]?mi->ssl_cipher:0); +#endif + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index 91583759c70..d07bcd52559 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -216,6 +216,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", &SV::net_retry_count, fix_net_retry_count); sys_var_thd_bool sys_new_mode("new", &SV::new_mode); +sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords); sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size", &SV::preload_buff_size); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", @@ -242,6 +243,7 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type", &SV::query_cache_type, &query_cache_type_typelib); #endif /* HAVE_QUERY_CACHE */ +sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth); sys_var_long_ptr sys_server_id("server_id",&server_id); sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", &opt_slave_compressed_protocol); @@ -432,6 +434,7 @@ sys_var *sys_variables[]= &sys_net_wait_timeout, &sys_net_write_timeout, &sys_new_mode, + &sys_old_passwords, &sys_preload_buff_size, &sys_pseudo_thread_id, &sys_query_cache_size, @@ -450,6 +453,7 @@ sys_var *sys_variables[]= #endif &sys_rpl_recovery_rank, &sys_safe_updates, + &sys_secure_auth, &sys_select_limit, &sys_server_id, #ifdef HAVE_REPLICATION @@ -608,6 +612,7 @@ struct show_var_st init_vars[]= { {sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS}, {sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS}, {sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS}, + {sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS}, {"open_files_limit", (char*) &open_files_limit, SHOW_LONG}, {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"log_error", (char*) log_error_file, SHOW_CHAR}, @@ -628,6 +633,7 @@ struct show_var_st init_vars[]= { SHOW_SYS}, {sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS}, {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, + {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ #ifdef HAVE_SMEM {"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL}, diff --git a/sql/set_var.h b/sql/set_var.h index f06b5ed22d3..9c9ad071967 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -689,6 +689,9 @@ public: } }; +/* updated in sql_acl.cc */ + +extern sys_var_thd_bool sys_old_passwords; /* For sql_yacc */ struct sys_var_with_base diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 2ff51418d14..1450243019f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -278,4 +278,6 @@ v/* "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index cd47f4098e9..014c35e81be 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -272,4 +272,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 406f2dd1cdd..ff866c284f0 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -280,4 +280,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 5e938074f32..a803f6673f4 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -274,4 +274,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index c1d7762fef8..9312dfa9dc2 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -274,4 +274,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 2e52ec04030..f4a29caf000 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 6910894b095..512f593dc53 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -278,4 +278,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index f52987e56cf..47ee14cf592 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 3fbec6f9fc7..e8e8cf6e1e3 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -271,4 +271,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 7ad72412035..c6b2b829fdd 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 9609fa8d8a4..1f134b6e9ba 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -271,4 +271,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index aeb62784594..08f635c8f20 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index a79d20cc20e..9089985b262 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -271,4 +271,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index b018313ea39..4e08813a5ac 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -271,4 +271,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 5fcdb6d84c2..b767125f73d 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -273,4 +273,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index ea639e1f8cd..95e388c2245 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 49c64272dd8..0f53d2a2010 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -273,4 +273,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index b711d107c23..0fb0646f040 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -271,4 +271,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ" "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 0129cd0d643..c8420110ee8 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -264,4 +264,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index ac8e7a5c7eb..6370d148ae2 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -277,4 +277,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 86a3ab090a2..6cb031c46e3 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -270,4 +270,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 0add28faab1..a36e0f9731f 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -269,4 +269,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 99d3f9c6a52..2865edf9175 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -274,4 +274,6 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d", diff --git a/sql/slave.cc b/sql/slave.cc index d45cf1aa8b9..dd25fe5e75e 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1554,9 +1554,21 @@ void init_master_info_with_options(MASTER_INFO* mi) if (master_user) strmake(mi->user, master_user, sizeof(mi->user) - 1); if (master_password) - strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); + strmake(mi->password, master_password, MAX_PASSWORD_LENGTH); mi->port = master_port; mi->connect_retry = master_connect_retry; + + mi->ssl= master_ssl; + if (master_ssl_ca) + strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1); + if (master_ssl_capath) + strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1); + if (master_ssl_cert) + strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1); + if (master_ssl_cipher) + strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1); + if (master_ssl_key) + strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1); } void clear_last_slave_error(RELAY_LOG_INFO* rli) @@ -1566,6 +1578,10 @@ void clear_last_slave_error(RELAY_LOG_INFO* rli) rli->last_slave_errno=0; } + +#define LINES_IN_MASTER_INFO_WITH_SSL 14 + + int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, bool abort_if_no_master_info_file) @@ -1643,25 +1659,87 @@ file '%s')", fname); } mi->fd = fd; - int port, connect_retry, master_log_pos; - + int port, connect_retry, master_log_pos, ssl= 0, lines; + char *first_non_digit; + + /* + Starting from 4.1.x master.info has new format. Now its + first line contains number of lines in file. By reading this + number we will be always distinguish to which version our + master.info corresponds to. We can't simply count lines in + file since versions before 4.1.x could generate files with more + lines than needed. + If first line doesn't contain a number or contain number less than + 14 then such file is treated like file from pre 4.1.1 version. + There is no ambiguity when reading an old master.info, as before + 4.1.1, the first line contained the binlog's name, which is either + empty or has an extension (contains a '.'), so can't be confused + with an integer. + + So we're just reading first line and trying to figure which version + is this. + */ + + /* + The first row is temporarily stored in mi->master_log_name, + if it is line count and not binlog name (new format) it will be + overwritten by the second row later. + */ if (init_strvar_from_file(mi->master_log_name, sizeof(mi->master_log_name), &mi->file, - "") || - init_intvar_from_file(&master_log_pos, &mi->file, 4) || + "")) + goto errwithmsg; + + lines= strtoul(mi->master_log_name, &first_non_digit, 10); + + if (mi->master_log_name[0]!='\0' && + *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL) + { // Seems to be new format + if (init_strvar_from_file(mi->master_log_name, + sizeof(mi->master_log_name), &mi->file, "")) + goto errwithmsg; + } + else + lines= 7; + + if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, master_host) || init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, master_user) || - init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file, - master_password) || + init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1, + &mi->file, master_password) || init_intvar_from_file(&port, &mi->file, master_port) || init_intvar_from_file(&connect_retry, &mi->file, master_connect_retry)) - { - sql_print_error("Error reading master configuration"); - goto err; - } + goto errwithmsg; + + /* + If file has ssl part use it even if we have server without + SSL support. But these option will be ignored later when + slave will try connect to master, so in this case warning + is printed. + */ + if (lines >= LINES_IN_MASTER_INFO_WITH_SSL && + (init_intvar_from_file(&ssl, &mi->file, master_ssl) || + init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), + &mi->file, master_ssl_ca) || + init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), + &mi->file, master_ssl_capath) || + init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert), + &mi->file, master_ssl_cert) || + init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher), + &mi->file, master_ssl_cipher) || + init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key), + &mi->file, master_ssl_key))) + goto errwithmsg; +#ifndef HAVE_OPENSSL + if (ssl) + sql_print_error("SSL information in the master info file " + "('%s') are ignored because this MySQL slave was compiled " + "without SSL support.", fname); +#endif /* HAVE_OPENSSL */ + /* This has to be handled here as init_intvar_from_file can't handle my_off_t types @@ -1669,6 +1747,7 @@ file '%s')", fname); mi->master_log_pos= (my_off_t) master_log_pos; mi->port= (uint) port; mi->connect_retry= (uint) connect_retry; + mi->ssl= (my_bool) ssl; } DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, @@ -1685,7 +1764,10 @@ file '%s')", fname); sql_print_error("Failed to flush master info file"); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); - + +errwithmsg: + sql_print_error("Error reading master configuration"); + err: if (fd >= 0) { @@ -1820,6 +1902,18 @@ int show_master_info(THD* thd, MASTER_INFO* mi) MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_return_int("Relay_log_space", 10, MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_empty_string("Master_SSL_Allowed", 7)); + field_list.push_back(new Item_empty_string("Master_SSL_CA_File", + sizeof(mi->ssl_ca))); + field_list.push_back(new Item_empty_string("Master_SSL_CA_Path", + sizeof(mi->ssl_capath))); + field_list.push_back(new Item_empty_string("Master_SSL_Cert", + sizeof(mi->ssl_cert))); + field_list.push_back(new Item_empty_string("Master_SSL_Cipher", + sizeof(mi->ssl_cipher))); + field_list.push_back(new Item_empty_string("Master_SSL_Key", + sizeof(mi->ssl_key))); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); @@ -1868,6 +1962,17 @@ int show_master_info(THD* thd, MASTER_INFO* mi) protocol->store((uint32) mi->rli.slave_skip_counter); protocol->store((ulonglong) mi->rli.group_master_log_pos); protocol->store((ulonglong) mi->rli.log_space_total); +#ifdef HAVE_OPENSSL + protocol->store(mi->ssl? "Yes":"No", &my_charset_bin); +#else + protocol->store(mi->ssl? "Ignored":"No", &my_charset_bin); +#endif + protocol->store(mi->ssl_ca, &my_charset_bin); + protocol->store(mi->ssl_capath, &my_charset_bin); + protocol->store(mi->ssl_cert, &my_charset_bin); + protocol->store(mi->ssl_cipher, &my_charset_bin); + protocol->store(mi->ssl_key, &my_charset_bin); + pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1886,11 +1991,22 @@ bool flush_master_info(MASTER_INFO* mi) DBUG_ENTER("flush_master_info"); DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); + /* + In certain cases this code may create master.info files that seems + corrupted, because of extra lines filled with garbage in the end + file (this happens if new contents take less space than previous + contents of file). But because of number of lines in the first line + of file we don't care about this garbage. + */ + my_b_seek(file, 0L); - my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", - mi->master_log_name, llstr(mi->master_log_pos, lbuf), + my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", + LINES_IN_MASTER_INFO_WITH_SSL, + mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, - mi->password, mi->port, mi->connect_retry); + mi->password, mi->port, mi->connect_retry, + (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, + mi->ssl_cipher, mi->ssl_key); flush_io_cache(file); DBUG_RETURN(0); } @@ -2303,9 +2419,10 @@ server_errno=%d)", return packet_error; } - if (len == 1) + /* Check if eof packet */ + if (len < 8 && mysql->net.read_pos[0] == 254) { - sql_print_error("Slave: received 0 length packet from server, apparent\ + sql_print_error("Slave: received end packet from server, apparent\ master shutdown: %s", mysql_error(mysql)); return packet_error; @@ -3273,6 +3390,17 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); + +#ifdef HAVE_OPENSSL + if (mi->ssl) + mysql_ssl_set(mysql, + mi->ssl_key[0]?mi->ssl_key:0, + mi->ssl_cert[0]?mi->ssl_cert:0, + mi->ssl_ca[0]?mi->ssl_ca:0, + mi->ssl_capath[0]?mi->ssl_capath:0, + mi->ssl_cipher[0]?mi->ssl_cipher:0); +#endif + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); /* This one is not strictly needed but we have it here for completeness */ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); diff --git a/sql/slave.h b/sql/slave.h index 0cd291a50f8..f7d288ca64e 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -288,16 +288,19 @@ Log_event* next_event(RELAY_LOG_INFO* rli); typedef struct st_master_info { + /* the variables below are needed because we can change masters on the fly */ char master_log_name[FN_REFLEN]; char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; char password[MAX_PASSWORD_LENGTH+1]; + my_bool ssl; // enables use of SSL connection if true + char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; + char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; my_off_t master_log_pos; File fd; // we keep the file open, so we need to remember the file pointer IO_CACHE file; - /* the variables below are needed because we can change masters on the fly */ pthread_mutex_t data_lock,run_lock; pthread_cond_t data_cond,start_cond,stop_cond; THD *io_thd; @@ -315,10 +318,13 @@ typedef struct st_master_info volatile ulong slave_run_id; st_master_info() - :fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT), + :ssl(0), fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT), abort_slave(0),slave_running(0), slave_run_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; + ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; + ssl_cipher[0]= 0; ssl_key[0]= 0; + bzero((char*) &file, sizeof(file)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); @@ -468,6 +474,10 @@ extern my_string master_user, master_password, master_host, master_info_file, relay_log_info_file, report_user, report_host, report_password; +extern my_bool master_ssl; +extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert, + master_ssl_cipher, master_ssl_key; + extern I_List<i_string> replicate_do_db, replicate_ignore_db; extern I_List<i_string_pair> replicate_rewrite_db; extern I_List<THD> threads; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9738c0c5d9e..a7fe77f6b06 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -51,7 +51,7 @@ static byte* acl_entry_get_key(acl_entry *entry,uint *length, return (byte*) entry->key; } -#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17) +#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+USERNAME_LENGTH+1) static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs; static MEM_ROOT mem, memex; @@ -68,12 +68,54 @@ static ulong get_sort(uint count,...); static void init_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user); static bool update_user_table(THD *thd, const char *host, const char *user, - const char *new_password); + const char *new_password, uint new_password_len); static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); /* + Convert scrambled password to binary form, according to scramble type, + Binary form is stored in user.salt. +*/ + +static +void +set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) +{ + if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) + { + get_salt_from_password(acl_user->salt, password); + acl_user->salt_len= SCRAMBLE_LENGTH; + } + else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) + { + get_salt_from_password_323((ulong *) acl_user->salt, password); + acl_user->salt_len= SCRAMBLE_LENGTH_323; + } + else + acl_user->salt_len= 0; +} + +/* + This after_update function is used when user.password is less than + SCRAMBLE_LENGTH bytes. +*/ + +static void restrict_update_of_old_passwords_var(THD *thd, + enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.old_passwords= 1; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.old_passwords= 1; +} + + +/* Read grant privileges from the privilege tables in the 'mysql' database. SYNOPSIS @@ -114,8 +156,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (!(thd=new THD)) DBUG_RETURN(1); /* purecov: inspected */ thd->store_globals(); - /* Use passwords according to command line option */ - use_old_passwords= opt_old_passwords; acl_cache->clear(1); // Clear locked hostname cache thd->db= my_strdup("mysql",MYF(0)); @@ -172,103 +212,126 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); - if (table->field[2]->field_length == 8 && - protocol_version == PROTOCOL_VERSION) + if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { - sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ - protocol_version=9; /* purecov: tested */ + sql_print_error("Fatal error: mysql.user table is damaged or in " + "unsupported 3.20 format."); + goto end; } DBUG_PRINT("info",("user table fields: %d, password length: %d", table->fields, table->field[2]->field_length)); - if (table->field[2]->field_length < 45 && !use_old_passwords) + + pthread_mutex_lock(&LOCK_global_system_variables); + if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) + { + if (opt_secure_auth) + { + pthread_mutex_unlock(&LOCK_global_system_variables); + sql_print_error("Fatal error: mysql.user table is in old format, " + "but server started with --secure-auth option."); + goto end; + } + sys_old_passwords.after_update= restrict_update_of_old_passwords_var; + if (global_system_variables.old_passwords) + pthread_mutex_unlock(&LOCK_global_system_variables); + else + { + global_system_variables.old_passwords= 1; + pthread_mutex_unlock(&LOCK_global_system_variables); + sql_print_error("mysql.user table is not updated to new password format; " + "Disabling new password usage until " + "mysql_fix_privilege_tables is run"); + } + thd->variables.old_passwords= 1; + } + else { - sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run"); - use_old_passwords= 1; + sys_old_passwords.after_update= 0; + pthread_mutex_unlock(&LOCK_global_system_variables); } allow_all_hosts=0; while (!(read_record_info.read_record(&read_record_info))) { ACL_USER user; - uint length=0; - update_hostname(&user.host,get_field(&mem, table->field[0])); - user.user=get_field(&mem, table->field[1]); - user.password=get_field(&mem, table->field[2]); - if (user.password && (length=(uint) strlen(user.password)) == 8 && - protocol_version == PROTOCOL_VERSION) - { - sql_print_error( - "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)", - user.user ? user.user : ""); /* purecov: tested */ - } - else /* non empty and not short passwords */ - { - user.pversion=get_password_version(user.password); - /* Only passwords of specific lengths depending on version are allowed */ - if ((!user.pversion && (length % 8 || length > 16)) || - (user.pversion && length != 45)) - { - sql_print_error( - "Found invalid password for user: '%s'@'%s'; Ignoring user", - user.user ? user.user : "", - user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ - continue; /* purecov: tested */ + update_hostname(&user.host, get_field(&mem, table->field[0])); + user.user= get_field(&mem, table->field[1]); + const char *password= get_field(&mem, table->field[2]); + uint password_len= password ? strlen(password) : 0; + set_user_salt(&user, password, password_len); + if (user.salt_len == 0 && password_len != 0) + { + switch (password_len) { + case 45: /* 4.1: to be removed */ + sql_print_error("Found 4.1 style password for user '%s@%s'. " + "Ignoring user. " + "You should change password for this user.", + user.user ? user.user : "", + user.host.hostname ? user.host.hostname : ""); + break; + default: + sql_print_error("Found invalid password for user: '%s@%s'; " + "Ignoring user", user.user ? user.user : "", + user.host.hostname ? user.host.hostname : ""); + break; } } - get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3) & GLOBAL_ACLS; - user.sort=get_sort(2,user.host.hostname,user.user); - user.hostname_length= (user.host.hostname ? - (uint) strlen(user.host.hostname) : 0); - if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ - { - char *ssl_type=get_field(&mem, table->field[24]); - if (!ssl_type) - user.ssl_type=SSL_TYPE_NONE; - else if (!strcmp(ssl_type, "ANY")) - user.ssl_type=SSL_TYPE_ANY; - else if (!strcmp(ssl_type, "X509")) - user.ssl_type=SSL_TYPE_X509; - else /* !strcmp(ssl_type, "SPECIFIED") */ - user.ssl_type=SSL_TYPE_SPECIFIED; - - user.ssl_cipher= get_field(&mem, table->field[25]); - user.x509_issuer= get_field(&mem, table->field[26]); - user.x509_subject= get_field(&mem, table->field[27]); - - char *ptr = get_field(&mem, table->field[28]); - user.user_resource.questions=atoi(ptr); - ptr = get_field(&mem, table->field[29]); - user.user_resource.updates=atoi(ptr); - ptr = get_field(&mem, table->field[30]); - user.user_resource.connections=atoi(ptr); - if (user.user_resource.questions || user.user_resource.updates || - user.user_resource.connections) - mqh_used=1; - } - else + else // password is correct { - user.ssl_type=SSL_TYPE_NONE; - bzero((char *)&(user.user_resource),sizeof(user.user_resource)); -#ifndef TO_BE_REMOVED - if (table->fields <= 13) - { // Without grant - if (user.access & CREATE_ACL) - user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + user.access= get_access(table,3) & GLOBAL_ACLS; + user.sort= get_sort(2,user.host.hostname,user.user); + user.hostname_length= (user.host.hostname ? + (uint) strlen(user.host.hostname) : 0); + if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ + { + char *ssl_type=get_field(&mem, table->field[24]); + if (!ssl_type) + user.ssl_type=SSL_TYPE_NONE; + else if (!strcmp(ssl_type, "ANY")) + user.ssl_type=SSL_TYPE_ANY; + else if (!strcmp(ssl_type, "X509")) + user.ssl_type=SSL_TYPE_X509; + else /* !strcmp(ssl_type, "SPECIFIED") */ + user.ssl_type=SSL_TYPE_SPECIFIED; + + user.ssl_cipher= get_field(&mem, table->field[25]); + user.x509_issuer= get_field(&mem, table->field[26]); + user.x509_subject= get_field(&mem, table->field[27]); + + char *ptr = get_field(&mem, table->field[28]); + user.user_resource.questions=atoi(ptr); + ptr = get_field(&mem, table->field[29]); + user.user_resource.updates=atoi(ptr); + ptr = get_field(&mem, table->field[30]); + user.user_resource.connections=atoi(ptr); + if (user.user_resource.questions || user.user_resource.updates || + user.user_resource.connections) + mqh_used=1; } - /* Convert old privileges */ - user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; - if (user.access & FILE_ACL) - user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; - if (user.access & PROCESS_ACL) - user.access|= SUPER_ACL | EXECUTE_ACL; + else + { + user.ssl_type=SSL_TYPE_NONE; + bzero((char *)&(user.user_resource),sizeof(user.user_resource)); +#ifndef TO_BE_REMOVED + if (table->fields <= 13) + { // Without grant + if (user.access & CREATE_ACL) + user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + } + /* Convert old privileges */ + user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; + if (user.access & FILE_ACL) + user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + if (user.access & PROCESS_ACL) + user.access|= SUPER_ACL | EXECUTE_ACL; #endif + } + VOID(push_dynamic(&acl_users,(gptr) &user)); + if (!user.host.hostname || user.host.hostname[0] == wild_many && + !user.host.hostname[1]) + allow_all_hosts=1; // Anyone can connect } - VOID(push_dynamic(&acl_users,(gptr) &user)); - if (!user.host.hostname || user.host.hostname[0] == wild_many && - !user.host.hostname[1]) - allow_all_hosts=1; // Anyone can connect } qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, sizeof(ACL_USER),(qsort_cmp) acl_compare); @@ -469,135 +532,105 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) /* - Prepare crypted scramble to be sent to the client -*/ - -void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) -{ - /* Binary password format to be used for generation*/ - char bin_password[SCRAMBLE41_LENGTH]; - /* Generate new long scramble for the thread */ - create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble); - thd->scramble[SCRAMBLE41_LENGTH]=0; - /* Get binary form, First 4 bytes of prepared scramble is salt */ - get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble, - (unsigned char*) bin_password); - /* Store "*" as identifier for old passwords */ - if (!acl_user->pversion) - prepared_scramble[0]='*'; - /* Finally encrypt password to get prepared scramble */ - password_crypt(thd->scramble, prepared_scramble+4, bin_password, - SCRAMBLE41_LENGTH); -} + Seek ACL entry for a user, check password, SSL cypher, and if + everything is OK, update THD user data and USER_RESOURCES struct. + IMPLEMENTATION + This function does not check if the user has any sensible privileges: + only user's existence and validity is checked. + Note, that entire operation is protected by acl_cache_lock. -/* - Get master privilges for user (priviliges for all tables). - Required before connecting to MySQL - - As we have 2 stage handshake now we cache user not to lookup - it second time. At the second stage we do not lookup user in case - we already know it; - + SYNOPSIS + acl_getroot() + thd thread handle. If all checks are OK, + thd->priv_user, thd->master_access are updated. + thd->host, thd->ip, thd->user are used for checks. + mqh user resources; on success mqh is reset, else + unchanged + passwd scrambled & crypted password, recieved from client + (to check): thd->scramble or thd->scramble_323 is + used to decrypt passwd, so they must contain + original random string, + passwd_len length of passwd, must be one of 0, 8, + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH + 'thd' and 'mqh' are updated on success; other params are IN. + + RETURN VALUE + 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are + updated + 1 user not found or authentification failure + 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format. + -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format. */ -ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *message,char **priv_user, - char *priv_host, bool old_ver, USER_RESOURCES *mqh, - char *prepared_scramble, uint *cur_priv_version, - ACL_USER **cached_user) +int acl_getroot(THD *thd, USER_RESOURCES *mqh, + const char *passwd, uint passwd_len) { - ulong user_access=NO_ACCESS; - *priv_user= (char*) user; - bool password_correct= 0; - int stage= (*cached_user != NULL); /* NULL passed as first stage */ - ACL_USER *acl_user= NULL; DBUG_ENTER("acl_getroot"); - bzero((char*) mqh, sizeof(USER_RESOURCES)); if (!initialized) { - // If no data allow anything - DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */ + /* + here if mysqld's been started with --skip-grant-tables option. + */ + thd->priv_user= (char *) ""; // privileges for + *thd->priv_host= '\0'; // the user are unknown + thd->master_access= ~NO_ACCESS; // everything is allowed + bzero(mqh, sizeof(*mqh)); + DBUG_RETURN(0); } + + int res= 1; + VOID(pthread_mutex_lock(&acl_cache->lock)); /* - Get possible access from user_list. This is or'ed to others not - fully specified - - If we have cached user use it, in other case look it up. + Find acl entry in user database. Note, that find_acl_user is not the same, + because it doesn't take into account the case when user is not empty, + but acl_user->user is empty */ - if (stage && (*cur_priv_version == priv_version)) - acl_user= *cached_user; - else + ACL_USER *acl_user= 0; + for (uint i=0 ; i < acl_users.elements ; i++) { - for (uint i=0 ; i < acl_users.elements ; i++) + ACL_USER *user_i = dynamic_element(&acl_users,i,ACL_USER*); + if (!user_i->user || !strcmp(thd->user, user_i->user)) { - ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*); - if (!acl_user_search->user || !strcmp(user,acl_user_search->user)) + if (compare_hostname(&user_i->host, thd->host, thd->ip)) { - if (compare_hostname(&acl_user_search->host,host,ip)) + /* check password: it should be empty or valid */ + if (passwd_len == user_i->salt_len) { - /* Found mathing user */ - acl_user= acl_user_search; - /* Store it as a cache */ - *cached_user= acl_user; - *cur_priv_version= priv_version; - break; + if (user_i->salt_len == 0 || + user_i->salt_len == SCRAMBLE_LENGTH && + check_scramble(passwd, thd->scramble, user_i->salt) == 0 || + check_scramble_323(passwd, thd->scramble, + (ulong *) user_i->salt) == 0) + { + acl_user= user_i; + res= 0; + } } + else if (passwd_len == SCRAMBLE_LENGTH && + user_i->salt_len == SCRAMBLE_LENGTH_323) + res= -1; + else if (passwd_len == SCRAMBLE_LENGTH_323 && + user_i->salt_len == SCRAMBLE_LENGTH) + res= 2; + /* linear search complete: */ + break; } } } - - /* Now we have acl_user found and may start our checks */ + /* + This was moved to separate tree because of heavy HAVE_OPENSSL case. + If acl_user is not null, res is 0. + */ if (acl_user) { - /* Password should present for both or absend for both */ - if (!acl_user->password && !*password) - password_correct=1; - else if (!acl_user->password || !*password) - { - *cached_user= 0; // Impossible to connect - } - else - { - /* New version password is checked differently */ - if (acl_user->pversion) - { - if (stage) /* We check password only on the second stage */ - { - if (!validate_password(password,message,acl_user->salt)) - password_correct=1; - } - else /* First stage - just prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - /* Old way to check password */ - else - { - /* Checking the scramble at any stage. First - old clients */ - if (!check_scramble(password,message,acl_user->salt, - (my_bool) old_ver)) - password_correct=1; - else if (!stage) /* Here if password incorrect */ - { - /* At the first stage - prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - } - } - } - - /* If user not found password_correct will also be zero */ - if (!password_correct) - goto unlock_and_exit; - - /* OK. User found and password checked continue validation */ - - { + /* OK. User found and password checked continue validation */ + thd->master_access= NO_ACCESS; Vio *vio=thd->net.vio; /* At this point we know that user is allowed to connect @@ -608,32 +641,32 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, switch (acl_user->ssl_type) { case SSL_TYPE_NOT_SPECIFIED: // Impossible case SSL_TYPE_NONE: /* SSL is not required to connect */ - user_access=acl_user->access; + thd->master_access= acl_user->access; break; #ifdef HAVE_OPENSSL case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ if (vio_type(vio) == VIO_TYPE_SSL) - user_access=acl_user->access; + thd->master_access= acl_user->access; break; case SSL_TYPE_X509: /* Client should have any valid certificate. */ /* - Connections with non-valid certificates are dropped already - in sslaccept() anyway, so we do not check validity here. - - We need to check for absence of SSL because without SSL - we should reject connection. + Connections with non-valid certificates are dropped already + in sslaccept() anyway, so we do not check validity here. + + We need to check for absence of SSL because without SSL + we should reject connection. */ if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_verify_result(vio->ssl_) == X509_V_OK && SSL_get_peer_certificate(vio->ssl_)) - user_access=acl_user->access; + thd->master_access= acl_user->access; break; case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ /* - We do not check for absence of SSL because without SSL it does - not pass all checks here anyway. - If cipher name is specified, we compare it to actual cipher in - use. + We do not check for absence of SSL because without SSL it does + not pass all checks here anyway. + If cipher name is specified, we compare it to actual cipher in + use. */ if (vio_type(vio) != VIO_TYPE_SSL || SSL_get_verify_result(vio->ssl_) != X509_V_OK) @@ -643,14 +676,13 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))); if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))) - user_access=acl_user->access; + thd->master_access= acl_user->access; else { if (global_system_variables.log_warnings) sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'", acl_user->ssl_cipher, SSL_get_cipher(vio->ssl_)); - user_access=NO_ACCESS; break; } } @@ -661,64 +693,58 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, /* If X509 issuer is speified, we check it... */ if (acl_user->x509_issuer) { - DBUG_PRINT("info",("checkpoint 3")); + DBUG_PRINT("info",("checkpoint 3")); char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); DBUG_PRINT("info",("comparing issuers: '%s' and '%s'", acl_user->x509_issuer, ptr)); - if (strcmp(acl_user->x509_issuer, ptr)) - { - if (global_system_variables.log_warnings) - sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'", - acl_user->x509_issuer, ptr); - user_access=NO_ACCESS; - free(ptr); - break; - } - user_access=acl_user->access; - free(ptr); + if (strcmp(acl_user->x509_issuer, ptr)) + { + if (global_system_variables.log_warnings) + sql_print_error("X509 issuer mismatch: should be '%s' " + "but is '%s'", acl_user->x509_issuer, ptr); + free(ptr); + break; + } + thd->master_access= acl_user->access; + free(ptr); } DBUG_PRINT("info",("checkpoint 4")); /* X509 subject is specified, we check it .. */ if (acl_user->x509_subject) { - char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); - DBUG_PRINT("info",("comparing subjects: '%s' and '%s'", - acl_user->x509_subject, ptr)); - if (strcmp(acl_user->x509_subject,ptr)) - { - if (global_system_variables.log_warnings) - sql_print_error("X509 subject mismatch: '%s' vs '%s'", - acl_user->x509_subject, ptr); - user_access=NO_ACCESS; - } - else - user_access=acl_user->access; - free(ptr); + char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); + DBUG_PRINT("info",("comparing subjects: '%s' and '%s'", + acl_user->x509_subject, ptr)); + if (strcmp(acl_user->x509_subject,ptr)) + { + if (global_system_variables.log_warnings) + sql_print_error("X509 subject mismatch: '%s' vs '%s'", + acl_user->x509_subject, ptr); + } + else + thd->master_access= acl_user->access; + free(ptr); } break; -#else /* HAVE_OPENSSL */ +#else /* HAVE_OPENSSL */ default: /* - If we don't have SSL but SSL is required for this user the - authentication should fail. - */ + If we don't have SSL but SSL is required for this user the + authentication should fail. + */ break; #endif /* HAVE_OPENSSL */ } - } + thd->priv_user= acl_user->user ? thd->user : (char *) ""; + *mqh= acl_user->user_resource; - *mqh=acl_user->user_resource; - if (!acl_user->user) - *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ - - if (acl_user->host.hostname) - strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME); - else - *priv_host= 0; - -unlock_and_exit: + if (acl_user->host.hostname) + strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + else + *thd->priv_host= 0; + } VOID(pthread_mutex_unlock(&acl_cache->lock)); - DBUG_RETURN(user_access); + DBUG_RETURN(res); } @@ -729,8 +755,9 @@ static byte* check_get_key(ACL_USER *buff,uint *length, return (byte*) buff->host.hostname; } + static void acl_update_user(const char *user, const char *host, - const char *password, + const char *password, uint password_len, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, @@ -766,20 +793,9 @@ static void acl_update_user(const char *user, const char *host, acl_user->x509_subject= (x509_subject ? strdup_root(&mem,x509_subject) : 0); } - if (password) - { - if (!password[0]) /* If password is empty set it to null */ - { - acl_user->password=0; - acl_user->pversion=0; // just initialize - } - else - { - acl_user->password=(char*) ""; // Just point at something - get_salt_from_password(acl_user->salt,password); - acl_user->pversion=get_password_version(acl_user->password); - } - } + + set_user_salt(acl_user, password, password_len); + /* search complete: */ break; } } @@ -788,7 +804,7 @@ static void acl_update_user(const char *user, const char *host, static void acl_insert_user(const char *user, const char *host, - const char *password, + const char *password, uint password_len, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, @@ -799,7 +815,6 @@ static void acl_insert_user(const char *user, const char *host, ACL_USER acl_user; acl_user.user=*user ? strdup_root(&mem,user) : 0; update_hostname(&acl_user.host,strdup_root(&mem,host)); - acl_user.password=0; acl_user.access=privileges; acl_user.user_resource = *mqh; acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user); @@ -809,12 +824,8 @@ static void acl_insert_user(const char *user, const char *host, acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0; acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0; acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0; - if (password) - { - acl_user.password=(char*) ""; // Just point at something - get_salt_from_password(acl_user.salt,password); - acl_user.pversion=get_password_version(password); - } + + set_user_salt(&acl_user, password, password_len); VOID(push_dynamic(&acl_users,(gptr) &acl_user)); if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many @@ -1151,7 +1162,6 @@ bool check_change_password(THD *thd, const char *host, const char *user) bool change_password(THD *thd, const char *host, const char *user, char *new_password) { - uint length=0; DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -1160,37 +1170,27 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user)) DBUG_RETURN(1); - /* - password should always be 0,16 or 45 chars; - Simple hack to avoid cracking - */ - length=(uint) strlen(new_password); - if (length != 45) - new_password[length & 16]=0; - VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; - if (!(acl_user= find_acl_user(host,user))) + if (!(acl_user= find_acl_user(host, user))) { - send_error(thd, ER_PASSWORD_NO_MATCH); VOID(pthread_mutex_unlock(&acl_cache->lock)); + send_error(thd, ER_PASSWORD_NO_MATCH); DBUG_RETURN(1); } + /* update loaded acl entry: */ + uint new_password_len= new_password ? strlen(new_password) : 0; + set_user_salt(acl_user, new_password, new_password_len); + if (update_user_table(thd, acl_user->host.hostname ? acl_user->host.hostname : "", acl_user->user ? acl_user->user : "", - new_password)) + new_password, new_password_len)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ send_error(thd,0); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */ } - get_salt_from_password(acl_user->salt,new_password); - acl_user->pversion=get_password_version(new_password); - if (!new_password[0]) - acl_user->password=0; - else - acl_user->password=(char*) ""; // Point at something acl_cache->clear(1); // Clear locked hostname cache VOID(pthread_mutex_unlock(&acl_cache->lock)); @@ -1230,7 +1230,7 @@ find_acl_user(const char *host, const char *user) if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { - if (compare_hostname(&(acl_user->host),host,host)) + if (compare_hostname(&acl_user->host,host,host)) { DBUG_RETURN(acl_user); } @@ -1303,7 +1303,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, */ static bool update_user_table(THD *thd, const char *host, const char *user, - const char *new_password) + const char *new_password, uint new_password_len) { TABLE_LIST tables; TABLE *table; @@ -1345,7 +1345,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, DBUG_RETURN(1); /* purecov: deadcode */ } store_record(table,record[1]); - table->field[2]->store(new_password,(uint) strlen(new_password), &my_charset_latin1); + table->field[2]->store(new_password, new_password_len, &my_charset_latin1); if ((error=table->file->update_row(table->record[1],table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: deadcode */ @@ -1393,24 +1393,23 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, { int error = -1; bool old_row_exists=0; - char *password,empty_string[1]; + const char *password= ""; + uint password_len= 0; char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_user_table"); safe_mutex_assert_owner(&acl_cache->lock); - password=empty_string; - empty_string[0]=0; - if (combo.password.str && combo.password.str[0]) { - if ((combo.password.length != HASH_PASSWORD_LENGTH) - && combo.password.length != HASH_OLD_PASSWORD_LENGTH) + if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH && + combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { my_printf_error(ER_PASSWORD_NO_MATCH, - "Password hash should be a %d-digit hexadecimal number", - MYF(0),HASH_PASSWORD_LENGTH); + "Password hash should be a %d-digit hexadecimal number", + MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); DBUG_RETURN(-1); } + password_len= combo.password.length; password=combo.password.str; } @@ -1435,17 +1434,20 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, goto end; } old_row_exists = 0; - restore_record(table,default_values); // cp empty row from default_values - table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); - table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1); - table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1); + restore_record(table,default_values); // cp empty row from default_values + table->field[0]->store(combo.host.str,combo.host.length, + &my_charset_latin1); + table->field[1]->store(combo.user.str,combo.user.length, + &my_charset_latin1); + table->field[2]->store(password, password_len, + &my_charset_latin1); } else { old_row_exists = 1; store_record(table,record[1]); // Save copy for update if (combo.password.str) // If password given - table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1); + table->field[2]->store(password, password_len, &my_charset_latin1); } /* Update table columns with new privileges */ @@ -1542,10 +1544,8 @@ end: if (!error) { acl_cache->clear(1); // Clear privilege cache - if (!combo.password.str) - password=0; // No password given on command if (old_row_exists) - acl_update_user(combo.user.str,combo.host.str,password, + acl_update_user(combo.user.str, combo.host.str, password, password_len, thd->lex.ssl_type, thd->lex.ssl_cipher, thd->lex.x509_issuer, @@ -1553,7 +1553,7 @@ end: &thd->lex.mqh, rights); else - acl_insert_user(combo.user.str,combo.host.str,password, + acl_insert_user(combo.user.str, combo.host.str, password, password_len, thd->lex.ssl_type, thd->lex.ssl_cipher, thd->lex.x509_issuer, @@ -3024,12 +3024,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append ("'@'",3); global.append(lex_user->host.str,lex_user->host.length); global.append ('\''); - if (acl_user->password) + if (acl_user->salt_len) { - char passd_buff[HASH_PASSWORD_LENGTH+1]; - make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion); + char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; + if (acl_user->salt_len == SCRAMBLE_LENGTH) + make_password_from_salt(passwd_buff, acl_user->salt); + else + make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); global.append(" IDENTIFIED BY PASSWORD '",25); - global.append(passd_buff); + global.append(passwd_buff); global.append('\''); } /* "show grants" SSL related stuff */ diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 0dc8c058b3d..0b2df8e765a 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -111,9 +111,9 @@ public: acl_host_and_ip host; uint hostname_length; USER_RESOURCES user_resource; - char *user,*password; - ulong salt[6]; // New password has longer length - uint8 pversion; // password version + char *user; + uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form + uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1 enum SSL_type ssl_type; const char *ssl_cipher, *x509_issuer, *x509_subject; }; @@ -135,11 +135,8 @@ void acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db, my_bool db_is_pattern); -ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *scramble, - char **priv_user, char *priv_host, - bool old_ver, USER_RESOURCES *max,char* prepared_scramble, - uint *cur_priv_version, ACL_USER **cached_user); +int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, + uint passwd_len); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, const char *host, const char *user); bool change_password(THD *thd, const char *host, const char *user, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 763408dc5c2..ba1952e533e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -138,6 +138,7 @@ THD::THD():user_time(0), is_fatal_error(0), set_query_id=1; db_access=NO_ACCESS; version=refresh_version; // For boot + *scramble= '\0'; init(); /* Initialize sub structures */ diff --git a/sql/sql_class.h b/sql/sql_class.h index e10795c4d9d..a49162bb4ef 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -385,6 +385,7 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; + /* Determines if which non-standard SQL behaviour should be enabled */ ulong sql_mode; ulong default_week_format; ulong max_seeks_for_key; @@ -398,6 +399,7 @@ struct system_variables my_bool log_warnings; my_bool low_priority_updates; my_bool new_mode; + my_bool old_passwords; CHARSET_INFO *character_set_server; CHARSET_INFO *character_set_database; @@ -459,7 +461,6 @@ public: const char *host_or_ip; ulong client_capabilities; /* What the client supports */ - /* Determines if which non-standard SQL behaviour should be enabled */ ulong max_client_packet_length; ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ @@ -556,10 +557,10 @@ public: enum_tx_isolation session_tx_isolation; /* for user variables replication*/ DYNAMIC_ARRAY user_var_events; - // extend scramble to handle new auth - char scramble[SCRAMBLE41_LENGTH+1]; - // old scramble is needed to handle old clients - char old_scramble[SCRAMBLE_LENGTH+1]; + + /* scramble - random string sent to client on handshake */ + char scramble[SCRAMBLE_LENGTH+1]; + uint8 query_cache_type; // type of query cache processing bool slave_thread; bool set_query_id,locked,count_cuted_fields,some_tables_deleted; diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc index 930ecfffef7..b0b8050e311 100644 --- a/sql/sql_crypt.cc +++ b/sql/sql_crypt.cc @@ -32,7 +32,7 @@ SQL_CRYPT::SQL_CRYPT(const char *password) { ulong rand_nr[2]; - hash_password(rand_nr,password); + hash_password(rand_nr,password, strlen(password)); crypt_init(rand_nr); } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 771d68e8462..5d05fea4fe3 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -96,7 +96,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, else res= check_access(thd, SELECT_ACL, any_db); if (res) - DBUG_RETURN(-1); + DBUG_RETURN(1); if (!(res=open_and_lock_tables(thd,tables))) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 947205949f1..6cc5d25c34e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -172,7 +172,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, else res= (table == 0); else + { + lock_type=TL_WRITE; res= open_and_lock_tables(thd, table_list); + } } else res= open_and_lock_tables(thd, table_list); @@ -627,6 +630,7 @@ public: thd.current_tablenr=0; thd.version=refresh_version; thd.command=COM_DELAYED_INSERT; + thd.lex.current_select= 0; /* for my_message_sql */ bzero((char*) &thd.net,sizeof(thd.net)); // Safety thd.system_thread=1; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d6cfd555c40..80d698dfc26 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -982,6 +982,7 @@ void st_select_lex::init_query() cond_count= with_wild= 0; ref_pointer_array= 0; select_n_having_items= 0; + prep_where= 0; } void st_select_lex::init_select() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7a7071ae56b..d4148ad3414 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -60,7 +60,7 @@ enum enum_sql_command { SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS, - SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, + SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, @@ -73,7 +73,7 @@ enum enum_sql_command { SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES, - SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, + SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, /* This should be the last !!! */ SQLCOM_END @@ -87,6 +87,13 @@ typedef struct st_lex_master_info uint port, connect_retry; ulonglong pos; ulong server_id; + /* + Variable for MASTER_SSL option. + MASTER_SSL=0 in CHANGE MASTER TO corresponds to SSL_DISABLE + MASTER_SSL=1 corresponds to SSL_ENABLE + */ + enum {SSL_UNCHANGED=0, SSL_DISABLE, SSL_ENABLE} ssl; + char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; } LEX_MASTER_INFO; @@ -272,8 +279,8 @@ protected: select_result *result; int res; - bool describe, found_rows_for_union, - prepared, // prepare phase already performed for UNION (unit) + ulong describe, found_rows_for_union; + bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) executed, // already executed t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods @@ -332,6 +339,7 @@ class st_select_lex: public st_select_lex_node public: char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ + Item *prep_where; /* saved WHERE clause for prepared statement processing */ enum olap_type olap; SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ List<Item> item_list; /* list of fields & expressions */ @@ -472,15 +480,21 @@ typedef struct st_lex SELECT_LEX *all_selects_list; uchar *ptr,*tok_start,*tok_end,*end_of_query; char *length,*dec,*change,*name; + char *help_arg; char *backup_dir; /* For RESTORE/BACKUP */ char* to_log; /* For PURGE MASTER LOGS TO */ time_t purge_time; /* For PURGE MASTER LOGS BEFORE */ char* x509_subject,*x509_issuer,*ssl_cipher; char* found_colon; /* For multi queries - next query */ - enum SSL_type ssl_type; /* defined in violite.h */ String *wild; sql_exchange *exchange; select_result *result; + Item *default_value, *comment; + LEX_USER *grant_user; + gptr yacc_yyss,yacc_yyvs; + THD *thd; + CHARSET_INFO *charset; + SQL_LIST *gorder_list; List<key_part_spec> col_list; List<key_part_spec> ref_list; @@ -499,11 +513,6 @@ typedef struct st_lex TYPELIB *interval; create_field *last_field; char *savepoint_name; // Transaction savepoint id - Item *default_value, *comment; - uint uint_geom_type; - LEX_USER *grant_user; - gptr yacc_yyss,yacc_yyvs; - THD *thd; udf_func udf; HA_CHECK_OPT check_opt; // check/repair options HA_CREATE_INFO create_info; @@ -512,6 +521,7 @@ typedef struct st_lex ulong thread_id,type; enum_sql_command sql_command; thr_lock_type lock_option; + enum SSL_type ssl_type; /* defined in violite.h */ enum my_lex_states next_state; enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; @@ -519,17 +529,15 @@ typedef struct st_lex enum ha_rkey_function ha_rkey_mode; enum enum_enable_or_disable alter_keys_onoff; enum enum_var_type option_type; + uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; uint param_count; + uint slave_thd_opt; bool drop_primary, drop_if_exists, drop_temporary, local_file; bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog; bool derived_tables, describe; bool safe_to_cache_query; - uint slave_thd_opt; - CHARSET_INFO *charset; - char *help_arg; - SQL_LIST *gorder_list; st_lex() {} inline void uncacheable() { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d030eaf617c..dd6bdf45e82 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -77,9 +77,6 @@ static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, List<Item> &fields, READ_INFO &read_info, String &enclosed); - -#ifndef EMBEDDED_LIBRARY - int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, List<Item> &fields, enum enum_duplicates handle_duplicates, bool read_file_from_client,thr_lock_type lock_type) @@ -91,7 +88,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, String *field_term=ex->field_term,*escaped=ex->escaped, *enclosed=ex->enclosed; bool is_fifo=0; +#ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; +#endif char *db = table_list->db; // This is never null /* If no current database, use database where table is located */ char *tdb= thd->db ? thd->db : db; @@ -184,6 +183,17 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } else { +#ifdef EMBEDDED_LIBRARY + char *chk_name= ex->file_name; + while ((*chk_name == ' ') || (*chk_name == 't')) + chk_name++; + if (*chk_name == FN_CURLIB) + { + sprintf(name, "%s%s", mysql_data_home, ex->file_name); + unpack_filename(name, name); + } + else +#endif /*EMBEDDED_LIBRARY*/ unpack_filename(name,ex->file_name); #if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__) MY_STAT stat_info; @@ -225,6 +235,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_RETURN(-1); // Can't allocate buffers } +#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { lf_info.thd = thd; @@ -238,6 +249,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, lf_info.log_delayed= log_delayed; read_info.set_io_cache_arg((void*) &lf_info); } +#endif /*!EMBEDDED_LIBRARY*/ + restore_record(table,default_values); thd->count_cuted_fields=1; /* calc cuted fields */ @@ -293,6 +306,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { if (transactional_table) ha_autocommit_or_rollback(thd,error); +#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { if (lf_info.wrote_create_file) @@ -315,6 +329,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, mysql_bin_log.write(&d); } } +#endif /*!EMBEDDED_LIBRARY*/ error= -1; // Error on read goto err; } @@ -327,6 +342,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (!log_delayed) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; +#ifndef EMBEDDED_LIBRARY if (mysql_bin_log.is_open()) { if (opt_old_rpl_compat) @@ -348,6 +364,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } } } +#endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) error=ha_autocommit_or_rollback(thd,error); err: @@ -359,8 +376,6 @@ err: DBUG_RETURN(error); } -#endif /* EMBEDDED_LIBRARY */ - /**************************************************************************** ** Read of rows of fixed size + optional garage + optonal newline ****************************************************************************/ @@ -640,11 +655,12 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, mysys/mf_iocache.c. So we work around the problem with a manual assignment */ + need_end_io_cache = 1; + +#ifndef EMBEDDED_LIBRARY if (get_it_from_net) cache.read_function = _my_b_net_read; - need_end_io_cache = 1; -#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) cache.pre_read = cache.pre_close = (IO_CACHE_CALLBACK) log_loaded_block; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 33e96cc2776..ff66892262d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -176,154 +176,184 @@ end: } +#ifndef EMBEDDED_LIBRARY /* - Check if user is ok - + Check if user exist and password supplied is correct. SYNOPSIS check_user() - thd Thread handle - command Command for connection (for log) - user Name of user trying to connect - passwd Scrambled password sent from client - db Database to connect to - check_count If set to 1, don't allow too many connection - simple_connect If 1 then client is of old type and we should connect - using the old method (no challange) - do_send_error Set to 1 if we should send error to user - prepared_scramble Buffer to store hash password of new connection - had_password Set to 1 if the user gave a password - cur_priv_version Check flag to know if someone flushed the privileges - since last code - hint_user Pointer used by acl_getroot() to remmeber user for - next call - - RETURN - 0 ok - thd->user, thd->master_access, thd->priv_user, thd->db and - thd->db_access are updated - 1 Access denied; Error sent to client - -1 If do_send_error == 1: Failed connect, error sent to client - If do_send_error == 0: Prepare for stage of connect + thd thread handle, thd->{host,user,ip} are used + command originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + passwd scrambled password recieved from client + passwd_len length of scrambled password + db database name to connect to, may be NULL + check_count dont know exactly + + Note, that host, user and passwd may point to communication buffer. + Current implementation does not depened on that, but future changes + should be done with this in mind; 'thd' is INOUT, all other params + are 'IN'. + + RETURN VALUE + 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and + thd->db_access are updated; OK is sent to client; + -1 access denied or handshake error; error is sent to client; + >0 error, not sent to client */ -static int check_user(THD *thd,enum_server_command command, const char *user, - const char *passwd, const char *db, bool check_count, - bool simple_connect, bool do_send_error, - char *prepared_scramble, bool had_password, - uint *cur_priv_version, ACL_USER** hint_user) +static int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count) { - thd->db=0; - thd->db_length=0; - USER_RESOURCES ur; - char tmp_passwd[SCRAMBLE41_LENGTH+1]; DBUG_ENTER("check_user"); + my_bool opt_secure_auth_local; + pthread_mutex_lock(&LOCK_global_system_variables); + opt_secure_auth_local= opt_secure_auth; + pthread_mutex_unlock(&LOCK_global_system_variables); + /* - Move password to temporary buffer as it may be stored in communication - buffer + If the server is running in secure auth mode, short scrambles are + forbidden. */ - strmake(tmp_passwd, passwd, sizeof(tmp_passwd)); - passwd= tmp_passwd; // Use local copy - - /* We shall avoid dupplicate user allocations here */ - if (!thd->user && !(thd->user = my_strdup(user, MYF(0)))) + if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) { - send_error(thd,ER_OUT_OF_RESOURCES); - DBUG_RETURN(1); + net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); + mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); } - thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, - passwd, thd->scramble, - &thd->priv_user, thd->priv_host, - (protocol_version == 9 || - !(thd->client_capabilities & - CLIENT_LONG_PASSWORD)), - &ur,prepared_scramble, - cur_priv_version,hint_user); - - DBUG_PRINT("info", - ("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'", - thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->user, thd->priv_user, - had_password ? "yes": "no", - thd->master_access, thd->db ? thd->db : "*none*")); + if (passwd_len != 0 && + passwd_len != SCRAMBLE_LENGTH && + passwd_len != SCRAMBLE_LENGTH_323) + DBUG_RETURN(ER_HANDSHAKE_ERROR); /* - In case we're going to retry we should not send error message at this - point + Clear thd->db as it points to something, that will be freed when + connection is closed. We don't want to accidently free a wrong pointer + if connect failed. Also in case of 'CHANGE USER' failure, current + database will be switched to 'no database selected'. */ - if (thd->master_access & NO_ACCESS) + thd->db= 0; + thd->db_length= 0; + + USER_RESOURCES ur; + int res= acl_getroot(thd, &ur, passwd, passwd_len); + if (res == -1) { - if (do_send_error || !had_password || !*hint_user) + /* + This happens when client (new) sends password scrambled with + scramble(), but database holds old value (scrambled with + scramble_323()). Here we please client to send scrambled_password + in old format. + */ + NET *net= &thd->net; + if (opt_secure_auth_local) { - DBUG_PRINT("info",("Access denied")); + net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, + thd->user, thd->host_or_ip); + mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), + thd->user, thd->host_or_ip); + DBUG_RETURN(-1); + } + if (send_old_password_request(thd) || + my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very + { // specific packet size + inc_host_errors(&thd->remote.sin_addr); + DBUG_RETURN(ER_HANDSHAKE_ERROR); + } + /* Final attempt to check the user based on reply */ + /* So as passwd is short, errcode is always >= 0 */ + res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); + } + /* here res is always >= 0 */ + if (res == 0) + { + if (!(thd->master_access & NO_ACCESS)) // authentification is OK + { + DBUG_PRINT("info", + ("Capabilities: %d packet_length: %ld Host: '%s' " + "Login user: '%s' Priv_user: '%s' Using password: %s " + "Access: %u db: '%s'", + thd->client_capabilities, thd->max_client_packet_length, + thd->host_or_ip, thd->user, thd->priv_user, + passwd_len ? "yes": "no", + thd->master_access, thd->db ? thd->db : "*none*")); + + if (check_count) + { + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool count_ok= thread_count < max_connections + delayed_insert_threads + || (thd->master_access & SUPER_ACL); + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!count_ok) + { // too many connections + send_error(thd, ER_CON_COUNT_ERROR); + DBUG_RETURN(-1); + } + } + + /* Why logging is performed before all checks've passed? */ + mysql_log.write(thd,command, + (thd->priv_user == thd->user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + thd->user, thd->host_or_ip, + db ? db : (char*) ""); + /* - Old client should get nicer error message if password version is - not supported + This is the default access rights for the current database. It's + set to 0 here because we don't have an active database yet (and we + may not have an active database to set. */ - if (simple_connect && *hint_user && (*hint_user)->pversion) + thd->db_access=0; + + /* Don't allow user to connect if he has done too many queries */ + if ((ur.questions || ur.updates || + ur.connections || max_user_connections) && + get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) + DBUG_RETURN(1); + if (thd->user_connect && thd->user_connect->user_resources.connections && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(1); + + /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ + if (db && db[0]) { - net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); - mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE)); + if (mysql_change_db(thd, db)) + { + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(-1); + } } else - { - net_printf(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); - mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); - } - DBUG_RETURN(1); // Error already given - } - DBUG_PRINT("info",("Prepare for second part of handshake")); - DBUG_RETURN(-1); // no report error in special handshake - } - - if (check_count) - { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool tmp=(thread_count - delayed_insert_threads >= max_connections && - !(thd->master_access & SUPER_ACL)); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - if (tmp) - { // Too many connections - send_error(thd, ER_CON_COUNT_ERROR); - DBUG_RETURN(1); + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages + /* Ready to handle queries */ + DBUG_RETURN(0); } } - mysql_log.write(thd,command, - (thd->priv_user == thd->user ? - (char*) "%s@%s on %s" : - (char*) "%s@%s as anonymous on %s"), - user, - thd->host_or_ip, - db ? db : (char*) ""); - thd->db_access=0; - /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.connections || max_user_connections) && - get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) - DBUG_RETURN(1); - if (thd->user_connect && ((thd->user_connect->user_resources.connections) || - max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(1); - - if (db && db[0]) - { - int error= test(mysql_change_db(thd,db)); - if (error && thd->user_connect) - decrease_user_connections(thd->user_connect); - DBUG_RETURN(error); - } - send_ok(thd); // Ready to handle questions - thd->password= test(passwd[0]); // Remember for error messages - DBUG_RETURN(0); // ok + else if (res == 2) // client gave short hash, server has long hash + { + net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); + mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } + net_printf(thd, ER_ACCESS_DENIED_ERROR, + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + DBUG_RETURN(-1); } +#endif // EMBEDDED_LIBRARY + /* Check for maximum allowable user connections, if the mysqld server is @@ -526,45 +556,36 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0) /* - Check connnectionn and get priviliges - + Perform handshake, authorize client and update thd ACL variables. SYNOPSIS - check_connections - thd Thread handle + check_connection() + thd thread handle RETURN - 0 ok - -1 Error, which is sent to user - > 0 Error code (not sent to user) + 0 success, OK is sent to user, thd is updated. + -1 error, which is sent to user + > 0 error code (not sent to user) */ #ifndef EMBEDDED_LIBRARY static int -check_connections(THD *thd) +check_connection(THD *thd) { - int res; - uint connect_errors=0; - uint cur_priv_version; - bool using_password; + uint connect_errors= 0; NET *net= &thd->net; - char *end, *user, *passwd, *db; - char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */ - char db_buff[NAME_LEN+1]; - ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */ - DBUG_PRINT("info",("New connection received on %s", - vio_description(net->vio))); - - /* Remove warning from valgrind. TODO: Fix it in password.c */ - bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble)); + + DBUG_PRINT("info", + ("New connection received on %s", vio_description(net->vio))); + if (!thd->host) // If TCP/IP connection { char ip[30]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) return (ER_BAD_HOST_ERROR); - if (!(thd->ip = my_strdup(ip,MYF(0)))) + if (!(thd->ip= my_strdup(ip,MYF(0)))) return (ER_OUT_OF_RESOURCES); - thd->host_or_ip=thd->ip; + thd->host_or_ip= thd->ip; #if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) /* Fast local hostname resolve for Win32 */ if (!strcmp(thd->ip,"127.0.0.1")) @@ -600,15 +621,16 @@ check_connections(THD *thd) DBUG_PRINT("info",("Host: %s",thd->host)); thd->host_or_ip= thd->host; thd->ip= 0; - bzero((char*) &thd->remote,sizeof(struct sockaddr)); + bzero((char*) &thd->remote, sizeof(struct sockaddr)); } /* Ensure that wrong hostnames doesn't cause buffer overflows */ vio_keepalive(net->vio, TRUE); - ulong pkt_len=0; + ulong pkt_len= 0; + char *end; { /* buff[] needs to big enough to hold the server_version variable */ - char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64]; + char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); @@ -622,19 +644,34 @@ check_connections(THD *thd) client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */ #endif /* HAVE_OPENSSL */ - end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1; - int4store((uchar*) end,thd->thread_id); - end+=4; - memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1); - end+=SCRAMBLE_LENGTH +1; - int2store(end,client_flags); + end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; + int4store((uchar*) end, thd->thread_id); + end+= 4; + /* + So as check_connection is the only entry point to authorization + procedure, scramble is set here. This gives us new scramble for + each handshake. + */ + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); + /* + Old clients does not understand long scrambles, but can ignore packet + tail: that's why first part of the scramble is placed here, and second + part at the end of packet. + */ + end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; + + int2store(end, client_flags); + /* write server characteristics: up to 16 bytes allowed */ end[2]=(char) default_charset_info->number; - int2store(end+3,thd->server_status); - bzero(end+5,13); - end+=18; - - // At this point we write connection message and read reply - if (net_write_command(net,(uchar) protocol_version, "", 0, buff, + int2store(end+3, thd->server_status); + bzero(end+5, 13); + end+= 18; + /* write scramble tail */ + end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; + + /* At this point we write connection message and read reply */ + if (net_write_command(net, (uchar) protocol_version, "", 0, buff, (uint) (end-buff)) || (pkt_len= my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) @@ -723,7 +760,7 @@ check_connections(THD *thd) return(ER_HANDSHAKE_ERROR); } DBUG_PRINT("info", ("Reading user information over SSL layer")); - if ((pkt_len=my_net_read(net)) == packet_error || + if ((pkt_len= my_net_read(net)) == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE) { DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", @@ -740,25 +777,6 @@ check_connections(THD *thd) return(ER_HANDSHAKE_ERROR); } - user= end; - passwd= strend(user)+1; - db=0; - using_password= test(passwd[0]); - if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) - { - db= strend(passwd)+1; - uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1, - system_charset_info, - db, strlen(db), - thd->charset()); - db_buff[length]= 0; - db= db_buff; - } - - /* We can get only old hash at this point */ - if (using_password && strlen(passwd) != SCRAMBLE_LENGTH) - return ER_HANDSHAKE_ERROR; - if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && @@ -766,60 +784,36 @@ check_connections(THD *thd) net->return_status= &thd->server_status; net->read_timeout=(uint) thd->variables.net_read_timeout; - /* Simple connect only for old clients. New clients always use secure auth */ - bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION)); + char *user= end; + char *passwd= strend(user)+1; + char *db= passwd; + char db_buff[NAME_LEN+1]; // buffer to store db in utf8 + /* + Old clients send null-terminated string as password; new clients send + the size (1 byte) + string (not null-terminated). Hence in case of empty + password both send '\0'. + */ + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? + db + passwd_len + 1 : 0; - /* Check user permissions. If password failure we'll get scramble back */ - if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect, - simple_connect, prepared_scramble, using_password, - &cur_priv_version, - &cached_user)) < 0) + /* Since 4.1 all database names are stored in utf8 */ + if (db) { - /* Store current used and database as they are erased with next packet */ - char tmp_user[USERNAME_LENGTH+1]; - char tmp_db[NAME_LEN+1]; - - /* If the client is old we just have to return error */ - if (simple_connect) - return -1; - - DBUG_PRINT("info",("password challenge")); - - tmp_user[0]= tmp_db[0]= 0; - if (user) - strmake(tmp_user,user,USERNAME_LENGTH); - if (db) - strmake(tmp_db,db,NAME_LEN); + uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1, + system_charset_info, + db, strlen(db), + thd->charset()); + db_buff[length]= 0; + db= db_buff; + } - /* Write hash and encrypted scramble to client */ - if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || - net_flush(net)) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* Reading packet back */ - if ((pkt_len= my_net_read(net)) == packet_error) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* We have to get very specific packet size */ - if (pkt_len != SCRAMBLE41_LENGTH) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* Final attempt to check the user based on reply */ - if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos, - tmp_db, 1, 0, 1, prepared_scramble, using_password, - &cur_priv_version, - &cached_user)) - return -1; - } - else if (res) - return -1; // Error sent from check_user() - return 0; + if (thd->user) + x_free(thd->user); + if (!(thd->user= my_strdup(user, MYF(0)))) + return (ER_OUT_OF_RESOURCES); + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true); } @@ -876,7 +870,7 @@ pthread_handler_decl(handle_one_connection,arg) NET *net= &thd->net; thd->thread_stack= (char*) &thd; - if ((error=check_connections(thd))) + if ((error=check_connection(thd))) { // Wrong permissions if (error > 0) net_printf(thd,error,thd->host_or_ip); @@ -1161,7 +1155,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_log.write(thd,command,"%s",thd->db); break; } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case COM_REGISTER_SLAVE: { if (!register_slave(thd, (uchar*)packet, packet_length)) @@ -1188,116 +1182,72 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_CHANGE_USER: { thd->change_user(); - thd->clear_error(); // If errors from rollback + thd->clear_error(); // if errors from rollback - statistic_increment(com_other,&LOCK_status); - char *user= (char*) packet; + statistic_increment(com_other, &LOCK_status); + char *user= (char*) packet; char *passwd= strend(user)+1; - char *db= strend(passwd)+1; - - /* Save user and privileges */ - uint save_master_access=thd->master_access; - uint save_db_access= thd->db_access; - uint save_db_length= thd->db_length; - char *save_user= thd->user; - thd->user=NULL; /* Needed for check_user to allocate new user */ - char *save_priv_user= thd->priv_user; - char *save_db= thd->db; - USER_CONN *save_uc= thd->user_connect; - bool simple_connect; - bool using_password; - char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */ - char tmp_user[USERNAME_LENGTH+1]; - char tmp_db[NAME_LEN+1]; - ACL_USER* cached_user ; /* Cached user */ - uint cur_priv_version; /* Cached grant version */ - int res; - ulong pkt_len= 0; /* Length of reply packet */ - - bzero((char*) prepared_scramble, sizeof(prepared_scramble)); + /* + Old clients send null-terminated string ('\0' for empty string) for + password. New clients send the size (1 byte) + string (not null + terminated, so also '\0' for empty string). + */ + char *db= passwd; + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db+= passwd_len + 1; /* Small check for incomming packet */ - if ((uint) ((uchar*) db - net->read_pos) > packet_length) - goto restore_user_err; - - /* Now we shall basically perform authentication again */ - - /* We can get only old hash at this point */ - if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH) - goto restore_user_err; - - cached_user= NULL; - - /* Simple connect only for old clients. New clients always use sec. auth*/ - simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION)); - - /* Store information if we used password. passwd will be dammaged */ - using_password=test(passwd[0]); + { + send_error(thd, ER_UNKNOWN_COM_ERROR); + break; + } - if (simple_connect) /* Restore scramble for old clients */ - memcpy(thd->scramble,thd->old_scramble,9); + /* Convert database name to utf8 */ + String convdb; + convdb.copy(db, strlen(db), thd->variables.character_set_client, + system_charset_info); + db= convdb.c_ptr(); - /* - Check user permissions. If password failure we'll get scramble back - Do not retry if we already have sent error (result>0) - */ - if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, - simple_connect, simple_connect, prepared_scramble, - using_password, &cur_priv_version, &cached_user)) < 0) + /* Save user and privileges */ + uint save_master_access= thd->master_access; + uint save_db_access= thd->db_access; + uint save_db_length= thd->db_length; + char *save_user= thd->user; + char *save_priv_user= thd->priv_user; + char *save_db= thd->db; + USER_CONN *save_uc= thd->user_connect; + thd->user= my_strdup(user, MYF(0)); + if (!thd->user) { - /* If the client is old we just have to have auth failure */ - if (simple_connect) - goto restore_user; /* Error is already reported */ - - /* Store current used and database as they are erased with next packet */ - tmp_user[0]= tmp_db[0]= 0; - if (user) - strmake(tmp_user,user,USERNAME_LENGTH); - if (db) - strmake(tmp_db,db,NAME_LEN); - - /* Write hash and encrypted scramble to client */ - if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || - net_flush(net)) - goto restore_user_err; - - /* Reading packet back */ - if ((pkt_len=my_net_read(net)) == packet_error) - goto restore_user_err; - - /* We have to get very specific packet size */ - if (pkt_len != SCRAMBLE41_LENGTH) - goto restore_user; - - /* Final attempt to check the user based on reply */ - if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos, - tmp_db, 0, 0, 1, prepared_scramble, using_password, - &cur_priv_version, &cached_user)) - goto restore_user; + thd->user= save_user; + send_error(thd, ER_OUT_OF_RESOURCES); + break; } - else if (res) - goto restore_user; - - /* Finally we've authenticated new user */ - if (max_connections && save_uc) - decrease_user_connections(save_uc); - x_free((gptr) save_db); - x_free((gptr) save_user); - thd->password=using_password; - break; - /* Bad luck we shall restore old user */ -restore_user_err: - send_error(thd, ER_UNKNOWN_COM_ERROR); + int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); -restore_user: - x_free(thd->user); - thd->master_access=save_master_access; - thd->db_access=save_db_access; - thd->db=save_db; - thd->db_length=save_db_length; - thd->user=save_user; - thd->priv_user=save_priv_user; + if (res) + { + /* authentification failure, we shall restore old user */ + if (res > 0) + send_error(thd, ER_UNKNOWN_COM_ERROR); + x_free(thd->user); + thd->user= save_user; + thd->priv_user= save_priv_user; + thd->master_access= save_master_access; + thd->db_access= save_db_access; + thd->db= save_db; + thd->db_length= save_db_length; + } + else + { + /* we've authenticated new user */ + if (max_connections && save_uc) + decrease_user_connections(save_uc); + x_free((gptr) save_db); + x_free((gptr) save_user); + } break; } #endif /* EMBEDDED_LIBRARY */ @@ -1711,7 +1661,7 @@ mysql_execute_command(THD *thd) } #endif } -#endif /* EMBEDDED_LIBRARY */ +#endif /* !EMBEDDED_LIBRARY */ /* TODO: make derived tables processing 'inside' SELECT processing. TODO: solve problem with depended derived tables in subselects @@ -1887,7 +1837,7 @@ mysql_execute_command(THD *thd) break; } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_SHOW_SLAVE_HOSTS: { if (check_global_access(thd, REPL_SLAVE_ACL)) @@ -1933,7 +1883,7 @@ mysql_execute_command(THD *thd) } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_CHANGE_MASTER: { if (check_global_access(thd, SUPER_ACL)) @@ -1970,7 +1920,7 @@ mysql_execute_command(THD *thd) else res = load_master_data(thd); break; -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: @@ -1982,7 +1932,7 @@ mysql_execute_command(THD *thd) } #endif -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_LOAD_MASTER_TABLE: { if (!tables->db) @@ -2014,7 +1964,7 @@ mysql_execute_command(THD *thd) UNLOCK_ACTIVE_MI; break; } -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ case SQLCOM_CREATE_TABLE: { @@ -2131,7 +2081,7 @@ mysql_execute_command(THD *thd) res = mysql_create_index(thd, tables, lex->key_list); break; -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_SLAVE_START: { LOCK_ACTIVE_MI; @@ -2164,7 +2114,7 @@ mysql_execute_command(THD *thd) UNLOCK_ACTIVE_MI; break; } -#endif +#endif /* HAVE_REPLICATION */ case SQLCOM_ALTER_TABLE: #if defined(DONT_ALLOW_SHOW_COMMANDS) @@ -2285,6 +2235,14 @@ mysql_execute_command(THD *thd) break; } #endif + case SQLCOM_CHECKSUM: + { + if (check_db_used(thd,tables) || + check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables)) + goto error; /* purecov: inspected */ + res = mysql_checksum_table(thd, tables, &lex->check_opt); + break; + } case SQLCOM_REPAIR: { if (check_db_used(thd,tables) || @@ -2662,8 +2620,10 @@ mysql_execute_command(THD *thd) break; #endif case SQLCOM_SHOW_PROCESSLIST: +#ifndef EMBEDDED_LIBRARY if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) break; +#endif mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS : thd->priv_user,lex->verbose); break; @@ -2797,7 +2757,7 @@ mysql_execute_command(THD *thd) case SQLCOM_CHANGE_DB: mysql_change_db(thd,select_lex->db); break; -#ifndef EMBEDDED_LIBRARY + case SQLCOM_LOAD: { uint privilege= (lex->duplicates == DUP_REPLACE ? @@ -2824,7 +2784,7 @@ mysql_execute_command(THD *thd) lex->duplicates, (bool) lex->local_file, lex->lock_option); break; } -#endif /* EMBEDDED_LIBRARY */ + case SQLCOM_SET_OPTION: if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) || (res= open_and_lock_tables(thd,tables)))) @@ -3247,7 +3207,7 @@ error: Check grants for commands which work only with one table and all other tables belong to subselects. - SYNOPSYS + SYNOPSIS single_table_command_access() thd - Thread handler privilege - asked privelage @@ -4418,7 +4378,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, refresh_status(); if (options & REFRESH_THREADS) flush_thread_cache(); -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION if (options & REFRESH_MASTER) { tmp_write_to_binlog= 0; @@ -4433,7 +4393,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, result=load_des_key_file(des_key_file); } #endif -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION if (options & REFRESH_SLAVE) { tmp_write_to_binlog= 0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 550e4bbe086..4abbbcaff1f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -873,11 +873,21 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); + + // save WHERE clause pointers to avoid damaging they by optimisation + for (SELECT_LEX *sl= thd->lex.all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + sl->prep_where= sl->where; + } + if (init_param_items(&stmt)) goto err; + - stmt.mem_root= stmt.thd->mem_root; + stmt.mem_root= stmt.thd->mem_root; tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0); thd->mem_root= thd_root; // restore main mem_root DBUG_RETURN(0); @@ -919,6 +929,16 @@ void mysql_stmt_execute(THD *thd, char *packet) LEX thd_lex= thd->lex; thd->lex= stmt->lex; + + for (SELECT_LEX *sl= stmt->lex.all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + // copy WHERE clause pointers to avoid damaging they by optimisation + if (sl->prep_where) + sl->where= sl->prep_where->copy_andor_structure(thd); + DBUG_ASSERT(sl->join == 0); + } init_stmt_execute(stmt); if (stmt->param_count && setup_params_data(stmt)) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 3cdf033c477..229fa770b0e 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -949,6 +949,25 @@ int change_master(THD* thd, MASTER_INFO* mi) mi->port = lex_mi->port; if (lex_mi->connect_retry) mi->connect_retry = lex_mi->connect_retry; + + if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED) + mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE); + if (lex_mi->ssl_ca) + strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1); + if (lex_mi->ssl_capath) + strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1); + if (lex_mi->ssl_cert) + strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1); + if (lex_mi->ssl_cipher) + strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1); + if (lex_mi->ssl_key) + strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1); +#ifndef HAVE_OPENSSL + if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath || + lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS)); +#endif if (lex_mi->relay_log_name) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 15d6b3954ff..5d96f6aeee1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -117,10 +117,8 @@ static Item* part_of_refkey(TABLE *form,Field *field); static uint find_shortest_key(TABLE *table, key_map usable_keys); static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, ha_rows select_limit, bool no_changes); -static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, +static int create_sort_index(THD *thd, JOIN *join, ORDER *order, ha_rows filesort_limit, ha_rows select_limit); -static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, - ha_rows select_limit); static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields, Item *having); static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field, @@ -326,8 +324,8 @@ JOIN::prepare(Item ***rref_pointer_array, { Item_subselect::trans_res res; if ((res= subselect->select_transformer(this)) != - Item_subselect::OK) - DBUG_RETURN((res == Item_subselect::ERROR)); + Item_subselect::RES_OK) + DBUG_RETURN((res == Item_subselect::RES_ERROR)); } } @@ -916,7 +914,7 @@ JOIN::optimize() { DBUG_PRINT("info",("Sorting for group")); thd->proc_info="Sorting for group"; - if (create_sort_index(thd, &join_tab[const_tables], group_list, + if (create_sort_index(thd, this, group_list, HA_POS_ERROR, HA_POS_ERROR) || alloc_group_fields(this, group_list) || make_sum_func_list(all_fields, fields_list, 1)) @@ -931,7 +929,7 @@ JOIN::optimize() { DBUG_PRINT("info",("Sorting for order")); thd->proc_info="Sorting for order"; - if (create_sort_index(thd, &join_tab[const_tables], order, + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) DBUG_RETURN(1); order=0; @@ -1005,12 +1003,6 @@ JOIN::reinit() /* Reset of sum functions */ first_record= 0; - if (sum_funcs) - { - Item_sum *func, **func_ptr= sum_funcs; - while ((func= *(func_ptr++))) - func->null_value= 1; - } if (exec_tmp_table1) { @@ -1045,6 +1037,7 @@ JOIN::exec() DBUG_ENTER("JOIN::exec"); error= 0; + thd->limit_found_rows= thd->examined_row_count= 0; if (procedure) { if (procedure->change_columns(fields_list) || @@ -1235,7 +1228,7 @@ JOIN::exec() if (curr_join->group_list) { thd->proc_info= "Creating sort index"; - if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list, + if (create_sort_index(thd, curr_join, curr_join->group_list, HA_POS_ERROR, HA_POS_ERROR) || make_group_fields(this, curr_join)) { @@ -1416,7 +1409,7 @@ JOIN::exec() } } } - if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables], + if (create_sort_index(thd, curr_join, curr_join->group_list ? curr_join->group_list : curr_join->order, curr_join->select_limit, unit->select_limit_cnt)) @@ -1427,6 +1420,8 @@ JOIN::exec() thd->proc_info="Sending data"; error= thd->net.report_error || do_select(curr_join, curr_fields_list, NULL, procedure); + thd->limit_found_rows= curr_join->send_records; + thd->examined_row_count= curr_join->examined_rows; DBUG_VOID_RETURN; } @@ -1549,8 +1544,6 @@ err: (join->tmp_join->error=join->error,join->tmp_join): join); - thd->limit_found_rows= curr_join->send_records; - thd->examined_row_count= curr_join->examined_rows; thd->proc_info="end"; err= join->cleanup(); if (thd->net.report_error) @@ -2461,7 +2454,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) Constant tables are ignored. To avoid bad matches, we don't make ref_table_rows less than 100. */ - keyuse->ref_table_rows= ~(table_map) 0; // If no ref + keyuse->ref_table_rows= ~(ha_rows) 0; // If no ref if (keyuse->used_tables & (map= (keyuse->used_tables & ~join->const_table_map & ~OUTER_REF_TABLE_BIT))) @@ -4796,7 +4789,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, keyinfo->algorithm= HA_KEY_ALG_UNDEF; for (; group ; group=group->next,key_part_info++) { - Field *field=(*group->item)->tmp_table_field(); + Field *field=(*group->item)->get_tmp_table_field(); bool maybe_null=(*group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -5980,8 +5973,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!join->first_record) { /* No matching rows for group function */ - clear_tables(join); - copy_fields(&join->tmp_table_param); + join->clear(); } if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having @@ -6065,7 +6057,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), Item *item= *group->item; if (item->maybe_null) { - Field *field=item->tmp_table_field(); + Field *field=item->get_tmp_table_field(); field->ptr[-1]= (byte) (field->is_null() ? 1 : 0); } } @@ -6247,8 +6239,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!join->first_record) { /* No matching rows for group function */ - clear_tables(join); - copy_fields(&join->tmp_table_param); + join->clear(); } copy_sum_funcs(join->sum_funcs); if (!join->having || join->having->val_int()) @@ -6770,16 +6761,23 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ static int -create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, +create_sort_index(THD *thd, JOIN *join, ORDER *order, ha_rows filesort_limit, ha_rows select_limit) { SORT_FIELD *sortorder; uint length; ha_rows examined_rows; - TABLE *table=tab->table; - SQL_SELECT *select=tab->select; + TABLE *table; + SQL_SELECT *select; + JOIN_TAB *tab; DBUG_ENTER("create_sort_index"); + if (join->tables == join->const_tables) + DBUG_RETURN(0); // One row, no need to sort + tab= join->join_tab + join->const_tables; + table= tab->table; + select= tab->select; + if (test_if_skip_sort_order(tab,order,select_limit,0)) DBUG_RETURN(0); if (!(sortorder=make_unireg_sortorder(order,&length))) @@ -6928,7 +6926,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) Item *item; while ((item=it++)) { - if (item->tmp_table_field() && ! item->const_item()) + if (item->get_tmp_table_field() && ! item->const_item()) field_count++; } @@ -7164,7 +7162,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length) pos->field= ((Item_field*) (*order->item))->field; else if (order->item[0]->type() == Item::SUM_FUNC_ITEM && !order->item[0]->const_item()) - pos->field= ((Item_sum*) order->item[0])->tmp_table_field(); + pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field(); else if (order->item[0]->type() == Item::COPY_STR_ITEM) { // Blob patch pos->item= ((Item_copy_string*) (*order->item))->item; @@ -7761,7 +7759,7 @@ calc_group_buffer(JOIN *join,ORDER *group) join->group= 1; for (; group ; group=group->next) { - Field *field=(*group->item)->tmp_table_field(); + Field *field=(*group->item)->get_tmp_table_field(); if (field) { if (field->type() == FIELD_TYPE_BLOB) @@ -8105,7 +8103,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, { item_field= item->get_tmp_table_item(thd); } - else if ((field= item->tmp_table_field())) + else if ((field= item->get_tmp_table_field())) { if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) item_field= ((Item_sum*) item)->result_item(field); @@ -8536,6 +8534,26 @@ int JOIN::rollup_send_data(uint idx) return 0; } +/* + clear results if there are not rows found for group + (end_send_group/end_write_group) + + SYNOPSYS + JOIN::clear() +*/ + +void JOIN::clear() +{ + clear_tables(this); + copy_fields(&tmp_table_param); + + if (sum_funcs) + { + Item_sum *func, **func_ptr= sum_funcs; + while ((func= *(func_ptr++))) + func->clear(); + } +} /**************************************************************************** EXPLAIN handling diff --git a/sql/sql_select.h b/sql/sql_select.h index 208eaaea7bd..9ca46a505aa 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -279,6 +279,7 @@ class JOIN :public Sql_alloc Item_sum ***func); int rollup_send_data(uint idx); bool test_in_subselect(Item **where); + void clear(); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9084269f486..7dd2004b664 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -503,6 +503,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Charset",32)); item->maybe_null=1; + field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21)); + item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Create_options",255)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Comment",80)); @@ -588,6 +590,10 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) } str= (table->table_charset ? table->table_charset->name : "default"); protocol->store(str, system_charset_info); + if (file->table_flags() & HA_HAS_CHECKSUM) + protocol->store((ulonglong)file->checksum()); + else + protocol->store_null(); // Checksum { char option_buff[350],*ptr; ptr=option_buff; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 37f8d0d7f4f..6ea7003eba6 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -350,10 +350,10 @@ static int sort_keys(KEY *a, KEY *b) fields List of fields to create keys List of keys to create tmp_table Set to 1 if this is an internal temporary table - (From ALTER TABLE) + (From ALTER TABLE) no_log Don't log the query to binary log. - DESCRIPTION + DESCRIPTION If one creates a temporary table, this is automaticly opened no_log is needed for the case of CREATE ... SELECT, @@ -672,11 +672,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, /* Make SPATIAL to be RTREE by default SPATIAL only on BLOB or at least BINARY, this - actually should be replaced by special GEOM type + actually should be replaced by special GEOM type in near future when new frm file is ready checking for proper key parts number: */ - + if (key_info->flags == HA_SPATIAL) { if (key_info->key_parts != 1) @@ -699,7 +699,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, MYF(0), "RTREE INDEX"); DBUG_RETURN(-1); } - + List_iterator<key_part_spec> cols(key->columns); for (uint column_nr=0 ; (column=cols++) ; column_nr++) { @@ -745,9 +745,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if (!column->length ) { - /* + /* BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case - Lately we'll extend this code to support more dimensions + Lately we'll extend this code to support more dimensions */ column->length=4*sizeof(double); } @@ -798,7 +798,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { } else if (column->length > length || - ((f_is_packed(sql_field->pack_flag) || + ((f_is_packed(sql_field->pack_flag) || ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && (key_info->flags & HA_NOSAME))) && column->length != length)) @@ -899,16 +899,18 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); DBUG_RETURN(-1); } + if (wait_if_global_read_lock(thd, 0)) + DBUG_RETURN(error); VOID(pthread_mutex_lock(&LOCK_open)); if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if (!access(path,F_OK)) { - VOID(pthread_mutex_unlock(&LOCK_open)); if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - DBUG_RETURN(0); - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); - DBUG_RETURN(-1); + error= 0; + else + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto end; } } @@ -946,6 +948,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, error=0; end: VOID(pthread_mutex_unlock(&LOCK_open)); + start_waiting_global_read_lock(thd); thd->proc_info="After create"; DBUG_RETURN(error); } @@ -2558,7 +2561,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, delete_count++; } else - found_count++; + found_count++; } end_read_record(&info); free_io_cache(from); @@ -2590,3 +2593,103 @@ copy_data_between_tables(TABLE *from,TABLE *to, *deleted=delete_count; DBUG_RETURN(error > 0 ? -1 : 0); } + +int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) +{ + TABLE_LIST *table; + List<Item> field_list; + Item *item; + Protocol *protocol= thd->protocol; + DBUG_ENTER("mysql_admin_table"); + + field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); + item->maybe_null= 1; + field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21)); + item->maybe_null= 1; + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(-1); + + for (table = tables; table; table = table->next) + { + char table_name[NAME_LEN*2+2]; + char* db = (table->db) ? table->db : thd->db; + bool fatal_error=0; + TABLE *t; + strxmov(table_name,db ? db : "",".",table->real_name,NullS); + + t=table->table = open_ltable(thd, table, TL_READ_NO_INSERT); +#ifdef EMBEDDED_LIBRARY + thd->net.last_errno= 0; // these errors shouldn't get client +#endif + + protocol->prepare_for_resend(); + protocol->store(table_name, system_charset_info); + + if (!t) + { + protocol->store_null(); + thd->net.last_error[0]=0; + } + else + { + t->pos_in_table_list= table; + + if (t->file->table_flags() & HA_HAS_CHECKSUM && + !(check_opt->flags & T_EXTEND)) + protocol->store((ulonglong)t->file->checksum()); + else if (!(t->file->table_flags() & HA_HAS_CHECKSUM) && + check_opt->flags & T_QUICK) + protocol->store_null(); + else + { + /* calculating table's checksum */ + ha_checksum crc=0; + if (t->file->rnd_init(1)) + protocol->store_null(); + else + { + while (!t->file->rnd_next(t->record[0])) + { + ha_checksum row_crc=0; + if (t->record[0] != t->field[0]->ptr) + row_crc=my_checksum(row_crc, t->record[0], + t->field[0]->ptr - t->record[0]); + + for (uint i=0; i < t->fields; i++ ) + { + Field *f=t->field[i]; + if (f->type() == FIELD_TYPE_BLOB) + { + String tmp; + f->val_str(&tmp,&tmp); + row_crc=my_checksum(row_crc, tmp.ptr(), tmp.length()); + } + else + row_crc=my_checksum(row_crc, f->ptr, f->pack_length()); + } + + crc+=row_crc; + } + protocol->store((ulonglong)crc); + } + } +#ifdef EMBEDDED_LIBRARY + thd->net.last_errno= 0; // these errors shouldn't get client +#endif + + close_thread_tables(thd); + table->table=0; // For query cache + } + if (protocol->write()) + goto err; + } + + send_eof(thd); + DBUG_RETURN(0); + err: + close_thread_tables(thd); // Shouldn't be needed + if (table) + table->table=0; + DBUG_RETURN(-1); +} + diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index d191550f396..99410bb34ac 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -92,10 +92,13 @@ static void init_syms(udf_func *tmp) tmp->func_deinit = dlsym(tmp->dlhandle, nm); if (tmp->type == UDFTYPE_AGGREGATE) { - (void)strmov( end, "_reset" ); - tmp->func_reset = dlsym( tmp->dlhandle, nm ); + (void)strmov( end, "_clear" ); + tmp->func_clear = dlsym( tmp->dlhandle, nm ); (void)strmov( end, "_add" ); tmp->func_add = dlsym( tmp->dlhandle, nm ); + /* Give error if _clear and _add doesn't exists */ + if (!tmp->func_clear || ! tmp->func_add) + tmp->func= 0; } } @@ -417,7 +420,7 @@ int mysql_create_function(THD *thd,udf_func *udf) u_d->func=udf->func; u_d->func_init=udf->func_init; u_d->func_deinit=udf->func_deinit; - u_d->func_reset=udf->func_reset; + u_d->func_clear=udf->func_clear; u_d->func_add=udf->func_add; /* create entry in mysql/func table */ @@ -429,7 +432,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; - restore_record(table,default_values); // Get default values for fields + restore_record(table,default_values); // Default values for fields table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info); table->field[1]->store((longlong) u_d->returns); table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info); diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 29a351ac52f..7b10b80f148 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -33,7 +33,7 @@ typedef struct st_udf_func void *func; void *func_init; void *func_deinit; - void *func_reset; + void *func_clear; void *func_add; ulong usage_count; } udf_func; @@ -49,7 +49,7 @@ class udf_handler :public Sql_alloc UDF_ARGS f_args; UDF_INIT initid; char *num_buffer; - uchar error; + uchar error, is_null; bool initialized; Item **args; @@ -57,7 +57,7 @@ class udf_handler :public Sql_alloc table_map used_tables_cache; bool const_item_cache; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), - initialized(0) + is_null(0), initialized(0) {} ~udf_handler(); const char *name() const { return u_d ? u_d->name.str : "?"; } @@ -73,7 +73,6 @@ class udf_handler :public Sql_alloc *null_value=1; return 0.0; } - uchar is_null=0; double (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= (double (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func; double tmp=func(&initid, &f_args, &is_null, &error); @@ -92,7 +91,6 @@ class udf_handler :public Sql_alloc *null_value=1; return LL(0); } - uchar is_null=0; longlong (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= (longlong (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func; longlong tmp=func(&initid, &f_args, &is_null, &error); @@ -104,22 +102,15 @@ class udf_handler :public Sql_alloc *null_value=0; return tmp; } - void reset(my_bool *null_value) + void clear() { - uchar is_null=0; - if (get_arguments()) - { - *null_value=1; - return; - } - void (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= - (void (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func_reset; - func(&initid, &f_args, &is_null, &error); - *null_value= (my_bool) (is_null || error); + is_null= 0; + void (*func)(UDF_INIT *, uchar *, uchar *)= + (void (*)(UDF_INIT *, uchar *, uchar *)) u_d->func_clear; + func(&initid, &is_null, &error); } void add(my_bool *null_value) { - uchar is_null=0; if (get_arguments()) { *null_value=1; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index ae91b0b3ace..55f697e9981 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -116,7 +116,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, bool tables_and_fields_initied) { SELECT_LEX *lex_select_save= thd->lex.current_select; - SELECT_LEX *select_cursor; + SELECT_LEX *select_cursor,*sl; DBUG_ENTER("st_select_lex_unit::prepare"); if (prepared) @@ -130,7 +130,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, t_and_f= tables_and_fields_initied; bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM)); - thd->lex.current_select= select_cursor= first_select_in_union(); + thd->lex.current_select= sl= select_cursor= first_select_in_union(); /* Global option */ if (t_and_f) { @@ -185,7 +185,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, union_result->not_describe=1; union_result->tmp_table_param=tmp_table_param; - for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) + for (;sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK, @@ -195,7 +195,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR && !sl->braces) + if (select_limit_cnt == HA_POS_ERROR || sl->braces) sl->options&= ~OPTION_FOUND_ROWS; res= join->prepare(&sl->ref_pointer_array, @@ -256,7 +256,7 @@ int st_select_lex_unit::exec() } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { - ha_rows rows= 0; + ha_rows records_at_start= 0; thd->lex.current_select= sl; if (optimized) @@ -267,12 +267,15 @@ int st_select_lex_unit::exec() select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) + if (select_limit_cnt == HA_POS_ERROR || sl->braces) sl->options&= ~OPTION_FOUND_ROWS; - else if (found_rows_for_union) + else { - rows= sl->select_limit; - sl->options|= OPTION_FOUND_ROWS; + /* + We are doing an union without braces. In this case + SQL_CALC_FOUND_ROWS should be done on all sub parts + */ + sl->options|= found_rows_for_union; } /* @@ -301,6 +304,7 @@ int st_select_lex_unit::exec() } if (!res) { + records_at_start= table->file->records; sl->join->exec(); res= sl->join->error; if (!res && union_result->flush()) @@ -314,10 +318,17 @@ int st_select_lex_unit::exec() thd->lex.current_select= lex_select_save; DBUG_RETURN(res); } - if (found_rows_for_union && !sl->braces && - (sl->options & OPTION_FOUND_ROWS)) - add_rows+= (sl->join->send_records > rows) ? - sl->join->send_records - rows : 0; + if (found_rows_for_union & sl->options) + { + /* + This is a union without braces. Remember the number of rows that could + also have been part of the result set. + We get this from the difference of between total number of possible + rows and actual rows added to the temporary table. + */ + add_rows+= (ha_rows) (thd->limit_found_rows - (ulonglong) + ((table->file->records - records_at_start))); + } } } optimized= 1; @@ -382,12 +393,8 @@ int st_select_lex_unit::exec() (ORDER*) NULL, NULL, (ORDER*) NULL, options | SELECT_NO_UNLOCK, result, this, fake_select_lex, 0); - if (found_rows_for_union && !res) - { - thd->limit_found_rows= table->file->records; - if (!select_cursor->braces) - thd->limit_found_rows+= add_rows; - } + if (!res) + thd->limit_found_rows = (ulonglong)table->file->records + add_rows; /* Mark for slow query log if any of the union parts didn't use indexes efficiently diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 539bb90d907..b84a21b1440 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -277,6 +277,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MASTER_PORT_SYM %token MASTER_CONNECT_RETRY_SYM %token MASTER_SERVER_ID_SYM +%token MASTER_SSL_SYM +%token MASTER_SSL_CA_SYM +%token MASTER_SSL_CAPATH_SYM +%token MASTER_SSL_CERT_SYM +%token MASTER_SSL_CIPHER_SYM +%token MASTER_SSL_KEY_SYM %token RELAY_LOG_FILE_SYM %token RELAY_LOG_POS_SYM %token MATCH @@ -500,6 +506,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MULTIPOINT %token MULTIPOLYGON %token NOW_SYM +%token OLD_PASSWORD %token PASSWORD %token POINTFROMTEXT %token POINT_SYM @@ -671,7 +678,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); show describe load alter optimize preload flush reset purge begin commit rollback savepoint slave master_def master_defs - repair restore backup analyze check start + repair restore backup analyze check start checksum field_list field_list_item field_spec kill column_def key_def preload_list preload_keys select_item_list select_item values_list no_braces @@ -729,23 +736,26 @@ verb_clause: | begin | change | check + | checksum | commit | create | delete | describe | do | drop + | flush | grant + | handler + | help | insert - | flush + | kill | load | lock - | kill | optimize | preload | purge | rename - | repair + | repair | replace | reset | restore @@ -754,15 +764,14 @@ verb_clause: | savepoint | select | set + | show | slave | start - | show | truncate - | handler | unlock | update | use - | help; + ; /* help */ @@ -850,6 +859,31 @@ master_def: /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); } + | MASTER_SSL_SYM EQ ULONG_NUM + { + Lex->mi.ssl= $3 ? + LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE; + } + | MASTER_SSL_CA_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_ca= $3.str; + } + | MASTER_SSL_CAPATH_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_capath= $3.str; + } + | MASTER_SSL_CERT_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_cert= $3.str; + } + | MASTER_SSL_CIPHER_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_cipher= $3.str; + } + | MASTER_SSL_KEY_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_key= $3.str; + } ; @@ -1099,7 +1133,7 @@ opt_select_from: | select_from select_lock_type; udf_func_type: - /* empty */ { $$ = UDFTYPE_FUNCTION; } + /* empty */ { $$ = UDFTYPE_FUNCTION; } | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; }; udf_type: @@ -1566,7 +1600,7 @@ opt_ident: opt_component: /* empty */ { $$.str= 0; $$.length= 0; } | '.' ident { $$=$2; }; - + string_list: text_string { Lex->interval_list.push_back($1); } | string_list ',' text_string { Lex->interval_list.push_back($3); }; @@ -1773,6 +1807,22 @@ backup: Lex->backup_dir = $6.str; }; +checksum: + CHECKSUM_SYM table_or_tables + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_CHECKSUM; + } + table_list opt_checksum_type + {} + ; + +opt_checksum_type: + /* nothing */ { Lex->check_opt.flags= 0; } + | QUICK { Lex->check_opt.flags= T_QUICK; } + | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; } + ; + repair: REPAIR opt_no_write_to_binlog table_or_tables { @@ -1962,8 +2012,9 @@ select_init: YYABORT; } /* select in braces, can't contain global parameters */ - sel->master_unit()->global_parameters= - sel->master_unit()->fake_select_lex; + if (sel->master_unit()->fake_select_lex) + sel->master_unit()->global_parameters= + sel->master_unit()->fake_select_lex; } union_opt; select_init2: @@ -2576,9 +2627,13 @@ simple_expr: | NOW_SYM '(' expr ')' { $$= new Item_func_now_local($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' - { $$= new Item_func_password($3); } - | PASSWORD '(' expr ',' expr ')' - { $$= new Item_func_password($3,$5); } + { + $$= YYTHD->variables.old_passwords ? + (Item *) new Item_func_old_password($3) : + (Item *) new Item_func_password($3); + } + | OLD_PASSWORD '(' expr ')' + { $$= new Item_func_old_password($3); } | POINT_SYM '(' expr ',' expr ')' { $$= new Item_func_point($3,$5); } | POINTFROMTEXT '(' expr ')' @@ -3382,7 +3437,7 @@ do: DO_SYM */ drop: - DROP opt_temporary TABLE_SYM if_exists table_list opt_restrict + DROP opt_temporary table_or_tables if_exists table_list opt_restrict { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_TABLE; @@ -4380,6 +4435,7 @@ keyword: | BOOL_SYM {} | BOOLEAN_SYM {} | BYTE_SYM {} + | BTREE_SYM {} | CACHE_SYM {} | CHANGED {} | CHARSET {} @@ -4408,6 +4464,7 @@ keyword: | DYNAMIC_SYM {} | END {} | ENUM {} + | ERRORS {} | ESCAPE_SYM {} | EVENTS_SYM {} | EXECUTE_SYM {} @@ -4425,6 +4482,7 @@ keyword: | GRANTS {} | GLOBAL_SYM {} | HANDLER_SYM {} + | HASH_SYM {} | HEAP_SYM {} | HELP_SYM {} | HOSTS_SYM {} @@ -4453,6 +4511,12 @@ keyword: | MASTER_USER_SYM {} | MASTER_PASSWORD_SYM {} | MASTER_CONNECT_RETRY_SYM {} + | MASTER_SSL_SYM {} + | MASTER_SSL_CA_SYM {} + | MASTER_SSL_CAPATH_SYM {} + | MASTER_SSL_CERT_SYM {} + | MASTER_SSL_CIPHER_SYM {} + | MASTER_SSL_KEY_SYM {} | MAX_CONNECTIONS_PER_HOUR {} | MAX_QUERIES_PER_HOUR {} | MAX_UPDATES_PER_HOUR {} @@ -4477,6 +4541,7 @@ keyword: | NO_SYM {} | NONE_SYM {} | OFFSET_SYM {} + | OLD_PASSWORD {} | OPEN_SYM {} | PACK_KEYS_SYM {} | PARTIAL {} @@ -4507,6 +4572,7 @@ keyword: | ROWS_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} + | RTREE_SYM {} | SAVEPOINT_SYM {} | SECOND_SYM {} | SERIAL_SYM {} @@ -4543,6 +4609,7 @@ keyword: | USE_FRM {} | VARIABLES {} | VALUE_SYM {} + | WARNINGS {} | WORK_SYM {} | X509_SYM {} | YEAR_SYM {} @@ -4699,15 +4766,15 @@ text_or_password: TEXT_STRING { $$=$1.str;} | PASSWORD '(' TEXT_STRING ')' { - if (!$3.length) - $$=$3.str; - else - { - char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); - make_scrambled_password(buff,$3.str,use_old_passwords, - &YYTHD->rand); - $$=buff; - } + $$= $3.length ? YYTHD->variables.old_passwords ? + Item_func_old_password::alloc(YYTHD, $3.str) : + Item_func_password::alloc(YYTHD, $3.str) : + $3.str; + } + | OLD_PASSWORD '(' TEXT_STRING ')' + { + $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) : + $3.str; } ; @@ -4883,7 +4950,7 @@ grant_privilege_list: | grant_privilege_list ',' grant_privilege; grant_privilege: - SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {} + SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {} | INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {} | UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {} | REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list {} @@ -5015,14 +5082,24 @@ grant_user: $$=$1; $1->password=$4; if ($4.length) { - char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); - if (buff) - { - make_scrambled_password(buff,$4.str,use_old_passwords, - &YYTHD->rand); - $1->password.str=buff; - $1->password.length=HASH_PASSWORD_LENGTH; - } + if (YYTHD->variables.old_passwords) + { + char *buff= + (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, $4.str); + $1->password.str= buff; + $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; + } + else + { + char *buff= + (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, $4.str); + $1->password.str= buff; + $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; + } } } | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING @@ -5181,7 +5258,7 @@ union_opt: ; optional_order_or_limit: - /* Empty */ {} + /* Empty */ {} | { THD *thd= YYTHD; @@ -5276,3 +5353,4 @@ subselect_end: LEX *lex=Lex; lex->current_select = lex->current_select->return_after_parsing(); }; + diff --git a/sql/table.cc b/sql/table.cc index 9d12de1f6c7..a980e086d60 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1207,17 +1207,14 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) char *get_field(MEM_ROOT *mem, Field *field) { - char buff[MAX_FIELD_WIDTH], *to; + char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff),&my_charset_bin); uint length; field->val_str(&str,&str); if (!(length= str.length())) return NullS; - to= (char*) alloc_root(mem,length+1); - memcpy(to, str.ptr(), (uint) length); - to[length]=0; - return to; + return strmake_root(mem, str.ptr(), length); } diff --git a/sql/udf_example.cc b/sql/udf_example.cc index 7f4417bf8fe..ba056a9d2fd 100644 --- a/sql/udf_example.cc +++ b/sql/udf_example.cc @@ -149,6 +149,7 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null, my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message ); void avgcost_deinit( UDF_INIT* initid ); void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); +void avgcost_clear( UDF_INIT* initid, char* is_null, char *error ); void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); } @@ -902,21 +903,29 @@ avgcost_deinit( UDF_INIT* initid ) delete initid->ptr; } + +/* This is only for MySQL 4.0 compability */ void -avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message ) +avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message) { - struct avgcost_data* data = (struct avgcost_data*)initid->ptr; - data->totalprice = 0.0; - data->totalquantity = 0; - data->count = 0; + avgcost_clear(initid, is_null, message); + avgcost_add(initid, args, is_null, message); +} - *is_null = 0; - avgcost_add( initid, args, is_null, message ); +/* This is needed to get things to work in MySQL 4.1.1 and above */ + +void +avgcost_clear(UDF_INIT* initid, char* is_null, char* message) +{ + struct avgcost_data* data = (struct avgcost_data*)initid->ptr; + data->totalprice= 0.0; + data->totalquantity= 0; + data->count= 0; } void -avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message ) +avgcost_add(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message) { if (args->args[0] && args->args[1]) { |