diff options
author | Sergei Golubchik <sergii@pisem.net> | 2011-10-19 21:45:18 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2011-10-19 21:45:18 +0200 |
commit | 76f0b94bb0b2994d639353530c5b251d0f1a204b (patch) | |
tree | 9ed50628aac34f89a37637bab2fc4915b86b5eb4 /sql/item_strfunc.cc | |
parent | 4e46d8e5bff140f2549841167dc4b65a3c0a645d (diff) | |
parent | 5dc1a2231f55bacc9aaf0e24816f3d9c2ee1f21d (diff) | |
download | mariadb-git-76f0b94bb0b2994d639353530c5b251d0f1a204b.tar.gz |
merge with 5.3
sql/sql_insert.cc:
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
******
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
sql/sql_table.cc:
small cleanup
******
small cleanup
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r-- | sql/item_strfunc.cc | 780 |
1 files changed, 775 insertions, 5 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b0fa090afcf..a0e5b42767f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -41,6 +41,8 @@ */ #include "sql_class.h" // set_var.h: THD #include "set_var.h" +#include "sql_base.h" +#include "sql_time.h" #include "sql_acl.h" // SUPER_ACL #include "des_key_file.h" // st_des_keyschedule, st_des_keyblock #include "password.h" // my_make_scrambled_password, @@ -171,7 +173,6 @@ String *Item_func_md5::val_str_ascii(String *str) { DBUG_ASSERT(fixed == 1); String * sptr= args[0]->val_str(str); - str->set_charset(&my_charset_bin); if (sptr) { uchar digest[16]; @@ -184,6 +185,7 @@ String *Item_func_md5::val_str_ascii(String *str) return 0; } array_to_hex((char *) str->ptr(), digest, 16); + str->set_charset(&my_charset_numeric); str->length((uint) 32); return str; } @@ -210,7 +212,6 @@ String *Item_func_sha::val_str_ascii(String *str) { DBUG_ASSERT(fixed == 1); String * sptr= args[0]->val_str(str); - str->set_charset(&my_charset_bin); if (sptr) /* If we got value different from NULL */ { SHA1_CONTEXT context; /* Context used to generate SHA1 hash */ @@ -220,11 +221,13 @@ String *Item_func_sha::val_str_ascii(String *str) /* No need to check error as the only case would be too long message */ mysql_sha1_input(&context, (const uchar *) sptr->ptr(), sptr->length()); + /* Ensure that memory is free and we got result */ if (!( str->alloc(SHA1_HASH_SIZE*2) || (mysql_sha1_result(&context,digest)))) { array_to_hex((char *) str->ptr(), digest, SHA1_HASH_SIZE); + str->set_charset(&my_charset_numeric); str->length((uint) SHA1_HASH_SIZE*2); null_value=0; return str; @@ -824,7 +827,7 @@ String *Item_func_concat_ws::val_str(String *str) use_as_buff= &tmp_value; str->length(0); // QQ; Should be removed - res=str; + res=str; // If 0 arg_count // Skip until non-null argument is found. // If not, return the empty string @@ -2468,6 +2471,7 @@ void Item_func_make_set::fix_length_and_dec() not_null_tables_cache&= item->not_null_tables(); const_item_cache&= item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; + with_field= with_field || item->with_field; } @@ -3257,7 +3261,7 @@ String *Item_load_file::val_str(String *str) func_name(), current_thd->variables.max_allowed_packet); goto err; } - if (tmp_value.alloc(stat_info.st_size)) + if (tmp_value.alloc((size_t)stat_info.st_size)) goto err; if ((file= mysql_file_open(key_file_loadfile, file_name->ptr(), O_RDONLY, MYF(0))) < 0) @@ -3268,7 +3272,7 @@ String *Item_load_file::val_str(String *str) mysql_file_close(file, MYF(0)); goto err; } - tmp_value.length(stat_info.st_size); + tmp_value.length((uint32)stat_info.st_size); mysql_file_close(file, MYF(0)); null_value = 0; DBUG_RETURN(&tmp_value); @@ -3739,3 +3743,769 @@ String *Item_func_uuid::val_str(String *str) return str; } + + +Item_func_dyncol_create::Item_func_dyncol_create(List<Item> &args, + DYNCALL_CREATE_DEF *dfs) + : Item_str_func(args), defs(dfs), vals(0), nums(0) +{ + DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments +} + + +bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref) +{ + bool res= Item_func::fix_fields(thd, ref); // no need Item_str_func here + vals= (DYNAMIC_COLUMN_VALUE *) alloc_root(thd->mem_root, + sizeof(DYNAMIC_COLUMN_VALUE) * + (arg_count / 2)); + nums= (uint *) alloc_root(thd->mem_root, + sizeof(uint) * (arg_count / 2)); + return res || vals == 0 || nums == 0; +} + + +void Item_func_dyncol_create::fix_length_and_dec() +{ + maybe_null= TRUE; + collation.set(&my_charset_bin); + decimals= 0; +} + +void Item_func_dyncol_create::prepare_arguments() +{ + char buff[STRING_BUFFER_USUAL_SIZE]; + String *res, tmp(buff, sizeof(buff), &my_charset_bin); + uint column_count= (arg_count / 2); + uint i; + my_decimal dtmp, *dres; + + /* get values */ + for (i= 0; i < column_count; i++) + { + uint valpos= i * 2 + 1; + DYNAMIC_COLUMN_TYPE type= defs[i].type; + if (type == DYN_COL_NULL) // auto detect + { + /* + We don't have a default here to ensure we get a warning if + one adds a new not handled MYSQL_TYPE_... + */ + switch (args[valpos]->field_type()) { + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + type= DYN_COL_DECIMAL; + break; + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_BIT: + type= args[valpos]->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; + break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + type= DYN_COL_DOUBLE; + break; + case MYSQL_TYPE_NULL: + type= DYN_COL_NULL; + break; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + type= DYN_COL_DATETIME; + break; + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + type= DYN_COL_DATE; + break; + case MYSQL_TYPE_TIME: + type= DYN_COL_TIME; + break; + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_GEOMETRY: + type= DYN_COL_STRING; + break; + } + } + nums[i]= (uint) args[i * 2]->val_int(); + vals[i].type= type; + switch (type) { + case DYN_COL_NULL: + DBUG_ASSERT(args[valpos]->field_type() == MYSQL_TYPE_NULL); + break; + case DYN_COL_INT: + vals[i].long_value= args[valpos]->val_int(); + break; + case DYN_COL_UINT: + vals[i].ulong_value= args[valpos]->val_int(); + break; + case DYN_COL_DOUBLE: + vals[i].double_value= args[valpos]->val_real(); + break; + case DYN_COL_STRING: + res= args[valpos]->val_str(&tmp); + if (res && + (vals[i].string_value.str= my_strndup(res->ptr(), res->length(), + MYF(MY_WME)))) + { + vals[i].string_value.length= res->length(); + vals[i].charset= res->charset(); + } + else + { + args[valpos]->null_value= 1; // In case of out of memory + vals[i].string_value.str= NULL; + vals[i].string_value.length= 0; // just to be safe + } + break; + case DYN_COL_DECIMAL: + if ((dres= args[valpos]->val_decimal(&dtmp))) + { + dynamic_column_prepare_decimal(&vals[i]); + DBUG_ASSERT(vals[i].decimal_value.len == dres->len); + vals[i].decimal_value.intg= dres->intg; + vals[i].decimal_value.frac= dres->frac; + vals[i].decimal_value.sign= dres->sign(); + memcpy(vals[i].decimal_buffer, dres->buf, + sizeof(vals[i].decimal_buffer)); + } + else + { + dynamic_column_prepare_decimal(&vals[i]); // just to be safe + DBUG_ASSERT(args[valpos]->null_value); + } + break; + case DYN_COL_DATETIME: + args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE); + break; + case DYN_COL_DATE: + args[valpos]->get_date(&vals[i].time_value, TIME_FUZZY_DATE); + break; + case DYN_COL_TIME: + args[valpos]->get_time(&vals[i].time_value); + break; + default: + DBUG_ASSERT(0); + vals[i].type= DYN_COL_NULL; + } + if (vals[i].type != DYN_COL_NULL && args[valpos]->null_value) + { + if (vals[i].type == DYN_COL_STRING) + my_free(vals[i].string_value.str); + vals[i].type= DYN_COL_NULL; + } + } +} + +void Item_func_dyncol_create::cleanup_arguments() +{ + uint column_count= (arg_count / 2); + uint i; + + for (i= 0; i < column_count; i++) + { + if (vals[i].type == DYN_COL_STRING) + my_free(vals[i].string_value.str); + } +} + +String *Item_func_dyncol_create::val_str(String *str) +{ + DYNAMIC_COLUMN col; + String *res; + uint column_count= (arg_count / 2); + enum enum_dyncol_func_result rc; + DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments + + prepare_arguments(); + + if ((rc= dynamic_column_create_many(&col, column_count, nums, vals))) + { + dynamic_column_error_message(rc); + dynamic_column_column_free(&col); + res= NULL; + null_value= TRUE; + } + else + { + /* Move result from DYNAMIC_COLUMN to str_value */ + char *ptr; + size_t length, alloc_length; + dynamic_column_reassociate(&col, &ptr, &length, &alloc_length); + str_value.reassociate(ptr, (uint32) length, (uint32) alloc_length, + &my_charset_bin); + res= &str_value; + null_value= FALSE; + } + + /* cleanup */ + cleanup_arguments(); + + return res; +} + +void Item_func_dyncol_create::print_arguments(String *str, + enum_query_type query_type) +{ + uint i; + uint column_count= (arg_count / 2); + for (i= 0; i < column_count; i++) + { + args[i*2]->print(str, query_type); + str->append(','); + args[i*2 + 1]->print(str, query_type); + switch (defs[i].type) { + case DYN_COL_NULL: // automatic type => write nothing + break; + case DYN_COL_INT: + str->append(STRING_WITH_LEN(" AS int")); + break; + case DYN_COL_UINT: + str->append(STRING_WITH_LEN(" AS unsigned int")); + break; + case DYN_COL_DOUBLE: + str->append(STRING_WITH_LEN(" AS double")); + break; + case DYN_COL_STRING: + str->append(STRING_WITH_LEN(" AS char")); + if (defs[i].cs) + { + str->append(STRING_WITH_LEN(" charset ")); + str->append(defs[i].cs->csname); + str->append(' '); + } + break; + case DYN_COL_DECIMAL: + str->append(STRING_WITH_LEN(" AS decimal")); + break; + case DYN_COL_DATETIME: + str->append(STRING_WITH_LEN(" AS datetime")); + break; + case DYN_COL_DATE: + str->append(STRING_WITH_LEN(" AS date")); + break; + case DYN_COL_TIME: + str->append(STRING_WITH_LEN(" AS time")); + break; + } + if (i < column_count - 1) + str->append(','); + } +} + + +void Item_func_dyncol_create::print(String *str, + enum_query_type query_type) +{ + DBUG_ASSERT((arg_count & 0x1) == 0); // even number of arguments + str->append(STRING_WITH_LEN("column_create(")); + print_arguments(str, query_type); + str->append(')'); +} + + +String *Item_func_dyncol_add::val_str(String *str) +{ + DYNAMIC_COLUMN col; + String *res; + uint column_count= (arg_count / 2); + enum enum_dyncol_func_result rc; + DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments + + /* We store the packed data last */ + res= args[arg_count - 1]->val_str(str); + if (args[arg_count - 1]->null_value) + goto null; + init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE, + STRING_BUFFER_USUAL_SIZE); + + col.length= res->length(); + memcpy(col.str, res->ptr(), col.length); + + prepare_arguments(); + + if ((rc= dynamic_column_update_many(&col, column_count, nums, vals))) + { + dynamic_column_error_message(rc); + dynamic_column_column_free(&col); + cleanup_arguments(); + goto null; + } + + { + /* Move result from DYNAMIC_COLUMN to str */ + char *ptr; + size_t length, alloc_length; + dynamic_column_reassociate(&col, &ptr, &length, &alloc_length); + str->reassociate(ptr, (uint32) length, (uint32) alloc_length, + &my_charset_bin); + null_value= FALSE; + } + + /* cleanup */ + dynamic_column_column_free(&col); + cleanup_arguments(); + + return str; + +null: + null_value= TRUE; + return NULL; +} + + +void Item_func_dyncol_add::print(String *str, + enum_query_type query_type) +{ + DBUG_ASSERT((arg_count & 0x1) == 1); // odd number of arguments + str->append(STRING_WITH_LEN("column_create(")); + args[arg_count - 1]->print(str, query_type); + str->append(','); + print_arguments(str, query_type); + str->append(')'); +} + + +/** + Get value for a column stored in a dynamic column + + @notes + This function ensures that null_value is set correctly +*/ + +bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp) +{ + DYNAMIC_COLUMN dyn_str; + String *res; + longlong num; + enum enum_dyncol_func_result rc; + + num= args[1]->val_int(); + if (args[1]->null_value || num < 0 || num > INT_MAX) + { + null_value= 1; + return 1; + } + + res= args[0]->val_str(tmp); + if (args[0]->null_value) + { + null_value= 1; + return 1; + } + + dyn_str.str= (char*) res->ptr(); + dyn_str.length= res->length(); + if ((rc= dynamic_column_get(&dyn_str, (uint) num, val))) + { + dynamic_column_error_message(rc); + null_value= 1; + return 1; + } + + null_value= 0; + return 0; // ok +} + + +String *Item_dyncol_get::val_str(String *str_result) +{ + DYNAMIC_COLUMN_VALUE val; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + + if (get_dyn_value(&val, &tmp)) + return NULL; + + switch (val.type) { + case DYN_COL_NULL: + goto null; + case DYN_COL_INT: + case DYN_COL_UINT: + str_result->set_int(val.long_value, test(val.type == DYN_COL_UINT), + &my_charset_latin1); + break; + case DYN_COL_DOUBLE: + str_result->set_real(val.double_value, NOT_FIXED_DEC, &my_charset_latin1); + break; + case DYN_COL_STRING: + if ((char*) tmp.ptr() <= val.string_value.str && + (char*) tmp.ptr() + tmp.length() >= val.string_value.str) + { + /* value is allocated in tmp buffer; We have to make a copy */ + str_result->copy(val.string_value.str, val.string_value.length, + val.charset); + } + else + { + /* + It's safe to use the current value because it's either pointing + into a field or in a buffer for another item and this buffer + is not going to be deleted during expression evaluation + */ + str_result->set(val.string_value.str, val.string_value.length, + val.charset); + } + break; + case DYN_COL_DECIMAL: + { + int res; + int length= + my_decimal_string_length((const my_decimal*)&val.decimal_value); + if (str_result->alloc(length)) + goto null; + if ((res= decimal2string(&val.decimal_value, (char*) str_result->ptr(), + &length, 0, 0, ' ')) != E_DEC_OK) + { + char buff[40]; + int len= sizeof(buff); + DBUG_ASSERT(length < (int)sizeof(buff)); + decimal2string(&val.decimal_value, buff, &len, 0, 0, ' '); + decimal_operation_results(res, buff, "CHAR"); + } + str_result->set_charset(&my_charset_latin1); + str_result->length(length); + break; + } + case DYN_COL_DATETIME: + case DYN_COL_DATE: + case DYN_COL_TIME: + { + int length; + /* + We use AUTO_SEC_PART_DIGITS here to ensure that we do not loose + any microseconds from the data. This is safe to do as we are + asked to return the time argument as a string. + */ + if (str_result->alloc(MAX_DATE_STRING_REP_LENGTH) || + !(length= my_TIME_to_str(&val.time_value, (char*) str_result->ptr(), + AUTO_SEC_PART_DIGITS))) + goto null; + str_result->set_charset(&my_charset_latin1); + str_result->length(length); + break; + } + } + return str_result; + +null: + null_value= TRUE; + return 0; +} + + +longlong Item_dyncol_get::val_int() +{ + DYNAMIC_COLUMN_VALUE val; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + + if (get_dyn_value(&val, &tmp)) + return 0; + + switch (val.type) { + case DYN_COL_NULL: + goto null; + case DYN_COL_UINT: + unsigned_flag= 1; // Make it possible for caller to detect sign + return val.long_value; + case DYN_COL_INT: + unsigned_flag= 0; // Make it possible for caller to detect sign + return val.long_value; + case DYN_COL_DOUBLE: + { + bool error; + longlong num; + + num= double_to_longlong(val.double_value, unsigned_flag, &error); + if (error) + { + char buff[30]; + sprintf(buff, "%lg", val.double_value); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_DATA_OVERFLOW, + ER(ER_DATA_OVERFLOW), + buff, + unsigned_flag ? "UNSIGNED INT" : "INT"); + } + return num; + } + case DYN_COL_STRING: + { + int error; + longlong num; + char *end= val.string_value.str + val.string_value.length, *org_end= end; + + num= my_strtoll10(val.string_value.str, &end, &error); + if (end != org_end || error > 0) + { + char buff[80]; + strmake(buff, val.string_value.str, min(sizeof(buff)-1, + val.string_value.length)); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_BAD_DATA, + ER(ER_BAD_DATA), + buff, + unsigned_flag ? "UNSIGNED INT" : "INT"); + } + unsigned_flag= error >= 0; + return num; + } + case DYN_COL_DECIMAL: + { + longlong num; + my_decimal2int(E_DEC_FATAL_ERROR, &val.decimal_value, unsigned_flag, + &num); + return num; + } + case DYN_COL_DATETIME: + case DYN_COL_DATE: + case DYN_COL_TIME: + unsigned_flag= !val.time_value.neg; + if (unsigned_flag) + return TIME_to_ulonglong(&val.time_value); + else + return -(longlong)TIME_to_ulonglong(&val.time_value); + } + +null: + null_value= TRUE; + return 0; +} + + +double Item_dyncol_get::val_real() +{ + DYNAMIC_COLUMN_VALUE val; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + + if (get_dyn_value(&val, &tmp)) + return 0.0; + + switch (val.type) { + case DYN_COL_NULL: + goto null; + case DYN_COL_UINT: + return ulonglong2double(val.ulong_value); + case DYN_COL_INT: + return (double) val.long_value; + case DYN_COL_DOUBLE: + return (double) val.double_value; + case DYN_COL_STRING: + { + int error; + char *end; + double res= my_strntod(val.charset, (char*) val.string_value.str, + val.string_value.length, &end, &error); + + if (end != (char*) val.string_value.str + val.string_value.length || + error) + { + char buff[80]; + strmake(buff, val.string_value.str, min(sizeof(buff)-1, + val.string_value.length)); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_BAD_DATA, + ER(ER_BAD_DATA), + buff, "DOUBLE"); + } + return res; + } + case DYN_COL_DECIMAL: + { + double res; + /* This will always succeed */ + decimal2double(&val.decimal_value, &res); + return res; + } + case DYN_COL_DATETIME: + case DYN_COL_DATE: + case DYN_COL_TIME: + return TIME_to_double(&val.time_value); + } + +null: + null_value= TRUE; + return 0.0; +} + + +my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value) +{ + DYNAMIC_COLUMN_VALUE val; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + + if (get_dyn_value(&val, &tmp)) + return NULL; + + switch (val.type) { + case DYN_COL_NULL: + goto null; + case DYN_COL_UINT: + int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, TRUE, decimal_value); + break; + case DYN_COL_INT: + int2my_decimal(E_DEC_FATAL_ERROR, val.long_value, FALSE, decimal_value); + break; + case DYN_COL_DOUBLE: + double2my_decimal(E_DEC_FATAL_ERROR, val.double_value, decimal_value); + break; + case DYN_COL_STRING: + { + int rc; + rc= str2my_decimal(0, val.string_value.str, val.string_value.length, + val.charset, decimal_value); + char buff[80]; + strmake(buff, val.string_value.str, min(sizeof(buff)-1, + val.string_value.length)); + if (rc != E_DEC_OK) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_BAD_DATA, + ER(ER_BAD_DATA), + buff, "DECIMAL"); + } + break; + } + case DYN_COL_DECIMAL: + decimal2my_decimal(&val.decimal_value, decimal_value); + break; + case DYN_COL_DATETIME: + case DYN_COL_DATE: + case DYN_COL_TIME: + decimal_value= seconds2my_decimal(val.time_value.neg, + TIME_to_ulonglong(&val.time_value), + val.time_value.second_part, + decimal_value); + break; + } + return decimal_value; + +null: + null_value= TRUE; + return 0; +} + + +bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, uint fuzzy_date) +{ + DYNAMIC_COLUMN_VALUE val; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + bool signed_value= 0; + + if (get_dyn_value(&val, &tmp)) + return 1; // Error + + switch (val.type) { + case DYN_COL_NULL: + goto null; + case DYN_COL_INT: + signed_value= 1; // For error message + /* fall_trough */ + case DYN_COL_UINT: + if (signed_value || val.ulong_value <= LONGLONG_MAX) + { + if (int_to_datetime_with_warn(val.ulong_value, ltime, fuzzy_date, + 0 /* TODO */)) + goto null; + return 0; + } + /* let double_to_datetime_with_warn() issue the warning message */ + val.double_value= static_cast<double>(ULONGLONG_MAX); + /* fall_trough */ + case DYN_COL_DOUBLE: + if (double_to_datetime_with_warn(val.double_value, ltime, fuzzy_date, + 0 /* TODO */)) + goto null; + return 0; + case DYN_COL_DECIMAL: + if (decimal_to_datetime_with_warn((my_decimal*)&val.decimal_value, ltime, + fuzzy_date, 0 /* TODO */)) + goto null; + return 0; + case DYN_COL_STRING: + if (str_to_datetime_with_warn(&my_charset_numeric, + val.string_value.str, + val.string_value.length, + ltime, fuzzy_date) <= MYSQL_TIMESTAMP_ERROR) + goto null; + return 0; + case DYN_COL_DATETIME: + case DYN_COL_DATE: + case DYN_COL_TIME: + *ltime= val.time_value; + return 0; + } + +null: + null_value= TRUE; + return 1; +} + + +void Item_dyncol_get::print(String *str, enum_query_type query_type) +{ + str->append(STRING_WITH_LEN("column_get(")); + args[0]->print(str, query_type); + str->append(','); + args[1]->print(str, query_type); + str->append(')'); +} + + +String *Item_func_dyncol_list::val_str(String *str) +{ + uint i; + enum enum_dyncol_func_result rc; + DYNAMIC_ARRAY arr; + DYNAMIC_COLUMN col; + String *res= args[0]->val_str(str); + + if (args[0]->null_value) + goto null; + col.length= res->length(); + /* We do not change the string, so could do this trick */ + col.str= (char *)res->ptr(); + if ((rc= dynamic_column_list(&col, &arr))) + { + dynamic_column_error_message(rc); + delete_dynamic(&arr); + goto null; + } + + /* + We support elements from 0 - 65536, so max size for one element is + 6 (including ,). + */ + if (str->alloc(arr.elements * 6)) + goto null; + + str->length(0); + for (i= 0; i < arr.elements; i++) + { + str->qs_append(*dynamic_element(&arr, i, uint*)); + if (i < arr.elements - 1) + str->qs_append(','); + } + + null_value= FALSE; + delete_dynamic(&arr); + return str; + +null: + null_value= TRUE; + return NULL; +} |