diff options
Diffstat (limited to 'sql')
75 files changed, 2090 insertions, 710 deletions
diff --git a/sql/derror.cc b/sql/derror.cc index 78efdcc33f3..7f4068c487e 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -20,27 +20,28 @@ #include "mysql_priv.h" #include "mysys_err.h" -static void read_texts(const char *file_name,const char ***point, +static bool read_texts(const char *file_name,const char ***point, uint error_messages); static void init_myfunc_errs(void); /* Read messages from errorfile */ -void init_errmessage(void) +bool init_errmessage(void) { DBUG_ENTER("init_errmessage"); - read_texts(ERRMSG_FILE,&my_errmsg[ERRMAPP],ER_ERROR_MESSAGES); + if (read_texts(ERRMSG_FILE,&my_errmsg[ERRMAPP],ER_ERROR_MESSAGES)) + DBUG_RETURN(TRUE); errmesg=my_errmsg[ERRMAPP]; /* Init global variabel */ init_myfunc_errs(); /* Init myfunc messages */ - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } /* Read text from packed textfile in language-directory */ /* If we can't read messagefile then it's panic- we can't continue */ -static void read_texts(const char *file_name,const char ***point, +static bool read_texts(const char *file_name,const char ***point, uint error_messages) { register uint i; @@ -116,7 +117,7 @@ Check that the above file is the right version for this program!", point[i]= *point +uint2korr(head+10+i+i); } VOID(my_close(file,MYF(0))); - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); err: switch (funktpos) { diff --git a/sql/field.cc b/sql/field.cc index 68c9922e887..b025f65a798 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -279,7 +279,8 @@ bool Field::get_date(TIME *ltime,bool fuzzydate) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate,current_thd)<= + WRONG_TIMESTAMP_FULL) return 1; return 0; } @@ -289,7 +290,7 @@ bool Field::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_time(res->ptr(),res->length(),ltime)) + str_to_time(res->ptr(),res->length(),ltime,current_thd)) return 1; return 0; } @@ -299,28 +300,29 @@ bool Field::get_time(TIME *ltime) void Field::store_time(TIME *ltime,timestamp_type type) { char buff[25]; + String tmp((char*) buff,sizeof(buff),&my_charset_bin); + DATETIME_FORMAT *tmp_format= 0; + bool is_time_only= 0; + switch (type) { case TIMESTAMP_NONE: + case WRONG_TIMESTAMP_FULL: store("",0,&my_charset_bin); // Probably an error - break; + return; case TIMESTAMP_DATE: - sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); - store(buff,10,&my_charset_bin); + tmp_format= &t_datetime_frm(current_thd, DATE_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_FULL: - sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", - ltime->year,ltime->month,ltime->day, - ltime->hour,ltime->minute,ltime->second); - store(buff,19,&my_charset_bin); + tmp_format=&t_datetime_frm(current_thd,DATETIME_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_TIME: - { - ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", - ltime->hour,ltime->minute,ltime->second)); - store(buff,(uint) length, &my_charset_bin); + tmp_format= &t_datetime_frm(current_thd, TIME_FORMAT_TYPE).datetime_format; + is_time_only= 1; break; } - } + make_datetime(&tmp, ltime, is_time_only, 0, + tmp_format->format, tmp_format->format_length, 1); + store(tmp.ptr(),tmp.length(),&my_charset_bin); } @@ -2691,7 +2693,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp=(long) str_to_timestamp(from,len); + long tmp=(long) str_to_timestamp(from,len,current_thd); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -3025,7 +3027,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) TIME ltime; long tmp; int error= 0; - if (str_to_time(from,len,<ime)) + if (str_to_time(from,len,<ime,current_thd)) { tmp=0L; error= 1; @@ -3134,19 +3136,25 @@ longlong Field_time::val_int(void) String *Field_time::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { + TIME ltime; val_buffer->alloc(16); long tmp=(long) sint3korr(ptr); const char *sign=""; + ltime.neg= 0; if (tmp < 0) { tmp= -tmp; - sign= "-"; - } - long length= my_sprintf((char*) val_buffer->ptr(), - ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", - sign,(int) (tmp/10000), (int) (tmp/100 % 100), - (int) (tmp % 100))); - val_buffer->length(length); + ltime.neg= 1; + } + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, TIME_FORMAT_TYPE).datetime_format); + ltime.day= (uint) 0; + ltime.hour= (uint) (tmp/10000); + ltime.minute= (uint) (tmp/100 % 100); + ltime.second= (uint) (tmp % 100); + make_datetime(val_buffer, <ime, 0, 0, + tmp_format->format, + tmp_format->format_length, 1); return val_buffer; } @@ -3312,7 +3320,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) TIME l_time; uint32 tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE) + if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) { tmp=0; error= 1; @@ -3422,6 +3430,7 @@ longlong Field_date::val_int(void) String *Field_date::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { + TIME ltime; val_buffer->alloc(field_length); val_buffer->length(field_length); int32 tmp; @@ -3431,9 +3440,15 @@ String *Field_date::val_str(String *val_buffer, else #endif longget(tmp,ptr); - sprintf((char*) val_buffer->ptr(),"%04d-%02d-%02d", - (int) ((uint32) tmp/10000L % 10000), (int) ((uint32) tmp/100 % 100), - (int) ((uint32) tmp % 100)); + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, DATE_FORMAT_TYPE).datetime_format); + ltime.neg= 0; + ltime.year= (int) ((uint32) tmp/10000L % 10000); + ltime.month= (int) ((uint32) tmp/100 % 100); + ltime.day= (int) ((uint32) tmp % 100); + make_datetime(val_buffer, <ime, 0, 0, + tmp_format->format, + tmp_format->format_length, 1); return val_buffer; } @@ -3492,7 +3507,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) TIME l_time; long tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE) + if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) { tmp=0L; error= 1; @@ -3661,7 +3676,7 @@ void Field_newdate::sql_type(String &res) const int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) { - longlong tmp=str_to_datetime(from,len,1); + longlong tmp=str_to_datetime(from,len,1,current_thd); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 6510a03f5a6..5f08c91372b 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -119,7 +119,7 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (current_thd->count_cuted_fields) + if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_DATA_TRUNCATED); return 0; @@ -176,7 +176,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= false; return 0; // field is set in handler.cc } - if (current_thd->count_cuted_fields) + if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_NULL_TO_NOTNULL); return 0; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 1b99efeaa43..5b0fc95442c 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -238,7 +238,8 @@ int berkeley_show_logs(Protocol *protocol) MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); DBUG_ENTER("berkeley_show_logs"); - init_alloc_root(&show_logs_root, 1024, 1024); + init_sql_alloc(&show_logs_root, BDB_LOG_ALLOC_BLOCK_SIZE, + BDB_LOG_ALLOC_BLOCK_SIZE); my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root); if ((error= db_env->log_archive(db_env, &all_logs, diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index f1072c3137a..7f8c99f7c15 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1451,7 +1451,7 @@ ha_innobase::open( DBUG_RETURN(1); } - if (ib_table->ibd_file_missing) { + if (ib_table->ibd_file_missing && !current_thd->tablespace_op) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB error:\n" "MySQL is trying to open a table handle but the .ibd file for\n" @@ -3629,6 +3629,42 @@ ha_innobase::create( } /********************************************************************* +Discards or imports an InnoDB tablespace. */ + +int +ha_innobase::discard_or_import_tablespace( +/*======================================*/ + /* out: 0 == success, -1 == error */ + my_bool discard) /* in: TRUE if discard, else import */ +{ + row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + dict_table_t* table; + trx_t* trx; + int err; + + DBUG_ENTER("ha_innobase::discard_or_import_tablespace"); + + ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N); + ut_a(prebuilt->trx == + (trx_t*) current_thd->transaction.all.innobase_tid); + + table = prebuilt->table; + trx = prebuilt->trx; + + if (discard) { + err = row_discard_tablespace_for_mysql(table->name, trx); + } else { + err = row_import_tablespace_for_mysql(table->name, trx); + } + + if (err == DB_SUCCESS) { + DBUG_RETURN(0); + } + + DBUG_RETURN(-1); +} + +/********************************************************************* Drops a table from an InnoDB database. Before calling this function, MySQL calls innobase_commit to commit the transaction of the current user. Then the current user cannot have locks set on the table. Drop table @@ -3647,7 +3683,7 @@ ha_innobase::delete_table( trx_t* trx; char norm_name[1000]; - DBUG_ENTER("ha_innobase::delete_table"); + DBUG_ENTER("ha_innobase::delete_table"); /* Get the transaction associated with the current thd, or create one if not yet created */ @@ -4536,7 +4572,7 @@ ha_innobase::external_lock( update_thd(thd); - if (lock_type != F_UNLCK && prebuilt->table->ibd_file_missing) { + if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB error:\n" "MySQL is trying to use a table handle but the .ibd file for\n" @@ -4546,6 +4582,7 @@ ha_innobase::external_lock( "Look from section 15.1 of http://www.innodb.com/ibman.html\n" "how you can resolve the problem.\n", prebuilt->table->name); + DBUG_RETURN(HA_ERR_CRASHED); } trx = prebuilt->trx; @@ -4793,11 +4830,12 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { - /* If we are not doing a LOCK TABLE, then allow multiple - writers */ + /* If we are not doing a LOCK TABLE or DISCARD/IMPORT + TABLESPACE, then allow multiple writers */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !thd->in_lock_tables) { + lock_type <= TL_WRITE) && !thd->in_lock_tables + && !thd->tablespace_op) { lock_type = TL_WRITE_ALLOW_WRITE; } diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index b17097b3c57..0c89a9d29ce 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -160,6 +160,7 @@ class ha_innobase: public handler void info(uint); int analyze(THD* thd,HA_CHECK_OPT* check_opt); int optimize(THD* thd,HA_CHECK_OPT* check_opt); + int discard_or_import_tablespace(my_bool discard); int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); diff --git a/sql/handler.h b/sql/handler.h index b74e06c6edf..ad209e5cec9 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -169,10 +169,10 @@ typedef struct st_ha_create_information SQL_LIST merge_list; enum db_type db_type; enum row_type row_type; - uint options; /* OR of HA_CREATE_ options */ + uint options; /* OR of HA_CREATE_ options */ uint raid_type,raid_chunks; uint merge_insert_method; - bool if_not_exists; + bool table_existed; /* 1 in create if table existed */ } HA_CREATE_INFO; @@ -317,6 +317,7 @@ public: virtual int dump(THD* thd, int fd = -1) { return ER_DUMP_NOT_IMPLEMENTED; } virtual void deactivate_non_unique_index(ha_rows rows) {} virtual bool activate_all_index(THD *thd) {return 0;} + virtual int discard_or_import_tablespace(my_bool discard) {return -1;} // not implemented by default virtual int net_read_dump(NET* net) { return ER_DUMP_NOT_IMPLEMENTED; } diff --git a/sql/init.cc b/sql/init.cc index 50d504068a0..8b15fef4ee3 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -37,7 +37,9 @@ void unireg_init(ulong options) #ifdef USE_MY_ATOF init_my_atof(); /* use our atof */ #endif +#ifndef EMBEDDED_LIBRARY my_abort_hook=unireg_abort; /* Abort with close of databases */ +#endif VOID(strmov(reg_ext,".frm")); for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS diff --git a/sql/item.cc b/sql/item.cc index 19ea85f123a..c6a27234304 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,7 +46,7 @@ Item::Item(): collation.set(default_charset(), DERIVATION_COERCIBLE); name= 0; decimals= 0; max_length= 0; - THD *thd= current_thd; + thd= current_thd; next= thd->free_list; // Put in free list thd->free_list= this; /* @@ -69,7 +69,7 @@ Item::Item(): Used for duplicating lists in processing queries with temporary tables */ -Item::Item(THD *thd, Item &item): +Item::Item(THD *c_thd, Item &item): str_value(item.str_value), name(item.name), max_length(item.max_length), @@ -82,7 +82,8 @@ Item::Item(THD *thd, Item &item): fixed(item.fixed), collation(item.collation) { - next=thd->free_list; // Put in free list + next=c_thd->free_list; // Put in free list + thd= c_thd; thd->free_list= this; } @@ -187,7 +188,8 @@ bool Item::get_date(TIME *ltime,bool fuzzydate) char buff[40]; String tmp(buff,sizeof(buff), &my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate, thd) <= + WRONG_TIMESTAMP_FULL) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -205,7 +207,7 @@ bool Item::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_time(res->ptr(),res->length(),ltime)) + str_to_time(res->ptr(),res->length(),ltime, thd)) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -285,11 +287,13 @@ Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) } // Constructor need to process subselect with temporary tables (see Item) -Item_field::Item_field(THD *thd, Item_field &item): - Item_ident(thd, item), - field(item.field), - result_field(item.result_field) -{ collation.set(DERIVATION_IMPLICIT); } +Item_field::Item_field(THD *thd, Item_field &item) + :Item_ident(thd, item), + field(item.field), + result_field(item.result_field) +{ + collation.set(DERIVATION_IMPLICIT); +} void Item_field::set_field(Field *field_par) { @@ -680,30 +684,28 @@ String *Item_param::query_val_str(String* str) } else { - char buff[25]; + DATETIME_FORMAT *tmp_format= 0; + bool is_time_only= 0; switch (ltime.time_type) { case TIMESTAMP_NONE: + case WRONG_TIMESTAMP_FULL: break; case TIMESTAMP_DATE: - sprintf(buff, "%04d-%02d-%02d", - ltime.year,ltime.month,ltime.day); - str->append(buff, 10); + tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_FULL: - sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d", - ltime.year,ltime.month,ltime.day, - ltime.hour,ltime.minute,ltime.second); - str->append(buff, 19); + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_TIME: { - sprintf(buff, "%02d:%02d:%02d", - ltime.hour,ltime.minute,ltime.second); - str->append(buff, 8); + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + is_time_only= 1; break; - } + } } + make_datetime(str, <ime, is_time_only, 0, + tmp_format->format, tmp_format->format_length, 0); } str->append("'"); } @@ -1303,6 +1305,14 @@ bool Item::send(Protocol *protocol, String *buffer) result= protocol->store_longlong(nr, unsigned_flag); break; } + case MYSQL_TYPE_FLOAT: + { + float nr; + nr= val(); + if (!null_value) + result= protocol->store(nr, decimals, buffer); + break; + } case MYSQL_TYPE_DOUBLE: { double nr; diff --git a/sql/item.h b/sql/item.h index 78ca5a8f3fe..5f691c9e4e4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -113,6 +113,14 @@ public: my_bool with_sum_func; my_bool fixed; /* If item fixed with fix_fields */ DTCollation collation; + + + /* + thd is current_thd value. Like some other Item's fields it + will be a problem for using one Item in different threads + (as stored procedures may want to do in the future) + */ + THD *thd; // alloc & destruct is done as start of select using sql_alloc Item(); @@ -124,7 +132,7 @@ public: top AND/OR ctructure of WHERE clause to protect it of optimisation changes in prepared statements */ - Item(THD *thd, Item &item); + Item(THD *c_thd, Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length, CHARSET_INFO *cs); void init_make_field(Send_field *tmp_field,enum enum_field_types type); @@ -324,7 +332,7 @@ public: bool long_data_supplied; uint pos_in_query; - Item_param::Item_param(uint position) + Item_param(uint position) { name= (char*) "?"; pos_in_query= position; diff --git a/sql/item_create.cc b/sql/item_create.cc index b1173b9c7b8..fce59d68c1f 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -701,3 +701,8 @@ Item *create_func_maketime(Item* a,Item* b,Item* c) { return new Item_func_maketime(a, b, c); } + +Item *create_func_str_to_date(Item* a,Item* b) +{ + return new Item_func_str_to_date(a, b); +} diff --git a/sql/item_create.h b/sql/item_create.h index c75f4404bad..5d6cbe1d58f 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -149,3 +149,4 @@ Item *create_func_addtime(Item* a,Item* b); Item *create_func_subtime(Item* a,Item* b); Item *create_func_timediff(Item* a,Item* b); Item *create_func_maketime(Item* a,Item* b,Item* c); +Item *create_func_str_to_date(Item* a,Item* b); diff --git a/sql/item_func.cc b/sql/item_func.cc index 5b3e6aa3139..e615167fa90 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2218,6 +2218,9 @@ double user_var_entry::val(my_bool *null_value) return (double) *(longlong*) value; case STRING_RESULT: return atof(value); // This is null terminated + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return 0.0; // Impossible } @@ -2237,6 +2240,9 @@ longlong user_var_entry::val_int(my_bool *null_value) return *(longlong*) value; case STRING_RESULT: return strtoull(value,NULL,10); // String is null terminated + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return LL(0); // Impossible } @@ -2260,6 +2266,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return(str); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 80767fb8866..5afd52e3738 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -33,7 +33,9 @@ #include "md5.h" #include "sha1.h" #include "my_aes.h" +C_MODE_START #include "../mysys/my_static.h" // For soundex_map +C_MODE_END String my_empty_string("",default_charset_info); @@ -2617,11 +2619,12 @@ String *Item_func_uncompress::val_str(String *str) int err= Z_OK; uint code; - if (new_size > MAX_BLOB_WIDTH) + if (new_size > current_thd->variables.max_allowed_packet) { push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, ER_TOO_BIG_FOR_UNCOMPRESS, - ER(ER_TOO_BIG_FOR_UNCOMPRESS),MAX_BLOB_WIDTH); + ER(ER_TOO_BIG_FOR_UNCOMPRESS), + current_thd->variables.max_allowed_packet); null_value= 0; return 0; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b61c19f994d..c26ed45d0cb 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -625,6 +625,20 @@ bool Item_sum_or::add() return 0; } +Item *Item_sum_xor::copy_or_same(THD* thd) +{ + return new (&thd->mem_root) Item_sum_xor(thd, *this); +} + + +bool Item_sum_xor::add() +{ + ulonglong value= (ulonglong) args[0]->val_int(); + if (!args[0]->null_value) + bits^=value; + return 0; +} + Item *Item_sum_and::copy_or_same(THD* thd) { return new (&thd->mem_root) Item_sum_and(thd, *this); @@ -912,6 +926,15 @@ void Item_sum_or::update_field() int8store(res,nr); } +void Item_sum_xor::update_field() +{ + ulonglong nr; + char *res=result_field->ptr; + + nr=uint8korr(res); + nr^= (ulonglong) args[0]->val_int(); + int8store(res,nr); +} void Item_sum_and::update_field() { @@ -1781,8 +1804,8 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i= 0 ; i < arg_count_order ; i++) { ORDER *order_item= order[i]; - Item *item=*order_item->item; - if (item->fix_fields(thd, tables, &item) || item->check_cols(1)) + if ((*order_item->item)->fix_fields(thd, tables, order_item->item) || + (*order_item->item)->check_cols(1)) return 1; } result_field= 0; diff --git a/sql/item_sum.h b/sql/item_sum.h index 36b38c22e08..d454f06ccde 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -485,6 +485,18 @@ class Item_sum_and :public Item_sum_bit Item *copy_or_same(THD* thd); }; +class Item_sum_xor :public Item_sum_bit +{ + public: + Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} + Item_sum_xor(THD *thd, Item_sum_xor &item) :Item_sum_bit(thd, item) {} + bool add(); + void update_field(); + const char *func_name() const { return "bit_xor"; } + Item *copy_or_same(THD* thd); +}; + + /* ** user defined aggregates */ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 511e372e40a..a8c8f9bcf7f 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -57,82 +57,544 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; -enum date_time_format_types -{ - TIME_ONLY= 0, TIME_MICROSECOND, - DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND -}; - -typedef struct date_time_format +uint check_names(String *arr,int item_count,const char *val_ptr, + const char *val_end, uint *val, bool check_part) { - const char* format_str; - uint length; -}; + for (int i= 0; i < item_count; i++) + { + String *tmp=&arr[i]; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) val_ptr, 3, + (const uchar *) tmp->ptr(), 3)) + { + if (check_part) + { + *val= i+1; + return 3; + } -static struct date_time_format date_time_formats[]= + int part_len= tmp->length() - 3; + int val_len= val_end - val_ptr - 3; + if (val_len < part_len) + return 0; + val_ptr+=3; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) val_ptr, part_len, + (const uchar *) tmp->ptr() + 3, part_len)) + { + *val= i+1; + return tmp->length(); + } + return 0; + } + } + return 0; +} + +uint check_val_is_digit(const char *ptr, uint val_len, uint digit_count) { - {"%s%02d:%02d:%02d", 10}, - {"%s%02d:%02d:%02d.%06d", 17}, - {"%04d-%02d-%02d", 10}, - {"%04d-%02d-%02d %02d:%02d:%02d", 19}, - {"%04d-%02d-%02d %02d:%02d:%02d.%06d", 26} -}; + uint i; + uint verify_count= (val_len < digit_count ? val_len : digit_count); + uint digit_found= 0; + for (i= 0; i < verify_count; i++) + { + if (!my_isdigit(&my_charset_latin1, *(ptr+i))) + break; + digit_found++; + } + return digit_found; +} /* - OPTIMIZATION TODO: - - Replace the switch with a function that should be called for each - date type. - - Remove sprintf and opencode the conversion, like we do in - Field_datetime. + Extract datetime value to TIME struct from string value + according to format string. */ - -String *make_datetime(String *str, TIME *ltime, - enum date_time_format_types format) +bool extract_datetime(const char *str_val, uint str_val_len, + const char *str_format, uint str_format_len, + TIME *l_time) { - char *buff; + char intbuff[15]; + int weekday= 0, yearday= 0, daypart= 0, len; + int val_len= 0; + int week_number= -1; + ulong length; CHARSET_INFO *cs= &my_charset_bin; - uint length= date_time_formats[format].length + 32; - const char* format_str= date_time_formats[format].format_str; + int err= 0; + bool usa_time= 0; + bool sunday_first= 0; + const char *rT_format= "%H:%i:%s"; + uint part_len= 0; + const char *val_ptr=str_val; + const char *val_end= str_val + str_val_len; + const char *ptr=str_format; + const char *end=ptr+ str_format_len; + + DBUG_ENTER("extract_datetime"); + for (; ptr != end && val_ptr != val_end; ptr++) + { + if (*ptr == '%' && ptr+1 != end) + { + val_len= val_end - val_ptr; + char *val_end1= (char *) val_end; + switch (*++ptr) { + case 'h': + case 'I': + case 'H': + l_time->hour= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + usa_time= (*ptr == 'I' || *ptr == 'h'); + val_ptr+=2; + break; + case 'k': + case 'l': + l_time->hour= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err) + return 1; + usa_time= (*ptr == 'l'); + val_ptr= val_end1; + break; + case 'e': + l_time->day= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err) + return 1; + val_ptr= val_end1; + break; + case 'c': + l_time->month= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err) + return 1; + val_ptr= val_end1; + break; + case 'Y': + l_time->year= my_strntoll(cs, val_ptr, + 4, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 4)) + return 1; + val_ptr+=4; + break; + case 'y': + l_time->year= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); + val_ptr+=2; + break; + case 'm': + l_time->month= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + val_ptr+=2; + break; + case 'd': + l_time->day= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + val_ptr+=2; + break; + case 'D': + l_time->day= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_len < val_end1 - val_ptr + 2)) + return 1; + val_ptr= val_end1 + 2; + break; + case 'i': + l_time->minute=my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + val_ptr+=2; + break; + case 's': + case 'S': + l_time->second= my_strntoll(cs, val_ptr, + 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + val_ptr+=2; + break; + case 'M': + if (val_len < 3 || + !(part_len= check_names(month_names, 12 , val_ptr, + val_end, &l_time->month, 0))) + return 1; + val_ptr+= part_len; + break; + case 'b': + if (val_len < 3 || + !(part_len= check_names(month_names, 12 , val_ptr, + val_end,(uint *) &l_time->month, 1))) + return 1; + val_ptr+= part_len; + break; + case 'W': + if (val_len < 3 || + !(part_len= check_names(day_names, 7 , val_ptr, + val_end,(uint *) &weekday, 0))) + return 1; + val_ptr+= part_len; + break; + case 'a': + if (val_len < 3 || + !(part_len= check_names(day_names, 7 , val_ptr, + val_end,(uint *) &weekday, 1))) + return 1; + val_ptr+= part_len; + break; + case 'w': + weekday= my_strntoll(cs, val_ptr, 1, 10, &val_end1, &err); + if (err) + return 1; + val_ptr++; + break; + case 'j': + yearday= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 3)) + return 1; + val_ptr+=3; + break; + case 'f': + l_time->second_part= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); + if (err) + return 1; + val_ptr= val_end1; + break; + case 'p': + if (val_len < 2) + return 1; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) val_ptr, 2, + (const uchar *) "PM", 2)) + { + daypart= 12; + val_ptr+= 2; + } + break; + case 'U': + week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + sunday_first= 1; + val_ptr+=2; + break; + case 'u': + week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); + if (err || (val_end1 - val_ptr != 2)) + return 1; + sunday_first=0; + val_ptr+=2; + break; + case 'r': + case 'T': + usa_time= (*ptr == 'r'); + if (extract_datetime(val_ptr, val_end-val_ptr, + rT_format, strlen(rT_format), + l_time)) + return 1; + val_ptr+=8; + break; + default: + if (*val_ptr != *ptr) + return 1; + val_ptr++; + } + } + else + { + if (*val_ptr != *ptr) + return 1; + val_ptr++; + } + } + if (usa_time) + { + if (l_time->hour > 12 || l_time->hour < 1) + return 1; + l_time->hour= l_time->hour%12+daypart; + } - if (str->alloc(length)) - return 0; + if (yearday > 0) + { + uint days= calc_daynr(l_time->year,1,1) + yearday - 1; + if (days > 0 || days < MAX_DAY_NUMBER) + { + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); + } + } - buff= (char*) str->ptr(); - switch (format) { - case TIME_ONLY: - length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", - ltime->hour, ltime->minute, ltime->second); - break; - case TIME_MICROSECOND: - length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", - ltime->hour, ltime->minute, ltime->second, - ltime->second_part); - break; - case DATE_ONLY: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day); - break; - case DATE_TIME: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day, - ltime->hour, ltime->minute, ltime->second); - break; - case DATE_TIME_MICROSECOND: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day, - ltime->hour, ltime->minute, ltime->second, - ltime->second_part); - break; - default: - return 0; + if (week_number >= 0 && weekday) + { + int days= calc_daynr(l_time->year,1,1); + uint weekday_b; + + if (weekday > 7 || weekday < 0) + return 1; + if (sunday_first) + weekday = weekday%7; + + if (week_number == 53) + { + days+= (week_number - 1)*7; + weekday_b= calc_weekday(days, sunday_first); + weekday = weekday - weekday_b - !sunday_first; + days+= weekday; + } + else if (week_number == 0) + { + weekday_b= calc_weekday(days, sunday_first); + weekday = weekday - weekday_b - !sunday_first; + days+= weekday; + } + else + { + days+= (week_number - !sunday_first)*7; + weekday_b= calc_weekday(days, sunday_first); + weekday =weekday - weekday_b - !sunday_first; + days+= weekday; + } + if (days > 0 || days < MAX_DAY_NUMBER) + { + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); + } } - str->length(length); - str->set_charset(cs); + if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || + l_time->minute > 59 || l_time->second > 59) + return 1; + + DBUG_RETURN(0); +} + + + +/* + Print datetime string from TIME struct + according to format string. +*/ + + +String *make_datetime(String *str, TIME *l_time, + const bool is_time_only, + const bool add_second_frac, + const char *ptr, uint format_length, + bool set_len_to_zero) +{ + char intbuff[15]; + uint days_i; + uint hours_i; + uint weekday; + ulong length; + if (set_len_to_zero) + str->length(0); + if (l_time->neg) + str->append("-", 1); + const char *end=ptr+format_length; + for (; ptr != end ; ptr++) + { + if (*ptr != '%' || ptr+1 == end) + str->append(*ptr); + else + { + switch (*++ptr) { + case 'M': + if (!l_time->month) + return 0; + str->append(month_names[l_time->month-1]); + break; + case 'b': + if (!l_time->month) + return 0; + str->append(month_names[l_time->month-1].ptr(),3); + break; + case 'W': + if (is_time_only) + return 0; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); + str->append(day_names[weekday]); + break; + case 'a': + if (is_time_only) + return 0; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); + str->append(day_names[weekday].ptr(),3); + break; + case 'D': + if (is_time_only) + return 0; + length= int10_to_str(l_time->day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + if (l_time->day >= 10 && l_time->day <= 19) + str->append("th"); + else + { + switch (l_time->day %10) { + case 1: + str->append("st",2); + break; + case 2: + str->append("nd",2); + break; + case 3: + str->append("rd",2); + break; + default: + str->append("th",2); + break; + } + } + break; + case 'Y': + length= int10_to_str(l_time->year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); + break; + case 'y': + length= int10_to_str(l_time->year%100, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'm': + length= int10_to_str(l_time->month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'c': + length= int10_to_str(l_time->month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'd': + length= int10_to_str(l_time->day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'e': + length= int10_to_str(l_time->day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'f': + length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 6, '0'); + break; + case 'H': + length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'h': + case 'I': + days_i= l_time->hour/24; + hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + length= int10_to_str(hours_i, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'i': /* minutes */ + length= int10_to_str(l_time->minute, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'j': + if (is_time_only) + return 0; + length= int10_to_str(calc_daynr(l_time->year,l_time->month,l_time->day) - + calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 3, '0'); + break; + case 'k': + length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'l': + days_i= l_time->hour/24; + hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + length= int10_to_str(hours_i, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'p': + hours_i= l_time->hour%24; + str->append(hours_i < 12 ? "AM" : "PM",2); + break; + case 'r': + length= my_sprintf(intbuff, + (intbuff, + (l_time->hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", + (l_time->hour+11)%12+1, + l_time->minute, + l_time->second)); + str->append(intbuff, length); + break; + case 'S': + case 's': + length= int10_to_str(l_time->second, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + if (add_second_frac) + { + str->append(".", 1); + length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 6, '0'); + } + break; + case 'T': + length= my_sprintf(intbuff, + (intbuff, + "%02d:%02d:%02d", + l_time->hour, + l_time->minute, + l_time->second)); + str->append(intbuff, length); + break; + case 'U': + case 'u': + { + uint year; + if (is_time_only) + return 0; + length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + } + break; + case 'v': + case 'V': + { + uint year; + if (is_time_only) + return 0; + length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + } + break; + case 'x': + case 'X': + { + uint year; + if (is_time_only) + return 0; + (void) calc_week(l_time, 1, (*ptr) == 'X', &year); + length= int10_to_str(year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); + } + break; + case 'w': + if (is_time_only) + return 0; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),1); + length= int10_to_str(weekday, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + default: + str->append(*ptr); + break; + } + } + } return str; } + /* ** Get a array of positive numbers from a string object. ** Each number is separated by 1 non digit character @@ -346,7 +808,7 @@ longlong Item_func_year::val_int() longlong Item_func_unix_timestamp::val_int() { if (arg_count == 0) - return (longlong) current_thd->query_start(); + return (longlong) thd->query_start(); if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; @@ -358,7 +820,7 @@ longlong Item_func_unix_timestamp::val_int() { return 0; /* purecov: inspected */ } - return (longlong) str_to_timestamp(str->ptr(),str->length()); + return (longlong) str_to_timestamp(str->ptr(),str->length(), thd); } @@ -522,22 +984,26 @@ static bool get_interval_value(Item *args,interval_type int_type, String *Item_date::val_str(String *str) { + DATETIME_FORMAT *tmp_format; + TIME ltime; ulong value=(ulong) val_int(); if (null_value) - return (String*) 0; - if (!value) // zero daynr - { - str->copy("0000-00-00",10,&my_charset_latin1,default_charset()); + goto null_date; + + ltime.year= (value/10000L) % 10000; + ltime.month= (value/100)%100; + ltime.day= (value%100); + ltime.neg=0; + ltime.time_type=TIMESTAMP_DATE; + + tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; - } - - char tmpbuff[11]; - sprintf(tmpbuff,"%04d-%02d-%02d", - (int) (value/10000L) % 10000, - (int) (value/100)%100, - (int) (value%100)); - str->copy(tmpbuff,10,&my_charset_latin1,default_charset()); - return str; + + null_value= 1; +null_date: + return 0; } @@ -577,7 +1043,7 @@ void Item_func_curdate::fix_length_and_dec() decimals=0; max_length=10*default_charset()->mbmaxlen; - store_now_in_tm(current_thd->query_start(),&start); + store_now_in_tm(thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ ((uint) start.tm_mon+1)*100+ @@ -632,22 +1098,27 @@ String *Item_func_curtime::val_str(String *str) void Item_func_curtime::fix_length_and_dec() { struct tm start; - CHARSET_INFO *cs= default_charset(); + DATETIME_FORMAT *tmp_format; + String tmp((char*) buff,sizeof(buff),default_charset()); + TIME ltime; decimals=0; - max_length=8*cs->mbmaxlen; - collation.set(cs); - - store_now_in_tm(current_thd->query_start(),&start); - + store_now_in_tm(thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+ (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec)); - - buff_length=cs->cset->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", - (int) start.tm_hour, - (int) start.tm_min, - (int) start.tm_sec); + ltime.day= 0; + ltime.hour= start.tm_hour; + ltime.minute= start.tm_min; + ltime.second= start.tm_sec; + ltime.second_part= 0; + ltime.neg= 0; + ltime.time_type= TIMESTAMP_TIME; + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + make_datetime(&tmp, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1); + buff_length= tmp.length(); + max_length= buff_length; } @@ -681,14 +1152,11 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { struct tm start; - CHARSET_INFO *cs= &my_charset_bin; + DATETIME_FORMAT *tmp_format; + String tmp((char*) buff,sizeof(buff),&my_charset_bin); decimals=0; - max_length=19*cs->mbmaxlen; - collation.set(cs); - - store_now_in_tm(current_thd->query_start(),&start); - + store_now_in_tm(thd->query_start(),&start); value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ (((uint) start.tm_mon+1)*100+ (uint) start.tm_mday))*(longlong) 1000000L+ @@ -696,14 +1164,6 @@ void Item_func_now::fix_length_and_dec() (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec))); - buff_length= (uint) cs->cset->snprintf(cs,buff, sizeof(buff), - "%04d-%02d-%02d %02d:%02d:%02d", - ((int) (start.tm_year+1900)) % 10000, - (int) start.tm_mon+1, - (int) start.tm_mday, - (int) start.tm_hour, - (int) start.tm_min, - (int) start.tm_sec); /* For getdate */ ltime.year= start.tm_year+1900; ltime.month= start.tm_mon+1; @@ -711,9 +1171,15 @@ void Item_func_now::fix_length_and_dec() ltime.hour= start.tm_hour; ltime.minute= start.tm_min; ltime.second= start.tm_sec; - ltime.second_part=0; - ltime.neg=0; - ltime.time_type=TIMESTAMP_FULL; + ltime.second_part= 0; + ltime.neg= 0; + ltime.time_type= TIMESTAMP_FULL; + + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + make_datetime(&tmp, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1); + buff_length= tmp.length(); + max_length= buff_length; } bool Item_func_now::get_date(TIME *res, @@ -754,22 +1220,36 @@ void Item_func_now_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_sec_to_time::val_str(String *str) { - char buff[23*2]; - const char *sign=""; longlong seconds=(longlong) args[0]->val_int(); - ulong length; + uint sec; + + DATETIME_FORMAT *tmp_format; + TIME ltime; + if ((null_value=args[0]->null_value)) - return (String*) 0; + goto null_date; + + ltime.neg= 0; if (seconds < 0) { seconds= -seconds; - sign= "-"; + ltime.neg= 1; } - uint sec= (uint) ((ulonglong) seconds % 3600); - length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), - sec/60, sec % 60)); - str->copy(buff, length, &my_charset_latin1, default_charset()); - return str; + + sec= (uint) ((ulonglong) seconds % 3600); + ltime.day= 0; + ltime.hour= seconds/3600; + ltime.minute= sec/60; + ltime.second= sec % 60; + + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) + return str; + + null_value= 1; +null_date: + return (String*) 0; } @@ -879,9 +1359,7 @@ String *Item_func_date_format::val_str(String *str) { String *format; TIME l_time; - char intbuff[15]; uint size,weekday; - ulong length; if (!date_or_time) { @@ -892,24 +1370,17 @@ String *Item_func_date_format::val_str(String *str) { String *res; if (!(res=args[0]->val_str(str))) - { - null_value=1; - return 0; - } - if (str_to_time(res->ptr(),res->length(),&l_time)) - { - null_value=1; - return 0; - } + goto null_date; + + if (str_to_time(res->ptr(),res->length(),&l_time, thd)) + goto null_date; + l_time.year=l_time.month=l_time.day=0; null_value=0; } if (!(format = args[1]->val_str(str)) || !format->length()) - { - null_value=1; - return 0; - } + goto null_date; if (fixed_length) size=max_length; @@ -918,237 +1389,53 @@ String *Item_func_date_format::val_str(String *str) if (format == str) str= &value; // Save result here if (str->alloc(size)) - { - null_value=1; - return 0; - } - str->length(0); + goto null_date; + /* Create the result string */ - const char *ptr=format->ptr(); - const char *end=ptr+format->length(); - for (; ptr != end ; ptr++) - { - if (*ptr != '%' || ptr+1 == end) - str->append(*ptr); - else - { - switch (*++ptr) { - case 'M': - if (!l_time.month) - { - null_value=1; - return 0; - } - str->append(month_names[l_time.month-1]); - break; - case 'b': - if (!l_time.month) - { - null_value=1; - return 0; - } - str->append(month_names[l_time.month-1].ptr(),3); - break; - case 'W': - if (date_or_time) - { - null_value=1; - return 0; - } - weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0); - str->append(day_names[weekday]); - break; - case 'a': - if (date_or_time) - { - null_value=1; - return 0; - } - weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0); - str->append(day_names[weekday].ptr(),3); - break; - case 'D': - if (date_or_time) - { - null_value=1; - return 0; - } - length= int10_to_str(l_time.day, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - if (l_time.day >= 10 && l_time.day <= 19) - str->append("th"); - else - { - switch (l_time.day %10) { - case 1: - str->append("st",2); - break; - case 2: - str->append("nd",2); - break; - case 3: - str->append("rd",2); - break; - default: - str->append("th",2); - break; - } - } - break; - case 'Y': - length= int10_to_str(l_time.year, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 4, '0'); - break; - case 'y': - length= int10_to_str(l_time.year%100, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'm': - length= int10_to_str(l_time.month, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'c': - length= int10_to_str(l_time.month, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'd': - length= int10_to_str(l_time.day, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'e': - length= int10_to_str(l_time.day, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'f': - length= int10_to_str(l_time.second_part, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 6, '0'); - break; - case 'H': - length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'h': - case 'I': - length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'i': /* minutes */ - length= int10_to_str(l_time.minute, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'j': - if (date_or_time) - { - null_value=1; - return 0; - } - length= int10_to_str(calc_daynr(l_time.year,l_time.month,l_time.day) - - calc_daynr(l_time.year,1,1) + 1, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 3, '0'); - break; - case 'k': - length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'l': - length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'p': - str->append(l_time.hour < 12 ? "AM" : "PM",2); - break; - case 'r': - length= my_sprintf(intbuff, - (intbuff, - (l_time.hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", - (l_time.hour+11)%12+1, - l_time.minute, - l_time.second)); - str->append(intbuff, length); - break; - case 'S': - case 's': - length= int10_to_str(l_time.second, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'T': - length= my_sprintf(intbuff, - (intbuff, - "%02d:%02d:%02d", - l_time.hour, - l_time.minute, - l_time.second)); - str->append(intbuff, length); - break; - case 'U': - case 'u': - { - uint year; - length= int10_to_str(calc_week(&l_time, 0, (*ptr) == 'U', &year), - intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - } - break; - case 'v': - case 'V': - { - uint year; - length= int10_to_str(calc_week(&l_time, 1, (*ptr) == 'V', &year), - intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - } - break; - case 'x': - case 'X': - { - uint year; - (void) calc_week(&l_time, 1, (*ptr) == 'X', &year); - length= int10_to_str(year, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 4, '0'); - } - break; - case 'w': - weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1); - length= int10_to_str(weekday, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); + if (make_datetime(str, &l_time, 0, 0, + format->ptr(), format->length(), 1)) + return str; - break; - default: - str->append(*ptr); - break; - } - } - } - return str; +null_date: + null_value=1; + return 0; } String *Item_func_from_unixtime::val_str(String *str) { struct tm tm_tmp,*start; + DATETIME_FORMAT *tmp_format; time_t tmp=(time_t) args[0]->val_int(); uint32 l; CHARSET_INFO *cs=default_charset(); + TIME ltime; if ((null_value=args[0]->null_value)) - return 0; + goto null_date; + localtime_r(&tmp,&tm_tmp); start=&tm_tmp; - + + ltime.year= start->tm_year+1900; + ltime.month= start->tm_mon+1; + ltime.day= start->tm_mday; + ltime.hour= start->tm_hour; + ltime.minute= start->tm_min; + ltime.second= start->tm_sec; + ltime.second_part= 0; + ltime.neg=0; + l=20*cs->mbmaxlen+32; - if (str->alloc(l)) - return str; /* purecov: inspected */ - l=cs->cset->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", - (int) start->tm_year+1900, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - str->length(l); - str->set_charset(cs); - return str; + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + if (str->alloc(l) && make_datetime(str, <ime, 1, 0, + tmp_format->format, + tmp_format->format_length, 1)) + return str; + null_value= 1; +null_date: + return 0; } @@ -1229,7 +1516,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) { long period,sign; INTERVAL interval; - + ltime->neg= 0; if (args[0]->get_date(ltime,0) || get_interval_value(args[1],int_type,&value,&interval)) goto null_date; @@ -1329,19 +1616,17 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; - enum date_time_format_types format; + DATETIME_FORMAT *tmp_format; if (Item_date_add_interval::get_date(<ime,0)) return 0; if (ltime.time_type == TIMESTAMP_DATE) - format= DATE_ONLY; - else if (ltime.second_part) - format= DATE_TIME_MICROSECOND; - else - format= DATE_TIME; - - if (make_datetime(str, <ime, format)) + tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; + else + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 1, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_value=1; @@ -1429,7 +1714,7 @@ longlong Item_extract::val_int() else { String *res= args[0]->val_str(&value); - if (!res || str_to_time(res->ptr(),res->length(),<ime)) + if (!res || str_to_time(res->ptr(),res->length(),<ime, thd)) { null_value=1; return 0; @@ -1437,7 +1722,6 @@ longlong Item_extract::val_int() neg= ltime.neg ? -1 : 1; null_value=0; } - switch (int_type) { case INTERVAL_YEAR: return ltime.year; case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month; @@ -1580,10 +1864,12 @@ void Item_char_typecast::fix_length_and_dec() String *Item_datetime_typecast::val_str(String *str) { TIME ltime; + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (thd, DATETIME_FORMAT_TYPE).datetime_format); if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, ltime.second_part ? - DATE_TIME_MICROSECOND : DATE_TIME)) + make_datetime(str, <ime, 1, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1603,9 +1889,12 @@ bool Item_time_typecast::get_time(TIME *ltime) String *Item_time_typecast::val_str(String *str) { TIME ltime; + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (thd, TIME_FORMAT_TYPE).datetime_format); if (!get_arg0_time(<ime) && - make_datetime(str, <ime, ltime.second_part ? TIME_MICROSECOND : TIME_ONLY)) + make_datetime(str, <ime, 0, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_value=1; @@ -1624,9 +1913,12 @@ bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_typecast::val_str(String *str) { TIME ltime; + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (thd, DATE_FORMAT_TYPE).datetime_format); if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, DATE_ONLY)) + make_datetime(str, <ime, 1, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1655,7 +1947,11 @@ String *Item_func_makedate::val_str(String *str) { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); - if (make_datetime(str, &l_time, DATE_ONLY)) + + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (thd, DATE_FORMAT_TYPE).datetime_format); + if (make_datetime(str, &l_time, 1, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; } @@ -1706,6 +2002,7 @@ String *Item_func_add_time::val_str(String *str) bool is_time= 0; long microseconds, seconds, days= 0; int l_sign= sign; + DATETIME_FORMAT *tmp_format; null_value=0; l_time3.neg= 0; @@ -1770,19 +2067,21 @@ String *Item_func_add_time::val_str(String *str) calc_time_from_sec(&l_time3, seconds, microseconds); if (!is_time) { + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); if (l_time3.day && - make_datetime(str, &l_time3, - l_time1.second_part || l_time2.second_part ? - DATE_TIME_MICROSECOND : DATE_TIME)) + make_datetime(str, &l_time3, 1, + l_time1.second_part || l_time2.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; goto null_date; } - + + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; l_time3.hour+= days*24; - if (make_datetime(str, &l_time3, - l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY)) + if (make_datetime(str, &l_time3, 0, + l_time1.second_part || l_time2.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1827,6 +2126,7 @@ String *Item_func_timediff::val_str(String *str) long days; int l_sign= 1; TIME l_time1 ,l_time2, l_time3; + DATETIME_FORMAT *tmp_format; null_value= 0; if (args[0]->get_time(&l_time1) || @@ -1872,9 +2172,11 @@ String *Item_func_timediff::val_str(String *str) l_time3.neg= l_time3.neg ? 0 : 1; calc_time_from_sec(&l_time3, seconds, microseconds); - if (make_datetime(str, &l_time3, - l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY)) + + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, &l_time3, 0, + l_time1.second_part || l_time2.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1891,6 +2193,7 @@ null_date: String *Item_func_maketime::val_str(String *str) { TIME ltime; + DATETIME_FORMAT *tmp_format; long hour= args[0]->val_int(); long minute= args[1]->val_int(); @@ -1912,7 +2215,9 @@ String *Item_func_maketime::val_str(String *str) ltime.hour= (ulong)hour; ltime.minute= (ulong)minute; ltime.second= (ulong)second; - if (make_datetime(str, <ime, TIME_ONLY)) + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1932,3 +2237,79 @@ longlong Item_func_microsecond::val_int() return ltime.second_part; return 0; } + +/* + Array of MySQL date/time/datetime formats + Firts element is date format + Second element is time format + Third element is datetime format + Fourth is format name. +*/ + +const char *datetime_formats[4][5]= +{ + {"%m.%d.%Y", "%Y-%m-%d", "%Y-%m-%d", "%d.%m.%Y", "%Y%m%d"}, + {"%h:%i:%s %p", "%H:%i:%s", "%H:%i:%s", "%H.%i.%S", "%H%i%s"}, + {"%Y-%m-%d-%H.%i.%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d-%H.%i.%s", "%Y%m%d%H%i%s"}, + {"USA", "JIS", "ISO", "EUR", "INTERNAL"} +}; + + +/* + Return format string according format name. + If name is unknown, result is ISO format string +*/ + +String *Item_func_get_format::val_str(String *str) +{ + String *val=args[0]->val_str(str); + const char *format_str= datetime_formats[tm_format][ISO_FORMAT]; + + if (!args[0]->null_value) + { + const char *val_ptr= val->ptr(); + uint val_len= val->length(); + for (int i= 0; i < 5; i++) + { + const char *name_format_str= datetime_formats[3][i]; + uint format_str_len= strlen(name_format_str); + if ( val_len == format_str_len && + !my_strnncoll(&my_charset_latin1, + (const uchar *) val_ptr, val_len, + (const uchar *) name_format_str, format_str_len)) + { + format_str= datetime_formats[tm_format][i]; + break; + } + } + } + + null_value= 0; + str->length(0); + str->append(format_str); + return str; +} + + +String *Item_func_str_to_date::val_str(String *str) +{ + TIME ltime; + bzero((char*) <ime, sizeof(ltime)); + DATETIME_FORMAT *tmp_format; + String *val=args[0]->val_str(str); + String *format=args[1]->val_str(str); + if (args[0]->null_value || args[1]->null_value || + extract_datetime(val->ptr(), val->length(), + format->ptr(), val->length(), + <ime)) + goto null_date; + + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, tmp_format->format, + tmp_format->format_length, 1)) + return str; + +null_date: + null_value=1; + return 0; +} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 123a9cd32dd..ea1e51614c7 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -767,3 +767,46 @@ public: maybe_null=1; } }; + + +enum datetime_format +{ + USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT +}; + + +enum datetime_format_types +{ + DATE_FORMAT_TYPE= 0, TIME_FORMAT_TYPE, DATETIME_FORMAT_TYPE +}; + + +class Item_func_get_format :public Item_str_func +{ + const datetime_format_types tm_format; +public: + Item_func_get_format(datetime_format_types type_arg1, Item *a) + :Item_str_func(a), tm_format(type_arg1) {} + String *val_str(String *str); + const char *func_name() const { return "get_format"; } + void fix_length_and_dec() + { + decimals=0; + max_length=17*MY_CHARSET_BIN_MB_MAXLEN; + } +}; + + +class Item_func_str_to_date :public Item_str_func +{ +public: + Item_func_str_to_date(Item *a, Item *b) + :Item_str_func(a, b) {} + String *val_str(String *str); + const char *func_name() const { return "str_to_date"; } + void fix_length_and_dec() + { + decimals=0; + max_length=29*MY_CHARSET_BIN_MB_MAXLEN; + } +}; diff --git a/sql/lex.h b/sql/lex.h index e11b50ed16d..5d79e378d4f 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -130,6 +130,7 @@ static SYMBOL symbols[] = { { "DESCRIBE", SYM(DESCRIBE),0,0}, { "DIRECTORY", SYM(DIRECTORY_SYM),0,0}, { "DISABLE", SYM(DISABLE_SYM),0,0}, + { "DISCARD", SYM(DISCARD),0,0}, { "DISTINCT", SYM(DISTINCT),0,0}, { "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */ { "DIV", SYM(DIV_SYM),0,0}, @@ -176,6 +177,7 @@ static SYMBOL symbols[] = { { "FUNCTION", SYM(UDF_SYM),0,0}, { "GEOMETRY", SYM(GEOMETRY_SYM),0,0}, { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0}, + { "GET_FORMAT", SYM(GET_FORMAT),0,0}, { "GLOBAL", SYM(GLOBAL_SYM),0,0}, { "GRANT", SYM(GRANT),0,0}, { "GRANTS", SYM(GRANTS),0,0}, @@ -200,6 +202,7 @@ static SYMBOL symbols[] = { { "INNER", SYM(INNER_SYM),0,0}, { "INNOBASE", SYM(INNOBASE_SYM),0,0}, { "INNODB", SYM(INNOBASE_SYM),0,0}, + { "IMPORT", SYM(IMPORT),0,0}, { "INSERT", SYM(INSERT),0,0}, { "INSERT_METHOD", SYM(INSERT_METHOD),0,0}, { "INT", SYM(INT_SYM),0,0}, @@ -387,6 +390,7 @@ static SYMBOL symbols[] = { { "SUPER", SYM(SUPER_SYM),0,0}, { "TABLE", SYM(TABLE_SYM),0,0}, { "TABLES", SYM(TABLES),0,0}, + { "TABLESPACE", SYM(TABLESPACE),0,0}, { "TEMPORARY", SYM(TEMPORARY),0,0}, { "TERMINATED", SYM(TERMINATED),0,0}, { "TEXT", SYM(TEXT_SYM),0,0}, @@ -462,6 +466,7 @@ static SYMBOL sql_functions[] = { { "BIT_COUNT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_count)}, { "BIT_OR", SYM(BIT_OR),0,0}, { "BIT_AND", SYM(BIT_AND),0,0}, + { "BIT_XOR", SYM(BIT_XOR),0,0}, { "CAST", SYM(CAST_SYM),0,0}, { "CEIL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)}, { "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)}, @@ -636,6 +641,7 @@ static SYMBOL sql_functions[] = { { "STARTPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_startpoint)}, { "STD", SYM(STD_SYM),0,0}, { "STDDEV", SYM(STD_SYM),0,0}, + { "STR_TO_DATE", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_str_to_date)}, { "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)}, { "SUBSTR", SYM(SUBSTRING),0,0}, { "SUBSTRING", SYM(SUBSTRING),0,0}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6ee6b8c5cb7..4b22d30fc46 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -85,6 +85,19 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int. #endif #define TEMP_POOL_SIZE 128 + +#define QUERY_ALLOC_BLOCK_SIZE 8192 +#define QUERY_ALLOC_PREALLOC_SIZE 8192 +#define TRANS_ALLOC_BLOCK_SIZE 4096 +#define TRANS_ALLOC_PREALLOC_SIZE 4096 +#define RANGE_ALLOC_BLOCK_SIZE 2048 +#define ACL_ALLOC_BLOCK_SIZE 1024 +#define UDF_ALLOC_BLOCK_SIZE 1024 +#define TABLE_ALLOC_BLOCK_SIZE 1024 +#define BDB_LOG_ALLOC_BLOCK_SIZE 1024 +#define WARN_ALLOC_BLOCK_SIZE 2048 +#define WARN_ALLOC_PREALLOC_SIZE 1024 + /* The following parameters is to decide when to use an extra cache to optimise seeks when reading a big table in sorted order @@ -217,7 +230,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_ORACLE 512 #define MODE_MSSQL 1024 #define MODE_DB2 2048 -#define MODE_SAPDB 4096 +#define MODE_MAXDB 4096 #define MODE_NO_KEY_OPTIONS 8192 #define MODE_NO_TABLE_OPTIONS 16384 #define MODE_NO_FIELD_OPTIONS 32768 @@ -489,6 +502,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name, bool drop_primary, enum enum_duplicates handle_duplicates, enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS, + enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP, bool simple_alter=0); int mysql_create_like_table(THD *thd, TABLE_LIST *table, HA_CREATE_INFO *create_info, @@ -714,7 +728,7 @@ void key_restore(TABLE *form,byte *key,uint index,uint key_length); int key_cmp(TABLE *form,const byte *key,uint index,uint key_length); void key_unpack(String *to,TABLE *form,uint index); bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields); -void init_errmessage(void); +bool init_errmessage(void); void sql_perror(const char *message); void sql_print_error(const char *format,...) @@ -811,7 +825,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables, LOCK_user_conn; -extern rw_lock_t LOCK_grant; +extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; @@ -828,6 +842,14 @@ extern SHOW_COMP_OPTION have_berkeley_db; extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern struct rand_struct sql_rand; + +#define g_datetime_frm(a) (global_system_variables.datetime_formats[(a)]) +#define t_datetime_frm(a, b) ((a)->variables.datetime_formats[(b)]) + +extern const char *datetime_formats[4][5]; +extern const char *opt_datetime_format_names[3]; +extern const char *opt_datetime_formats[3]; + extern String null_string; extern HASH open_cache; extern TABLE *unused_tables; @@ -898,17 +920,31 @@ void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); void init_time(void); long my_gmt_sec(TIME *, long *current_timezone); -time_t str_to_timestamp(const char *str,uint length); -bool str_to_time(const char *str,uint length,TIME *l_time); -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); +time_t str_to_timestamp(const char *str,uint length, THD *thd); +bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd); +longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, - bool fuzzy_date); + bool fuzzy_date, THD *thd); void localtime_to_TIME(TIME *to, struct tm *from); void calc_time_from_sec(TIME *to, long seconds, long microseconds); +extern DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, + datetime_format_types format_type, + const char *format_str, + uint format_length, bool is_alloc); +extern String *make_datetime(String *str, TIME *l_time, + const bool is_time_only, + const bool add_second_frac, + const char *ptr, uint format_length, + bool set_len_to_zero); + int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); +#ifndef EMBEDDED_LIBRARY extern "C" void unireg_abort(int exit_code); +#else +#define unireg_abort(exit_code) DBUG_RETURN(exit_code) +#endif void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1c26d4a8b7c..da7d3df0251 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -217,7 +217,7 @@ const char *sql_mode_names[] = "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", "NO_DIR_IN_CREATE", - "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", + "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI", "NO_AUTO_VALUE_ON_ZERO", NullS }; @@ -319,6 +319,12 @@ char* log_error_file_ptr= log_error_file; char mysql_real_data_home[FN_REFLEN], language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; + +const char *opt_datetime_formats[3]; +const char *opt_datetime_format_names[3]= {"date_format", + "time_format", + "datetime_format"}; + char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION; @@ -845,6 +851,7 @@ extern "C" sig_handler print_signal_warning(int sig) (Mac OS X) we have to call exit() instead if pthread_exit(). */ +#ifndef EMBEDDED_LIBRARY void unireg_end(void) { clean_up(1); @@ -856,7 +863,6 @@ void unireg_end(void) #endif } - extern "C" void unireg_abort(int exit_code) { DBUG_ENTER("unireg_abort"); @@ -868,7 +874,7 @@ extern "C" void unireg_abort(int exit_code) my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); exit(exit_code); /* purecov: inspected */ } - +#endif void clean_up(bool print_message) { @@ -906,6 +912,9 @@ void clean_up(bool print_message) #ifdef USE_RAID end_raid(); #endif + g_datetime_frm(DATE_FORMAT_TYPE).clean(); + g_datetime_frm(TIME_FORMAT_TYPE).clean(); + g_datetime_frm(DATETIME_FORMAT_TYPE).clean(); if (defaults_argv) free_defaults(defaults_argv); free_tmpdir(&mysql_tmpdir_list); @@ -1015,6 +1024,7 @@ static void set_ports() } } +#ifndef EMBEDDED_LIBRARY /* Change to run as another user if started with --user */ static void set_user(const char *user) @@ -1097,7 +1107,6 @@ static void set_root(const char *path) #endif } - static void server_init(void) { struct sockaddr_in IPaddr; @@ -1248,6 +1257,7 @@ static void server_init(void) DBUG_VOID_RETURN; } +#endif /*!EMBEDDED_LIBRARY*/ void yyerror(const char *s) { @@ -1998,6 +2008,36 @@ bool open_log(MYSQL_LOG *log, const char *hostname, } +int init_global_datetime_format(datetime_format_types format_type, bool is_alloc) +{ + const char *format_str= opt_datetime_formats[format_type]; + uint format_length= 0; + DATETIME_FORMAT *tmp_format= &g_datetime_frm(format_type).datetime_format; + + if (format_str) + { + format_str= opt_datetime_formats[format_type]; + format_length= strlen(format_str); + } + else + { + format_str= datetime_formats[format_type][ISO_FORMAT]; + format_length= strlen(datetime_formats[format_type][ISO_FORMAT]); + opt_datetime_formats[format_type]= format_str; + } + if (make_format(tmp_format, format_type, format_str, + format_length, is_alloc)) + { + g_datetime_frm(format_type).name= opt_datetime_format_names[format_type]; + g_datetime_frm(format_type).name_length= + strlen(opt_datetime_format_names[format_type]); + g_datetime_frm(format_type).format_type= format_type; + return 0; + } + return 1; +} + + static int init_common_variables(const char *conf_file_name, int argc, char **argv, const char **groups) { @@ -2081,7 +2121,8 @@ static int init_common_variables(const char *conf_file_name, int argc, open_files_limit= 0; /* Can't set or detect limit */ #endif unireg_init(opt_specialflag); /* Set up extern variabels */ - init_errmessage(); /* Read error messages from file */ + if (init_errmessage()) /* Read error messages from file */ + return 1; init_client_errs(); lex_init(); item_init(); @@ -2113,6 +2154,12 @@ static int init_common_variables(const char *conf_file_name, int argc, global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; global_system_variables.character_set_client= default_charset_info; + global_system_variables.collation_connection= default_charset_info; + + if (init_global_datetime_format(DATE_FORMAT_TYPE, 1) || + init_global_datetime_format(TIME_FORMAT_TYPE, 1) || + init_global_datetime_format(DATETIME_FORMAT_TYPE, 1)) + return 1; if (use_temp_pool && bitmap_init(&temp_pool,1024,1)) return 1; @@ -2188,6 +2235,7 @@ static void init_ssl() static int init_server_components() { + DBUG_ENTER("init_server_components"); table_cache_init(); hostname_cache_init(); query_cache_result_size_limit(query_cache_limit); @@ -2279,7 +2327,7 @@ Now disabling --log-slave-updates."); init_max_user_conn(); init_update_queries(); - return 0; + DBUG_RETURN(0); } @@ -3453,10 +3501,10 @@ error: Handle start options ******************************************************************************/ -enum options +enum options_mysqld { - OPT_ISAM_LOG=256, OPT_SKIP_NEW, - OPT_SKIP_GRANT, OPT_SKIP_LOCK, + OPT_ISAM_LOG=256, OPT_SKIP_NEW, + OPT_SKIP_GRANT, OPT_SKIP_LOCK, OPT_ENABLE_LOCK, OPT_USE_LOCKING, OPT_SOCKET, OPT_UPDATE_LOG, OPT_BIN_LOG, OPT_SKIP_RESOLVE, @@ -3567,14 +3615,20 @@ enum options OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, OPT_ERROR_LOG_FILE, + OPT_DEFAULT_WEEK_FORMAT, + OPT_RANGE_ALLOC_BLOCK_SIZE, + OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE, + OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, OPT_ENABLE_SHARED_MEMORY, OPT_SHARED_MEMORY_BASE_NAME, OPT_OLD_PASSWORDS, OPT_EXPIRE_LOGS_DAYS, - OPT_DEFAULT_WEEK_FORMAT, OPT_GROUP_CONCAT_MAX_LEN, OPT_DEFAULT_COLLATION, OPT_SECURE_AUTH, + OPT_DATE_FORMAT, + OPT_TIME_FORMAT, + OPT_DATETIME_FORMAT, OPT_LOG_QUERIES_NOT_USING_INDEXES }; @@ -3992,7 +4046,7 @@ relay logs.", 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO, - "Show user and password in SHOW SLAVE STATUS.", + "Show user and password in SHOW SLAVE HOSTS.", (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"concurrent-insert", OPT_CONCURRENT_INSERT, @@ -4392,6 +4446,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.preload_buff_size, (gptr*) &max_system_variables.preload_buff_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, + {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE, + "Allocation block size for query parsing and execution", + (gptr*) &global_system_variables.query_alloc_block_size, + (gptr*) &max_system_variables.query_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_limit", OPT_QUERY_CACHE_LIMIT, "Don't cache results that are bigger than this.", @@ -4413,6 +4472,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.query_cache_type, (gptr*) &max_system_variables.query_cache_type, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0}, + {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE, + "Persistent buffer for query parsing and execution", + (gptr*) &global_system_variables.query_prealloc_size, + (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, #endif /*HAVE_QUERY_CACHE*/ {"read_buffer_size", OPT_RECORD_BUFFER, "Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.", @@ -4451,6 +4515,11 @@ The minimum value for this variable is 4096.", (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0, GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, #endif /* HAVE_REPLICATION */ + {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, + "Allocation block size for storing ranges during optimization", + (gptr*) &global_system_variables.range_alloc_block_size, + (gptr*) &max_system_variables.range_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, {"read-only", OPT_READONLY, "Make all tables readonly, with the expections for replications (slave) threads and users with the SUPER privilege.", (gptr*) &opt_readonly, @@ -4487,6 +4556,16 @@ The minimum value for this variable is 4096.", "The stack size for each thread.", (gptr*) &thread_stack, (gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, 1024*32, ~0L, 0, 1024, 0}, + {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE, + "Allocation block size for transactions to be stored in binary log", + (gptr*) &global_system_variables.trans_alloc_block_size, + (gptr*) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, + {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE, + "Persistent buffer for transactions to be stored in binary log", + (gptr*) &global_system_variables.trans_prealloc_size, + (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, + REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, {"wait_timeout", OPT_WAIT_TIMEOUT, "The number of seconds the server waits for activity on a connection before closing it.", (gptr*) &global_system_variables.net_wait_timeout, @@ -4502,6 +4581,21 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.default_week_format, (gptr*) &max_system_variables.default_week_format, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0}, + { "date-format", OPT_DATE_FORMAT, + "The DATE format.", + (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], + (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "datetime-format", OPT_DATETIME_FORMAT, + "The DATETIME/TIMESTAMP format.", + (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], + (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + { "time-format", OPT_TIME_FORMAT, + "The TIME format.", + (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], + (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -4879,6 +4973,10 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; + init_global_datetime_format(DATE_FORMAT_TYPE, 0); + init_global_datetime_format(TIME_FORMAT_TYPE, 0); + init_global_datetime_format(DATETIME_FORMAT_TYPE, 0); + /* Variables that depends on compile options */ #ifndef DBUG_OFF default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", @@ -5509,8 +5607,10 @@ static void get_options(int argc,char **argv) /* Set global MyISAM variables from delay_key_write_options */ fix_delay_key_write((THD*) 0, OPT_GLOBAL); +#ifndef EMBEDDED_LIBRARY if (mysqld_chroot) set_root(mysqld_chroot); +#endif fix_paths(); /* diff --git a/sql/opt_ft.cc b/sql/opt_ft.cc index b35b3230a39..74349819937 100644 --- a/sql/opt_ft.cc +++ b/sql/opt_ft.cc @@ -26,11 +26,11 @@ ** Create a FT or QUICK RANGE based on a key ****************************************************************************/ -QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab) +QUICK_SELECT *get_ft_or_quick_select_for_ref(THD *thd, TABLE *table, + JOIN_TAB *tab) { if (tab->type == JT_FT) - return new FT_SELECT(table, &tab->ref); - else - return get_quick_select_for_ref(table, &tab->ref); + return new FT_SELECT(thd, table, &tab->ref); + return get_quick_select_for_ref(thd, table, &tab->ref); } diff --git a/sql/opt_ft.h b/sql/opt_ft.h index b055edc107c..69b6b72f3fc 100644 --- a/sql/opt_ft.h +++ b/sql/opt_ft.h @@ -28,13 +28,14 @@ class FT_SELECT: public QUICK_SELECT { public: TABLE_REF *ref; - FT_SELECT(TABLE *table, TABLE_REF *tref) : - QUICK_SELECT (table,tref->key,1), ref(tref) { init(); } + FT_SELECT(THD *thd, TABLE *table, TABLE_REF *tref) : + QUICK_SELECT (thd, table, tref->key, 1), ref(tref) { init(); } int init() { return error=file->ft_init(); } int get_next() { return error=file->ft_read(record); } }; -QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab); +QUICK_SELECT *get_ft_or_quick_select_for_ref(THD *thd, TABLE *table, + JOIN_TAB *tab); #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 24768537e3d..b356bda6112 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -279,6 +279,7 @@ public: typedef struct st_qsel_param { + THD *thd; TABLE *table; KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY]; MEM_ROOT *mem_root; @@ -378,13 +379,14 @@ SQL_SELECT::~SQL_SELECT() #undef index // Fix for Unixware 7 -QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc) +QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc) :dont_free(0),error(0),index(key_nr),max_used_key_length(0), used_key_parts(0), head(table), it(ranges),range(0) { if (!no_alloc) { - init_sql_alloc(&alloc,1024,0); // Allocates everything here + // Allocates everything through the internal memroot + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); my_pthread_setspecific_ptr(THR_MALLOC,&alloc); } else @@ -456,17 +458,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) SEL_ARG *tmp; if (type != KEY_RANGE) { - if (!(tmp=new SEL_ARG(type))) - return 0; // out of memory + if (!(tmp= new SEL_ARG(type))) + return 0; // out of memory tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; } else { - if (!(tmp=new SEL_ARG(field,part, min_value,max_value, - min_flag, max_flag, maybe_flag))) - return 0; // out of memory + if (!(tmp= new SEL_ARG(field,part, min_value,max_value, + min_flag, max_flag, maybe_flag))) + return 0; // OOM tmp->parent=new_parent; tmp->next_key_part=next_key_part; if (left != &null_element) @@ -477,7 +479,8 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) (*next_arg)= tmp; if (right != &null_element) - tmp->right=right->clone(tmp,next_arg); + if (!(tmp->right= right->clone(tmp,next_arg))) + return 0; // OOM } increment_use_count(1); return tmp; @@ -556,10 +559,11 @@ SEL_ARG *SEL_ARG::clone_tree() { SEL_ARG tmp_link,*next_arg,*root; next_arg= &tmp_link; - root=clone((SEL_ARG *) 0, &next_arg); + root= clone((SEL_ARG *) 0, &next_arg); next_arg->next=0; // Fix last link tmp_link.next->prev=0; // Fix first link - root->use_count=0; + if (root) // If not OOM + root->use_count= 0; return root; } @@ -577,7 +581,8 @@ SEL_ARG *SEL_ARG::clone_tree() ** quick_rows ; How many rows the key matches *****************************************************************************/ -int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, +int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, + table_map prev_tables, ha_rows limit, bool force_quick_range) { uint basflag; @@ -618,9 +623,9 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, SEL_TREE *tree; KEY_PART *key_parts; PARAM param; - THD *thd= current_thd; - + /* set up parameter that is passed to all functions */ + param.thd= thd; param.baseflag=basflag; param.prev_tables=prev_tables | const_tables; param.read_tables=read_tables; @@ -630,7 +635,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, param.mem_root= &alloc; thd->no_errors=1; // Don't warn about NULL - init_sql_alloc(&alloc,2048,0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc, sizeof(KEY_PART)* head->key_parts))) @@ -765,7 +770,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) while ((item=li++)) { SEL_TREE *new_tree=get_mm_tree(param,item); - if (current_thd->is_fatal_error) + if (param->thd->is_fatal_error) DBUG_RETURN(0); // out of memory tree=tree_and(param,tree,new_tree); if (tree && tree->type == SEL_TREE::IMPOSSIBLE) @@ -906,7 +911,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, { SEL_ARG *sel_arg=0; if (!tree && !(tree=new SEL_TREE())) - DBUG_RETURN(0); // out of memory + DBUG_RETURN(0); // OOM if (!value || !(value->used_tables() & ~param->read_tables)) { sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value); @@ -918,10 +923,11 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, DBUG_RETURN(tree); } } - else { + else + { // This key may be used later - if (!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY))) - DBUG_RETURN(0); // out of memory + if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY))) + DBUG_RETURN(0); // OOM } sel_arg->part=(uchar) key_part->part; tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); @@ -1126,8 +1132,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, ******************************************************************************/ /* -** Add a new key test to a key when scanning through all keys -** This will never be called for same key parts. + Add a new key test to a key when scanning through all keys + This will never be called for same key parts. */ static SEL_ARG * @@ -1311,7 +1317,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) // key1->part < key2->part key1->use_count--; if (key1->use_count > 0) - key1=key1->clone_tree(); + if (!(key1= key1->clone_tree())) + return 0; // OOM return and_all_keys(key1,key2,clone_flag); } @@ -1330,7 +1337,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) if (key1->use_count > 1) { key1->use_count--; - key1=key1->clone_tree(); + if (!(key1=key1->clone_tree())) + return 0; // OOM key1->use_count++; } if (key1->type == SEL_ARG::MAYBE_KEY) @@ -1374,6 +1382,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) if (!next || next->type != SEL_ARG::IMPOSSIBLE) { SEL_ARG *new_arg= e1->clone_and(e2); + if (!new_arg) + return &null_element; // End of memory new_arg->next_key_part=next; if (!new_tree) { @@ -1461,8 +1471,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) { swap(SEL_ARG *,key1,key2); } - else - key1=key1->clone_tree(); + else if (!(key1=key1->clone_tree())) + return 0; // OOM } // Add tree at key2 to tree at key1 @@ -1530,7 +1540,10 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) SEL_ARG *next=key2->next; // Keys are not overlapping if (key2_shared) { - key1=key1->insert(new SEL_ARG(*key2)); // Must make copy + SEL_ARG *tmp= new SEL_ARG(*key2); // Must make copy + if (!tmp) + return 0; // OOM + key1=key1->insert(tmp); key2->increment_use_count(key1->use_count+1); } else @@ -1576,6 +1589,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) { // tmp.min <= x < key2.min SEL_ARG *new_arg=tmp->clone_first(key2); + if (!new_arg) + return 0; // OOM if ((new_arg->next_key_part= key1->next_key_part)) new_arg->increment_use_count(key1->use_count+1); tmp->copy_min_to_min(key2); @@ -1589,6 +1604,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) if (tmp->cmp_min_to_min(&key) > 0) { // key.min <= x < tmp.min SEL_ARG *new_arg=key.clone_first(tmp); + if (!new_arg) + return 0; // OOM if ((new_arg->next_key_part=key.next_key_part)) new_arg->increment_use_count(key1->use_count+1); key1=key1->insert(new_arg); @@ -1603,19 +1620,27 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) key.copy_max_to_min(tmp); if (!(tmp=tmp->next)) { - key1=key1->insert(new SEL_ARG(key)); + SEL_ARG *tmp2= new SEL_ARG(key); + if (!tmp2) + return 0; // OOM + key1=key1->insert(tmp2); key2=key2->next; goto end; } if (tmp->cmp_min_to_max(&key) > 0) { - key1=key1->insert(new SEL_ARG(key)); + SEL_ARG *tmp2= new SEL_ARG(key); + if (!tmp2) + return 0; // OOM + key1=key1->insert(tmp2); break; } } else { SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max + if (!new_arg) + return 0; // OOM tmp->copy_max_to_min(&key); tmp->increment_use_count(key1->use_count+1); new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part); @@ -1632,8 +1657,11 @@ end: SEL_ARG *next=key2->next; if (key2_shared) { + SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy + if (!tmp) + return 0; key2->increment_use_count(key1->use_count+1); - key1=key1->insert(new SEL_ARG(*key2)); // Must make copy + key1=key1->insert(tmp); } else key1=key1->insert(key2); // Will destroy key2_root @@ -2222,7 +2250,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree) { QUICK_SELECT *quick; DBUG_ENTER("get_quick_select"); - if ((quick=new QUICK_SELECT(param->table,param->real_keynr[idx]))) + if ((quick=new QUICK_SELECT(param->thd, param->table, + param->real_keynr[idx]))) { if (quick->error || get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0, @@ -2334,10 +2363,10 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, /* Get range for retrieving rows in QUICK_SELECT::get_next */ if (!(range= new QUICK_RANGE(param->min_key, - (uint) (tmp_min_key - param->min_key), - param->max_key, - (uint) (tmp_max_key - param->max_key), - flag))) + (uint) (tmp_min_key - param->min_key), + param->max_key, + (uint) (tmp_max_key - param->max_key), + flag))) return 1; // out of memory set_if_bigger(quick->max_used_key_length,range->min_length); @@ -2394,10 +2423,10 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) ** Create a QUICK RANGE based on a key ****************************************************************************/ -QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) +QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) { table->file->index_end(); // Remove old cursor - QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1); + QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1); KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; uint part; @@ -2406,7 +2435,7 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) return 0; /* no ranges found */ if (cp_buffer_from_ref(ref)) { - if (current_thd->is_fatal_error) + if (thd->is_fatal_error) return 0; // out of memory return quick; // empty range } diff --git a/sql/opt_range.h b/sql/opt_range.h index 00736bfc22f..128f6259055 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -83,7 +83,7 @@ public: ha_rows records; double read_time; - QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0); + QUICK_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0); virtual ~QUICK_SELECT(); void reset(void) { next=0; it.rewind(); } int init() { return error=file->index_init(index); } @@ -127,13 +127,14 @@ class SQL_SELECT :public Sql_alloc { SQL_SELECT(); ~SQL_SELECT(); - bool check_quick(bool force_quick_range=0, ha_rows limit = HA_POS_ERROR) - { return test_quick_select(~0L,0,limit, force_quick_range) < 0; } + bool check_quick(THD *thd, bool force_quick_range, ha_rows limit) + { return test_quick_select(thd, ~0L,0,limit, force_quick_range) < 0; } inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; } - int test_quick_select(key_map keys,table_map prev_tables,ha_rows limit, - bool force_quick_range=0); + int test_quick_select(THD *thd, key_map keys, table_map prev_tables, + ha_rows limit, bool force_quick_range=0); }; -QUICK_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref); +QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, + struct st_table_ref *ref); #endif diff --git a/sql/protocol.cc b/sql/protocol.cc index 79420fb71d5..0fe759cff67 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -833,17 +833,12 @@ bool Protocol_simple::store(TIME *tm) field_pos++; #endif char buff[40]; - uint length; - length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", - (int) tm->year, - (int) tm->month, - (int) tm->day, - (int) tm->hour, - (int) tm->minute, - (int) tm->second)); - if (tm->second_part) - length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); - return net_store_data((char*) buff, length); + String tmp((char*) buff,sizeof(buff),&my_charset_bin); + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, DATETIME_FORMAT_TYPE).datetime_format); + make_datetime(&tmp, tm, 1, tm->second_part, + tmp_format->format, tmp_format->format_length, 1); + return net_store_data((char*) tmp.ptr(), tmp.length()); } @@ -855,12 +850,12 @@ bool Protocol_simple::store_date(TIME *tm) field_pos++; #endif char buff[40]; - uint length; - length= my_sprintf(buff,(buff, "%04d-%02d-%02d", - (int) tm->year, - (int) tm->month, - (int) tm->day)); - return net_store_data((char*) buff, length); + String tmp((char*) buff,sizeof(buff),&my_charset_bin); + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, DATE_FORMAT_TYPE).datetime_format); + make_datetime(&tmp, tm, 1, 0, + tmp_format->format, tmp_format->format_length, 1); + return net_store_data((char*) tmp.ptr(), tmp.length()); } @@ -878,16 +873,14 @@ bool Protocol_simple::store_time(TIME *tm) field_pos++; #endif char buff[40]; - uint length; + String tmp((char*) buff,sizeof(buff),&my_charset_bin); + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, TIME_FORMAT_TYPE).datetime_format); uint day= (tm->year || tm->month) ? 0 : tm->day; - length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", - tm->neg ? "-" : "", - (long) day*24L+(long) tm->hour, - (int) tm->minute, - (int) tm->second)); - if (tm->second_part) - length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); - return net_store_data((char*) buff, length); + tm->hour= (long) day*24L+(long) tm->hour; + make_datetime(&tmp, tm, 0, tm->second_part, + tmp_format->format, tmp_format->format_length, 1); + return net_store_data((char*) tmp.ptr(), tmp.length()); } diff --git a/sql/set_var.cc b/sql/set_var.cc index eb456b0745f..48580960399 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -51,6 +51,7 @@ #include "slave.h" #include "sql_acl.h" #include <my_getopt.h> +#include <thr_alarm.h> #include <myisam.h> #ifdef HAVE_BERKELEY_DB #include "ha_berkeley.h" @@ -90,6 +91,7 @@ static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); +static void fix_max_connections(THD *thd, enum_var_type type); static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); @@ -162,11 +164,13 @@ sys_var_long_ptr sys_max_binlog_size("max_binlog_size", &max_binlog_size, fix_max_binlog_size); sys_var_long_ptr sys_max_connections("max_connections", - &max_connections); + &max_connections, + fix_max_connections); sys_var_long_ptr sys_max_connect_errors("max_connect_errors", &max_connect_errors); sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads", - &max_insert_delayed_threads); + &max_insert_delayed_threads, + fix_max_connections); sys_var_thd_ulong sys_max_error_count("max_error_count", &SV::max_error_count); sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", @@ -235,6 +239,18 @@ sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", sys_var_long_ptr sys_query_cache_size("query_cache_size", &query_cache_size, fix_query_cache_size); + +sys_var_thd_ulong sys_range_alloc_block_size("range_alloc_block_size", + &SV::range_alloc_block_size); +sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size", + &SV::query_alloc_block_size); +sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size", + &SV::query_prealloc_size); +sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", + &SV::trans_alloc_block_size); +sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", + &SV::trans_prealloc_size); + #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", &query_cache.query_cache_limit); @@ -387,6 +403,9 @@ sys_var *sys_variables[]= &sys_collation_server, &sys_concurrent_insert, &sys_connect_timeout, + &g_datetime_frm(DATE_FORMAT_TYPE), + &g_datetime_frm(DATETIME_FORMAT_TYPE), + &g_datetime_frm(TIME_FORMAT_TYPE), &sys_default_week_format, &sys_delay_key_write, &sys_delayed_insert_limit, @@ -441,7 +460,9 @@ sys_var *sys_variables[]= &sys_old_passwords, &sys_preload_buff_size, &sys_pseudo_thread_id, + &sys_query_alloc_block_size, &sys_query_cache_size, + &sys_query_prealloc_size, #ifdef HAVE_QUERY_CACHE &sys_query_cache_limit, &sys_query_cache_min_res_unit, @@ -450,6 +471,7 @@ sys_var *sys_variables[]= &sys_quote_show_create, &sys_rand_seed1, &sys_rand_seed2, + &sys_range_alloc_block_size, &sys_read_buff_size, &sys_read_rnd_buff_size, #ifdef HAVE_REPLICATION @@ -478,6 +500,8 @@ sys_var *sys_variables[]= &sys_thread_cache_size, &sys_timestamp, &sys_tmp_table_size, + &sys_trans_alloc_block_size, + &sys_trans_prealloc_size, &sys_tx_isolation, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, @@ -519,6 +543,8 @@ struct show_var_st init_vars[]= { {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, + {"date_format", (char*) &g_datetime_frm(DATE_FORMAT_TYPE), SHOW_SYS}, + {"datetime_format", (char*) &g_datetime_frm(DATETIME_FORMAT_TYPE), SHOW_SYS}, {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS}, {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, @@ -629,6 +655,8 @@ struct show_var_st init_vars[]= { {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, + {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, + SHOW_SYS}, #ifdef HAVE_QUERY_CACHE {sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS}, {sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit, @@ -637,6 +665,9 @@ struct show_var_st init_vars[]= { {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ + {sys_query_prealloc_size.name, (char*) &sys_query_prealloc_size, SHOW_SYS}, + {sys_range_alloc_block_size.name, (char*) &sys_range_alloc_block_size, + SHOW_SYS}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, @@ -670,19 +701,89 @@ struct show_var_st init_vars[]= { #endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS}, + {"time_format", (char*) &g_datetime_frm(TIME_FORMAT_TYPE), SHOW_SYS}, #ifdef HAVE_TZNAME {"timezone", time_zone, SHOW_CHAR}, #endif {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, + {sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size, + SHOW_SYS}, + {sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS}, {"version", server_version, SHOW_CHAR}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} }; + /* Functions to check and update variables */ +char *update_datetime_format(THD *thd, enum enum_var_type type, + enum datetime_format_types format_type, + DATETIME_FORMAT *tmp_format) +{ + char *old_value; + if (type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + old_value= g_datetime_frm(format_type).datetime_format.format; + g_datetime_frm(format_type).datetime_format= *tmp_format; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + { + old_value= t_datetime_frm(thd,format_type).datetime_format.format; + t_datetime_frm(thd, format_type).datetime_format= *tmp_format; + } + return old_value; +} + + +bool sys_var_datetime_format::update(THD *thd, set_var *var) +{ + DATETIME_FORMAT tmp_format; + char *old_value; + uint new_length; + + if ((new_length= var->value->str_value.length())) + { + if (!make_format(&tmp_format, format_type, + var->value->str_value.ptr(), + new_length, 1)) + return 1; + } + + old_value= update_datetime_format(thd, var->type, format_type, &tmp_format); + my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); + return 0; +} + +byte *sys_var_datetime_format::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + if (type == OPT_GLOBAL) + return (byte*) g_datetime_frm(format_type).datetime_format.format; + return (byte*) t_datetime_frm(thd, format_type).datetime_format.format; +} + +void sys_var_datetime_format::set_default(THD *thd, enum_var_type type) +{ + DATETIME_FORMAT tmp_format; + char *old_value; + uint new_length; + + if ((new_length= strlen(opt_datetime_formats[format_type]))) + { + if (!make_format(&tmp_format, format_type, + opt_datetime_formats[format_type], + new_length, 1)) + return; + } + + old_value= update_datetime_format(thd, type, format_type, &tmp_format); + my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); +} /* The following 3 functions need to be changed in 4.1 when we allow @@ -748,7 +849,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type) thd->options&= ~OPTION_BIG_SELECTS; } } - + /* If one doesn't use the SESSION modifier, the isolation level @@ -816,7 +917,7 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type) #endif -void fix_delay_key_write(THD *thd, enum_var_type type) +extern void fix_delay_key_write(THD *thd, enum_var_type type) { switch ((enum_delay_key_write) delay_key_write_options) { case DELAY_KEY_WRITE_NONE: @@ -832,7 +933,7 @@ void fix_delay_key_write(THD *thd, enum_var_type type) } } -void fix_max_binlog_size(THD *thd, enum_var_type type) +static void fix_max_binlog_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_binlog_size"); DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", @@ -845,7 +946,7 @@ void fix_max_binlog_size(THD *thd, enum_var_type type) DBUG_VOID_RETURN; } -void fix_max_relay_log_size(THD *thd, enum_var_type type) +static void fix_max_relay_log_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_relay_log_size"); DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", @@ -857,6 +958,13 @@ void fix_max_relay_log_size(THD *thd, enum_var_type type) DBUG_VOID_RETURN; } + +static void fix_max_connections(THD *thd, enum_var_type type) +{ + resize_thr_alarm(max_connections + max_insert_delayed_threads + 10); +} + + bool sys_var_long_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->value->val_int(); @@ -1082,7 +1190,8 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type, bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { - char buff[80], *value; + char buff[80]; + const char *value; String str(buff, sizeof(buff), system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) @@ -1092,7 +1201,7 @@ bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) (ulong) find_type(res->c_ptr(), enum_names, 3)-1)) < 0) { - value=res->c_ptr(); + value= res ? res->c_ptr() : "NULL"; goto err; } } @@ -2050,7 +2159,7 @@ int set_var::check(THD *thd) { my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name); return -1; - } + } return var->check(thd, this) ? -1 : 0; } @@ -2205,7 +2314,7 @@ ulong fix_sql_mode(ulong sql_mode) MODE_IGNORE_SPACE | MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS); - if (sql_mode & MODE_SAPDB) + if (sql_mode & MODE_MAXDB) sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | diff --git a/sql/set_var.h b/sql/set_var.h index 812bd6c9420..4c67c5ccc59 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -49,6 +49,8 @@ public: const char *name; sys_after_update_func after_update; + sys_var() + {} sys_var(const char *name_arg) :name(name_arg),after_update(0) {} sys_var(const char *name_arg,sys_after_update_func func) @@ -188,6 +190,9 @@ public: class sys_var_thd :public sys_var { public: + sys_var_thd() + :sys_var() + {} sys_var_thd(const char *name_arg) :sys_var(name_arg) {} @@ -555,6 +560,51 @@ public: }; +class sys_var_datetime_format :public sys_var_thd +{ +public: + enum datetime_format_types format_type; + DATETIME_FORMAT datetime_format; + sys_var_datetime_format(): sys_var_thd() + {} + + void clean() + { + my_free(datetime_format.format, MYF(MY_ALLOW_ZERO_PTR)); + datetime_format.format=0; + } + + /* + It's for copying of global_system_variables structure + in THD constructor. + */ + inline sys_var_datetime_format& operator= (sys_var_datetime_format& s) + { + if (&s != this) + { + name= s.name; name_length= s.name_length; + datetime_format= s.datetime_format; + datetime_format.format= (my_strdup_with_length + (s.datetime_format.format, + s.datetime_format. + format_length, MYF(0))); + format_type= s.format_type; + } + return *this; + } + + SHOW_TYPE type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) + { + return type != STRING_RESULT; /* Only accept strings */ + } + bool check_default(enum_var_type type) { return 0; } + bool update(THD *thd, set_var *var); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + void set_default(THD *thd, enum_var_type type); +}; + + /* Variable that you can only read from */ class sys_var_readonly: public sys_var @@ -693,7 +743,7 @@ public: uint name_length_arg, gptr data_arg) :name_length(name_length_arg), data(data_arg) { - name= my_memdup(name_arg, name_length, MYF(MY_WME)); + name= my_memdup((byte*) name_arg, name_length, MYF(MY_WME)); links->push_back(this); } inline bool cmp(const char *name_cmp, uint length) diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 29d8b255251..bb7cd90b4c4 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -268,8 +268,8 @@ character-set=latin2 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -291,3 +291,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index d603555727b..48a4fee22f8 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -262,8 +262,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -285,3 +285,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 53a19464745..98fb9278cc2 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -270,8 +270,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -293,3 +293,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index c54f56b2529..9a266c41669 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -259,8 +259,8 @@ character-set=latin1 "Slave is already running" "Slave has already been stopped" "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)" -"Z_BUF_ERROR: Not enough memory available for zlib" -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)" +"Z_MEM_ERROR: Not enough memory available for zlib" +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)" "Z_DATA_ERROR: Input data was corrupted for zlib" "%d line(s) was(were) cut by group_concat()" "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 2997a4d4501..e596863907f 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -264,8 +264,8 @@ character-set=latin7 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -287,3 +287,4 @@ character-set=latin7 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index cd346270ea8..a81b8859692 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -259,8 +259,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index bbace563bcb..9554822a5ff 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -271,8 +271,8 @@ character-set=latin1 "Slave läuft bereits", "Slave wurde bereits angehalten", "Unkomprimierte Daten sind zu groß. Die maximale Größe beträgt %d", -"Z_BUF_ERROR: Für zlib steht nicht genug Speicher zur Verfügung", -"Z_MEM_ERROR: Im Ausgabepuffer ist nicht genug Platz für zlib vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)", +"Z_MEM_ERROR: Für zlib steht nicht genug Speicher zur Verfügung", +"Z_BUF_ERROR: Im Ausgabepuffer ist nicht genug Platz für zlib vorhanden (wahrscheinlich wurde die Länge der unkomprimierten Daten beschädigt)", "Z_DATA_ERROR: Eingabedaten für zlib beschädigt", "%d Zeile(n) durch group_concat() abgeschnitten", "Anzahl der Datensätze in Zeile %ld geringer als Anzahl der Spalten", @@ -294,3 +294,4 @@ character-set=latin1 "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL", "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet", "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert" +"Incorrect index name '%-.100s'", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 31259e9e02f..073289562b3 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -259,8 +259,8 @@ character-set=greek "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=greek "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 52dfb702231..c62a7c7b1ae 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -261,8 +261,8 @@ character-set=latin2 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 7efca542348..004d7d00994 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -259,8 +259,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index f7d6d7be29b..888ac449a8b 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -261,8 +261,8 @@ character-set=ujis "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=ujis "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 654081c6895..a72d6c3fdee 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -259,8 +259,8 @@ character-set=euckr "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=euckr "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 76f725a9419..3c6dca27016 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -261,8 +261,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index fe15f7c9b8b..bafc635a184 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -261,8 +261,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 12e1d539e76..0aa25aabb44 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -263,8 +263,8 @@ character-set=latin2 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -286,3 +286,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 49ca7ee5c56..33d8f68291d 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -260,8 +260,8 @@ character-set=latin1 "O slave já está rodando", "O slave já está parado", "Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)", -"Z_BUF_ERROR: Não suficiente memória disponível para zlib", -"Z_MEM_ERROR: Não suficiente espaço no buffer emissor para zlib (provavelmente, o comprimento dos dados descomprimidos está corrupto)", +"Z_MEM_ERROR: Não suficiente memória disponível para zlib", +"Z_BUF_ERROR: Não suficiente espaço no buffer emissor para zlib (provavelmente, o comprimento dos dados descomprimidos está corrupto)", "Z_DATA_ERROR: Dados de entrada está corrupto para zlib", "%d linha(s) foi(foram) cortada(s) por group_concat()", "Record count is fewer than the column count at row %ld"; @@ -283,3 +283,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 30e87fe3d0a..ff46caf2c6c 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -263,8 +263,8 @@ character-set=latin2 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -286,3 +286,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index b444348612f..f8bdb8bf4a5 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -261,8 +261,8 @@ character-set=koi8r "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=koi8r "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 32b94548bc5..cede04e36ed 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -254,8 +254,8 @@ character-set=cp1250 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -277,3 +277,4 @@ character-set=cp1250 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 45e40caedee..0759f68a1bb 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -267,8 +267,8 @@ character-set=latin2 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -290,3 +290,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index bce03456941..b9c1b297e43 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -261,8 +261,8 @@ character-set=latin1 "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 827419d76e7..456b93fbc4d 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -259,8 +259,8 @@ character-set=latin1 "Slaven har redan startat", "Slaven har redan stoppat", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d rad(er) kapades av group_concat()", "Record count is fewer than the column count at row %ld"; @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index fcf0c695c29..dba62fd60c8 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -264,8 +264,8 @@ character-set=koi8u "Slave is already running", "Slave has already been stopped", "Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"Z_MEM_ERROR: Not enough memory available for zlib", +"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", "Z_DATA_ERROR: Input data was corrupted for zlib", "%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; @@ -287,3 +287,4 @@ character-set=koi8u "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Incorrect index name '%-.100s'", diff --git a/sql/slave.cc b/sql/slave.cc index 3e98386bbb1..bb190762855 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1086,11 +1086,12 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) BINLOG_FORMAT_323_GEQ_57 ; break; case '4': - case '5': mi->old_format = BINLOG_FORMAT_CURRENT; break; default: - errmsg = "Master reported unrecognized MySQL version"; + /* 5.0 is not supported */ + errmsg = "Master reported an unrecognized MySQL version. Note that 4.0 \ +slaves can't replicate a 5.0 or newer master."; break; } @@ -3165,6 +3166,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff)); err: + /* Free temporary tables etc */ + thd->cleanup(); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety VOID(pthread_mutex_unlock(&LOCK_thread_count)); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 179da6096de..a27dd3999fe 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -186,7 +186,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) thd->net.last_error); goto end; } - init_sql_alloc(&mem,1024,0); + init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); while (!(read_record_info.read_record(&read_record_info))) @@ -2450,7 +2450,7 @@ my_bool grant_init(THD *org_thd) (void) hash_init(&column_priv_hash,&my_charset_latin1, 0,0,0, (hash_get_key) get_grant_table, (hash_free_key) free_grant_table,0); - init_sql_alloc(&memex,1024,0); + init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); /* Don't do anything if running with --skip-grant */ if (!initialized) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index cdca7454698..588031643d4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -90,8 +90,9 @@ THD::THD():user_time(0), is_fatal_error(0), { host=user=priv_user=db=query=ip=0; host_or_ip= "connecting host"; - locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password= + locked=killed=some_tables_deleted=no_errors=password= query_start_used=prepare_command=0; + count_cuted_fields= CHECK_FIELD_IGNORE; db_length=query_length=col_access=0; query_error= tmp_table_used= 0; next_insert_id=last_insert_id=0; @@ -147,7 +148,7 @@ THD::THD():user_time(0), is_fatal_error(0), bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root)); bzero((char*) &con_root,sizeof(con_root)); bzero((char*) &warn_root,sizeof(warn_root)); - init_alloc_root(&warn_root, 1024, 0); + init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); user_connect=(USER_CONN *)0; hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, @@ -173,6 +174,7 @@ THD::THD():user_time(0), is_fatal_error(0), protocol_simple.init(this); protocol_prep.init(this); + tablespace_op=FALSE; #ifdef USING_TRANSACTIONS bzero((char*) &transaction,sizeof(transaction)); if (opt_using_transactions) @@ -229,9 +231,11 @@ void THD::init(void) void THD::init_for_queries() { - init_sql_alloc(&mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); + init_sql_alloc(&mem_root, variables.query_alloc_block_size, + variables.query_prealloc_size); init_sql_alloc(&transaction.mem_root, - TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC); + variables.trans_alloc_block_size, + variables.trans_prealloc_size); } @@ -275,6 +279,9 @@ void THD::cleanup(void) close_thread_tables(this); } close_temporary_tables(this); + variables.datetime_formats[DATE_FORMAT_TYPE].clean(); + variables.datetime_formats[TIME_FORMAT_TYPE].clean(); + variables.datetime_formats[DATETIME_FORMAT_TYPE].clean(); delete_dynamic(&user_var_events); hash_free(&user_vars); if (global_read_lock) diff --git a/sql/sql_class.h b/sql/sql_class.h index 5e5d0335e9d..06bc29dbb2a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -34,6 +34,9 @@ enum enum_log_type { LOG_CLOSED, LOG_TO_BE_OPENED, LOG_NORMAL, LOG_NEW, LOG_BIN} enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; +enum enum_check_fields { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN, + CHECK_FIELD_ERROR_FOR_NULL }; + extern char internal_table_name[2]; /* log info errors */ @@ -389,10 +392,15 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; - /* Determines if which non-standard SQL behaviour should be enabled */ + /* Determines which non-standard SQL behaviour should be enabled */ ulong sql_mode; ulong default_week_format; ulong max_seeks_for_key; + ulong range_alloc_block_size; + ulong query_alloc_block_size; + ulong query_prealloc_size; + ulong trans_alloc_block_size; + ulong trans_prealloc_size; ulong group_concat_max_len; /* In slave thread we need to know in behalf of which @@ -413,6 +421,7 @@ struct system_variables CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; + sys_var_datetime_format datetime_formats[3]; }; void free_tmp_table(THD *thd, TABLE *entry); @@ -502,6 +511,7 @@ public: time_t connect_time,thr_create_time; // track down slow pthread_create thr_lock_type update_lock_default; delayed_insert *di; + my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ struct st_transactions { IO_CACHE trans_log; THD_TRANS all; // Trans since BEGIN WORK @@ -568,6 +578,7 @@ public: uint select_number; //number of select (used for EXPLAIN) /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; + enum_check_fields count_cuted_fields; /* for user variables replication*/ DYNAMIC_ARRAY user_var_events; @@ -575,7 +586,7 @@ public: char scramble[SCRAMBLE_LENGTH+1]; bool slave_thread; - bool set_query_id,locked,count_cuted_fields,some_tables_deleted; + bool set_query_id,locked,some_tables_deleted; bool last_cuted_field; bool no_errors, allow_sum_func, password, is_fatal_error; bool query_start_used,last_insert_id_used,insert_id_used,rand_used; @@ -857,8 +868,7 @@ public: List<Item> &select_fields,enum_duplicates duplic) :select_insert (NULL, &select_fields, duplic), db(db_name), name(table_name), extra_fields(&fields_par),keys(&keys_par), - create_info(create_info_par), - lock(0) + create_info(create_info_par), lock(0) {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &values); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 48ef5b4b74c..070d4cbbce9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -89,7 +89,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, select=make_select(table,0,0,conds,&error); if (error) DBUG_RETURN(-1); - if ((select && select->check_quick(safe_update, limit)) || !limit) + if ((select && select->check_quick(thd, safe_update, limit)) || !limit) { delete select; free_underlaid_joins(thd, &thd->lex.select_lex); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index aac2e17086b..719686a56c3 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -220,7 +220,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, } } else - unit->exclude_level(); + unit->exclude_tree(); org_table_list->db= (char *)""; // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 93ab332bcd5..bce1022d5c0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -33,7 +33,7 @@ The second is to be freeed only on thread end. mysql_ha_open should then do { handler_items=concat(handler_items, free_list); free_list=0; } - But !!! do_cammand calls free_root at the end of every query and frees up + But !!! do_command calls free_root at the end of every query and frees up all the sql_alloc'ed memory. It's harder to work around... */ @@ -72,7 +72,11 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) if (*ptr) { VOID(pthread_mutex_lock(&LOCK_open)); - close_thread_table(thd, ptr); + if (close_thread_table(thd, ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } VOID(pthread_mutex_unlock(&LOCK_open)); } else @@ -89,8 +93,11 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) int mysql_ha_closeall(THD *thd, TABLE_LIST *tables) { TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0); - if (*ptr) - close_thread_table(thd, ptr); + if (*ptr && close_thread_table(thd, ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } return 0; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 02fc8591370..6af4ffde0e1 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -599,7 +599,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, { cond->fix_fields(thd, tables, &cond); // can never fail SQL_SELECT *res= make_select(table,0,0,cond,error); - return (*error || (res && res->check_quick(0, HA_POS_ERROR))) ? 0 : res; + return (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR))) ? 0 : res; } /* @@ -627,6 +627,8 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, Item *cond= new Item_func_like(new Item_field(pfname), new Item_string(mask,mlen,pfname->charset()), (char*) "\\"); + if (thd->is_fatal_error) + return 0; // OOM return prepare_simple_select(thd,cond,tables,table,error); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0ad66beec2e..9077d4c6a2d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -240,9 +240,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, info.handle_duplicates=duplic; info.update_fields=&update_fields; info.update_values=&update_values; - // Don't count warnings for simple inserts - if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS)) - thd->count_cuted_fields = 1; + /* + Count warnings for all inserts. + For single line insert, generate an error if try to set a NOT NULL field + to NULL + */ + thd->count_cuted_fields= ((values_list.elements == 1) ? + CHECK_FIELD_ERROR_FOR_NULL : + CHECK_FIELD_WARN); thd->cuted_fields = 0L; table->next_number_field=table->found_next_number_field; @@ -394,7 +399,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, } thd->proc_info="end"; table->next_number_field=0; - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used if (duplic != DUP_ERROR) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); @@ -1391,7 +1396,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) restore_record(table,default_values); // Get empty record table->next_number_field=table->found_next_number_field; - thd->count_cuted_fields=1; // calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0; if (info.handle_duplicates != DUP_REPLACE) table->file->extra(HA_EXTRA_WRITE_CACHE); @@ -1409,7 +1414,7 @@ select_insert::~select_insert() table->next_number_field=0; table->file->extra(HA_EXTRA_RESET); } - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; } @@ -1548,6 +1553,14 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (!table) DBUG_RETURN(-1); // abort() deletes table + if (table->fields < values.elements) + { + my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, + ER(ER_WRONG_VALUE_COUNT_ON_ROW), + MYF(0),1); + DBUG_RETURN(-1); + } + /* First field to copy */ field=table->field+table->fields - values.elements; @@ -1559,7 +1572,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->next_number_field=table->found_next_number_field; restore_record(table,default_values); // Get empty record - thd->count_cuted_fields=1; // count warnings + thd->count_cuted_fields= CHECK_FIELD_WARN; // count warnings thd->cuted_fields=0; if (info.handle_duplicates == DUP_IGNORE || info.handle_duplicates == DUP_REPLACE) @@ -1606,7 +1619,7 @@ bool select_create::send_eof() */ if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); - lock=0; + lock=0; table=0; VOID(pthread_mutex_unlock(&LOCK_open)); } @@ -1627,7 +1640,8 @@ void select_create::abort() enum db_type table_type=table->db_type; if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); - quick_rm_table(table_type,db,name); + if (!create_info->table_existed) + quick_rm_table(table_type,db,name); table=0; } VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 024d35150d8..ee9831c1f5b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1097,6 +1097,16 @@ void st_select_lex_node::exclude() */ } + +/* + Exclude level of current unit from tree of SELECTs + + SYNOPSYS + st_select_lex_unit::exclude_level() + + NOTE: units which belong to current will be brought up on level of + currernt unit +*/ void st_select_lex_unit::exclude_level() { SELECT_LEX_UNIT *units= 0, **units_last= &units; @@ -1125,6 +1135,30 @@ void st_select_lex_unit::exclude_level() (*prev)= next; } + +/* + Exclude subtree of current unit from tree of SELECTs + + SYNOPSYS + st_select_lex_unit::exclude_tree() +*/ +void st_select_lex_unit::exclude_tree() +{ + SELECT_LEX_UNIT *units= 0, **units_last= &units; + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->link_prev && (*sl->link_prev= sl->link_next)) + sl->link_next->link_prev= sl->link_prev; + + for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) + { + u->exclude_level(); + } + } + (*prev)= next; +} + + /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from this to 'last' as dependent @@ -1135,7 +1169,6 @@ void st_select_lex_unit::exclude_level() NOTE 'last' should be reachable from this st_select_lex_node - */ void st_select_lex::mark_as_dependent(SELECT_LEX *last) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2e62d65fd20..f78f1171d06 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -114,6 +114,11 @@ enum olap_type UNSPECIFIED_OLAP_TYPE, CUBE_TYPE, ROLLUP_TYPE }; +enum tablespace_op_type +{ + NO_TABLESPACE_OP, DISCARD_TABLESPACE, IMPORT_TABLESPACE +}; + /* The state of the lex parsing for selects @@ -320,6 +325,7 @@ public: st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } st_select_lex* return_after_parsing() { return return_to; } void exclude_level(); + void exclude_tree(); /* UNION methods */ int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); @@ -539,6 +545,7 @@ 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; + enum tablespace_op_type tablespace_op; uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0a5c544c2e7..0e7895689b5 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -252,7 +252,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, restore_record(table,default_values); - thd->count_cuted_fields=1; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; if (ex->line_term->length() && field_term->length()) { @@ -293,7 +293,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ table->copy_blobs=0; - thd->count_cuted_fields=0; /* Don`t calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* We must invalidate the table in query cache before binlog writing and diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fbd74c68ffb..5af944dac87 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2217,7 +2217,9 @@ mysql_execute_command(THD *thd) select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, lex->drop_primary, lex->duplicates, - lex->alter_keys_onoff, lex->simple_alter); + lex->alter_keys_onoff, + lex->tablespace_op, + lex->simple_alter); } break; } @@ -3415,7 +3417,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, /* grant_option is set if there exists a single table or column grant */ if (db_access == want_access || ((grant_option && !dont_check_global_grants) && - !(want_access & ~TABLE_ACLS))) + !(want_access & ~(db_access | TABLE_ACLS)))) DBUG_RETURN(FALSE); /* Ok */ if (!no_errors) net_printf(thd,ER_DBACCESS_DENIED_ERROR, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dd8d5613880..522879c863a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -888,12 +888,15 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { MEM_ROOT thd_root= thd->mem_root; PREP_STMT stmt; + SELECT_LEX *sl; DBUG_ENTER("mysql_stmt_prepare"); bzero((char*) &stmt, sizeof(stmt)); stmt.stmt_id= ++thd->current_stmt_id; - init_sql_alloc(&stmt.mem_root, 8192, 8192); + init_sql_alloc(&stmt.mem_root, + thd->variables.query_alloc_block_size, + thd->variables.query_prealloc_size); stmt.thd= thd; stmt.thd->mem_root= stmt.mem_root; @@ -908,7 +911,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) 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; + for (sl= thd->lex.all_selects_list; sl; sl= sl->next_select_in_list()) { @@ -943,8 +946,9 @@ err: void mysql_stmt_execute(THD *thd, char *packet) { - ulong stmt_id= uint4korr(packet); - PREP_STMT *stmt; + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + SELECT_LEX *sl; DBUG_ENTER("mysql_stmt_execute"); if (!(stmt=find_prepared_statement(thd, stmt_id, "execute"))) @@ -963,11 +967,13 @@ 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; + for (sl= stmt->lex.all_selects_list; sl; sl= sl->next_select_in_list()) { - // copy WHERE clause pointers to avoid damaging they by optimisation + /* + 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); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f86435e1bb0..278839442e3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1600,7 +1600,8 @@ err: Approximate how many records will be used in each table *****************************************************************************/ -static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, +static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, + TABLE *table, key_map keys,ha_rows limit) { int error; @@ -1609,7 +1610,7 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, { select->head=table; table->reginfo.impossible_range=0; - if ((error=select->test_quick_select(keys,(table_map) 0,limit)) + if ((error=select->test_quick_select(thd, keys,(table_map) 0,limit)) == 1) DBUG_RETURN(select->quick->records); if (error == -1) @@ -1892,8 +1893,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, found_const_table_map, s->on_expr ? s->on_expr : conds, &error); - records= get_quick_record_count(select,s->table, s->const_keys, - join->row_limit); + records= get_quick_record_count(join->thd, select, s->table, + s->const_keys, join->row_limit); s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; @@ -3244,9 +3245,9 @@ store_val_in_field(Field *field,Item *item) bool error; THD *thd=current_thd; ha_rows cuted_fields=thd->cuted_fields; - thd->count_cuted_fields=1; + thd->count_cuted_fields= CHECK_FIELD_WARN; error= item->save_in_field(field, 1); - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; return error || cuted_fields != thd->cuted_fields; } @@ -3403,7 +3404,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) /* Join with outer join condition */ COND *orig_cond=sel->cond; sel->cond=and_conds(sel->cond,tab->on_expr); - if (sel->test_quick_select(tab->keys, + if (sel->test_quick_select(join->thd, tab->keys, used_tables & ~ current_map, (join->select_options & OPTION_FOUND_ROWS ? @@ -3416,7 +3417,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ sel->cond=orig_cond; if (!tab->on_expr || - sel->test_quick_select(tab->keys, + sel->test_quick_select(join->thd, tab->keys, used_tables & ~ current_map, (join->select_options & OPTION_FOUND_ROWS ? @@ -4891,6 +4892,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, recinfo->type=FIELD_NORMAL; if (!--hidden_field_count) null_count=(null_count+7) & ~7; // move to next byte + + // fix table name in field entry + field->table_name= table->table_name; } param->copy_field_end=copy; @@ -5854,7 +5858,8 @@ test_if_quick_select(JOIN_TAB *tab) { delete tab->select->quick; tab->select->quick=0; - return tab->select->test_quick_select(tab->keys,(table_map) 0,HA_POS_ERROR); + return tab->select->test_quick_select(tab->join->thd, tab->keys, + (table_map) 0, HA_POS_ERROR); } @@ -6947,7 +6952,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, For impossible ranges (like when doing a lookup on NULL on a NOT NULL field, quick will contain an empty record set. */ - if (!(select->quick=get_ft_or_quick_select_for_ref(table, tab))) + if (!(select->quick=get_ft_or_quick_select_for_ref(tab->join->thd, + table, tab))) goto err; } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8550973ff88..fce25da2cd0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1073,7 +1073,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) MODE_ORACLE | MODE_MSSQL | MODE_DB2 | - MODE_SAPDB | + MODE_MAXDB | MODE_ANSI)) != 0; my_bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 16afd592e59..3d07c7e04de 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -861,6 +861,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, key_info->name=(char*) key_name; } } + if (!key_info->name || check_column_name(key_info->name)) + { + my_error(ER_WRONG_INDEX_NAME, MYF(0), key_info->name); + DBUG_RETURN(-1); + } if (!(key_info->flags & HA_NULL_PART_KEY)) unique_key=1; key_info->key_length=(uint16) key_length; @@ -901,7 +906,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, && find_temporary_table(thd,db,table_name)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + create_info->table_existed= 1; // Mark that table existed DBUG_RETURN(0); + } my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); DBUG_RETURN(-1); } @@ -913,14 +921,18 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (!access(path,F_OK)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + create_info->table_existed= 1; // Mark that table existed error= 0; + } else - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } thd->proc_info="creating table"; + create_info->table_existed= 0; // Mark that table is created if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) create_info->data_file_name= create_info->index_file_name= 0; @@ -1748,6 +1760,69 @@ int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt) &handler::check)); } +/* table_list should contain just one table */ +int mysql_discard_or_import_tablespace(THD *thd, + TABLE_LIST *table_list, + enum tablespace_op_type tablespace_op) +{ + TABLE *table; + my_bool discard; + int error; + DBUG_ENTER("mysql_discard_or_import_tablespace"); + + /* Note that DISCARD/IMPORT TABLESPACE always is the only operation in an + ALTER TABLE */ + + thd->proc_info="discard_or_import_tablespace"; + + if (tablespace_op == DISCARD_TABLESPACE) + discard = TRUE; + else + discard = FALSE; + + thd->tablespace_op=TRUE; /* we set this flag so that ha_innobase::open + and ::external_lock() do not complain when we + lock the table */ + mysql_ha_closeall(thd, table_list); + + if (!(table=open_ltable(thd,table_list,TL_WRITE))) + { + thd->tablespace_op=FALSE; + DBUG_RETURN(-1); + } + + error=table->file->discard_or_import_tablespace(discard); + + thd->proc_info="end"; + + if (error) + goto err; + + /* The 0 in the call below means 'not in a transaction', which means + immediate invalidation; that is probably what we wish here */ + query_cache_invalidate3(thd, table_list, 0); + + /* The ALTER TABLE is always in its own transaction */ + error = ha_commit_stmt(thd); + if (ha_commit(thd)) + error=1; + if (error) + goto err; + mysql_update_log.write(thd, thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, 0); + mysql_bin_log.write(&qinfo); + } +err: + close_thread_tables(thd); + thd->tablespace_op=FALSE; + if (error == 0) { + send_ok(thd); + DBUG_RETURN(0); + } + DBUG_RETURN(error); +} int mysql_alter_table(THD *thd,char *new_db, char *new_name, HA_CREATE_INFO *create_info, @@ -1759,6 +1834,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, bool drop_primary, enum enum_duplicates handle_duplicates, enum enum_enable_or_disable keys_onoff, + enum tablespace_op_type tablespace_op, bool simple_alter) { TABLE *table,*new_table; @@ -1771,6 +1847,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, ulonglong next_insert_id; uint save_time_stamp,db_create_options, used_fields; enum db_type old_db_type,new_db_type; + thr_lock_type lock_type; DBUG_ENTER("mysql_alter_table"); thd->proc_info="init"; @@ -1781,6 +1858,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, used_fields=create_info->used_fields; mysql_ha_closeall(thd, table_list); + + /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ + if (tablespace_op != NO_TABLESPACE_OP) + DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, + tablespace_op)); if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) DBUG_RETURN(-1); @@ -1834,8 +1916,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (create_info->row_type == ROW_TYPE_NOT_USED) create_info->row_type=table->row_type; - /* In some simple cases we need not to recreate the table */ - thd->proc_info="setup"; if (simple_alter && !table->tmp_table) { @@ -1860,6 +1940,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } VOID(pthread_mutex_unlock(&LOCK_open)); } + if (!error) { switch (keys_onoff) { @@ -2236,7 +2317,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (use_timestamp) new_table->time_stamp=0; new_table->next_number_field=new_table->found_next_number_field; - thd->count_cuted_fields=1; // calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; thd->proc_info="copy to tmp table"; next_insert_id=thd->next_insert_id; // Remember for loggin @@ -2246,7 +2327,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, handle_duplicates, order_num, order, &copied, &deleted); thd->last_insert_id=next_insert_id; // Needed for correct log - thd->count_cuted_fields=0; // Don`t calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_IGNORE; new_table->time_stamp=save_time_stamp; if (table->tmp_table) @@ -2395,8 +2476,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; } } - - /* The ALTER TABLE is always in it's own transaction */ + /* The ALTER TABLE is always in its own transaction */ error = ha_commit_stmt(thd); if (ha_commit(thd)) error=1; @@ -2656,9 +2736,9 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) while (!t->file->rnd_next(t->record[0])) { ha_checksum row_crc= 0; - if (t->record[0] != t->field[0]->ptr) + if (t->record[0] != (byte*) t->field[0]->ptr) row_crc= my_checksum(row_crc, t->record[0], - t->field[0]->ptr - t->record[0]); + ((byte*) t->field[0]->ptr) - t->record[0]); for (uint i= 0; i < t->fields; i++ ) { @@ -2667,10 +2747,11 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) { String tmp; f->val_str(&tmp,&tmp); - row_crc= my_checksum(row_crc, tmp.ptr(), tmp.length()); + row_crc= my_checksum(row_crc, (byte*) tmp.ptr(), tmp.length()); } else - row_crc= my_checksum(row_crc, f->ptr, f->pack_length()); + row_crc= my_checksum(row_crc, (byte*) f->ptr, + f->pack_length()); } crc+= row_crc; @@ -2695,4 +2776,3 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) table->table=0; DBUG_RETURN(-1); } - diff --git a/sql/sql_test.cc b/sql/sql_test.cc index f991a09398b..112d42e4643 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -22,6 +22,7 @@ #include "sql_select.h" #include <hash.h> #include <thr_alarm.h> +#include <malloc.h> /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; @@ -300,6 +301,8 @@ void mysql_print_status(THD *thd) printf("\nStatus information:\n\n"); my_getwd(current_dir, sizeof(current_dir),MYF(0)); printf("Current dir: %s\n", current_dir); + printf("Running threads: %d Stack size: %ld\n", thread_count, + (long) thread_stack); if (thd) thd->proc_info="locks"; thr_print_locks(); // Write some debug info @@ -365,6 +368,34 @@ Next alarm time: %lu\n", thd->proc_info="malloc"; my_checkmalloc(); TERMINATE(stdout); // Write malloc information + +#ifdef HAVE_MALLINFO + struct mallinfo info= mallinfo(); + printf("\nMemory status:\n\ +Non-mmapped space allocated from system: %d\n\ +Number of free chunks: %d\n\ +Number of fastbin blocks: %d\n\ +Number of mmapped regions: %d\n\ +Space in mmapped regions: %d\n\ +Maximum total allocated space: %d\n\ +Space available in freed fastbin blocks: %d\n\ +Total allocated space: %d\n\ +Total free space: %d\n\ +Top-most, releasable space: %d\n\ +Estimated memory (with thread stack): %ld\n", + (int) info.arena , + (int) info.ordblks, + (int) info.smblks, + (int) info.hblks, + (int) info.hblkhd, + (int) info.usmblks, + (int) info.fsmblks, + (int) info.uordblks, + (int) info.fordblks, + (int) info.keepcost, + (long) (thread_count * thread_stack + info.hblkhd + info.arena)); +#endif + puts(""); if (thd) thd->proc_info=0; } diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index c237b023e7b..337f2540a39 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -128,7 +128,7 @@ void udf_init() my_rwlock_init(&THR_LOCK_udf,NULL); - init_sql_alloc(&mem, 1024,0); + init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0); THD *new_thd = new THD; if (!new_thd || hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0)) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 2ecc526a612..e14e20b62d6 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -152,7 +152,7 @@ int mysql_update(THD *thd, table->used_keys=0; select=make_select(table,0,0,conds,&error); if (error || - (select && select->check_quick(safe_update, limit)) || !limit) + (select && select->check_quick(thd, safe_update, limit)) || !limit) { delete select; free_underlaid_joins(thd, &thd->lex.select_lex); @@ -295,7 +295,7 @@ int mysql_update(THD *thd, init_read_record(&info,thd,table,select,0,1); updated= found= 0; - thd->count_cuted_fields=1; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; thd->proc_info="Updating"; query_id=thd->query_id; @@ -386,7 +386,7 @@ int mysql_update(THD *thd, thd->insert_id_used ? thd->insert_id() : 0L,buff); DBUG_PRINT("info",("%d records updated",updated)); } - thd->count_cuted_fields=0; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ free_io_cache(table); DBUG_RETURN(0); @@ -492,7 +492,7 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) uint i, max_fields; DBUG_ENTER("multi_update::prepare"); - thd->count_cuted_fields=1; + thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; thd->proc_info="updating main table"; @@ -733,7 +733,7 @@ multi_update::~multi_update() } if (copy_field) delete [] copy_field; - thd->count_cuted_fields=0; // Restore this setting + thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting if (!trans_safe) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 38d251c3aef..01cec47f717 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -78,6 +78,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) CHARSET_INFO *charset; thr_lock_type lock_type; interval_type interval; + datetime_format_types datetime_format_type; st_select_lex *select_lex; chooser_compare_func_creator boolfunc2creator; } @@ -211,6 +212,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DESCRIBE %token DES_KEY_FILE %token DISABLE_SYM +%token DISCARD %token DISTINCT %token DUPLICATE_SYM %token DYNAMIC_SYM @@ -244,6 +246,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token HOSTS_SYM %token IDENT %token IGNORE_SYM +%token IMPORT %token INDEX %token INDEXES %token INFILE @@ -360,6 +363,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SUBJECT_SYM %token TABLES %token TABLE_SYM +%token TABLESPACE %token TEMPORARY %token TERMINATED %token TEXT_STRING @@ -446,6 +450,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token BETWEEN_SYM %token BIT_AND %token BIT_OR +%token BIT_XOR %token CASE_SYM %token CONCAT %token CONCAT_WS @@ -478,6 +483,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token GEOMETRYCOLLECTION %token GROUP_CONCAT_SYM %token GROUP_UNIQUE_USERS +%token GET_FORMAT %token HOUR_MICROSECOND_SYM %token HOUR_MINUTE_SYM %token HOUR_SECOND_SYM @@ -640,6 +646,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM +%type <datetime_format_type> datetime_format_type; %type <interval> interval %type <db_type> table_types @@ -1251,7 +1258,7 @@ type: | TIME_SYM { $$=FIELD_TYPE_TIME; } | TIMESTAMP { - if (YYTHD->variables.sql_mode & MODE_SAPDB) + if (YYTHD->variables.sql_mode & MODE_MAXDB) $$=FIELD_TYPE_DATETIME; else $$=FIELD_TYPE_TIMESTAMP; @@ -1636,6 +1643,7 @@ alter: lex->create_info.table_charset= thd->variables.collation_database; lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->alter_keys_onoff=LEAVE_AS_IS; + lex->tablespace_op=NO_TABLESPACE_OP; lex->simple_alter=1; } alter_list @@ -1649,6 +1657,8 @@ alter: alter_list: + | DISCARD TABLESPACE { Lex->tablespace_op=DISCARD_TABLESPACE; } + | IMPORT TABLESPACE { Lex->tablespace_op=IMPORT_TABLESPACE; } | alter_list_item | alter_list ',' alter_list_item; @@ -2575,6 +2585,8 @@ simple_expr: { $$= new Item_func_spatial_collection(* $3, Geometry::wkbGeometryCollection, Geometry::wkbPoint); } + | GET_FORMAT '(' datetime_format_type ',' expr ')' + { $$= new Item_func_get_format($3, $5); } | HOUR_SYM '(' expr ')' { $$= new Item_func_hour($3); } | IF '(' expr ',' expr ',' expr ')' @@ -2841,6 +2853,8 @@ sum_expr: { $$=new Item_sum_and($3); } | BIT_OR '(' in_sum_expr ')' { $$=new Item_sum_or($3); } + | BIT_XOR '(' in_sum_expr ')' + { $$=new Item_sum_xor($3); } | COUNT_SYM '(' opt_all '*' ')' { $$=new Item_sum_count(new Item_int((int32) 0L,1)); } | COUNT_SYM '(' in_sum_expr ')' @@ -3188,6 +3202,11 @@ interval: | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; } | YEAR_SYM { $$=INTERVAL_YEAR; }; +datetime_format_type: + DATE_SYM {$$=DATE_FORMAT_TYPE;} + | TIME_SYM {$$=TIME_FORMAT_TYPE;} + | DATETIME {$$=DATETIME_FORMAT_TYPE;}; + table_alias: /* empty */ | AS @@ -4520,6 +4539,7 @@ keyword: | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {} | DIRECTORY_SYM {} + | DISCARD {} | DO_SYM {} | DUAL_SYM {} | DUMPFILE {} @@ -4542,6 +4562,7 @@ keyword: | FLUSH_SYM {} | GEOMETRY_SYM {} | GEOMETRYCOLLECTION {} + | GET_FORMAT {} | GRANTS {} | GLOBAL_SYM {} | HANDLER_SYM {} @@ -4551,6 +4572,7 @@ keyword: | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} + | IMPORT {} | INDEXES {} | ISOLATION {} | ISAM_SYM {} @@ -4659,6 +4681,7 @@ keyword: | SUBDATE_SYM {} | SUBJECT_SYM {} | SUPER_SYM {} + | TABLESPACE {} | TEMPORARY {} | TEXT_SYM {} | TRANSACTION_SYM {} diff --git a/sql/structs.h b/sql/structs.h index 05ebdba7a37..d9be230c049 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -24,6 +24,11 @@ typedef struct st_date_format { /* How to print date */ uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */ } DATE_FORMAT; +typedef struct st_datetime_format { + byte dt_pos[8]; + char *format; + uint format_length; +} DATETIME_FORMAT; typedef struct st_keyfile_info { /* used with ha_info() */ byte ref[MAX_REFLENGTH]; /* Pointer to current row */ @@ -110,8 +115,8 @@ typedef struct st_read_record { /* Parameter to read_record */ bool print_error, ignore_not_found_rows; } READ_RECORD; -enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL, - TIMESTAMP_TIME }; +enum timestamp_type { TIMESTAMP_NONE, WRONG_TIMESTAMP_FULL, TIMESTAMP_DATE, TIMESTAMP_FULL, + TIMESTAMP_TIME}; typedef struct st_time { uint year,month,day,hour,minute,second; diff --git a/sql/table.cc b/sql/table.cc index c31b68fc2dc..be5b7edfd93 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -90,7 +90,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->db_stat = db_stat; error=1; - init_sql_alloc(&outparam->mem_root,1024,0); + init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root); diff --git a/sql/time.cc b/sql/time.cc index 70ae8dcd8ed..f2e41afa560 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -27,6 +27,10 @@ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037 /* Init some variabels needed when using my_local_time */ /* Currently only my_time_zone is inited */ +bool parse_datetime_formats(datetime_format_types format_type, + const char *format_str, uint format_length, + byte *dt_pos); + static long my_time_zone=0; void init_time(void) @@ -316,10 +320,12 @@ ulong convert_month_to_period(ulong month) */ timestamp_type -str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) +str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) { - uint field_length,year_length,digits,i,number_of_fields,date[7]; + uint field_length= 0, year_length= 0, digits, i, number_of_fields; + uint date[7], date_len[7]; uint not_zero_date; + bool is_internal_format= 0; const char *pos; const char *end=str+length; bool found_delimitier= 0; @@ -336,24 +342,32 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) ; + /* Check for internal format */ digits= (uint) (pos-str); - year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; - field_length=year_length-1; + + if (pos == end || digits>=12) + { + is_internal_format= 1; + year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; + field_length=year_length-1; + date_len[0]= year_length; + } not_zero_date= 0; for (i=0 ; i < 6 && str != end && my_isdigit(&my_charset_latin1,*str) ; i++) { + if (!is_internal_format) + date_len[i]= 1; uint tmp_value=(uint) (uchar) (*str++ - '0'); - while (str != end && my_isdigit(&my_charset_latin1,str[0]) && - field_length--) + while (str != end && my_isdigit(&my_charset_latin1,str[0]) + && (is_internal_format && field_length-- || !is_internal_format) ) { tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); str++; + if (!is_internal_format) + date_len[i]+= 1; } - if (found_delimitier && (int) field_length < 0) - { - /* The number can't match any valid date or datetime string */ + if (i == 2 && *str == '.') DBUG_RETURN(TIMESTAMP_NONE); - } date[i]=tmp_value; not_zero_date|= tmp_value; if (i == 2 && str != end && *str == 'T') @@ -371,7 +385,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) found_delimitier=1; // Should be a 'normal' date } } - field_length=1; // Rest fields can only be 2 + if (is_internal_format) + field_length=1; // Rest fields can only be 2 } /* Handle second fractions */ if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && @@ -389,14 +404,69 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) else date[6]=0; - if (year_length == 2 && i >=2 && (date[1] || date[2])) - date[0]+= (date[0] < YY_PART_YEAR ? 2000 : 1900); + while (str != end && (my_ispunct(&my_charset_latin1,*str) || + my_isspace(&my_charset_latin1,*str))) + str++; + + uint add_hours= 0; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)str, 2, + (const uchar *)"PM", 2)) + add_hours= 12; + number_of_fields=i; while (i < 6) date[i++]=0; - if (number_of_fields < 3 || date[1] > 12 || - date[2] > 31 || date[3] > 23 || date[4] > 59 || date[5] > 59 || - (!fuzzy_date && (date[1] == 0 || date[2] == 0))) + + if (!is_internal_format) + { + byte *frm_pos; + + if (number_of_fields <= 3) + { + frm_pos= t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format.dt_pos; + l_time->hour= 0; + l_time->minute= 0; + l_time->second= 0; + } + else + { + frm_pos= t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format.dt_pos; + l_time->hour= date[(int) frm_pos[3]]; + l_time->minute=date[(int) frm_pos[4]]; + l_time->second=date[(int) frm_pos[5]]; + if (frm_pos[6] == 1) + { + if (l_time->hour > 12) + DBUG_RETURN(WRONG_TIMESTAMP_FULL); + l_time->hour= l_time->hour%12 + add_hours; + } + } + + l_time->year= date[(int) frm_pos[0]]; + l_time->month= date[(int) frm_pos[1]]; + l_time->day= date[(int) frm_pos[2]]; + year_length= date_len[(int) frm_pos[0]]; + } + else + { + l_time->year= date[0]; + l_time->month= date[1]; + l_time->day= date[2]; + l_time->hour= date[3]; + l_time->minute=date[4]; + l_time->second=date[5]; + } + l_time->second_part=date[6]; + l_time->neg= 0; + if (year_length == 2 && i >=2 && (l_time->month || l_time->day)) + l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); + + + if (number_of_fields < 3 || l_time->month > 12 || + l_time->day > 31 || l_time->hour > 23 || + l_time->minute > 59 || l_time->second > 59 || + (!fuzzy_date && (l_time->month == 0 || l_time->day == 0))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date @@ -411,53 +481,46 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) } } if (not_zero_date) - current_thd->cuted_fields++; - DBUG_RETURN(TIMESTAMP_NONE); + thd->cuted_fields++; + DBUG_RETURN(WRONG_TIMESTAMP_FULL); } - if (str != end && current_thd->count_cuted_fields) + if (str != end && thd->count_cuted_fields) { for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) { - current_thd->cuted_fields++; + thd->cuted_fields++; break; } } } - l_time->year= date[0]; - l_time->month= date[1]; - l_time->day= date[2]; - l_time->hour= date[3]; - l_time->minute=date[4]; - l_time->second=date[5]; - l_time->second_part=date[6]; - l_time->neg= 0; + DBUG_RETURN(l_time->time_type= (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); } -time_t str_to_timestamp(const char *str,uint length) +time_t str_to_timestamp(const char *str,uint length, THD *thd) { TIME l_time; long not_used; - if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE) + if (str_to_TIME(str,length,&l_time,0,thd) <= WRONG_TIMESTAMP_FULL) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) { - current_thd->cuted_fields++; + thd->cuted_fields++; return(0); } return(my_gmt_sec(&l_time, ¬_used)); } -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date) +longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) { TIME l_time; - if (str_to_TIME(str,length,&l_time,fuzzy_date) == TIMESTAMP_NONE) + if (str_to_TIME(str,length,&l_time,fuzzy_date,thd) <= WRONG_TIMESTAMP_FULL) return(0); return (longlong) (l_time.year*LL(10000000000) + l_time.month*LL(100000000)+ @@ -484,12 +547,13 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date) 1 error */ -bool str_to_time(const char *str,uint length,TIME *l_time) +bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) { long date[5],value; const char *end=str+length; bool found_days,found_hours; uint state; + byte *frm_pos= t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format.dt_pos; l_time->neg=0; for (; str != end && @@ -507,8 +571,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time) /* Check first if this is a full TIMESTAMP */ if (length >= 12) { // Probably full timestamp - if (str_to_TIME(str,length,l_time,1) == TIMESTAMP_FULL) - return 0; // Was an ok timestamp + enum timestamp_type tres= str_to_TIME(str,length,l_time,1,thd); + if (tres == TIMESTAMP_FULL) + return 0; + else if (tres == WRONG_TIMESTAMP_FULL) + return 1; } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ @@ -533,7 +600,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time) found_days=1; str++; // Skip space; } - else if ((end-str) > 1 && *str == ':' && + else if ((end-str) > 1 && *str == frm_pos[7] && my_isdigit(&my_charset_latin1,str[1])) { date[0]=0; // Assume we found hours @@ -559,8 +626,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time) for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); date[state++]=value; - if (state == 4 || (end-str) < 2 || *str != ':' || - !my_isdigit(&my_charset_latin1,str[1])) + if (state == 4 || (end-str) < 2 || *str != frm_pos[7] || + !my_isdigit(&my_charset_latin1,str[1])) break; str++; // Skip ':' } @@ -577,7 +644,6 @@ bool str_to_time(const char *str,uint length,TIME *l_time) else bzero((char*) (date+state), sizeof(long)*(4-state)); } - fractional: /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) @@ -593,6 +659,20 @@ bool str_to_time(const char *str,uint length,TIME *l_time) else date[4]=0; + while (str != end && !my_isalpha(&my_charset_latin1,*str)) + str++; + + if ( (end-str)>= 2 && + !my_strnncoll(&my_charset_latin1, + (const uchar *)str, 2, + (const uchar *)"PM", 2) && + frm_pos[6] == 1) + { + uint days_i= date[1]/24; + uint hours_i= date[1]%24; + date[1]= hours_i%12 + 12 + 24*days_i; + } + /* Some simple checks */ if (date[2] >= 60 || date[3] >= 60) { @@ -601,9 +681,9 @@ bool str_to_time(const char *str,uint length,TIME *l_time) } l_time->month=0; l_time->day=date[0]; - l_time->hour=date[1]; - l_time->minute=date[2]; - l_time->second=date[3]; + l_time->hour=date[frm_pos[3] + 1]; + l_time->minute=date[frm_pos[4] + 1]; + l_time->second=date[frm_pos[5] + 1]; l_time->second_part=date[4]; l_time->time_type= TIMESTAMP_TIME; @@ -648,3 +728,165 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds) to->second= t_seconds%60L; to->second_part= microseconds; } + + +DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, + datetime_format_types format_type, + const char *format_str, + uint format_length, bool is_alloc) +{ + if (format_length && + !parse_datetime_formats(format_type, format_str, + format_length, + datetime_format->dt_pos)) + { + if (is_alloc) + { + if (!(datetime_format->format= my_strdup_with_length(format_str, + format_length, + MYF(0)))) + return 0; + } + else + datetime_format->format= (char *) format_str; + datetime_format->format_length= format_length; + return datetime_format; + } + return 0; +} + + +bool parse_datetime_formats(datetime_format_types format_type, + const char *format_str, uint format_length, + byte *dt_pos) +{ + uint pos= 0; + dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]= + dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= -1; + + const char *ptr=format_str; + const char *end=ptr+format_length; + bool need_p= 0; + + for (; ptr != end; ptr++) + { + if (*ptr == '%' && ptr+1 != end) + { + switch (*++ptr) { + case 'y': + case 'Y': + if (dt_pos[0] > -1) + return 1; + dt_pos[0]= pos; + break; + case 'c': + case 'm': + if (dt_pos[1] > -1) + return 1; + dt_pos[1]= pos; + break; + case 'd': + case 'e': + if (dt_pos[2] > -1) + return 1; + dt_pos[2]= pos; + break; + case 'H': + case 'k': + case 'h': + case 'I': + case 'l': + if (dt_pos[3] > -1) + return 1; + dt_pos[3]= pos; + need_p= (*ptr == 'h' || *ptr == 'l' || *ptr == 'I'); + break; + case 'i': + if (dt_pos[4] > -1) + return 1; + dt_pos[4]= pos; + break; + case 's': + case 'S': + if (dt_pos[5] > -1) + return 1; + dt_pos[5]= pos; + break; + case 'p': + if (dt_pos[6] > -1) + return 1; + /* %p should be last in format string */ + if (format_type == DATE_FORMAT_TYPE || + (pos != 6 && format_type == DATETIME_FORMAT_TYPE) || + (pos != 3 && format_type == TIME_FORMAT_TYPE)) + return 1; + dt_pos[6]= 1; + break; + default: + return 1; + } + if (dt_pos[6] == -1) + pos++; + } + } + + if (pos > 5 && format_type == DATETIME_FORMAT_TYPE && + (dt_pos[0] + dt_pos[1] + dt_pos[2] + + dt_pos[3] + dt_pos[4] + dt_pos[5] != 15) || + pos > 2 && format_type == DATE_FORMAT_TYPE && + (dt_pos[0] + dt_pos[1] + dt_pos[2] != 3) || + pos > 2 && format_type == TIME_FORMAT_TYPE && + (dt_pos[3] + dt_pos[4] + dt_pos[5] != 3) || + (need_p && dt_pos[6] != 1)) + return 1; + + /* + Check for valid separators between date/time parst + */ + uint tmp_len= format_length; + if (dt_pos[6] == 1) + { + end= end - 2; + if (my_ispunct(&my_charset_latin1, *end) || my_isspace(&my_charset_latin1, *end)) + end--; + tmp_len= end - format_str; + } + switch (format_type) { + case DATE_FORMAT_TYPE: + case TIME_FORMAT_TYPE: + if ((tmp_len == 6 && + !my_strnncoll(&my_charset_bin, + (const uchar *) format_str, 6, + (const uchar *) datetime_formats + [format_type][INTERNAL_FORMAT], 6)) || + tmp_len == 8 && + my_ispunct(&my_charset_latin1, *(format_str+2)) && + my_ispunct(&my_charset_latin1, *(format_str+5))) + { + if (format_type == TIME_FORMAT_TYPE && tmp_len == 8) + { + if (*(format_str+2) != *(format_str+5)) + return 1; + dt_pos[7]= *(format_str+2); + } + return 0; + } + break; + case DATETIME_FORMAT_TYPE: + if ((tmp_len == 12 && + !my_strnncoll(&my_charset_bin, + (const uchar *) format_str, 12, + (const uchar *) datetime_formats + [DATETIME_FORMAT_TYPE][INTERNAL_FORMAT], 12)) || + tmp_len == 17 && + my_ispunct(&my_charset_latin1, *(format_str+2)) && + my_ispunct(&my_charset_latin1, *(format_str+5)) && + my_ispunct(&my_charset_latin1, *(format_str+11)) && + my_ispunct(&my_charset_latin1, *(format_str+14)) && + (my_ispunct(&my_charset_latin1, *(format_str+8)) || + my_isspace(&my_charset_latin1, *(format_str+8)))) + return 0; + break; + } + return 1; +} |