Commit 245298f2 authored by unknown's avatar unknown

MDEV-506 Cassandra dynamic columns access

parent 7327cd97
...@@ -39,6 +39,12 @@ ...@@ -39,6 +39,12 @@
*/ */
#define MAX_DYNAMIC_COLUMN_LENGTH 0X1FFFFFFFL #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 */ /* NO and OK is the same used just to show semantics */
#define ER_DYNCOL_NO ER_DYNCOL_OK #define ER_DYNCOL_NO ER_DYNCOL_OK
...@@ -50,7 +56,8 @@ enum enum_dyncol_func_result ...@@ -50,7 +56,8 @@ enum enum_dyncol_func_result
ER_DYNCOL_LIMIT= -2, /* Some limit reached */ ER_DYNCOL_LIMIT= -2, /* Some limit reached */
ER_DYNCOL_RESOURCE= -3, /* Out of resourses */ ER_DYNCOL_RESOURCE= -3, /* Out of resourses */
ER_DYNCOL_DATA= -4, /* Incorrect input data */ 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; typedef DYNAMIC_STRING DYNAMIC_COLUMN;
...@@ -81,6 +88,7 @@ struct st_dynamic_column_value ...@@ -81,6 +88,7 @@ struct st_dynamic_column_value
struct { struct {
LEX_STRING value; LEX_STRING value;
CHARSET_INFO *charset; CHARSET_INFO *charset;
my_bool nonfreeable;
} string; } string;
struct { struct {
decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; decimal_digit_t buffer[DECIMAL_BUFF_LENGTH];
...@@ -108,6 +116,13 @@ dynamic_column_create_many_fmt(DYNAMIC_COLUMN *str, ...@@ -108,6 +116,13 @@ dynamic_column_create_many_fmt(DYNAMIC_COLUMN *str,
uchar *column_keys, uchar *column_keys,
DYNAMIC_COLUMN_VALUE *values, DYNAMIC_COLUMN_VALUE *values,
my_bool names); 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 enum enum_dyncol_func_result
dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr, dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
...@@ -163,6 +178,21 @@ dynamic_column_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json); ...@@ -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_initialize(A) memset((A), 0, sizeof(*(A)))
#define dynamic_column_column_free(V) dynstr_free(V) #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... Internal functions, don't use if you don't know what you are doing...
***************************************************************************/ ***************************************************************************/
......
...@@ -365,8 +365,9 @@ CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA ...@@ -365,8 +365,9 @@ CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4'; thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
select * from t2; select * from t2;
rowkey datecol rowkey datecol
1 1346189025000 1 1346192625000
10 1346189026000 10 1346192626000
delete from t2;
drop table t2; drop table t2;
# #
# Check whether changing parameters with ALTER TABLE works. # Check whether changing parameters with ALTER TABLE works.
...@@ -407,3 +408,141 @@ new-rowkey12 data1-value3 454 ...@@ -407,3 +408,141 @@ new-rowkey12 data1-value3 454
rowkey11 updated-1 34543 rowkey11 updated-1 34543
delete from t1; delete from t1;
drop table 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;
...@@ -89,6 +89,24 @@ The following options may be given as the first argument: ...@@ -89,6 +89,24 @@ The following options may be given as the first argument:
--bulk-insert-buffer-size=# --bulk-insert-buffer-size=#
Size of tree cache used in bulk insert optimisation. Note Size of tree cache used in bulk insert optimisation. Note
that this is a limit per thread! 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 --character-set-client-handshake
Don't ignore client side character set value sent during Don't ignore client side character set value sent during
handshake. handshake.
...@@ -863,6 +881,14 @@ binlog-optimize-thread-scheduling TRUE ...@@ -863,6 +881,14 @@ binlog-optimize-thread-scheduling TRUE
binlog-row-event-max-size 1024 binlog-row-event-max-size 1024
binlog-stmt-cache-size 32768 binlog-stmt-cache-size 32768
bulk-insert-buffer-size 8388608 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-client-handshake TRUE
character-set-filesystem binary character-set-filesystem binary
character-set-server latin1 character-set-server latin1
......
...@@ -94,6 +94,18 @@ CREATE COLUMN FAMILY cf10 ...@@ -94,6 +94,18 @@ CREATE COLUMN FAMILY cf10
WITH comparator = UTF8Type WITH comparator = UTF8Type
AND key_validation_class=UTF8Type AND key_validation_class=UTF8Type
AND default_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 EOF
--error 0,1,2 --error 0,1,2
...@@ -463,7 +475,7 @@ drop table t2; ...@@ -463,7 +475,7 @@ drop table t2;
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol bigint) ENGINE=CASSANDRA
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4'; thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
select * from t2; select * from t2;
delete from t2;
drop table t2; drop table t2;
--echo # --echo #
...@@ -511,6 +523,118 @@ select * from t1; ...@@ -511,6 +523,118 @@ select * from t1;
delete from t1; delete from t1;
drop table 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 ## Cassandra cleanup
############################################################################ ############################################################################
......
This diff is collapsed.
...@@ -9773,6 +9773,7 @@ int dynamic_column_error_message(enum_dyncol_func_result rc) ...@@ -9773,6 +9773,7 @@ int dynamic_column_error_message(enum_dyncol_func_result rc)
switch (rc) { switch (rc) {
case ER_DYNCOL_YES: case ER_DYNCOL_YES:
case ER_DYNCOL_OK: case ER_DYNCOL_OK:
case ER_DYNCOL_TRUNCATED:
break; // it is not an error break; // it is not an error
case ER_DYNCOL_FORMAT: case ER_DYNCOL_FORMAT:
my_error(ER_DYN_COL_WRONG_FORMAT, MYF(0)); my_error(ER_DYN_COL_WRONG_FORMAT, MYF(0));
......
...@@ -272,6 +272,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db, ...@@ -272,6 +272,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
const char *table_name); const char *table_name);
bool is_equal(const LEX_STRING *a, const LEX_STRING *b); bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
class Open_tables_backup;
/* Functions to work with system tables. */ /* Functions to work with system tables. */
bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
Open_tables_backup *backup); Open_tables_backup *backup);
......
...@@ -12,7 +12,7 @@ SET(cassandra_sources ...@@ -12,7 +12,7 @@ SET(cassandra_sources
gen-cpp/Cassandra.h) gen-cpp/Cassandra.h)
#INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS}) #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-exceptions" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
......
...@@ -17,6 +17,12 @@ ...@@ -17,6 +17,12 @@
#include "cassandra_se.h" #include "cassandra_se.h"
struct st_mysql_lex_string
{
char *str;
size_t length;
};
using namespace std; using namespace std;
using namespace apache::thrift; using namespace apache::thrift;
using namespace apache::thrift::transport; using namespace apache::thrift::transport;
...@@ -74,6 +80,7 @@ class Cassandra_se_impl: public Cassandra_se_interface ...@@ -74,6 +80,7 @@ class Cassandra_se_impl: public Cassandra_se_interface
std::string rowkey; /* key of the record we're returning now */ std::string rowkey; /* key of the record we're returning now */
SlicePredicate slice_pred; SlicePredicate slice_pred;
SliceRange slice_pred_sr;
bool get_slices_returned_less; bool get_slices_returned_less;
bool get_slice_found_rows; bool get_slice_found_rows;
public: public:
...@@ -91,6 +98,8 @@ class Cassandra_se_impl: public Cassandra_se_interface ...@@ -91,6 +98,8 @@ class Cassandra_se_impl: public Cassandra_se_interface
void first_ddl_column(); void first_ddl_column();
bool next_ddl_column(char **name, int *name_len, char **value, int *value_len); bool next_ddl_column(char **name, int *name_len, char **value, int *value_len);
void get_rowkey_type(char **name, char **type); void get_rowkey_type(char **name, char **type);
size_t get_ddl_size();
const char* get_default_validator();
/* Settings */ /* Settings */
void set_consistency_levels(ulong read_cons_level, ulong write_cons_level); void set_consistency_levels(ulong read_cons_level, ulong write_cons_level);
...@@ -98,15 +107,19 @@ class Cassandra_se_impl: public Cassandra_se_interface ...@@ -98,15 +107,19 @@ class Cassandra_se_impl: public Cassandra_se_interface
/* Writes */ /* Writes */
void clear_insert_buffer(); void clear_insert_buffer();
void start_row_insert(const char *key, int key_len); 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, 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(); bool do_insert();
/* Reads, point lookups */ /* Reads, point lookups */
bool get_slice(char *key, size_t key_len, bool *found); 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); void get_read_rowkey(char **value, int *value_len);
/* Reads, multi-row scans */ /* Reads, multi-row scans */
...@@ -122,6 +135,7 @@ class Cassandra_se_impl: public Cassandra_se_interface ...@@ -122,6 +135,7 @@ class Cassandra_se_impl: public Cassandra_se_interface
/* Setup that's necessary before a multi-row read. (todo: use it before point lookups, too) */ /* Setup that's necessary before a multi-row read. (todo: use it before point lookups, too) */
void clear_read_columns(); void clear_read_columns();
void clear_read_all_columns();
void add_read_column(const char *name); void add_read_column(const char *name);
/* Reads, MRR scans */ /* Reads, MRR scans */
...@@ -277,6 +291,16 @@ void Cassandra_se_impl::get_rowkey_type(char **name, char **type) ...@@ -277,6 +291,16 @@ void Cassandra_se_impl::get_rowkey_type(char **name, char **type)
*name= NULL; *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 // Data writes
...@@ -315,8 +339,9 @@ void Cassandra_se_impl::start_row_insert(const char *key, int key_len) ...@@ -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, void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
Column_name_enumerator *col_names) Column_name_enumerator *col_names,
LEX_STRING *names, uint nnames)
{ {
std::string key_to_delete; std::string key_to_delete;
key_to_delete.assign(key, key_len); key_to_delete.assign(key, key_len);
...@@ -344,6 +369,9 @@ void Cassandra_se_impl::add_row_deletion(const char *key, int key_len, ...@@ -344,6 +369,9 @@ void Cassandra_se_impl::add_row_deletion(const char *key, int key_len,
const char *col_name; const char *col_name;
while ((col_name= col_names->get_next_name())) while ((col_name= col_names->get_next_name()))
slice_pred.column_names.push_back(std::string(col_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; mut.deletion.predicate= slice_pred;
...@@ -351,7 +379,9 @@ void Cassandra_se_impl::add_row_deletion(const char *key, int key_len, ...@@ -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) int value_len)
{ {
Mutation mut; Mutation mut;
...@@ -359,7 +389,10 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value, ...@@ -359,7 +389,10 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value,
mut.column_or_supercolumn.__isset.column= true; mut.column_or_supercolumn.__isset.column= true;
Column& col=mut.column_or_supercolumn.column; 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.value.assign(value, value_len);
col.timestamp= insert_timestamp; col.timestamp= insert_timestamp;
col.__isset.value= true; col.__isset.value= true;
...@@ -367,6 +400,23 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value, ...@@ -367,6 +400,23 @@ void Cassandra_se_impl::add_insert_column(const char *name, const char *value,
insert_list->push_back(mut); 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() bool Cassandra_se_impl::retryable_do_insert()
{ {
...@@ -444,8 +494,8 @@ bool Cassandra_se_impl::retryable_get_slice() ...@@ -444,8 +494,8 @@ bool Cassandra_se_impl::retryable_get_slice()
} }
bool Cassandra_se_impl::get_next_read_column(char **name, char **value, bool Cassandra_se_impl::get_next_read_column(char **name, int *name_len,
int *value_len) char **value, int *value_len)
{ {
bool use_counter=false; bool use_counter=false;
while (1) while (1)
...@@ -468,12 +518,14 @@ bool Cassandra_se_impl::get_next_read_column(char **name, char **value, ...@@ -468,12 +518,14 @@ bool Cassandra_se_impl::get_next_read_column(char **name, char **value,
ColumnOrSuperColumn& cs= *column_data_it; ColumnOrSuperColumn& cs= *column_data_it;
if (use_counter) if (use_counter)
{ {
*name_len= cs.counter_column.name.size();
*name= (char*)cs.counter_column.name.c_str(); *name= (char*)cs.counter_column.name.c_str();
*value= (char*)&cs.counter_column.value; *value= (char*)&cs.counter_column.value;
*value_len= sizeof(cs.counter_column.value); *value_len= sizeof(cs.counter_column.value);
} }
else else
{ {
*name_len= cs.column.name.size();
*name= (char*)cs.column.name.c_str(); *name= (char*)cs.column.name.c_str();
*value= (char*)cs.column.value.c_str(); *value= (char*)cs.column.value.c_str();
*value_len= cs.column.value.length(); *value_len= cs.column.value.length();
...@@ -601,6 +653,13 @@ void Cassandra_se_impl::clear_read_columns() ...@@ -601,6 +653,13 @@ void Cassandra_se_impl::clear_read_columns()
slice_pred.column_names.clear(); 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) void Cassandra_se_impl::add_read_column(const char *name_arg)
{ {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
both together causes compile errors due to conflicts). 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 */ /* We need to define this here so that ha_cassandra.cc also has access to it */
typedef enum typedef enum
...@@ -50,19 +52,25 @@ class Cassandra_se_interface ...@@ -50,19 +52,25 @@ class Cassandra_se_interface
virtual bool next_ddl_column(char **name, int *name_len, char **value, virtual bool next_ddl_column(char **name, int *name_len, char **value,
int *value_len)=0; int *value_len)=0;
virtual void get_rowkey_type(char **name, char **type)=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 */ /* Writes */
virtual void clear_insert_buffer()=0; virtual void clear_insert_buffer()=0;
virtual void add_row_deletion(const char *key, int key_len, 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 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; int value_len)=0;
virtual bool do_insert()=0; virtual bool do_insert()=0;
/* Reads */ /* Reads */
virtual bool get_slice(char *key, size_t key_len, bool *found)=0 ; 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; virtual void get_read_rowkey(char **value, int *value_len)=0;
/* Reads, multi-row scans */ /* Reads, multi-row scans */
...@@ -70,7 +78,7 @@ class Cassandra_se_interface ...@@ -70,7 +78,7 @@ class Cassandra_se_interface
virtual bool get_range_slices(bool last_key_as_start_key)=0; virtual bool get_range_slices(bool last_key_as_start_key)=0;
virtual void finish_reading_range_slices()=0; virtual void finish_reading_range_slices()=0;
virtual bool get_next_range_slice_row(bool *eof)=0; virtual bool get_next_range_slice_row(bool *eof)=0;
/* Reads, MRR scans */ /* Reads, MRR scans */
virtual void new_lookup_keys()=0; virtual void new_lookup_keys()=0;
virtual int add_lookup_key(const char *key, size_t key_len)=0; virtual int add_lookup_key(const char *key, size_t key_len)=0;
...@@ -79,8 +87,9 @@ class Cassandra_se_interface ...@@ -79,8 +87,9 @@ class Cassandra_se_interface
/* read_set setup */ /* read_set setup */
virtual void clear_read_columns()=0; virtual void clear_read_columns()=0;
virtual void clear_read_all_columns()=0;
virtual void add_read_column(const char *name)=0; virtual void add_read_column(const char *name)=0;
virtual bool truncate()=0; virtual bool truncate()=0;
virtual bool remove_row()=0; virtual bool remove_row()=0;
......
...@@ -11,7 +11,7 @@ namespace org { namespace apache { namespace cassandra { ...@@ -11,7 +11,7 @@ namespace org { namespace apache { namespace cassandra {
const cassandraConstants g_cassandra_constants; const cassandraConstants g_cassandra_constants;
cassandraConstants::cassandraConstants() { cassandraConstants::cassandraConstants() {
cassandra_const_VERSION = "19.32.0"; cassandra_const_VERSION = (char *)"19.32.0";
} }
}}} // namespace }}} // namespace
......
This diff is collapsed.
...@@ -40,6 +40,33 @@ class ColumnDataConverter; ...@@ -40,6 +40,33 @@ class ColumnDataConverter;
struct ha_table_option_struct; 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 /** @brief
Class definition for the storage engine Class definition for the storage engine
*/ */
...@@ -48,23 +75,35 @@ class ha_cassandra: public handler ...@@ -48,23 +75,35 @@ class ha_cassandra: public handler
friend class Column_name_enumerator_impl; friend class Column_name_enumerator_impl;
THR_LOCK_DATA lock; ///< MySQL lock THR_LOCK_DATA lock; ///< MySQL lock
CASSANDRA_SHARE *share; ///< Shared lock info CASSANDRA_SHARE *share; ///< Shared lock info
Cassandra_se_interface *se; Cassandra_se_interface *se;
/* description of static part of the table definition */
ColumnDataConverter **field_converters; ColumnDataConverter **field_converters;
uint n_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; ColumnDataConverter *rowkey_converter;
bool setup_field_converters(Field **field, uint n_fields); bool setup_field_converters(Field **field, uint n_fields);
void free_field_converters(); void free_field_converters();
int read_cassandra_columns(bool unpack_pk); int read_cassandra_columns(bool unpack_pk);
int check_table_options(struct ha_table_option_struct* options); int check_table_options(struct ha_table_option_struct* options);
bool doing_insert_batch; bool doing_insert_batch;
ha_rows insert_rows_batched; ha_rows insert_rows_batched;
uint dyncol_field;
bool dyncol_set;
/* Used to produce 'wrong column %s at row %lu' warnings */ /* Used to produce 'wrong column %s at row %lu' warnings */
ha_rows insert_lineno; ha_rows insert_lineno;
void print_conversion_error(const char *field_name, void print_conversion_error(const char *field_name,
...@@ -191,6 +230,14 @@ class ha_cassandra: public handler ...@@ -191,6 +230,14 @@ class ha_cassandra: public handler
private: private:
bool source_exhausted; bool source_exhausted;
bool mrr_start_read(); 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: public:
/* /*
......
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