diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 236 |
1 files changed, 190 insertions, 46 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 79cec85927e..5f3875ba934 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -29,12 +29,6 @@ #include <io.h> #endif -#define tmp_disable_binlog(A) \ - ulong save_options= (A)->options; \ - (A)->options&= ~OPTION_BIN_LOG; - -#define reenable_binlog(A) (A)->options= save_options; - const char *primary_key_name="PRIMARY"; static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end); @@ -42,6 +36,7 @@ static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end); static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, enum enum_duplicates handle_duplicates, + bool ignore, uint order_num, ORDER *order, ha_rows *copied,ha_rows *deleted); @@ -282,7 +277,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, if (!error) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, - tmp_table_deleted && !some_tables_deleted); + tmp_table_deleted && !some_tables_deleted, + FALSE); mysql_bin_log.write(&qinfo); } } @@ -392,6 +388,41 @@ void check_duplicates_in_interval(const char *set_or_name, } } + +/* + Check TYPELIB (set or enum) max and total lengths + + SYNOPSIS + calculate_interval_lengths() + cs charset+collation pair of the interval + typelib list of values for the column + max_length length of the longest item + tot_length sum of the item lengths + + DESCRIPTION + After this function call: + - ENUM uses max_length + - SET uses tot_length. + + RETURN VALUES + void +*/ +void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval, + uint32 *max_length, uint32 *tot_length) +{ + const char **pos; + uint *len; + *max_length= *tot_length= 0; + for (pos= interval->type_names, len= interval->type_lengths; + *pos ; pos++, len++) + { + uint length= cs->cset->numchars(cs, *pos, *pos + *len); + *tot_length+= length; + set_if_bigger(*max_length, (uint32)length); + } +} + + /* Preparation for table creation @@ -455,6 +486,93 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } + if (sql_field->sql_type == FIELD_TYPE_SET || + sql_field->sql_type == FIELD_TYPE_ENUM) + { + uint32 dummy; + CHARSET_INFO *cs= sql_field->charset; + TYPELIB *interval= sql_field->interval; + + /* + Create typelib from interval_list, and if necessary + convert strings from client character set to the + column character set. + */ + if (!interval) + { + interval= sql_field->interval= typelib(sql_field->interval_list); + List_iterator<String> it(sql_field->interval_list); + String conv, *tmp; + for (uint i= 0; (tmp= it++); i++) + { + if (String::needs_conversion(tmp->length(), tmp->charset(), + cs, &dummy)) + { + uint cnv_errs; + conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); + char *buf= (char*) sql_alloc(conv.length()+1); + memcpy(buf, conv.ptr(), conv.length()); + buf[conv.length()]= '\0'; + interval->type_names[i]= buf; + interval->type_lengths[i]= conv.length(); + } + + // Strip trailing spaces. + uint lengthsp= cs->cset->lengthsp(cs, interval->type_names[i], + interval->type_lengths[i]); + interval->type_lengths[i]= lengthsp; + ((uchar *)interval->type_names[i])[lengthsp]= '\0'; + } + sql_field->interval_list.empty(); // Don't need interval_list anymore + } + + /* + Convert the default value from client character + set into the column character set if necessary. + */ + if (sql_field->def) + { + sql_field->def= + sql_field->def->safe_charset_converter(cs); + } + + if (sql_field->sql_type == FIELD_TYPE_SET) + { + if (sql_field->def) + { + char *not_used; + uint not_used2; + bool not_found= 0; + String str, *def= sql_field->def->val_str(&str); + def->length(cs->cset->lengthsp(cs, def->ptr(), def->length())); + (void) find_set(interval, def->ptr(), def->length(), + cs, ¬_used, ¬_used2, ¬_found); + if (not_found) + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(-1); + } + } + calculate_interval_lengths(cs, interval, &dummy, &sql_field->length); + sql_field->length+= (interval->count - 1); + } + else /* FIELD_TYPE_ENUM */ + { + if (sql_field->def) + { + String str, *def= sql_field->def->val_str(&str); + def->length(cs->cset->lengthsp(cs, def->ptr(), def->length())); + if (!find_type2(interval, def->ptr(), def->length(), cs)) + { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(-1); + } + } + calculate_interval_lengths(cs, interval, &sql_field->length, &dummy); + } + set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1); + } + sql_field->create_length_to_internal_length(); /* Don't pack keys in old tables if the user has requested this */ @@ -814,8 +932,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } } - else - if (key_info->algorithm == HA_KEY_ALG_RTREE) + else if (key_info->algorithm == HA_KEY_ALG_RTREE) { #ifdef HAVE_RTREE_KEYS if ((key_info->key_parts & 1) == 1) @@ -835,10 +952,12 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, #endif } - List_iterator<key_part_spec> cols(key->columns); + List_iterator<key_part_spec> cols(key->columns), cols2(key->columns); CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++) { + key_part_spec *dup_column; + it.rewind(); field=0; while ((sql_field=it++) && @@ -853,12 +972,18 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, column->field_name); DBUG_RETURN(-1); } - /* for fulltext keys keyseg length is 1 for blobs (it's ignored in - ft code anyway, and 0 (set to column width later) for char's. - it has to be correct col width for char's, as char data are not - prefixed with length (unlike blobs, where ft code takes data length - from a data prefix, ignoring column->length). - */ + while ((dup_column= cols2++) != column) + { + if (!my_strcasecmp(system_charset_info, + column->field_name, dup_column->field_name)) + { + my_printf_error(ER_DUP_FIELDNAME, + ER(ER_DUP_FIELDNAME),MYF(0), + column->field_name); + DBUG_RETURN(-1); + } + } + cols2.rewind(); if (key->type == Key::FULLTEXT) { if ((sql_field->sql_type != FIELD_TYPE_STRING && @@ -1292,7 +1417,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, test(create_info->options & - HA_LEX_CREATE_TMP_TABLE)); + HA_LEX_CREATE_TMP_TABLE), + FALSE); mysql_bin_log.write(&qinfo); } } @@ -1418,7 +1544,6 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } table->file->extra(HA_EXTRA_WRITE_CACHE); DBUG_RETURN(table); - /* Note that leaving the function resets binlogging properties */ } @@ -1734,6 +1859,12 @@ end: } +/* + RETURN VALUES + 0 Message sent to net (admin operation went ok) + -1 Message should be sent by caller + (admin operation or network communication failed) +*/ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt, const char *operator_name, @@ -1766,9 +1897,9 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; - char* db = (table->db) ? table->db : thd->db; + char* db = table->db; bool fatal_error=0; - strxmov(table_name,db ? db : "",".",table->real_name,NullS); + strxmov(table_name, db, ".", table->real_name, NullS); thd->open_options|= extra_open_options; table->table = open_ltable(thd, table, lock_type); @@ -1780,9 +1911,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { - case 1: continue; // error, message written to net - case -1: goto err; // error, message could be written to net - default: ; // should be 0 otherwise + case 1: // error, message written to net + close_thread_tables(thd); + continue; + case -1: // error, message could be written to net + goto err; + default: // should be 0 otherwise + ; } } @@ -2139,6 +2274,8 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, { strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table, reg_ext, NullS); + /* Resolve symlinks (for windows) */ + fn_format(src_path, src_path, "", "", MYF(MY_UNPACK_FILENAME)); if (access(src_path, F_OK)) { my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); @@ -2167,6 +2304,7 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, { strxmov(dst_path, mysql_data_home, "/", db, "/", table_name, reg_ext, NullS); + fn_format(dst_path, dst_path, "", "", MYF(MY_UNPACK_FILENAME)); if (!access(dst_path, F_OK)) goto table_exists; } @@ -2208,7 +2346,8 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, test(create_info->options & - HA_LEX_CREATE_TMP_TABLE)); + HA_LEX_CREATE_TMP_TABLE), + FALSE); mysql_bin_log.write(&qinfo); } res= 0; @@ -2319,7 +2458,7 @@ mysql_discard_or_import_tablespace(THD *thd, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); } err: @@ -2330,7 +2469,11 @@ err: send_ok(thd); DBUG_RETURN(0); } - DBUG_RETURN(error); + + if (error == HA_ERR_ROW_IS_REFERENCED) + my_error(ER_ROW_IS_REFERENCED, MYF(0)); + + DBUG_RETURN(-1); } @@ -2547,7 +2690,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, TABLE_LIST *table_list, List<create_field> &fields, List<Key> &keys, uint order_num, ORDER *order, - enum enum_duplicates handle_duplicates, + enum enum_duplicates handle_duplicates, bool ignore, ALTER_INFO *alter_info, bool do_send_ok) { TABLE *table,*new_table; @@ -2706,7 +2849,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); } if (do_send_ok) @@ -3066,7 +3209,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, copied=deleted=0; if (!new_table->is_view) error=copy_data_between_tables(table,new_table,create_list, - handle_duplicates, + handle_duplicates, ignore, order_num, order, &copied, &deleted); thd->last_insert_id=next_insert_id; // Needed for correct log thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -3091,7 +3234,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } /* Remove link to old table and rename the new one */ close_temporary_table(thd,table->table_cache_key,table_name); - if (rename_temporary_table(thd, new_table, new_db, new_alias)) + /* Should pass the 'new_name' as we store table name in the cache */ + if (rename_temporary_table(thd, new_table, new_db, new_name)) { // Fatal error close_temporary_table(thd,new_db,tmp_name); my_free((gptr) new_table,MYF(0)); @@ -3101,7 +3245,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); } goto end_temporary; @@ -3236,7 +3380,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); } VOID(pthread_cond_broadcast(&COND_refresh)); @@ -3286,6 +3430,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, enum enum_duplicates handle_duplicates, + bool ignore, uint order_num, ORDER *order, ha_rows *copied, ha_rows *deleted) @@ -3305,6 +3450,16 @@ copy_data_between_tables(TABLE *from,TABLE *to, ulong save_sql_mode; DBUG_ENTER("copy_data_between_tables"); + /* + Turn off recovery logging since rollback of an alter table is to + delete the new table so there is no need to log the changes to it. + + This needs to be done before external_lock + */ + error= ha_enable_transaction(thd, FALSE); + if (error) + DBUG_RETURN(-1); + if (!(copy= new Copy_field[to->fields])) DBUG_RETURN(-1); /* purecov: inspected */ @@ -3363,23 +3518,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, goto err; }; - /* - Turn off recovery logging since rollback of an alter table is to - delete the new table so there is no need to log the changes to it. - */ - error= ha_enable_transaction(thd,FALSE); - if (error) - { - error= 1; - goto err; - } - /* Handler must be told explicitly to retrieve all columns, because this function does not set field->query_id in the columns to the current query id */ from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); - if (handle_duplicates == DUP_IGNORE || + if (ignore || handle_duplicates == DUP_REPLACE) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); thd->row_count= 0; @@ -3405,7 +3549,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, } if ((error=to->file->write_row((byte*) to->record[0]))) { - if ((handle_duplicates != DUP_IGNORE && + if ((!ignore && handle_duplicates != DUP_REPLACE) || (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)) @@ -3481,7 +3625,7 @@ int mysql_recreate_table(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info, table_list, lex->create_list, lex->key_list, 0, (ORDER *) 0, - DUP_ERROR, &lex->alter_info, do_send_ok)); + DUP_ERROR, 0, &lex->alter_info, do_send_ok)); } |