Commit 7327cd97 authored by unknown's avatar unknown

MDEV-377 Name support for dynamic columns

MDEV-127 Optimization of memory allocation
MDEV-483 Make column_check function which cheсks dynamic columns integrit
JSON conversion function
parent 4db207d5
......@@ -102,6 +102,13 @@ dynamic_column_create_many(DYNAMIC_COLUMN *str,
uint *column_numbers,
DYNAMIC_COLUMN_VALUE *values);
enum enum_dyncol_func_result
dynamic_column_create_many_fmt(DYNAMIC_COLUMN *str,
uint column_count,
uchar *column_keys,
DYNAMIC_COLUMN_VALUE *values,
my_bool names);
enum enum_dyncol_func_result
dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
DYNAMIC_COLUMN_VALUE *value);
......@@ -110,16 +117,30 @@ dynamic_column_update_many(DYNAMIC_COLUMN *str,
uint add_column_count,
uint *column_numbers,
DYNAMIC_COLUMN_VALUE *values);
enum enum_dyncol_func_result
dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
uint add_column_count,
void *column_keys,
DYNAMIC_COLUMN_VALUE *values,
my_bool string_keys);
enum enum_dyncol_func_result
dynamic_column_delete(DYNAMIC_COLUMN *org, uint column_nr);
enum enum_dyncol_func_result
dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr);
enum enum_dyncol_func_result
dynamic_column_exists_str(DYNAMIC_COLUMN *str, LEX_STRING *name);
enum enum_dyncol_func_result
dynamic_column_exists_fmt(DYNAMIC_COLUMN *str, void *key, my_bool string_keys);
/* List of not NULL columns */
enum enum_dyncol_func_result
dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint);
enum enum_dyncol_func_result
dynamic_column_list_str(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_lexstr);
enum enum_dyncol_func_result
dynamic_column_list_fmt(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array, my_bool string_keys);
/*
if the column do not exists it is NULL
......@@ -127,6 +148,17 @@ dynamic_column_list(DYNAMIC_COLUMN *org, DYNAMIC_ARRAY *array_of_uint);
enum enum_dyncol_func_result
dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr,
DYNAMIC_COLUMN_VALUE *store_it_here);
enum enum_dyncol_func_result
dynamic_column_get_str(DYNAMIC_COLUMN *str, LEX_STRING *name,
DYNAMIC_COLUMN_VALUE *store_it_here);
my_bool dynamic_column_has_names(DYNAMIC_COLUMN *str);
enum enum_dyncol_func_result
dynamic_column_check(DYNAMIC_COLUMN *str);
enum enum_dyncol_func_result
dynamic_column_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json);
#define dynamic_column_initialize(A) memset((A), 0, sizeof(*(A)))
#define dynamic_column_column_free(V) dynstr_free(V)
......
......@@ -793,12 +793,18 @@ my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
size_t length);
extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append,
...);
extern my_bool dynstr_append_quoted(DYNAMIC_STRING *str,
const char *append, size_t len);
extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str);
extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size);
extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n);
extern void dynstr_free(DYNAMIC_STRING *str);
extern void dynstr_reassociate(DYNAMIC_STRING *str, char **res, size_t *length,
size_t *alloc_length);
extern uint32 copy_and_convert_extended(char *to, uint32 to_length,
CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
CHARSET_INFO *from_cs, uint *errors);
#ifdef HAVE_MLOCK
extern void *my_malloc_lock(size_t length,myf flags);
extern void my_free_lock(void *ptr);
......
This diff is collapsed.
......@@ -550,3 +550,125 @@ select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL(19,0))));
select hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal)));
select hex(COLUMN_CREATE(0, 0.0 as decimal));
--echo #
--echo # test of symbolic names
--echo #
--echo # creation test (names)
set names utf8;
select hex(column_create("адын", 1212));
select hex(column_create("1212", 1212));
select hex(column_create(1212, 2, "www", 3));
select hex(column_create("1212", 2, "www", 3));
select hex(column_create("1212", 2, 3, 3));
select hex(column_create("1212", 2, "адын", 1, 3, 3));
set names default;
--echo # fetching column test (names)
set names utf8;
select column_get(column_create("адын", 1212), "адын" as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "адын" as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 1212 as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "3" as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 3 as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 4 as int);
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "4" as int);
set names default;
--echo # column existance test (names)
set names utf8;
select column_exists(column_create("адын", 1212), "адын");
select column_exists(column_create("адын", 1212), "aады");
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "адын");
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 1212);
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "3");
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 3);
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 4);
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "4");
set names default;
--echo # column changing test (names)
select hex(column_add(column_create(1, "AAA"), "b", "BBB"));
select hex(column_add(column_create("1", "AAA"), "b", "BBB"));
select column_get(column_add(column_create(1, "AAA"), "b", "BBB"), 1 as char);
select column_get(column_add(column_create(1, "AAA"), "b", "BBB"), "b" as char);
select hex(column_add(column_create("a", "AAA"), 1, "BBB"));
select hex(column_add(column_create("a", "AAA"), "1", "BBB"));
select hex(column_add(column_create("a", 1212 as integer), "b", "1212" as integer));
select hex(column_add(column_create("a", 1212 as integer), "a", "1212" as integer));
select hex(column_add(column_create("a", 1212 as integer), "a", NULL as integer));
select hex(column_add(column_create("a", 1212 as integer), "b", NULL as integer));
select hex(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer));
select column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "a" as integer);
select column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "b" as integer);
select hex(column_add(column_create("a", 1212 as integer), "a", 1212 as integer, "b", 11 as integer));
select hex(column_add(column_create("a", NULL as integer), "a", 1212 as integer, "b", 11 as integer));
select hex(column_add(column_create("a", 1212 as integer, "b", 1212 as integer), "a", 11 as integer));
select hex(column_add(column_create("a", 1), "a", null));
select column_list(column_add(column_create("a", 1), "a", null));
select column_list(column_add(column_create("a", 1), "a", ""));
select hex(column_add("", "a", 1));
-- echo # column delete (names)
select hex(column_delete(column_create("a", 1212 as integer, "b", 1212 as integer), "a"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b"));
select hex(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "c"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "d"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "a"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "c"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c"));
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c", "e"));
select hex(column_delete(column_create("a", 1), "a"));
select hex(column_delete("", "a"));
--echo #
--echo # MDEV-458 DNAMES: Server crashes on using an unquoted string
--echo # as a dynamic column name
--echo #
--error ER_BAD_FIELD_ERROR
select COLUMN_CREATE(color, "black");
--echo #
--echo # MDEV-489 Assertion `offset < 0x1f' failed in
--echo # type_and_offset_store on COLUMN_ADD
--echo #
CREATE TABLE t1 (f1 tinyblob);
INSERT INTO t1 VALUES (COLUMN_CREATE('col1', REPEAT('a',30)));
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('b',211), 'val2' );
--error ER_DYN_COL_WRONG_FORMAT
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('c',211), 'val3' );
drop table t1;
--echo #
--echo # MDEV-490/MDEV-491 null as arguments
--echo #
SELECT COLUMN_GET( COLUMN_CREATE( 'col', 'val' ), NULL AS CHAR );
SELECT COLUMN_GET( NULL, 'col' as char );
SELECT COLUMN_EXISTS( COLUMN_CREATE( 'col', 'val' ), NULL);
SELECT COLUMN_EXISTS( NULL, 'col');
SELECT COLUMN_CREATE( NULL, 'val' );
SELECT COLUMN_ADD( NULL, 'val', 'col');
--echo #
--echo # MDEV-488: Assertion `column_name->length < 255' failed on a
--echo # column name with length 255 (precisely)
--echo #
SELECT hex(COLUMN_CREATE(REPEAT('a',255),1));
--error ER_DYN_COL_DATA
SELECT hex(COLUMN_CREATE(REPEAT('a',256),1));
--echo #
--echo # JSON conversion
--echo #
select column_json(column_create("int", -1212 as int, "uint", 12334 as unsigned int, "decimal", "23.344" as decimal, "double", 1.23444e50 as double, "string", 'gdgd\\dhdjh"dhdhd' as char, "time", "0:45:49.000001" AS time, "datetime", "2011-04-05 0:45:49.000001" AS datetime, "date", "2011-04-05" AS date));
select column_json(column_create(1, -1212 as int, 2, 12334 as unsigned int, 3, "23.344" as decimal, 4, 1.23444e50 as double, 5, 'gdgd\\dhdjh"dhdhd' as char, 6, "0:45:49.000001" AS time, 7, "2011-04-05 0:45:49.000001" AS datetime, 8, "2011-04-05" AS date));
--echo #
--echo # CHECK test
--echo #
SELECT COLUMN_CHECK(COLUMN_CREATE(1,'a'));
SELECT COLUMN_CHECK('abracadabra');
SELECT COLUMN_CHECK('');
SELECT COLUMN_CHECK(NULL);
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -175,6 +175,34 @@ my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...)
return ret;
}
my_bool dynstr_append_quoted(DYNAMIC_STRING *str,
const char *append, size_t len)
{
uint additional= (str->alloc_increment ? str->alloc_increment : 10);
uint lim= additional;
uint i;
if (dynstr_realloc(str, len + additional + 2))
return TRUE;
str->str[str->length++]= '"';
for (i= 0; i < len; i++)
{
register char c= append[i];
if (c == '"' || c == '\\')
{
if (!lim)
{
if (dynstr_realloc(str, additional))
return TRUE;
lim= additional;
}
lim--;
str->str[str->length++]= '\\';
}
str->str[str->length++]= c;
}
str->str[str->length++]= '"';
return FALSE;
}
void dynstr_free(DYNAMIC_STRING *str)
{
......@@ -193,3 +221,77 @@ void dynstr_reassociate(DYNAMIC_STRING *str, char **ptr, size_t *length,
*alloc_length= str->max_length;
str->str=0;
}
/*
copy a string from one character set to another
SYNOPSIS
copy_and_convert()
to Store result here
to_cs Character set of result string
from Copy from here
from_length Length of from string
from_cs From character set
NOTES
'to' must be big enough as form_length * to_cs->mbmaxlen
RETURN
length of bytes copied to 'to'
*/
uint32
copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
CHARSET_INFO *from_cs,
uint *errors)
{
int cnvres;
my_wc_t wc;
const uchar *from_end= (const uchar*) from+from_length;
char *to_start= to;
uchar *to_end= (uchar*) to+to_length;
my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
uint error_count= 0;
while (1)
{
if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from,
from_end)) > 0)
from+= cnvres;
else if (cnvres == MY_CS_ILSEQ)
{
error_count++;
from++;
wc= '?';
}
else if (cnvres > MY_CS_TOOSMALL)
{
/*
A correct multibyte sequence detected
But it doesn't have Unicode mapping.
*/
error_count++;
from+= (-cnvres);
wc= '?';
}
else
break; // Not enough characters
outp:
if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
to+= cnvres;
else if (cnvres == MY_CS_ILUNI && wc != '?')
{
error_count++;
wc= '?';
goto outp;
}
else
break;
}
*errors= error_count;
return (uint32) (to - to_start);
}
......@@ -523,7 +523,7 @@ public:
struct st_dyncall_create_def
{
Item *num, *value;
Item *key, *value;
CHARSET_INFO *cs;
uint len, frac;
DYNAMIC_COLUMN_TYPE type;
......
......@@ -6048,24 +6048,87 @@ Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item)
return NULL;
}
longlong Item_func_dyncol_exists::val_int()
longlong Item_func_dyncol_check::val_int()
{
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), &my_charset_bin);
DYNAMIC_COLUMN col;
String *str;
ulonglong num;
enum enum_dyncol_func_result rc;
str= args[0]->val_str(&tmp);
if (args[0]->null_value)
goto null;
col.length= str->length();
/* We do not change the string, so could do this trick */
col.str= (char *)str->ptr();
rc= dynamic_column_check(&col);
if (rc < 0 && rc != ER_DYNCOL_FORMAT)
{
dynamic_column_error_message(rc);
goto null;
}
null_value= FALSE;
return rc == ER_DYNCOL_OK;
null:
null_value= TRUE;
return 0;
}
longlong Item_func_dyncol_exists::val_int()
{
char buff[STRING_BUFFER_USUAL_SIZE], nmstrbuf[11];
String tmp(buff, sizeof(buff), &my_charset_bin),
nmbuf(nmstrbuf, sizeof(nmstrbuf), system_charset_info);
DYNAMIC_COLUMN col;
String *str;
LEX_STRING buf, *name= NULL;
ulonglong num= 0;
enum enum_dyncol_func_result rc;
if (args[1]->result_type() == INT_RESULT)
num= args[1]->val_int();
else
{
String *nm= args[1]->val_str(&nmbuf);
if (!nm || args[1]->null_value)
{
null_value= 1;
return 1;
}
if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci))
{
buf.str= (char *) nm->ptr();
buf.length= nm->length();
}
else
{
uint strlen;
uint dummy_errors;
buf.str= (char *)sql_alloc((strlen= nm->length() *
my_charset_utf8_general_ci.mbmaxlen + 1));
if (buf.str)
{
buf.length=
copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci,
nm->ptr(), nm->length(), nm->charset(),
&dummy_errors);
}
else
buf.length= 0;
}
name= &buf;
}
str= args[0]->val_str(&tmp);
if (args[0]->null_value || args[1]->null_value || num > UINT_MAX16)
goto null;
col.length= str->length();
/* We do not change the string, so could do this trick */
col.str= (char *)str->ptr();
rc= dynamic_column_exists(&col, (uint) num);
rc= ((name == NULL) ?
dynamic_column_exists(&col, (uint) num) :
dynamic_column_exists_str(&col, name));
if (rc < 0)
{
dynamic_column_error_message(rc);
......
......@@ -1861,6 +1861,14 @@ public:
Item *neg_transformer(THD *thd);
};
class Item_func_dyncol_check :public Item_bool_func
{
public:
Item_func_dyncol_check(Item *str) :Item_bool_func(str) {}
longlong val_int();
const char *func_name() const { return "column_check"; }
};
class Item_func_dyncol_exists :public Item_bool_func
{
public:
......
......@@ -5704,7 +5704,7 @@ static List<Item> *create_func_dyncol_prepare(THD *thd,
for (uint i= 0; (def= li++) ;)
{
dfs[0][i++]= *def;
args->push_back(def->num);
args->push_back(def->key);
args->push_back(def->value);
}
return args;
......@@ -5720,6 +5720,10 @@ Item *create_func_dyncol_create(THD *thd, List<DYNCALL_CREATE_DEF> &list)
return new (thd->mem_root) Item_func_dyncol_create(*args, dfs);
}
Item *create_func_dyncol_json(THD *thd, Item *str)
{
return new (thd->mem_root) Item_func_dyncol_json(str);
}
Item *create_func_dyncol_add(THD *thd, Item *str,
List<DYNCALL_CREATE_DEF> &list)
......@@ -5740,7 +5744,7 @@ Item *create_func_dyncol_add(THD *thd, Item *str,
Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums)
{
DYNCALL_CREATE_DEF *dfs;
Item *num;
Item *key;
List_iterator_fast<Item> it(nums);
List<Item> *args= new (thd->mem_root) List<Item>;
......@@ -5750,12 +5754,12 @@ Item *create_func_dyncol_delete(THD *thd, Item *str, List<Item> &nums)
if (!args || !dfs)
return NULL;
for (uint i= 0; (num= it++); i++)
for (uint i= 0; (key= it++); i++)
{
dfs[i].num= num;
dfs[i].key= key;
dfs[i].value= new Item_null();
dfs[i].type= DYN_COL_INT;
args->push_back(dfs[i].num);
args->push_back(dfs[i].key);
args->push_back(dfs[i].value);
}
......
......@@ -180,5 +180,6 @@ Item *create_func_dyncol_get(THD *thd, Item *num, Item *str,
Cast_target cast_type,
const char *c_len, const char *c_dec,
CHARSET_INFO *cs);
Item *create_func_dyncol_json(THD *thd, Item *str);
#endif
......@@ -3760,7 +3760,8 @@ String *Item_func_uuid::val_str(String *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)
: Item_str_func(args), defs(dfs), vals(0), keys(NULL), names(FALSE),
force_names(FALSE)
{
DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments
}
......@@ -3768,13 +3769,26 @@ Item_func_dyncol_create::Item_func_dyncol_create(List<Item> &args,
bool Item_func_dyncol_create::fix_fields(THD *thd, Item **ref)
{
uint i;
bool res= Item_func::fix_fields(thd, ref); // no need Item_str_func here
if (!res)
{
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;
for (i= 0; i + 1 < arg_count && args[i]->result_type() == INT_RESULT; i+= 2);
if (i + 1 < arg_count)
{
names= TRUE;
}
keys= (uchar *) alloc_root(thd->mem_root,
(sizeof(LEX_STRING) > sizeof(uint) ?
sizeof(LEX_STRING) :
sizeof(uint)) *
(arg_count / 2));
}
return res || vals == 0 || keys == 0;
}
......@@ -3785,13 +3799,14 @@ void Item_func_dyncol_create::fix_length_and_dec()
decimals= 0;
}
void Item_func_dyncol_create::prepare_arguments()
bool Item_func_dyncol_create::prepare_arguments(bool force_names_arg)
{
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;
force_names= force_names_arg;
/* get values */
for (i= 0; i < column_count; i++)
......@@ -3850,7 +3865,54 @@ void Item_func_dyncol_create::prepare_arguments()
break;
}
}
nums[i]= (uint) args[i * 2]->val_int();
if (names || force_names)
{
res= args[i * 2]->val_str(&tmp);
if (res)
{
// guaranty UTF-8 string for names
if (my_charset_same(res->charset(), &my_charset_utf8_general_ci))
{
((LEX_STRING *)keys)[i].length= res->length();
if (!(((LEX_STRING *)keys)[i].str=
(char *)sql_memdup(res->ptr(), res->length())))
((LEX_STRING *)keys)[i].length= 0;
}
else
{
uint strlen;
uint dummy_errors;
char *str=
(char *)sql_alloc((strlen= res->length() *
my_charset_utf8_general_ci.mbmaxlen + 1));
if (str)
{
((LEX_STRING *)keys)[i].length=
copy_and_convert(str, strlen, &my_charset_utf8_general_ci,
res->ptr(), res->length(), res->charset(),
&dummy_errors);
((LEX_STRING *)keys)[i].str= str;
}
else
((LEX_STRING *)keys)[i].length= 0;
}
}
else
{
((LEX_STRING *)keys)[i].length= 0;
((LEX_STRING *)keys)[i].str= NULL;
}
}
else
((uint *)keys)[i]= (uint) args[i * 2]->val_int();
if (args[i * 2]->null_value)
{
/* to make cleanup possible */
for (; i < column_count; i++)
vals[i].type= DYN_COL_NULL;
return 1;
}
vals[i].type= type;
switch (type) {
case DYN_COL_NULL:
......@@ -3918,6 +3980,7 @@ void Item_func_dyncol_create::prepare_arguments()
vals[i].type= DYN_COL_NULL;
}
}
return FALSE;
}
void Item_func_dyncol_create::cleanup_arguments()
......@@ -3930,6 +3993,7 @@ void Item_func_dyncol_create::cleanup_arguments()
if (vals[i].type == DYN_COL_STRING)
my_free(vals[i].x.string.value.str);
}
force_names= FALSE;
}
String *Item_func_dyncol_create::val_str(String *str)
......@@ -3940,9 +4004,15 @@ String *Item_func_dyncol_create::val_str(String *str)
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)))
if (prepare_arguments(FALSE))
{
res= NULL;
null_value= 1;
}
else
{
if ((rc= dynamic_column_create_many_fmt(&col, column_count, keys,
vals, names || force_names)))
{
dynamic_column_error_message(rc);
dynamic_column_column_free(&col);
......@@ -3960,6 +4030,7 @@ String *Item_func_dyncol_create::val_str(String *str)
res= &str_value;
null_value= FALSE;
}
}
/* cleanup */
cleanup_arguments();
......@@ -4026,6 +4097,40 @@ void Item_func_dyncol_create::print(String *str,
str->append(')');
}
String *Item_func_dyncol_json::val_str(String *str)
{
DYNAMIC_STRING json, col;
String *res;
enum enum_dyncol_func_result rc;
res= args[0]->val_str(str);
if (args[0]->null_value)
goto null;
col.str= (char *)res->ptr();
col.length= res->length();
if ((rc= dynamic_column_json(&col, &json)))
{
dynamic_column_error_message(rc);
goto null;
}
bzero(&col, sizeof(col));
{
/* Move result from DYNAMIC_COLUMN to str */
char *ptr;
size_t length, alloc_length;
dynstr_reassociate(&json, &ptr, &length, &alloc_length);
str->reassociate(ptr, (uint32) length, (uint32) alloc_length,
&my_charset_utf8_general_ci);
null_value= FALSE;
}
return str;
null:
bzero(&col, sizeof(col));
null_value= TRUE;
return NULL;
}
String *Item_func_dyncol_add::val_str(String *str)
{
......@@ -4037,17 +4142,19 @@ String *Item_func_dyncol_add::val_str(String *str)
/* We store the packed data last */
res= args[arg_count - 1]->val_str(str);
if (args[arg_count - 1]->null_value)
goto null;
if (args[arg_count - 1]->null_value ||
init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
STRING_BUFFER_USUAL_SIZE);
STRING_BUFFER_USUAL_SIZE))
goto null;
col.length= res->length();
memcpy(col.str, res->ptr(), col.length);
prepare_arguments();
if (prepare_arguments(dynamic_column_has_names(&col)))
goto null;
if ((rc= dynamic_column_update_many(&col, column_count, nums, vals)))
if ((rc= dynamic_column_update_many_fmt(&col, column_count, keys,
vals, names || force_names)))
{
dynamic_column_error_message(rc);
dynamic_column_column_free(&col);
......@@ -4066,7 +4173,6 @@ String *Item_func_dyncol_add::val_str(String *str)
}
/* cleanup */
dynamic_column_column_free(&col);
cleanup_arguments();
return str;
......@@ -4100,10 +4206,48 @@ bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp)
{
DYNAMIC_COLUMN dyn_str;
String *res;
longlong num;
longlong num= 0;
LEX_STRING buf, *name= NULL;
char nmstrbuf[11];
String nmbuf(nmstrbuf, sizeof(nmstrbuf), system_charset_info);
enum enum_dyncol_func_result rc;
if (args[1]->result_type() == INT_RESULT)
num= args[1]->val_int();
else
{
String *nm= args[1]->val_str(&nmbuf);
if (!nm || args[1]->null_value)
{
null_value= 1;
return 1;
}
if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci))
{
buf.str= (char *) nm->ptr();
buf.length= nm->length();
}
else
{
uint strlen;
uint dummy_errors;
buf.str= (char *)sql_alloc((strlen= nm->length() *
my_charset_utf8_general_ci.mbmaxlen + 1));
if (buf.str)
{
buf.length=
copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci,
nm->ptr(), nm->length(), nm->charset(),
&dummy_errors);
}
else
buf.length= 0;
}
name= &buf;
}
if (args[1]->null_value || num < 0 || num > INT_MAX)
{
null_value= 1;
......@@ -4119,7 +4263,9 @@ bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp)
dyn_str.str= (char*) res->ptr();
dyn_str.length= res->length();
if ((rc= dynamic_column_get(&dyn_str, (uint) num, val)))
if ((rc= ((name == NULL) ?
dynamic_column_get(&dyn_str, (uint) num, val) :
dynamic_column_get_str(&dyn_str, name, val))))
{
dynamic_column_error_message(rc);
null_value= 1;
......@@ -4468,6 +4614,8 @@ null:
return 1;
}
void
append_identifier(THD *thd, String *packet, const char *name, uint length);
void Item_dyncol_get::print(String *str, enum_query_type query_type)
{
......@@ -4492,26 +4640,30 @@ String *Item_func_dyncol_list::val_str(String *str)
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)))
if ((rc= dynamic_column_list_str(&col, &arr)))
{
dynamic_column_error_message(rc);
for (i= 0; i < arr.elements; i++)
my_free(dynamic_element(&arr, i, LEX_STRING*)->str);
delete_dynamic(&arr);
goto null;
}
/*
We support elements from 0 - 65536, so max size for one element is
6 (including ,).
We estimate average name length as 10
*/
if (str->alloc(arr.elements * 6))
if (str->alloc(arr.elements * 13))
goto null;
str->length(0);
str->set_charset(&my_charset_utf8_general_ci);
for (i= 0; i < arr.elements; i++)
{
str->qs_append(*dynamic_element(&arr, i, uint*));
LEX_STRING *name= dynamic_element(&arr, i, LEX_STRING *);
append_identifier(current_thd, str, name->str, name->length);
if (i < arr.elements - 1)
str->qs_append(',');
my_free(name->str);
}
null_value= FALSE;
......
......@@ -1001,8 +1001,9 @@ class Item_func_dyncol_create: public Item_str_func
protected:
DYNCALL_CREATE_DEF *defs;
DYNAMIC_COLUMN_VALUE *vals;
uint *nums;
void prepare_arguments();
uchar *keys;
bool names, force_names;
bool prepare_arguments(bool force_names);
void cleanup_arguments();
void print_arguments(String *str, enum_query_type query_type);
public:
......@@ -1026,6 +1027,19 @@ public:
virtual void print(String *str, enum_query_type query_type);
};
class Item_func_dyncol_json: public Item_str_func
{
public:
Item_func_dyncol_json(Item *str) :Item_str_func(str) {}
const char *func_name() const{ return "column_json"; }
String *val_str(String *);
void fix_length_and_dec()
{
maybe_null= TRUE;
collation.set(&my_charset_bin);
decimals= 0;
}
};
/*
The following functions is always called from an Item_cast function
......
......@@ -123,10 +123,12 @@ static SYMBOL symbols[] = {
{ "COLUMN_NAME", SYM(COLUMN_NAME_SYM)},
{ "COLUMNS", SYM(COLUMNS)},
{ "COLUMN_ADD", SYM(COLUMN_ADD_SYM)},
{ "COLUMN_CHECK", SYM(COLUMN_CHECK_SYM)},
{ "COLUMN_CREATE", SYM(COLUMN_CREATE_SYM)},
{ "COLUMN_DELETE", SYM(COLUMN_DELETE_SYM)},
{ "COLUMN_EXISTS", SYM(COLUMN_EXISTS_SYM)},
{ "COLUMN_GET", SYM(COLUMN_GET_SYM)},
{ "COLUMN_JSON", SYM(COLUMN_JSON_SYM)},
{ "COLUMN_LIST", SYM(COLUMN_LIST_SYM)},
{ "COMMENT", SYM(COMMENT_SYM)},
{ "COMMIT", SYM(COMMIT_SYM)},
......
......@@ -750,79 +750,6 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
Help functions
****************************************************************************/
/*
copy a string from one character set to another
SYNOPSIS
copy_and_convert()
to Store result here
to_cs Character set of result string
from Copy from here
from_length Length of from string
from_cs From character set
NOTES
'to' must be big enough as form_length * to_cs->mbmaxlen
RETURN
length of bytes copied to 'to'
*/
static uint32
copy_and_convert_extended(char *to, uint32 to_length, CHARSET_INFO *to_cs,
const char *from, uint32 from_length,
CHARSET_INFO *from_cs,
uint *errors)
{
int cnvres;
my_wc_t wc;
const uchar *from_end= (const uchar*) from+from_length;
char *to_start= to;
uchar *to_end= (uchar*) to+to_length;
my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
uint error_count= 0;
while (1)
{
if ((cnvres= (*mb_wc)(from_cs, &wc, (uchar*) from,
from_end)) > 0)
from+= cnvres;
else if (cnvres == MY_CS_ILSEQ)
{
error_count++;
from++;
wc= '?';
}
else if (cnvres > MY_CS_TOOSMALL)
{
/*
A correct multibyte sequence detected
But it doesn't have Unicode mapping.
*/
error_count++;
from+= (-cnvres);
wc= '?';
}
else
break; // Not enough characters
outp:
if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
to+= cnvres;
else if (cnvres == MY_CS_ILUNI && wc != '?')
{
error_count++;
wc= '?';
goto outp;
}
else
break;
}
*errors= error_count;
return (uint32) (to - to_start);
}
/*
......
......@@ -882,10 +882,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token COLLATION_SYM /* SQL-2003-N */
%token COLUMNS
%token COLUMN_ADD_SYM
%token COLUMN_CHECK_SYM
%token COLUMN_CREATE_SYM
%token COLUMN_DELETE_SYM
%token COLUMN_EXISTS_SYM
%token COLUMN_GET_SYM
%token COLUMN_JSON_SYM
%token COLUMN_LIST_SYM
%token COLUMN_SYM /* SQL-2003-R */
%token COLUMN_NAME_SYM /* SQL-2003-N */
......@@ -8245,7 +8247,7 @@ dyncall_create_element:
alloc_root(YYTHD->mem_root, sizeof(DYNCALL_CREATE_DEF));
if ($$ == NULL)
MYSQL_YYABORT;
$$->num= $1;
$$->key= $1;
$$->value= $3;
$$->type= (DYNAMIC_COLUMN_TYPE)$4;
$$->cs= lex->charset;
......@@ -8798,6 +8800,13 @@ function_call_nonkeyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
|
COLUMN_CHECK_SYM '(' expr ')'
{
$$= new (YYTHD->mem_root) Item_func_dyncol_check($3);
if ($$ == NULL)
MYSQL_YYABORT;
}
|
COLUMN_EXISTS_SYM '(' expr ',' expr ')'
{
......@@ -8819,6 +8828,13 @@ function_call_nonkeyword:
if ($$ == NULL)
MYSQL_YYABORT;
}
|
COLUMN_JSON_SYM '(' expr ')'
{
$$= create_func_dyncol_json(YYTHD, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
|
COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')'
{
......@@ -12908,10 +12924,12 @@ keyword:
| CHECKPOINT_SYM {}
| CLOSE_SYM {}
| COLUMN_ADD_SYM {}
| COLUMN_CHECK_SYM {}
| COLUMN_CREATE_SYM {}
| COLUMN_DELETE_SYM {}
| COLUMN_EXISTS_SYM {}
| COLUMN_GET_SYM {}
| COLUMN_JSON_SYM {}
| COLUMN_LIST_SYM {}
| COMMENT_SYM {}
| COMMIT_SYM {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment