diff options
author | Michael Widenius <monty@askmonty.org> | 2011-05-08 13:24:06 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2011-05-08 13:24:06 +0300 |
commit | 5ab92b1f850c62718907d166b47553440502043c (patch) | |
tree | 447166d5a99f147b27daa6f637b0a23df789a0aa /sql/item_create.cc | |
parent | 8ac88c88f0038350064429fda626233260eb6721 (diff) | |
download | mariadb-git-5ab92b1f850c62718907d166b47553440502043c.tar.gz |
Adding support for Dynamic columns (WL#34):
- COLUMN_CREATE(column_nr, value, [column_nr,value]...)
- COLUMN_ADD(blob,column_nr, value, column_nr,value]...)
- COLUMN_DELETE(blob, column_nr, column_nr...)
- COLUMN_EXISTS(blob, column_nr)
- COLUMN_LIST(blob, column_nr)
- COLUMN_GET(string, column_nr AS type)
Added cast(X as DOUBLE) and cast(x as INT)
Better warning and error messages for wrong cast's
Created some sub functions to simplify and reuse code.
Added a lot of conversation functions with error/warnings for what went wrong.
Fixed some issues when casting time to datetime.
Added functions to dynamic strings and Strings to allow one to move a string buffer from dynamic strings to String (to save malloc+ copy)
Added dynamic columns library to libmysqlclient
include/Makefile.am:
Added ma_dyncol.h
include/decimal.h:
Added 'const' to arguments for some functions.
include/my_sys.h:
Added dynstr_reassociate()
include/my_time.h:
Added TIME_SUBSECOND_RANGE
Added double_to_datetime()
Added flag argument to str_to_time()
libmysql/CMakeLists.txt:
Added mysys/ma_dyncol.c
libmysql/Makefile.shared:
Added ma_dyncol
libmysql/libmysql.c:
Added argument to str_to_time()
mysql-test/r/bigint.result:
Better error messages
mysql-test/r/cast.result:
Better warning and error messages
A lot of new cast() tests
mysql-test/r/func_math.result:
Better warning messages
mysql-test/r/func_str.result:
Better warning messages
mysql-test/r/func_time.result:
Better warning messages
mysql-test/r/sp-vars.result:
Better warning messages
mysql-test/r/strict.result:
Better warning messages
New test result
mysql-test/r/type_newdecimal.result:
Better warning messages
mysql-test/r/warnings.result:
Better warning messages
mysql-test/suite/funcs_1/r/innodb_func_view.result:
Updated results after better cast warnings
mysql-test/suite/funcs_1/r/memory_func_view.result:
Updated results after better cast warnings
mysql-test/suite/funcs_1/r/myisam_func_view.result:
Updated results after better cast warnings
mysql-test/suite/optimizer_unfixed_bugs/t/bug43448.test:
Added begin...commit to speed up test.
mysql-test/suite/parts/inc/part_supported_sql_funcs_delete.inc:
Added begin...commit to speed up test.
mysql-test/suite/parts/inc/partition_supported_sql_funcs.inc:
Added begin...commit to speed up test.
mysql-test/suite/parts/r/part_supported_sql_func_innodb.result:
Added begin...commit to speed up test.
mysql-test/suite/parts/r/part_supported_sql_func_myisam.result:
Added begin...commit to speed up test.
mysql-test/suite/parts/r/rpl_partition.result:
Added begin...commit to speed up test.
mysql-test/suite/parts/t/part_supported_sql_func_innodb.test:
Removed duplicated --big_test
mysql-test/suite/parts/t/rpl_partition.test:
Added begin...commit to speed up test.
mysql-test/suite/pbxt/r/cast.result:
Updated results after better cast warnings
mysql-test/suite/pbxt/r/func_str.result:
Updated results after better cast warnings
mysql-test/suite/pbxt/r/type_newdecimal.result:
Updated results after better cast warnings
mysql-test/suite/rpl/r/rpl_innodb_bug28430.result:
Added begin...commit to speed up test.
mysql-test/suite/rpl/t/rpl_innodb_bug28430.test:
Added begin...commit to speed up test.
mysql-test/suite/vcol/r/vcol_supported_sql_funcs_innodb.result:
More warnings
mysql-test/suite/vcol/r/vcol_supported_sql_funcs_myisam.result:
More warnings
mysql-test/t/cast.test:
A lot of new cast() tests
mysql-test/t/strict.test:
Added new test
mysys/CMakeLists.txt:
Added ma_dyncol.c
mysys/Makefile.am:
Added ma_dyncol.c
mysys/string.c:
Added dynstr_reassociate() to move a buffer from dynamic_strings to some other allocator
sql-common/my_time.c:
Added 'fuzzydate' flag to str_to_time()
Added support for microseconds to my_time_to_str() and my_datetime_to_str()
Reset second_parts in number_to_datetime()
Added double_to_datetime()
sql/field.cc:
Added double_to_longlong() and truncate_double() to simplify and reuse code
sql/field.h:
New prototypes
sql/item.cc:
Changed Item::get_date(MYSQL_TIME *ltime,uint fuzzydate) to be aware of type of argument.
(Needed to make it microsecond safe and get better warnings).
Updated call to str_to_time_with_warn()
sql/item.h:
Added struct st_dyncall_create_def used by dynamic columns
Added virtual bool dynamic_result() to tell if type of argument may change over calls.
sql/item_cmpfunc.cc:
Added Item_func_dyncol_exists()
sql/item_cmpfunc.h:
Added class Item_func_dyncol_exists
sql/item_create.cc:
Added get_length_and_scale() to simplify other functions
Simplified and extended create_func_cast()
Added support for cast(X as double(X,Y))
Added functions to create dynamic column functions.
sql/item_create.h:
Added prototypes
sql/item_func.cc:
Extended cast functions Item_func_signed() and Item_func_unsigned() to work with dynamic types
Added Item_double_typecast()
sql/item_func.h:
Added class Item_double_typecast()
sql/item_strfunc.cc:
Added functions for COLUMN_CREATE(), COLUMN_ADD(), COLUMN_GET() and COLUMN_LIST()
sql/item_strfunc.h:
Added classes for COLUMN_CREATE(), COLUMN_ADD(), COLUMN_GET() and COLUMN_LIST()
sql/item_timefunc.cc:
Added flag argument to str_to_time_with_warn()
Updated Item_char_typecast() to handle result type that may change between calls (for dynamic columns)
Added Item_time_typecast::get_date() to ensure that we cast a datetime to time properly.
sql/item_timefunc.h:
Added get_date() to Item_time_typecast() to allow proper results for casting time to datetime
sql/lex.h:
Added new SQL function names
sql/my_decimal.cc:
Added 'const' to some arguments.
Better error message in case of errors (we now print out the wrong value)
Added my_decimal2int()
sql/my_decimal.h:
Moved some constants to my_decimal_limits.h
Updated prototypes.
Made my_decimal2int() a function as it's rather long (no reason to have it inline)
Added decimal2my_decimal() function.
sql/mysql_priv.h:
Prototypes for new functions
sql/share/errmsg.txt:
New error messages for wrong casts and dynamic columns
sql/sql_acl.cc:
Fixed indentation
sql/sql_base.cc:
Added dynamic_column_error_message()
sql/sql_string.h:
Added reassociate() to move a buffer to be owned by String object.
sql/sql_yacc.yy:
Added syntax for COLUMN_ functions.
sql/time.cc:
Updated str_to_datetime_with_warn() flag argument to same type as other functions
Added conversion flag to str_to_time_with_warn() (Similar to all datetime functions)
Added conversion functions with warnings: double_to_datetime_with_warn() and decimal_to_datetime_with_warn()
strings/decimal.c:
Added 'const' to arguments for some functions.
unittest/mysys/Makefile.am:
Added test for dynamic columns code
Diffstat (limited to 'sql/item_create.cc')
-rw-r--r-- | sql/item_create.cc | 225 |
1 files changed, 173 insertions, 52 deletions
diff --git a/sql/item_create.cc b/sql/item_create.cc index b3a0e7cf3b2..9c66c94382d 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -27,6 +27,50 @@ /* ============================================================================= + HELPER FUNCTIONS +============================================================================= +*/ + +/* + Get precision and scale for a declaration + + return + 0 ok + 1 error +*/ + +bool get_length_and_scale(ulonglong length, ulonglong decimals, + ulong *out_length, uint *out_decimals, + uint max_precision, uint max_scale, + const char *name) +{ + if (length > (ulonglong) max_precision) + { + my_error(ER_TOO_BIG_PRECISION, MYF(0), (int) length, name, + max_precision); + return 1; + } + if (decimals > (ulonglong) max_scale) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), (int) decimals, name, + DECIMAL_MAX_SCALE); + return 1; + } + + *out_length= (ulong) length; + *out_decimals= (uint) decimals; + my_decimal_trim(out_length, out_decimals); + + if (*out_length < *out_decimals) + { + my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); + return 1; + } + return 0; +} + +/* +============================================================================= LOCAL DECLARATIONS ============================================================================= */ @@ -5054,6 +5098,17 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, CHARSET_INFO *cs) { Item *UNINIT_VAR(res); + ulonglong length= 0, decimals= 0; + int error; + + /* + We don't have to check for error here as sql_yacc.yy has guaranteed + that the values are in range of ulonglong + */ + if (c_len) + length= (ulonglong) my_strtoll10(c_len, NULL, &error); + if (c_dec) + decimals= (ulonglong) my_strtoll10(c_dec, NULL, &error); switch (cast_type) { case ITEM_CAST_BINARY: @@ -5076,55 +5131,31 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, break; case ITEM_CAST_DECIMAL: { - ulong len= 0; - uint dec= 0; - - if (c_len) - { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if (errno != 0) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), c_len, a->name, - DECIMAL_MAX_PRECISION); - return NULL; - } - len= decoded_size; - } + ulong len; + uint dec; + if (get_length_and_scale(length, decimals, &len, &dec, + DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE, + a->name)) + return NULL; + res= new (thd->mem_root) Item_decimal_typecast(a, len, dec); + break; + } + case ITEM_CAST_DOUBLE: + { + ulong len; + uint dec; - if (c_dec) + if (!c_len) { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_dec, NULL, 10); - if ((errno != 0) || (decoded_size > UINT_MAX)) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), c_dec, a->name, - DECIMAL_MAX_SCALE); - return NULL; - } - dec= decoded_size; - } - my_decimal_trim(&len, &dec); - if (len < dec) - { - my_error(ER_M_BIGGER_THAN_D, MYF(0), ""); - return 0; + length= DBL_DIG+7; + decimals= NOT_FIXED_DEC; } - if (len > DECIMAL_MAX_PRECISION) - { - my_error(ER_TOO_BIG_PRECISION, MYF(0), len, a->name, - DECIMAL_MAX_PRECISION); - return 0; - } - if (dec > DECIMAL_MAX_SCALE) - { - my_error(ER_TOO_BIG_SCALE, MYF(0), dec, a->name, - DECIMAL_MAX_SCALE); - return 0; - } - res= new (thd->mem_root) Item_decimal_typecast(a, len, dec); + else if (get_length_and_scale(length, decimals, &len, &dec, + DECIMAL_MAX_PRECISION, NOT_FIXED_DEC-1, + a->name)) + return NULL; + res= new (thd->mem_root) Item_double_typecast(a, (uint) length, + (uint) decimals); break; } case ITEM_CAST_CHAR: @@ -5133,15 +5164,13 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection); if (c_len) { - ulong decoded_size; - errno= 0; - decoded_size= strtoul(c_len, NULL, 10); - if ((errno != 0) || (decoded_size > MAX_FIELD_BLOBLENGTH)) + if (length > MAX_FIELD_BLOBLENGTH) { - my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", MAX_FIELD_BLOBLENGTH); + my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), "cast as char", + MAX_FIELD_BLOBLENGTH); return NULL; } - len= (int) decoded_size; + len= (int) length; } res= new (thd->mem_root) Item_char_typecast(a, len, real_cs); break; @@ -5155,3 +5184,95 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, } return res; } + + +static List<Item> *create_func_dyncol_prepare(THD *thd, + DYNCALL_CREATE_DEF **dfs, + List<DYNCALL_CREATE_DEF> &list) +{ + DYNCALL_CREATE_DEF *def; + List_iterator_fast<DYNCALL_CREATE_DEF> li(list); + List<Item> *args= new (thd->mem_root) List<Item>; + + *dfs= (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root, + sizeof(DYNCALL_CREATE_DEF) * + list.elements); + + if (!args || !*dfs) + return NULL; + + for (uint i= 0; (def= li++) ;) + { + dfs[0][i++]= *def; + args->push_back(def->num); + args->push_back(def->value); + } + return args; +} + +Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list) +{ + List<Item> *args; + DYNCALL_CREATE_DEF *dfs; + if (!(args= create_func_dyncol_prepare(thd, &dfs, list))) + return NULL; + + return new (thd->mem_root) Item_func_dyncol_create(*args, dfs); +} + + +Item *create_func_dyncol_add(THD *thd, Item *str, + List<DYNCALL_CREATE_DEF> &list) +{ + List<Item> *args; + DYNCALL_CREATE_DEF *dfs; + + if (!(args= create_func_dyncol_prepare(thd, &dfs, list))) + return NULL; + + args->push_back(str); + + return new (thd->mem_root) Item_func_dyncol_add(*args, dfs); +} + + + +Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums) +{ + DYNCALL_CREATE_DEF *dfs; + Item *num; + List_iterator_fast<Item> it(nums); + List<Item> *args= new (thd->mem_root) List<Item>; + + dfs= (DYNCALL_CREATE_DEF *)alloc_root(thd->mem_root, + sizeof(DYNCALL_CREATE_DEF) * + nums.elements); + if (!args || !dfs) + return NULL; + + for (uint i= 0; (num= it++); i++) + { + dfs[i].num= num; + dfs[i].value= new Item_null(); + dfs[i].type= DYN_COL_INT; + args->push_back(dfs[i].num); + args->push_back(dfs[i].value); + } + + args->push_back(str); + + return new (thd->mem_root) Item_func_dyncol_add(*args, dfs); +} + + +Item *create_func_dyncol_get(THD *thd, Item *str, Item *num, + Cast_target cast_type, + const char *c_len, const char *c_dec, + CHARSET_INFO *cs) +{ + Item *res; + + if (!(res= new (thd->mem_root) Item_dyncol_get(str, num))) + return res; // Return NULL + return create_func_cast(thd, res, cast_type, c_len, c_dec, cs); +} |