MDEV-506 Cassandra dynamic columns access

This commit is contained in:
unknown 2012-09-28 15:27:16 +03:00
parent 7327cd9717
commit 245298f25d
13 changed files with 1673 additions and 143 deletions

View File

@ -39,6 +39,12 @@
*/
#define MAX_DYNAMIC_COLUMN_LENGTH 0X1FFFFFFFL
/*
Limits of implementation
*/
#define MAX_NAME_LENGTH 255
#define MAX_TOTAL_NAME_LENGTH 65535
/* NO and OK is the same used just to show semantics */
#define ER_DYNCOL_NO ER_DYNCOL_OK
@ -50,7 +56,8 @@ enum enum_dyncol_func_result
ER_DYNCOL_LIMIT= -2, /* Some limit reached */
ER_DYNCOL_RESOURCE= -3, /* Out of resourses */
ER_DYNCOL_DATA= -4, /* Incorrect input data */
ER_DYNCOL_UNKNOWN_CHARSET= -5 /* Unknown character set */
ER_DYNCOL_UNKNOWN_CHARSET= -5, /* Unknown character set */
ER_DYNCOL_TRUNCATED= 2 /* OK, but data was truncated */
};
typedef DYNAMIC_STRING DYNAMIC_COLUMN;
@ -81,6 +88,7 @@ struct st_dynamic_column_value
struct {
LEX_STRING value;
CHARSET_INFO *charset;
my_bool nonfreeable;
} string;
struct {
decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
@ -108,6 +116,13 @@ dynamic_column_create_many_fmt(DYNAMIC_COLUMN *str,
uchar *column_keys,
DYNAMIC_COLUMN_VALUE *values,
my_bool names);
enum enum_dyncol_func_result
dynamic_column_create_many_internal_fmt(DYNAMIC_COLUMN *str,
uint column_count,
void *column_keys,
DYNAMIC_COLUMN_VALUE *values,
my_bool new_str,
my_bool string_keys);
enum enum_dyncol_func_result
dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
@ -163,6 +178,21 @@ 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)
/* conversion of values to 3 base types */
enum enum_dyncol_func_result
dynamic_column_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
CHARSET_INFO *cs, my_bool quote);
enum enum_dyncol_func_result
dynamic_column_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val);
enum enum_dyncol_func_result
dynamic_column_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val);
enum enum_dyncol_func_result
dynamic_column_vals(DYNAMIC_COLUMN *str,
DYNAMIC_ARRAY *names, DYNAMIC_ARRAY *vals,
char **free_names);
/***************************************************************************
Internal functions, don't use if you don't know what you are doing...
***************************************************************************/

View File

@ -365,8 +365,9 @@ CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
select * from t2;
rowkey datecol
1 1346189025000
10 1346189026000
1 1346192625000
10 1346192626000
delete from t2;
drop table t2;
#
# Check whether changing parameters with ALTER TABLE works.
@ -407,3 +408,141 @@ new-rowkey12 data1-value3 454
rowkey11 updated-1 34543
delete from t1;
drop table t1;
#
# Dynamic columns support
#
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
drop table t2;
#error: dynamic column is not a blob
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36) DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
ERROR 42000: Incorrect column specifier for column 'uuidcol'
#error: double dynamic column
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1, textcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
ERROR 42000: Incorrect column specifier for column 'textcol'
#
# Dynamic column read
#
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
delete from t2;
insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
insert into t2 values(2,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
drop table t2;
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
select rowkey, column_list(dyn), column_get(dyn, 'uuidcol' as char) from t2;
rowkey column_list(dyn) column_get(dyn, 'uuidcol' as char)
1 `uuidcol` 9b5658dc-f32f-11e1-94cd-f46d046e9f09
2 `uuidcol` 9b5658dc-f32f-11e1-94cd-f46d046e9f0a
drop table t2;
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
delete from t2;
drop table t2;
#
# Dynamic column insert
#
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
insert into t2 values (1, column_create("dyn1", 1, "dyn2", "two"));
select rowkey, column_json(dyn) from t2;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn2":"two"}]
delete from t2;
drop table t2;
# bigint
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'a', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'a', 2543));
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":254324},{"dyn1":"1"},{"dyn2":"two"}]
2 [{"a":2543},{"dyn1":"1"},{"dyn2":"two"}]
delete from t1;
drop table t1;
# int
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf3';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'intcol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'intcol', 2543));
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn2":"two"},{"intcol":254324}]
2 [{"dyn1":"1"},{"dyn2":"two"},{"intcol":2543}]
delete from t1;
drop table t1;
# timestamp
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'datecol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'datecol', 2543));
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn2":"two"},{"datecol":254324}]
2 [{"dyn1":"1"},{"dyn2":"two"},{"datecol":2543}]
delete from t1;
drop table t1;
# boolean
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf7';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 0));
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn2":"two"},{"boolcol":1}]
2 [{"dyn1":"1"},{"dyn2":"two"},{"boolcol":0}]
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn2":"two"},{"boolcol":1}]
2 [{"dyn1":"1"},{"dyn2":"two"},{"boolcol":0}]
update t1 set dyn=column_add(dyn, "dyn2", null, "dyn3", "3");
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn1":"1"},{"dyn3":"3"},{"boolcol":1}]
2 [{"dyn1":"1"},{"dyn3":"3"},{"boolcol":0}]
update t1 set dyn=column_add(dyn, "dyn1", null) where rowkey= 1;
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"dyn3":"3"},{"boolcol":1}]
2 [{"dyn1":"1"},{"dyn3":"3"},{"boolcol":0}]
update t1 set dyn=column_add(dyn, "dyn3", null, "a", "ddd");
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":"ddd"},{"boolcol":1}]
2 [{"a":"ddd"},{"dyn1":"1"},{"boolcol":0}]
update t1 set dyn=column_add(dyn, "12345678901234", "ddd");
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":"ddd"},{"boolcol":1},{"12345678901234":"ddd"}]
2 [{"a":"ddd"},{"dyn1":"1"},{"boolcol":0},{"12345678901234":"ddd"}]
update t1 set dyn=column_add(dyn, "12345678901234", null);
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":"ddd"},{"boolcol":1}]
2 [{"a":"ddd"},{"dyn1":"1"},{"boolcol":0}]
update t1 set dyn=column_add(dyn, 'boolcol', null) where rowkey= 2;
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":"ddd"},{"boolcol":1}]
2 [{"a":"ddd"},{"dyn1":"1"}]
update t1 set rowkey= 3, dyn=column_add(dyn, "dyn1", null, 'boolcol', 0) where rowkey= 2;
select rowkey, column_json(dyn) from t1;
rowkey column_json(dyn)
1 [{"a":"ddd"},{"boolcol":1}]
3 [{"a":"ddd"},{"boolcol":0}]
delete from t1;
drop table t1;
CREATE TABLE t1 (rowkey varchar(10) PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd1';
select * from t1;
ERROR HY000: Internal error: 'Unable to convert value for field `dyn` from Cassandra's data format. Name length exceed limit of 255: 'very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_ver'
drop table t1;
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
DELETE FROM t1;
insert into t1 values (1, column_create("dyn", 1));
select rowkey, column_list(dyn) from t1;
rowkey column_list(dyn)
1 `dyn`
delete from t1;
DROP TABLE t1;
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
insert into t1 values (1,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
ERROR HY000: Encountered illegal format of dynamic column string
delete from t1;
DROP TABLE t1;

View File

@ -89,6 +89,24 @@ The following options may be given as the first argument:
--bulk-insert-buffer-size=#
Size of tree cache used in bulk insert optimisation. Note
that this is a limit per thread!
--cassandra[=name] Enable or disable CASSANDRA plugin. Possible values are
ON, OFF, FORCE (don't start if the plugin fails to load).
--cassandra-default-thrift-host=name
Default host for Cassandra thrift connections
--cassandra-failure-retries=#
Number of times to retry Cassandra calls that failed due
to timeouts or network communication problems. The
default, 0, means not to retry.
--cassandra-insert-batch-size=#
Number of rows in an INSERT batch
--cassandra-multiget-batch-size=#
Number of rows in a multiget(MRR) batch
--cassandra-read-consistency=name
Cassandra consistency level to use for read operations
--cassandra-rnd-batch-size=#
Number of rows in an rnd_read (full scan) batch
--cassandra-write-consistency=name
Cassandra consistency level to use for write operations
--character-set-client-handshake
Don't ignore client side character set value sent during
handshake.
@ -863,6 +881,14 @@ binlog-optimize-thread-scheduling TRUE
binlog-row-event-max-size 1024
binlog-stmt-cache-size 32768
bulk-insert-buffer-size 8388608
cassandra ON
cassandra-default-thrift-host (No default value)
cassandra-failure-retries 0
cassandra-insert-batch-size 100
cassandra-multiget-batch-size 100
cassandra-read-consistency ONE
cassandra-rnd-batch-size 10000
cassandra-write-consistency ONE
character-set-client-handshake TRUE
character-set-filesystem binary
character-set-server latin1

View File

@ -94,6 +94,18 @@ CREATE COLUMN FAMILY cf10
WITH comparator = UTF8Type
AND key_validation_class=UTF8Type
AND default_validation_class = UTF8Type;
CREATE COLUMN FAMILY cfd1
WITH comparator = UTF8Type
AND key_validation_class=UTF8Type
AND default_validation_class = UTF8Type;
SET cfd1['1']['very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_long_name']='1';
CREATE COLUMN FAMILY cfd2
WITH comparator = UTF8Type
AND key_validation_class=Int32Type
AND default_validation_class = UTF8Type;
EOF
--error 0,1,2
@ -463,7 +475,7 @@ drop table t2;
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
select * from t2;
delete from t2;
drop table t2;
--echo #
@ -511,6 +523,118 @@ select * from t1;
delete from t1;
drop table t1;
--echo #
--echo # Dynamic columns support
--echo #
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
drop table t2;
--echo #error: dynamic column is not a blob
--error ER_WRONG_FIELD_SPEC
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36) DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
--echo #error: double dynamic column
--error ER_WRONG_FIELD_SPEC
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol blob DYNAMIC_COLUMN_STORAGE=1, textcol blob DYNAMIC_COLUMN_STORAGE=1) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
--echo #
--echo # Dynamic column read
--echo #
#prepare data
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
delete from t2;
insert into t2 values(1,'9b5658dc-f32f-11e1-94cd-f46d046e9f09');
insert into t2 values(2,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
drop table t2;
#test dynamic column read
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
select rowkey, column_list(dyn), column_get(dyn, 'uuidcol' as char) from t2;
drop table t2;
#cleanup data
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, uuidcol char(36)) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
delete from t2;
drop table t2;
--echo #
--echo # Dynamic column insert
--echo #
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf5';
insert into t2 values (1, column_create("dyn1", 1, "dyn2", "two"));
select rowkey, column_json(dyn) from t2;
delete from t2;
drop table t2;
--echo # bigint
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'a', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'a', 2543));
select rowkey, column_json(dyn) from t1;
delete from t1;
drop table t1;
--echo # int
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf3';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'intcol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'intcol', 2543));
select rowkey, column_json(dyn) from t1;
delete from t1;
drop table t1;
--echo # timestamp
CREATE TABLE t1 (rowkey bigint PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'datecol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'datecol', 2543));
select rowkey, column_json(dyn) from t1;
delete from t1;
drop table t1;
--echo # boolean
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf7';
insert into t1 values (1, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 254324));
insert into t1 values (2, column_create("dyn1", 1, "dyn2", "two", 'boolcol', 0));
select rowkey, column_json(dyn) from t1;
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, "dyn2", null, "dyn3", "3");
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, "dyn1", null) where rowkey= 1;
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, "dyn3", null, "a", "ddd");
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, "12345678901234", "ddd");
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, "12345678901234", null);
select rowkey, column_json(dyn) from t1;
update t1 set dyn=column_add(dyn, 'boolcol', null) where rowkey= 2;
select rowkey, column_json(dyn) from t1;
update t1 set rowkey= 3, dyn=column_add(dyn, "dyn1", null, 'boolcol', 0) where rowkey= 2;
select rowkey, column_json(dyn) from t1;
delete from t1;
drop table t1;
CREATE TABLE t1 (rowkey varchar(10) PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes) ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd1';
--error ER_INTERNAL_ERROR
select * from t1;
drop table t1;
# MDEV-560
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
DELETE FROM t1;
insert into t1 values (1, column_create("dyn", 1));
select rowkey, column_list(dyn) from t1;
# Cleanup
delete from t1;
DROP TABLE t1;
# MDEV-561 (incorrect format data to dynamic column)
CREATE TABLE t1 (rowkey int PRIMARY KEY, dyn blob DYNAMIC_COLUMN_STORAGE=yes)
ENGINE=CASSANDRA thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cfd2';
--error ER_DYN_COL_WRONG_FORMAT
insert into t1 values (1,'9b5658dc-f32f-11e1-94cd-f46d046e9f0a');
delete from t1;
DROP TABLE t1;
############################################################################
## Cassandra cleanup
############################################################################

View File

@ -68,6 +68,8 @@ uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
#define MAX_OFFSET_LENGTH 5
#define DYNCOL_NUM_CHAR 6
my_bool dynamic_column_has_names(DYNAMIC_COLUMN *str)
{
if (str->length < 1)
@ -211,7 +213,7 @@ static my_bool check_limit_num(const void *val)
static my_bool check_limit_str(const void *val)
{
return (*((LEX_STRING **)val))->length > 255;
return (*((LEX_STRING **)val))->length > MAX_NAME_LENGTH;
}
@ -288,7 +290,7 @@ my_bool put_header_entry_str(DYN_HEADER *hdr,
size_t offset)
{
LEX_STRING *column_name= (LEX_STRING *)column_key;
DBUG_ASSERT(column_name->length <= 255);
DBUG_ASSERT(column_name->length <= MAX_NAME_LENGTH);
hdr->entry[0]= column_name->length;
DBUG_ASSERT(hdr->name - hdr->nmpool < (long) 0x10000L);
int2store(hdr->entry + 1, hdr->name - hdr->nmpool);
@ -1381,6 +1383,9 @@ dynamic_new_column_store(DYNAMIC_COLUMN *str,
DYNCOL_SYZERESERVE))
goto err;
}
if (!column_count)
return ER_DYNCOL_OK;
bzero(str->str, fmt->fixed_hdr);
str->length= fmt->fixed_hdr;
@ -1501,7 +1506,7 @@ calc_var_sizes(DYN_HEADER *hdr,
@return ER_DYNCOL_* return code
*/
static enum enum_dyncol_func_result
enum enum_dyncol_func_result
dynamic_column_create_many_internal_fmt(DYNAMIC_COLUMN *str,
uint column_count,
void *column_keys,
@ -1761,7 +1766,7 @@ static my_bool
find_column(DYN_HEADER *hdr, uint numkey, LEX_STRING *strkey)
{
LEX_STRING nmkey;
char nmkeybuff[6]; /* to fit max 2 bytes number */
char nmkeybuff[DYNCOL_NUM_CHAR]; /* to fit max 2 bytes number */
DBUG_ASSERT(hdr->header != NULL);
if (hdr->header + hdr->header_size > hdr->data_end)
@ -2169,10 +2174,10 @@ dynamic_column_list_str(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_lexstr)
if (header.format == DYNCOL_FMT_NUM)
{
uint nm= uint2korr(read);
tmp.str= my_malloc(6, MYF(0));
tmp.str= my_malloc(DYNCOL_NUM_CHAR, MYF(0));
if (!tmp.str)
return ER_DYNCOL_RESOURCE;
tmp.length= snprintf(tmp.str, 6, "%u", nm);
tmp.length= snprintf(tmp.str, DYNCOL_NUM_CHAR, "%u", nm);
}
else
{
@ -2208,7 +2213,7 @@ find_place(DYN_HEADER *hdr, void *key, my_bool string_keys)
uint mid, start, end, val;
int flag;
LEX_STRING str;
char buff[6];
char buff[DYNCOL_NUM_CHAR];
my_bool need_conversion= ((string_keys ? DYNCOL_FMT_STR : DYNCOL_FMT_NUM) !=
hdr->format);
LINT_INIT(flag); /* 100 % safe */
@ -2425,7 +2430,7 @@ dynamic_column_update_copy(DYNAMIC_COLUMN *str, PLAN *plan,
size_t offs;
uint nm;
DYNAMIC_COLUMN_TYPE tp;
char buff[6];
char buff[DYNCOL_NUM_CHAR];
if (hdr->format == DYNCOL_FMT_NUM)
{
@ -3438,7 +3443,7 @@ end:
enum enum_dyncol_func_result
dynamic_column_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
my_bool quote)
CHARSET_INFO *cs, my_bool quote)
{
char buff[40];
int len;
@ -3468,24 +3473,22 @@ dynamic_column_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
char *alloc= NULL;
char *from= val->x.string.value.str;
uint bufflen;
my_bool conv= !my_charset_same(val->x.string.charset,
&my_charset_utf8_general_ci);
my_bool conv= !my_charset_same(val->x.string.charset, cs);
my_bool rc;
len= val->x.string.value.length;
bufflen= (len * (conv ? my_charset_utf8_general_ci.mbmaxlen : 1));
bufflen= (len * (conv ? cs->mbmaxlen : 1));
if (dynstr_realloc(str, bufflen))
return ER_DYNCOL_RESOURCE;
// guaranty UTF-8 string for value
if (!my_charset_same(val->x.string.charset,
&my_charset_utf8_general_ci))
if (!my_charset_same(val->x.string.charset, cs))
{
uint dummy_errors;
if (!quote)
{
/* convert to the destination */
str->length+= copy_and_convert_extended(str->str, bufflen,
&my_charset_utf8_general_ci,
cs,
from, len,
val->x.string.charset,
&dummy_errors);
@ -3494,8 +3497,7 @@ dynamic_column_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
if ((alloc= (char *)my_malloc(bufflen, MYF(0))))
{
len=
copy_and_convert_extended(alloc, bufflen,
&my_charset_utf8_general_ci,
copy_and_convert_extended(alloc, bufflen, cs,
from, len, val->x.string.charset,
&dummy_errors);
from= alloc;
@ -3543,6 +3545,155 @@ dynamic_column_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
return(ER_DYNCOL_OK);
}
enum enum_dyncol_func_result
dynamic_column_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val)
{
enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
*ll= 0;
switch (val->type) {
case DYN_COL_INT:
*ll= val->x.long_value;
break;
case DYN_COL_UINT:
*ll= (longlong)val->x.ulong_value;
if (val->x.ulong_value > ULONGLONG_MAX)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_DOUBLE:
*ll= (longlong)val->x.double_value;
if (((double) *ll) != val->x.double_value)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_STRING:
{
longlong i= 0, sign= 1;
char *src= val->x.string.value.str;
uint len= val->x.string.value.length;
while (len && my_isspace(&my_charset_latin1, *src)) src++,len--;
if (len)
{
if (*src == '-')
{
sign= -1;
src++;
} else if (*src == '-')
src++;
while(len && my_isdigit(&my_charset_latin1, *src))
{
i= i * 10 + (*src - '0');
src++;
}
}
else
rc= ER_DYNCOL_TRUNCATED;
if (len)
rc= ER_DYNCOL_TRUNCATED;
*ll= i * sign;
break;
}
case DYN_COL_DECIMAL:
if (decimal2longlong(&val->x.decimal.value, ll) != E_DEC_OK)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_DATETIME:
*ll= (val->x.time_value.year * 10000000000L +
val->x.time_value.month * 100000000L +
val->x.time_value.day * 1000000 +
val->x.time_value.hour * 10000 +
val->x.time_value.minute * 100 +
val->x.time_value.second) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_DATE:
*ll= (val->x.time_value.year * 10000 +
val->x.time_value.month * 100 +
val->x.time_value.day) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_TIME:
*ll= (val->x.time_value.hour * 10000 +
val->x.time_value.minute * 100 +
val->x.time_value.second) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_NULL:
rc= ER_DYNCOL_TRUNCATED;
break;
default:
return(ER_DYNCOL_FORMAT);
}
return(rc);
}
enum enum_dyncol_func_result
dynamic_column_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val)
{
enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
*dbl= 0;
switch (val->type) {
case DYN_COL_INT:
*dbl= (double)val->x.long_value;
if (((longlong) *dbl) != val->x.long_value)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_UINT:
*dbl= (double)val->x.ulong_value;
if (((ulonglong) *dbl) != val->x.ulong_value)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_DOUBLE:
*dbl= val->x.double_value;
break;
case DYN_COL_STRING:
{
char *str, *end;
if ((str= malloc(val->x.string.value.length + 1)))
return ER_DYNCOL_RESOURCE;
memcpy(str, val->x.string.value.str, val->x.string.value.length);
str[val->x.string.value.length]= '\0';
*dbl= strtod(str, &end);
if (*end != '\0')
rc= ER_DYNCOL_TRUNCATED;
}
case DYN_COL_DECIMAL:
if (decimal2double(&val->x.decimal.value, dbl) != E_DEC_OK)
rc= ER_DYNCOL_TRUNCATED;
break;
case DYN_COL_DATETIME:
*dbl= (double)(val->x.time_value.year * 10000000000L +
val->x.time_value.month * 100000000L +
val->x.time_value.day * 1000000 +
val->x.time_value.hour * 10000 +
val->x.time_value.minute * 100 +
val->x.time_value.second) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_DATE:
*dbl= (double)(val->x.time_value.year * 10000 +
val->x.time_value.month * 100 +
val->x.time_value.day) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_TIME:
*dbl= (double)(val->x.time_value.hour * 10000 +
val->x.time_value.minute * 100 +
val->x.time_value.second) *
(val->x.time_value.neg ? -1 : 1);
break;
case DYN_COL_NULL:
rc= ER_DYNCOL_TRUNCATED;
break;
default:
return(ER_DYNCOL_FORMAT);
}
return(rc);
}
/**
Convert to JSON
@ -3602,10 +3753,11 @@ dynamic_column_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json)
if (header.format == DYNCOL_FMT_NUM)
{
uint nm= uint2korr(header.entry);
if (dynstr_realloc(json, 6 + 3))
if (dynstr_realloc(json, DYNCOL_NUM_CHAR + 3))
goto err;
json->str[json->length++]= '"';
json->length+= (snprintf(json->str + json->length, 6, "%u", nm));
json->length+= (snprintf(json->str + json->length,
DYNCOL_NUM_CHAR, "%u", nm));
}
else
{
@ -3619,7 +3771,8 @@ dynamic_column_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json)
}
json->str[json->length++]= '"';
json->str[json->length++]= ':';
if ((rc= dynamic_column_val_str(json, &val, TRUE)) < 0 ||
if ((rc= dynamic_column_val_str(json, &val,
&my_charset_utf8_general_ci, TRUE)) < 0 ||
dynstr_append_mem(json, "}", 1))
goto err;
}
@ -3631,3 +3784,99 @@ err:
json->length= 0;
return rc;
}
/**
Convert to DYNAMIC_COLUMN_VALUE values and names (LEX_STING) dynamic array
@param str The packed string
@param names Where to put names
@param vals Where to put values
@param free_names pointer to free names buffer if there is it.
@return ER_DYNCOL_* return code
*/
enum enum_dyncol_func_result
dynamic_column_vals(DYNAMIC_COLUMN *str,
DYNAMIC_ARRAY *names, DYNAMIC_ARRAY *vals,
char **free_names)
{
DYN_HEADER header;
char *nm;
uint i;
enum enum_dyncol_func_result rc;
*free_names= 0;
bzero(names, sizeof(DYNAMIC_ARRAY)); /* In case of errors */
bzero(vals, sizeof(DYNAMIC_ARRAY)); /* In case of errors */
if (str->length == 0)
return ER_DYNCOL_OK; /* no columns */
if ((rc= init_read_hdr(&header, str)) < 0)
return rc;
if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
str->length)
return ER_DYNCOL_FORMAT;
if (init_dynamic_array(names, sizeof(LEX_STRING),
header.column_count, 0) ||
init_dynamic_array(vals, sizeof(DYNAMIC_COLUMN_VALUE),
header.column_count, 0) ||
(header.format == DYNCOL_FMT_NUM &&
!(*free_names= (char *)malloc(DYNCOL_NUM_CHAR * header.column_count))))
{
rc= ER_DYNCOL_RESOURCE;
goto err;
}
nm= *free_names;
for (i= 0, header.entry= header.header;
i < header.column_count;
i++, header.entry+= header.entry_size)
{
DYNAMIC_COLUMN_VALUE val;
LEX_STRING name;
header.length=
hdr_interval_length(&header, header.entry + header.entry_size);
header.data= header.dtpool + header.offset;
/*
Check that the found data is withing the ranges. This can happen if
we get data with wrong offsets.
*/
if (header.length == DYNCOL_OFFSET_ERROR ||
header.length > INT_MAX || header.offset > header.data_size)
{
rc= ER_DYNCOL_FORMAT;
goto err;
}
if ((rc= dynamic_column_get_value(&header, &val)) < 0)
goto err;
if (header.format == DYNCOL_FMT_NUM)
{
uint num= uint2korr(header.entry);
name.str= nm;
name.length= snprintf(nm, DYNCOL_NUM_CHAR, "%u", num);
nm+= name.length + 1;
}
else
{
name.length= header.entry[0];
name.str= (char *)header.nmpool + uint2korr(header.entry + 1);
}
/* following is preallocated and so do not fail */
(void) insert_dynamic(names, (uchar *)&name);
(void) insert_dynamic(vals, (uchar *)&val);
}
return ER_DYNCOL_OK;
err:
delete_dynamic(names);
delete_dynamic(vals);
if (*free_names)
my_free(*free_names);
*free_names= 0;
return rc;
}

View File

@ -9773,6 +9773,7 @@ int dynamic_column_error_message(enum_dyncol_func_result rc)
switch (rc) {
case ER_DYNCOL_YES:
case ER_DYNCOL_OK:
case ER_DYNCOL_TRUNCATED:
break; // it is not an error
case ER_DYNCOL_FORMAT:
my_error(ER_DYN_COL_WRONG_FORMAT, MYF(0));

View File

@ -272,6 +272,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
const char *table_name);
bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
class Open_tables_backup;
/* Functions to work with system tables. */
bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
Open_tables_backup *backup);

View File

@ -12,7 +12,7 @@ SET(cassandra_sources
gen-cpp/Cassandra.h)
#INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(AFTER /home/psergey/cassandra/thrift/include/thrift/)
INCLUDE_DIRECTORIES(AFTER /usr/local/include/thrift)
#
STRING(REPLACE "-fno-exceptions" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})

View File

@ -17,6 +17,12 @@
#include "cassandra_se.h"
struct st_mysql_lex_string
{
char *str;
size_t length;
};
using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::transport;
@ -74,6 +80,7 @@ class Cassandra_se_impl: public Cassandra_se_interface
std::string rowkey; /* key of the record we're returning now */
SlicePredicate slice_pred;
SliceRange slice_pred_sr;
bool get_slices_returned_less;
bool get_slice_found_rows;
public:
@ -91,6 +98,8 @@ public:
void first_ddl_column();
bool next_ddl_column(char **name, int *name_len, char **value, int *value_len);
void get_rowkey_type(char **name, char **type);
size_t get_ddl_size();
const char* get_default_validator();
/* Settings */
void set_consistency_levels(ulong read_cons_level, ulong write_cons_level);
@ -98,15 +107,19 @@ public:
/* Writes */
void clear_insert_buffer();
void start_row_insert(const char *key, int key_len);
void add_insert_column(const char *name, const char *value, int value_len);
void add_insert_column(const char *name, int name_len,
const char *value, int value_len);
void add_insert_delete_column(const char *name, int name_len);
void add_row_deletion(const char *key, int key_len,
Column_name_enumerator *col_names);
Column_name_enumerator *col_names,
LEX_STRING *names, uint nnames);
bool do_insert();
/* Reads, point lookups */
bool get_slice(char *key, size_t key_len, bool *found);
bool get_next_read_column(char **name, char **value, int *value_len);
bool get_next_read_column(char **name, int *name_len,
char **value, int *value_len );
void get_read_rowkey(char **value, int *value_len);
/* Reads, multi-row scans */
@ -122,6 +135,7 @@ public:
/* Setup that's necessary before a multi-row read. (todo: use it before point lookups, too) */
void clear_read_columns();
void clear_read_all_columns();
void add_read_column(const char *name);
/* Reads, MRR scans */
@ -277,6 +291,16 @@ void Cassandra_se_impl::get_rowkey_type(char **name, char **type)
*name= NULL;
}
size_t Cassandra_se_impl::get_ddl_size()
{
return cf_def.column_metadata.size();
}
const char* Cassandra_se_impl::get_default_validator()
{
return cf_def.default_validation_class.c_str();
}
/////////////////////////////////////////////////////////////////////////////
// Data writes
@ -315,8 +339,9 @@ void Cassandra_se_impl::start_row_insert(const char *key, int key_len)
}
void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
Column_name_enumerator *col_names)
void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
Column_name_enumerator *col_names,
LEX_STRING *names, uint nnames)
{
std::string key_to_delete;
key_to_delete.assign(key, key_len);
@ -344,6 +369,9 @@ void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
const char *col_name;
while ((col_name= col_names->get_next_name()))
slice_pred.column_names.push_back(std::string(col_name));
for (uint i= 0; i < nnames; i++)
slice_pred.column_names.push_back(std::string(names[i].str,
names[i].length));
mut.deletion.predicate= slice_pred;
@ -351,7 +379,9 @@ void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
}
void Cassandra_se_impl::add_insert_column(const char *name, const char *value,
void Cassandra_se_impl::add_insert_column(const char *name,
int name_len,
const char *value,
int value_len)
{
Mutation mut;
@ -359,7 +389,10 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value,
mut.column_or_supercolumn.__isset.column= true;
Column& col=mut.column_or_supercolumn.column;
col.name.assign(name);
if (name_len)
col.name.assign(name, name_len);
else
col.name.assign(name);
col.value.assign(value, value_len);
col.timestamp= insert_timestamp;
col.__isset.value= true;
@ -367,6 +400,23 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value,
insert_list->push_back(mut);
}
void Cassandra_se_impl::add_insert_delete_column(const char *name,
int name_len)
{
Mutation mut;
mut.__isset.deletion= true;
mut.deletion.__isset.timestamp= true;
mut.deletion.timestamp= insert_timestamp;
mut.deletion.__isset.predicate= true;
SlicePredicate slice_pred;
slice_pred.__isset.column_names= true;
slice_pred.column_names.push_back(std::string(name, name_len));
mut.deletion.predicate= slice_pred;
insert_list->push_back(mut);
}
bool Cassandra_se_impl::retryable_do_insert()
{
@ -444,8 +494,8 @@ bool Cassandra_se_impl::retryable_get_slice()
}
bool Cassandra_se_impl::get_next_read_column(char **name, char **value,
int *value_len)
bool Cassandra_se_impl::get_next_read_column(char **name, int *name_len,
char **value, int *value_len)
{
bool use_counter=false;
while (1)
@ -468,12 +518,14 @@ bool Cassandra_se_impl::get_next_read_column(char **name, char **value,
ColumnOrSuperColumn& cs= *column_data_it;
if (use_counter)
{
*name_len= cs.counter_column.name.size();
*name= (char*)cs.counter_column.name.c_str();
*value= (char*)&cs.counter_column.value;
*value_len= sizeof(cs.counter_column.value);
}
else
{
*name_len= cs.column.name.size();
*name= (char*)cs.column.name.c_str();
*value= (char*)cs.column.value.c_str();
*value_len= cs.column.value.length();
@ -601,6 +653,13 @@ void Cassandra_se_impl::clear_read_columns()
slice_pred.column_names.clear();
}
void Cassandra_se_impl::clear_read_all_columns()
{
slice_pred_sr.start = "";
slice_pred_sr.finish = "";
slice_pred.__set_slice_range(slice_pred_sr);
}
void Cassandra_se_impl::add_read_column(const char *name_arg)
{

View File

@ -6,6 +6,8 @@
both together causes compile errors due to conflicts).
*/
struct st_mysql_lex_string;
typedef struct st_mysql_lex_string LEX_STRING;
/* We need to define this here so that ha_cassandra.cc also has access to it */
typedef enum
@ -50,19 +52,25 @@ public:
virtual bool next_ddl_column(char **name, int *name_len, char **value,
int *value_len)=0;
virtual void get_rowkey_type(char **name, char **type)=0;
virtual size_t get_ddl_size()=0;
virtual const char* get_default_validator()=0;
/* Writes */
virtual void clear_insert_buffer()=0;
virtual void add_row_deletion(const char *key, int key_len,
Column_name_enumerator *col_names)=0;
Column_name_enumerator *col_names,
LEX_STRING *names, uint nnames)=0;
virtual void start_row_insert(const char *key, int key_len)=0;
virtual void add_insert_column(const char *name, const char *value,
virtual void add_insert_delete_column(const char *name, int name_len)= 0;
virtual void add_insert_column(const char *name, int name_len,
const char *value,
int value_len)=0;
virtual bool do_insert()=0;
/* Reads */
virtual bool get_slice(char *key, size_t key_len, bool *found)=0 ;
virtual bool get_next_read_column(char **name, char **value, int *value_len)=0;
virtual bool get_next_read_column(char **name, int *name_len,
char **value, int *value_len)=0;
virtual void get_read_rowkey(char **value, int *value_len)=0;
/* Reads, multi-row scans */
@ -70,7 +78,7 @@ public:
virtual bool get_range_slices(bool last_key_as_start_key)=0;
virtual void finish_reading_range_slices()=0;
virtual bool get_next_range_slice_row(bool *eof)=0;
/* Reads, MRR scans */
virtual void new_lookup_keys()=0;
virtual int add_lookup_key(const char *key, size_t key_len)=0;
@ -79,8 +87,9 @@ public:
/* read_set setup */
virtual void clear_read_columns()=0;
virtual void clear_read_all_columns()=0;
virtual void add_read_column(const char *name)=0;
virtual bool truncate()=0;
virtual bool remove_row()=0;

View File

@ -11,7 +11,7 @@ namespace org { namespace apache { namespace cassandra {
const cassandraConstants g_cassandra_constants;
cassandraConstants::cassandraConstants() {
cassandra_const_VERSION = "19.32.0";
cassandra_const_VERSION = (char *)"19.32.0";
}
}}} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,33 @@ class ColumnDataConverter;
struct ha_table_option_struct;
struct st_dynamic_column_value;
typedef bool (* CAS2DYN_CONVERTER)(const char *cass_data,
int cass_data_len,
struct st_dynamic_column_value *value);
typedef bool (* DYN2CAS_CONVERTER)(struct st_dynamic_column_value *value,
char **cass_data,
int *cass_data_len,
void *buf, void **freemem);
struct cassandra_type_def
{
const char *name;
CAS2DYN_CONVERTER cassandra_to_dynamic;
DYN2CAS_CONVERTER dynamic_to_cassandra;
};
typedef struct cassandra_type_def CASSANDRA_TYPE_DEF;
enum cassandtra_type_enum {CT_BIGINT, CT_INT, CT_COUNTER, CT_FLOAT, CT_DOUBLE,
CT_BLOB, CT_ASCII, CT_TEXT, CT_TIMESTAMP, CT_UUID, CT_BOOLEAN, CT_VARINT,
CT_DECIMAL};
typedef enum cassandtra_type_enum CASSANDRA_TYPE;
/** @brief
Class definition for the storage engine
*/
@ -48,23 +75,35 @@ class ha_cassandra: public handler
friend class Column_name_enumerator_impl;
THR_LOCK_DATA lock; ///< MySQL lock
CASSANDRA_SHARE *share; ///< Shared lock info
Cassandra_se_interface *se;
/* description of static part of the table definition */
ColumnDataConverter **field_converters;
uint n_field_converters;
CASSANDRA_TYPE_DEF *default_type_def;
/* description of dynamic columns part */
CASSANDRA_TYPE_DEF *special_type_field_converters;
LEX_STRING *special_type_field_names;
uint n_special_type_fields;
DYNAMIC_ARRAY dynamic_values, dynamic_names;
DYNAMIC_STRING dynamic_rec;
ColumnDataConverter *rowkey_converter;
bool setup_field_converters(Field **field, uint n_fields);
void free_field_converters();
int read_cassandra_columns(bool unpack_pk);
int check_table_options(struct ha_table_option_struct* options);
bool doing_insert_batch;
ha_rows insert_rows_batched;
uint dyncol_field;
bool dyncol_set;
/* Used to produce 'wrong column %s at row %lu' warnings */
ha_rows insert_lineno;
void print_conversion_error(const char *field_name,
@ -191,6 +230,14 @@ public:
private:
bool source_exhausted;
bool mrr_start_read();
int check_field_options(Field **fields);
int read_dyncol(DYNAMIC_ARRAY *vals, DYNAMIC_ARRAY *names,
String *valcol, char **freenames);
int write_dynamic_row(DYNAMIC_ARRAY *names, DYNAMIC_ARRAY *vals);
void static free_dynamic_row(DYNAMIC_ARRAY *vals, DYNAMIC_ARRAY *names,
char *free_names);
CASSANDRA_TYPE_DEF * get_cassandra_field_def(char *cass_name,
int cass_name_length);
public:
/*