Cassandra SE merge
This commit is contained in:
commit
f54a4819b6
@ -46,6 +46,8 @@ SET(FEATURE_SET_large 5)
|
||||
SET(FEATURE_SET_xlarge 6)
|
||||
SET(FEATURE_SET_community 7)
|
||||
|
||||
SET(WITH_CASSANDRA_STORAGE_ENGINE ON)
|
||||
|
||||
IF(FEATURE_SET)
|
||||
STRING(TOLOWER ${FEATURE_SET} feature_set)
|
||||
SET(num ${FEATURE_SET_${feature_set}})
|
||||
|
@ -34,10 +34,10 @@
|
||||
#include <mysql_time.h>
|
||||
|
||||
/*
|
||||
Max length for data in a dynamic colums. This comes from how the
|
||||
how the offset are stored.
|
||||
Limits of implementation
|
||||
*/
|
||||
#define MAX_DYNAMIC_COLUMN_LENGTH 0X1FFFFFFFL
|
||||
#define MAX_TOTAL_NAME_LENGTH 65535
|
||||
#define MAX_NAME_LENGTH (MAX_TOTAL_NAME_LENGTH/4)
|
||||
|
||||
/* NO and OK is the same used just to show semantics */
|
||||
#define ER_DYNCOL_NO ER_DYNCOL_OK
|
||||
@ -50,7 +50,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;
|
||||
@ -65,7 +66,8 @@ enum enum_dynamic_column_type
|
||||
DYN_COL_DECIMAL,
|
||||
DYN_COL_DATETIME,
|
||||
DYN_COL_DATE,
|
||||
DYN_COL_TIME
|
||||
DYN_COL_TIME,
|
||||
DYN_COL_DYNCOL
|
||||
};
|
||||
|
||||
typedef enum enum_dynamic_column_type DYNAMIC_COLUMN_TYPE;
|
||||
@ -79,7 +81,7 @@ struct st_dynamic_column_value
|
||||
unsigned long long ulong_value;
|
||||
double double_value;
|
||||
struct {
|
||||
LEX_STRING value;
|
||||
MYSQL_LEX_STRING value;
|
||||
CHARSET_INFO *charset;
|
||||
} string;
|
||||
struct {
|
||||
@ -92,6 +94,7 @@ struct st_dynamic_column_value
|
||||
|
||||
typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
|
||||
|
||||
#ifdef MADYNCOL_DEPRECATED
|
||||
enum enum_dyncol_func_result
|
||||
dynamic_column_create(DYNAMIC_COLUMN *str,
|
||||
uint column_nr, DYNAMIC_COLUMN_VALUE *value);
|
||||
@ -101,7 +104,6 @@ dynamic_column_create_many(DYNAMIC_COLUMN *str,
|
||||
uint column_count,
|
||||
uint *column_numbers,
|
||||
DYNAMIC_COLUMN_VALUE *values);
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
dynamic_column_update(DYNAMIC_COLUMN *org, uint column_nr,
|
||||
DYNAMIC_COLUMN_VALUE *value);
|
||||
@ -110,38 +112,106 @@ 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_delete(DYNAMIC_COLUMN *org, uint column_nr);
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
dynamic_column_exists(DYNAMIC_COLUMN *org, uint column_nr);
|
||||
|
||||
/* 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_get(DYNAMIC_COLUMN *org, uint column_nr,
|
||||
DYNAMIC_COLUMN_VALUE *store_it_here);
|
||||
#endif
|
||||
|
||||
/* new functions */
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_create_many(DYNAMIC_COLUMN *str,
|
||||
uint column_count,
|
||||
uint *column_numbers,
|
||||
DYNAMIC_COLUMN_VALUE *values,
|
||||
my_bool new_string);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
|
||||
uint column_count,
|
||||
MYSQL_LEX_STRING *column_keys,
|
||||
DYNAMIC_COLUMN_VALUE *values,
|
||||
my_bool new_string);
|
||||
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_update_many(DYNAMIC_COLUMN *str,
|
||||
uint add_column_count,
|
||||
uint *column_keys,
|
||||
DYNAMIC_COLUMN_VALUE *values);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
|
||||
uint add_column_count,
|
||||
MYSQL_LEX_STRING *column_keys,
|
||||
DYNAMIC_COLUMN_VALUE *values);
|
||||
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_exists(DYNAMIC_COLUMN *org, uint column_nr);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name);
|
||||
|
||||
/* List of not NULL columns */
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_list(DYNAMIC_COLUMN *str, uint *count, uint **nums);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count,
|
||||
MYSQL_LEX_STRING **names);
|
||||
|
||||
/*
|
||||
if the column do not exists it is NULL
|
||||
*/
|
||||
enum enum_dyncol_func_result
|
||||
dynamic_column_get(DYNAMIC_COLUMN *org, uint column_nr,
|
||||
mariadb_dyncol_get(DYNAMIC_COLUMN *org, uint column_nr,
|
||||
DYNAMIC_COLUMN_VALUE *store_it_here);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, MYSQL_LEX_STRING *name,
|
||||
DYNAMIC_COLUMN_VALUE *store_it_here);
|
||||
|
||||
my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str);
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_check(DYNAMIC_COLUMN *str);
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_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)
|
||||
|
||||
/***************************************************************************
|
||||
Internal functions, don't use if you don't know what you are doing...
|
||||
***************************************************************************/
|
||||
/* conversion of values to 3 base types */
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
|
||||
CHARSET_INFO *cs, my_bool quote);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val);
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val);
|
||||
|
||||
#define dynamic_column_reassociate(V,P,L, A) dynstr_reassociate((V),(P),(L),(A))
|
||||
|
||||
#define dynamic_column_value_init(V) (V)->type= DYN_COL_NULL
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
|
||||
uint *count,
|
||||
MYSQL_LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals);
|
||||
|
||||
int mariadb_dyncol_column_cmp_named(const MYSQL_LEX_STRING *s1,
|
||||
const MYSQL_LEX_STRING *s2);
|
||||
|
||||
enum enum_dyncol_func_result
|
||||
mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count);
|
||||
|
||||
#define mariadb_dyncol_value_init(V) (V)->type= DYN_COL_NULL
|
||||
|
||||
/*
|
||||
Prepare value for using as decimal
|
||||
*/
|
||||
void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);
|
||||
void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value);
|
||||
|
||||
#endif
|
||||
|
@ -801,12 +801,23 @@ 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,
|
||||
char quote);
|
||||
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 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);
|
||||
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);
|
||||
|
10
mysql-test/include/have_cassandra.inc
Normal file
10
mysql-test/include/have_cassandra.inc
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# suite.pm will make sure that all tests including this file
|
||||
# will be skipped unless innodb or xtradb is enabled
|
||||
#
|
||||
# The test below is redundant
|
||||
|
||||
if (`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'cassandra' AND support IN ('YES', 'DEFAULT', 'ENABLED')`)
|
||||
{
|
||||
--skip Test requires Cassandra.
|
||||
}
|
1
mysql-test/include/have_cassandra.opt
Normal file
1
mysql-test/include/have_cassandra.opt
Normal file
@ -0,0 +1 @@
|
||||
--plugin-load=$HA_CASSANDRA_SO --cassandra=on
|
593
mysql-test/r/cassandra.result
Normal file
593
mysql-test/r/cassandra.result
Normal file
@ -0,0 +1,593 @@
|
||||
drop table if exists t0, t1;
|
||||
create table t1 (a int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='foo' column_family='colfam';
|
||||
ERROR 42000: This table type requires a primary key
|
||||
create table t1 (a int primary key, b int) engine=cassandra
|
||||
thrift_host='localhost' keyspace='foo' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: Default TException. [Keyspace foo does not exist]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='127.0.0.2' keyspace='foo' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: connect() failed: Connection refused [1]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='localhost' keyspace='no_such_keyspace' column_family='colfam';
|
||||
ERROR HY000: Unable to connect to foreign data source: Default TException. [Keyspace no_such_keyspace does not exist]
|
||||
create table t1 (rowkey char(10) primary key, column1 char(10)) engine=cassandra
|
||||
thrift_host='localhost' keyspace='no_such_keyspace';
|
||||
ERROR HY000: Unable to connect to foreign data source: keyspace and column_family table options must be specified
|
||||
# Now, create a table for real and insert data
|
||||
create table t1 (pk varchar(36) primary key, data1 varchar(60), data2 bigint) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
# Just in case there were left-overs from previous:
|
||||
delete from t1;
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 data1-value2 34543
|
||||
explain
|
||||
select * from t1 where pk='rowkey11';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 const PRIMARY PRIMARY 38 const 1
|
||||
select * from t1 where pk='rowkey11';
|
||||
pk data1 data2
|
||||
rowkey11 data1-value2 34543
|
||||
delete from t1 where pk='rowkey11';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
delete from t1;
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
#
|
||||
# A query with filesort (check that table_flags() & HA_REC_NOT_IN_SEQ,
|
||||
# also check ::rnd_pos()
|
||||
#
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1 order by data2;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey11 data1-value2 34543
|
||||
rowkey10 data1-value 123456
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-476: Cassandra: Server crashes in calculate_key_len on DELETE with ORDER BY
|
||||
#
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||
DELETE FROM t1 ORDER BY a LIMIT 1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Batched INSERT
|
||||
#
|
||||
show variables like 'cassandra_insert_batch_size';
|
||||
Variable_name Value
|
||||
cassandra_insert_batch_size 100
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_insert_batches 7
|
||||
Cassandra_row_inserts 8
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
delete from t1;
|
||||
INSERT INTO t1 VALUES (1,1),(2,2);
|
||||
DELETE FROM t1 ORDER BY a LIMIT 1;
|
||||
DROP TABLE t1;
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_insert_batches 8
|
||||
Cassandra_row_inserts 10
|
||||
# FLUSH STATUS doesn't work for our variables, just like with InnoDB.
|
||||
flush status;
|
||||
show status like 'cassandra_row_insert%';
|
||||
Variable_name Value
|
||||
Cassandra_row_insert_batches 0
|
||||
Cassandra_row_inserts 0
|
||||
#
|
||||
# Batched Key Access
|
||||
#
|
||||
# Control variable (we are not yet able to make use of MRR's buffer)
|
||||
show variables like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
cassandra_multiget_batch_size 100
|
||||
# MRR-related status variables:
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 0
|
||||
Cassandra_multiget_reads 0
|
||||
Cassandra_multiget_rows_read 0
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
delete from t1;
|
||||
INSERT INTO t1 VALUES (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
|
||||
set @tmp_jcl=@@join_cache_level;
|
||||
set join_cache_level=8;
|
||||
explain select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE A ALL NULL NULL NULL NULL 1000 Using where
|
||||
1 SIMPLE B eq_ref PRIMARY PRIMARY 8 test.A.a 1 Using join buffer (flat, BKAH join); multiget_slice
|
||||
select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
rowkey a rowkey a
|
||||
0 0 0 0
|
||||
1 1 1 1
|
||||
2 2 2 2
|
||||
3 3 3 3
|
||||
4 4 4 4
|
||||
5 5 5 5
|
||||
6 6 6 6
|
||||
7 7 7 7
|
||||
8 8 8 8
|
||||
9 9 9 9
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 10
|
||||
Cassandra_multiget_reads 1
|
||||
Cassandra_multiget_rows_read 10
|
||||
insert into t1 values(1, 8);
|
||||
insert into t1 values(3, 8);
|
||||
insert into t1 values(5, 8);
|
||||
insert into t1 values(7, 8);
|
||||
select * from t1 A, t1 B where B.rowkey=A.a;
|
||||
rowkey a rowkey a
|
||||
0 0 0 0
|
||||
2 2 2 2
|
||||
4 4 4 4
|
||||
6 6 6 6
|
||||
1 8 8 8
|
||||
7 8 8 8
|
||||
8 8 8 8
|
||||
5 8 8 8
|
||||
3 8 8 8
|
||||
9 9 9 9
|
||||
show status like 'cassandra_multi%';
|
||||
Variable_name Value
|
||||
Cassandra_multiget_keys_scanned 16
|
||||
Cassandra_multiget_reads 2
|
||||
Cassandra_multiget_rows_read 16
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-480: TRUNCATE TABLE on a Cassandra table does not remove rows
|
||||
#
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
INSERT INTO t1 VALUES (0,0),(1,1),(2,2);
|
||||
truncate table t1;
|
||||
select * from t1;
|
||||
rowkey a
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-494, part #1: phantom row for big full-scan selects
|
||||
#
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, a BIGINT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf2';
|
||||
insert into t1 select A.a + 10 * B.a + 100*C.a, 12345 from t0 A, t0 B, t0 C;
|
||||
select count(*) from t1;
|
||||
count(*)
|
||||
1000
|
||||
select count(*) from t1 where a=12345;
|
||||
count(*)
|
||||
1000
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
drop table t0;
|
||||
# 32-bit INT type support
|
||||
CREATE TABLE t1 (rowkey BIGINT PRIMARY KEY, intcol INT) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf3';
|
||||
insert into t1 values (10,10);
|
||||
insert into t1 values (12,12);
|
||||
delete from t1;
|
||||
drop table t1;
|
||||
#
|
||||
# Try accessing column family w/o explicitly defined columns
|
||||
#
|
||||
CREATE TABLE t1 (my_primary_key varchar(10) PRIMARY KEY) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf10';
|
||||
ERROR HY000: Internal error: 'target column family has no key_alias defined, PRIMARY KEY column must be named 'rowkey''
|
||||
CREATE TABLE t1 (rowkey varchar(10) PRIMARY KEY) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf10';
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Timestamp datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol timestamp) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
delete from t2;
|
||||
insert into t2 values (1, '2012-08-29 01:23:45');
|
||||
select * from t2;
|
||||
rowkey datecol
|
||||
1 2012-08-29 01:23:45
|
||||
delete from t2;
|
||||
# MDEV-498: Cassandra: Inserting a timestamp does not work on a 32-bit system
|
||||
INSERT INTO t2 VALUES (10,'2012-12-12 12:12:12');
|
||||
SELECT * FROM t2;
|
||||
rowkey datecol
|
||||
10 2012-12-12 12:12:12
|
||||
delete from t2;
|
||||
#
|
||||
# (no MDEV#) Check that insert counters work correctly
|
||||
#
|
||||
create table t0 (a int);
|
||||
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
set cassandra_insert_batch_size=10;
|
||||
insert into t2 select A.a+10*B.a, now() from t0 A, t0 B;
|
||||
inserts insert_batches
|
||||
100 10
|
||||
set cassandra_insert_batch_size=1;
|
||||
insert into t2 select A.a+10*B.a+100, now() from t0 A, t0 B;
|
||||
inserts insert_batches
|
||||
100 100
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
drop table t0;
|
||||
#
|
||||
# UUID datatype support
|
||||
#
|
||||
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,'not-an-uuid');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values(3,'9b5658dc-f32f-11e1=94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values(4,'9b5658dc-fzzf-11e1-94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 1
|
||||
insert into t2 values
|
||||
(5,'9b5658dc-f11f-11e1-94cd-f46d046e9f09'),
|
||||
(6,'9b5658dc-f11f011e1-94cd-f46d046e9f09');
|
||||
ERROR 22003: Out of range value for column 'uuidcol' at row 2
|
||||
select * from t2;
|
||||
rowkey uuidcol
|
||||
1 9b5658dc-f32f-11e1-94cd-f46d046e9f09
|
||||
5 9b5658dc-f11f-11e1-94cd-f46d046e9f09
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey char(36) PRIMARY KEY, col1 int) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf6';
|
||||
delete from t2;
|
||||
insert into t2 values('9b5658dc-f32f-11e1-94cd-f46d046e9f09', 1234);
|
||||
insert into t2 values('not-an-uuid', 563);
|
||||
ERROR 22003: Out of range value for column 'rowkey' at row 1
|
||||
select * from t2;
|
||||
rowkey col1
|
||||
9b5658dc-f32f-11e1-94cd-f46d046e9f09 1234
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
#
|
||||
# boolean datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey int PRIMARY KEY, boolcol bool) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf7';
|
||||
insert into t2 values (0, 0);
|
||||
insert into t2 values (1, 1);
|
||||
select * from t2;
|
||||
rowkey boolcol
|
||||
0 0
|
||||
1 1
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
#
|
||||
# Counter datatype support (read-only)
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, countercol bigint) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf8';
|
||||
select * from t2;
|
||||
rowkey countercol
|
||||
cnt1 1
|
||||
cnt2 100
|
||||
drop table t2;
|
||||
#
|
||||
# Check that @@cassandra_default_thrift_host works
|
||||
#
|
||||
show variables like 'cassandra_default_thrift_host';
|
||||
Variable_name Value
|
||||
cassandra_default_thrift_host
|
||||
set @tmp=@@cassandra_default_thrift_host;
|
||||
set cassandra_default_thrift_host='localhost';
|
||||
ERROR HY000: Variable 'cassandra_default_thrift_host' is a GLOBAL variable and should be set with SET GLOBAL
|
||||
set global cassandra_default_thrift_host='localhost';
|
||||
# Try creating a table without specifying thrift_host:
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, countercol bigint) ENGINE=CASSANDRA
|
||||
keyspace='mariadbtest2' column_family = 'cf8';
|
||||
select * from t2;
|
||||
rowkey countercol
|
||||
cnt1 1
|
||||
cnt2 100
|
||||
drop table t2;
|
||||
set global cassandra_default_thrift_host=@tmp;
|
||||
#
|
||||
# Consistency settings
|
||||
#
|
||||
show variables like 'cassandra_%consistency';
|
||||
Variable_name Value
|
||||
cassandra_read_consistency ONE
|
||||
cassandra_write_consistency ONE
|
||||
set @tmp=@@cassandra_write_consistency;
|
||||
# Unfortunately, there is no easy way to check if setting have the effect..
|
||||
set cassandra_write_consistency='ONE';
|
||||
set cassandra_write_consistency='QUORUM';
|
||||
set cassandra_write_consistency='LOCAL_QUORUM';
|
||||
set cassandra_write_consistency='EACH_QUORUM';
|
||||
set cassandra_write_consistency='ALL';
|
||||
set cassandra_write_consistency='ANY';
|
||||
set cassandra_write_consistency='TWO';
|
||||
set cassandra_write_consistency='THREE';
|
||||
set cassandra_write_consistency=@tmp;
|
||||
#
|
||||
# varint datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, varint_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf9';
|
||||
select rowkey, hex(varint_col) from t2;
|
||||
rowkey hex(varint_col)
|
||||
val-01 01
|
||||
val-0x123456 123456
|
||||
val-0x12345678 12345678
|
||||
drop table t2;
|
||||
# now, let's check what happens when MariaDB's column is not wide enough:
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, varint_col varbinary(2)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf9';
|
||||
select rowkey, hex(varint_col) from t2;
|
||||
ERROR HY000: Internal error: 'Unable to convert value for field `varint_col` from Cassandra's data format. Source data is 4 bytes, 0x12345678'
|
||||
drop table t2;
|
||||
#
|
||||
# Decimal datatype support
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
select rowkey, hex(decimal_col) from t2;
|
||||
rowkey hex(decimal_col)
|
||||
val_1.5 000000010F
|
||||
val_0.5 0000000105
|
||||
val_1234 0000000004D2
|
||||
drop table t2;
|
||||
#
|
||||
# Mapping TIMESTAMP -> int64
|
||||
#
|
||||
set @save_tz= @@time_zone;
|
||||
set time_zone='UTC';
|
||||
CREATE TABLE t2 (rowkey bigint PRIMARY KEY, datecol timestamp) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf4';
|
||||
insert into t2 values (1, '2012-08-29 01:23:45');
|
||||
INSERT INTO t2 VALUES (10,'2012-08-29 01:23:46');
|
||||
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;
|
||||
rowkey datecol
|
||||
1 1346203425000
|
||||
10 1346203426000
|
||||
delete from t2;
|
||||
drop table t2;
|
||||
set time_zone=@save_tz;
|
||||
#
|
||||
# Check whether changing parameters with ALTER TABLE works.
|
||||
#
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
drop table t2;
|
||||
CREATE TABLE t2 (rowkey varchar(32) PRIMARY KEY, decimal_col varbinary(32)) ENGINE=CASSANDRA
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family = 'cf11';
|
||||
alter table t2 column_family='cf12';
|
||||
Writes made during ALTER TABLE
|
||||
0
|
||||
drop table t2;
|
||||
#
|
||||
# UPDATE command support
|
||||
#
|
||||
create table t1 (pk varchar(36) primary key, data1 varchar(60), data2 bigint) engine=cassandra
|
||||
thrift_host='localhost' keyspace='mariadbtest2' column_family='cf1';
|
||||
insert into t1 values ('rowkey10', 'data1-value', 123456);
|
||||
insert into t1 values ('rowkey11', 'data1-value2', 34543);
|
||||
insert into t1 values ('rowkey12', 'data1-value3', 454);
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 data1-value2 34543
|
||||
update t1 set data1='updated-1' where pk='rowkey11';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey12 data1-value3 454
|
||||
rowkey10 data1-value 123456
|
||||
rowkey11 updated-1 34543
|
||||
update t1 set pk='new-rowkey12' where pk='rowkey12';
|
||||
select * from t1;
|
||||
pk data1 data2
|
||||
rowkey10 data1-value 123456
|
||||
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 16383: 'very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_v'
|
||||
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;
|
||||
#
|
||||
# MDEV-565: Server crashes in ha_cassandra::write_row on
|
||||
# inserting NULL into a 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';
|
||||
insert into t1 values (1, NULL);
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# strange side effect of Cassandra - remiving all columns of primary
|
||||
# key removes all row.
|
||||
#
|
||||
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(2,column_create("ab","ab"));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
2 {"ab":"ab"}
|
||||
UPDATE t1 set dyn=NULL;
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
INSERT INTO t1 VALUES(2,column_create("ab","ab"));
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
2 {"ab":"ab"}
|
||||
UPDATE t1 set dyn="";
|
||||
select rowkey, column_json(dyn) from t1;
|
||||
rowkey column_json(dyn)
|
||||
delete from t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-4005 #Server crashes on creating a Cassandra table
|
||||
# with a mix of static and dynamic columns
|
||||
#
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (
|
||||
pk int primary key,
|
||||
col_int int,
|
||||
dyncol blob DYNAMIC_COLUMN_STORAGE=yes
|
||||
) ENGINE=cassandra keyspace='bug' thrift_host = '127.0.0.1' column_family='cf1';
|
||||
drop table t1;
|
@ -1088,7 +1088,7 @@ column_list(column_add(column_create(1, 1), 1, null))
|
||||
|
||||
select column_list(column_add(column_create(1, 1), 1, ""));
|
||||
column_list(column_add(column_create(1, 1), 1, ""))
|
||||
1
|
||||
`1`
|
||||
select hex(column_add("", 1, 1));
|
||||
hex(column_add("", 1, 1))
|
||||
00010001000002
|
||||
@ -1133,10 +1133,10 @@ column_exists(column_create(1, 1212 as integer, 2, 1212 as integer), 4)
|
||||
# column list
|
||||
select column_list(column_create(1, 1212 as integer, 2, 1212 as integer));
|
||||
column_list(column_create(1, 1212 as integer, 2, 1212 as integer))
|
||||
1,2
|
||||
`1`,`2`
|
||||
select column_list(column_create(1, 1212 as integer));
|
||||
column_list(column_create(1, 1212 as integer))
|
||||
1
|
||||
`1`
|
||||
select column_list(column_create(1, NULL as integer));
|
||||
column_list(column_create(1, NULL as integer))
|
||||
|
||||
@ -1218,35 +1218,35 @@ sum(column_get(str, 1 as int))
|
||||
11
|
||||
select id, column_list(str) from t1 where id= 5;
|
||||
id column_list(str)
|
||||
5 1,2,3,10
|
||||
5 `1`,`2`,`3`,`10`
|
||||
update t1 set str=column_delete(str, 3, 4, 2) where id= 5;
|
||||
select id, length(str), column_list(str), column_get(str, 1 as int), column_get(str, 2 as char), column_get(str, 3 as int) from t1;
|
||||
id length(str) column_list(str) column_get(str, 1 as int) column_get(str, 2 as char) column_get(str, 3 as int)
|
||||
1 12 1,2 1 a NULL
|
||||
2 12 1,2 2 a NULL
|
||||
3 12 2,3 NULL c 100
|
||||
4 16 1,2,3 5 c 100
|
||||
5 15 1,10 6 NULL NULL
|
||||
6 21 2,3,10 NULL c 100
|
||||
1 12 `1`,`2` 1 a NULL
|
||||
2 12 `1`,`2` 2 a NULL
|
||||
3 12 `2`,`3` NULL c 100
|
||||
4 16 `1`,`2`,`3` 5 c 100
|
||||
5 15 `1`,`10` 6 NULL NULL
|
||||
6 21 `2`,`3`,`10` NULL c 100
|
||||
update t1 set str=column_add(str, 4, 45 as char, 2, 'c') where id= 5;
|
||||
select id, length(str), column_list(str), column_get(str, 1 as int), column_get(str, 2 as char), column_get(str, 3 as int) from t1 where id = 5;
|
||||
id length(str) column_list(str) column_get(str, 1 as int) column_get(str, 2 as char) column_get(str, 3 as int)
|
||||
5 26 1,2,4,10 6 c NULL
|
||||
5 26 `1`,`2`,`4`,`10` 6 c NULL
|
||||
select id, length(str), column_list(str), column_exists(str, 4) from t1;
|
||||
id length(str) column_list(str) column_exists(str, 4)
|
||||
1 12 1,2 0
|
||||
2 12 1,2 0
|
||||
3 12 2,3 0
|
||||
4 16 1,2,3 0
|
||||
5 26 1,2,4,10 1
|
||||
6 21 2,3,10 0
|
||||
1 12 `1`,`2` 0
|
||||
2 12 `1`,`2` 0
|
||||
3 12 `2`,`3` 0
|
||||
4 16 `1`,`2`,`3` 0
|
||||
5 26 `1`,`2`,`4`,`10` 1
|
||||
6 21 `2`,`3`,`10` 0
|
||||
select sum(column_get(str, 1 as int)), column_list(str) from t1 group by 2;
|
||||
sum(column_get(str, 1 as int)) column_list(str)
|
||||
3 1,2
|
||||
5 1,2,3
|
||||
6 1,2,4,10
|
||||
NULL 2,3
|
||||
NULL 2,3,10
|
||||
3 `1`,`2`
|
||||
5 `1`,`2`,`3`
|
||||
6 `1`,`2`,`4`,`10`
|
||||
NULL `2`,`3`
|
||||
NULL `2`,`3`,`10`
|
||||
select id, hex(str) from t1;
|
||||
id hex(str)
|
||||
1 00020001000002000B020861
|
||||
@ -1282,11 +1282,11 @@ id
|
||||
5
|
||||
select id, column_list(str), length(str) from t1 where id=5;
|
||||
id column_list(str) length(str)
|
||||
5 1,2,4,5,10 100048
|
||||
5 `1`,`2`,`4`,`5`,`10` 100048
|
||||
update t1 set str=column_delete(str, 5) where id=5;
|
||||
select id, column_list(str), length(str) from t1 where id=5;
|
||||
id column_list(str) length(str)
|
||||
5 1,2,4,10 34
|
||||
5 `1`,`2`,`4`,`10` 34
|
||||
drop table t1;
|
||||
#
|
||||
# LP#778905: Assertion `value->year <= 9999' failed in
|
||||
@ -1306,7 +1306,7 @@ INSERT INTO t1 SET f1 = COLUMN_CREATE( 2 , 'cde' );
|
||||
SELECT HEX(COLUMN_ADD(f1, 1, 'abc')), COLUMN_LIST(f1) FROM t1;
|
||||
HEX(COLUMN_ADD(f1, 1, 'abc')) COLUMN_LIST(f1)
|
||||
NULL NULL
|
||||
0002000100030200230861626308636465 2
|
||||
0002000100030200230861626308636465 `2`
|
||||
SELECT COLUMN_ADD(f1, 1, 'abc'), COLUMN_LIST(f1) FROM t1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
@ -1335,3 +1335,305 @@ 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));
|
||||
hex(COLUMN_CREATE(0, 0.0 as decimal))
|
||||
000100000004
|
||||
#
|
||||
# test of symbolic names
|
||||
#
|
||||
# creation test (names)
|
||||
set names utf8;
|
||||
select hex(column_create("адын", 1212));
|
||||
hex(column_create("адын", 1212))
|
||||
040100080000000000D0B0D0B4D18BD0BD7809
|
||||
select hex(column_create("1212", 1212));
|
||||
hex(column_create("1212", 1212))
|
||||
040100040000000000313231327809
|
||||
select hex(column_create(1212, 2, "www", 3));
|
||||
hex(column_create(1212, 2, "www", 3))
|
||||
04020007000000000003001000777777313231320604
|
||||
select hex(column_create("1212", 2, "www", 3));
|
||||
hex(column_create("1212", 2, "www", 3))
|
||||
04020007000000000003001000777777313231320604
|
||||
select hex(column_create("1212", 2, 3, 3));
|
||||
hex(column_create("1212", 2, 3, 3))
|
||||
0402000500000000000100100033313231320604
|
||||
select hex(column_create("1212", 2, "адын", 1, 3, 3));
|
||||
hex(column_create("1212", 2, "адын", 1, 3, 3))
|
||||
0403000D000000000001001000050020003331323132D0B0D0B4D18BD0BD060402
|
||||
set names default;
|
||||
# fetching column test (names)
|
||||
set names utf8;
|
||||
select column_get(column_create("адын", 1212), "адын" as int);
|
||||
column_get(column_create("адын", 1212), "адын" as int)
|
||||
1212
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "адын" as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), "адын" as int)
|
||||
1
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 1212 as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), 1212 as int)
|
||||
2
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "3" as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), "3" as int)
|
||||
3
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 3 as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), 3 as int)
|
||||
3
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), 4 as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), 4 as int)
|
||||
NULL
|
||||
select column_get(column_create("1212", 2, "адын", 1, 3, 3), "4" as int);
|
||||
column_get(column_create("1212", 2, "адын", 1, 3, 3), "4" as int)
|
||||
NULL
|
||||
set names default;
|
||||
# column existance test (names)
|
||||
set names utf8;
|
||||
select column_exists(column_create("адын", 1212), "адын");
|
||||
column_exists(column_create("адын", 1212), "адын")
|
||||
1
|
||||
select column_exists(column_create("адын", 1212), "aады");
|
||||
column_exists(column_create("адын", 1212), "aады")
|
||||
0
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "адын");
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), "адын")
|
||||
1
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 1212);
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), 1212)
|
||||
1
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "3");
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), "3")
|
||||
1
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 3);
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), 3)
|
||||
1
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), 4);
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), 4)
|
||||
0
|
||||
select column_exists(column_create("1212", 2, "адын", 1, 3, 3), "4");
|
||||
column_exists(column_create("1212", 2, "адын", 1, 3, 3), "4")
|
||||
0
|
||||
set names default;
|
||||
# column changing test (names)
|
||||
select hex(column_add(column_create(1, "AAA"), "b", "BBB"));
|
||||
hex(column_add(column_create(1, "AAA"), "b", "BBB"))
|
||||
0402000200000003000100430031620841414108424242
|
||||
select hex(column_add(column_create("1", "AAA"), "b", "BBB"));
|
||||
hex(column_add(column_create("1", "AAA"), "b", "BBB"))
|
||||
0402000200000003000100430031620841414108424242
|
||||
select column_get(column_add(column_create(1, "AAA"), "b", "BBB"), 1 as char);
|
||||
column_get(column_add(column_create(1, "AAA"), "b", "BBB"), 1 as char)
|
||||
AAA
|
||||
select column_get(column_add(column_create(1, "AAA"), "b", "BBB"), "b" as char);
|
||||
column_get(column_add(column_create(1, "AAA"), "b", "BBB"), "b" as char)
|
||||
BBB
|
||||
select hex(column_add(column_create("a", "AAA"), 1, "BBB"));
|
||||
hex(column_add(column_create("a", "AAA"), 1, "BBB"))
|
||||
0402000200000003000100430031610842424208414141
|
||||
select hex(column_add(column_create("a", "AAA"), "1", "BBB"));
|
||||
hex(column_add(column_create("a", "AAA"), "1", "BBB"))
|
||||
0402000200000003000100430031610842424208414141
|
||||
select hex(column_add(column_create("a", 1212 as integer), "b", "1212" as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "b", "1212" as integer))
|
||||
04020002000000000001002000616278097809
|
||||
select hex(column_add(column_create("a", 1212 as integer), "a", "1212" as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "a", "1212" as integer))
|
||||
040100010000000000617809
|
||||
select hex(column_add(column_create("a", 1212 as integer), "a", NULL as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "a", NULL as integer))
|
||||
0400000000
|
||||
select hex(column_add(column_create("a", 1212 as integer), "b", NULL as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "b", NULL as integer))
|
||||
040100010000000000617809
|
||||
select hex(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer))
|
||||
040200020000000000010010006162167809
|
||||
select column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "a" as integer);
|
||||
column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "a" as integer)
|
||||
11
|
||||
select column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "b" as integer);
|
||||
column_get(column_add(column_create("a", 1212 as integer), "b", 1212 as integer, "a", 11 as integer), "b" as integer)
|
||||
1212
|
||||
select hex(column_add(column_create("a", 1212 as integer), "a", 1212 as integer, "b", 11 as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer), "a", 1212 as integer, "b", 11 as integer))
|
||||
040200020000000000010020006162780916
|
||||
select hex(column_add(column_create("a", NULL as integer), "a", 1212 as integer, "b", 11 as integer));
|
||||
hex(column_add(column_create("a", NULL as integer), "a", 1212 as integer, "b", 11 as integer))
|
||||
040200020000000000010020006162780916
|
||||
select hex(column_add(column_create("a", 1212 as integer, "b", 1212 as integer), "a", 11 as integer));
|
||||
hex(column_add(column_create("a", 1212 as integer, "b", 1212 as integer), "a", 11 as integer))
|
||||
040200020000000000010010006162167809
|
||||
select hex(column_add(column_create("a", 1), "a", null));
|
||||
hex(column_add(column_create("a", 1), "a", null))
|
||||
0400000000
|
||||
select column_list(column_add(column_create("a", 1), "a", null));
|
||||
column_list(column_add(column_create("a", 1), "a", null))
|
||||
|
||||
select column_list(column_add(column_create("a", 1), "a", ""));
|
||||
column_list(column_add(column_create("a", 1), "a", ""))
|
||||
`a`
|
||||
select hex(column_add("", "a", 1));
|
||||
hex(column_add("", "a", 1))
|
||||
0401000100000000006102
|
||||
# column delete (names)
|
||||
select hex(column_delete(column_create("a", 1212 as integer, "b", 1212 as integer), "a"));
|
||||
hex(column_delete(column_create("a", 1212 as integer, "b", 1212 as integer), "a"))
|
||||
040100010000000000627809
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b"))
|
||||
0402000200000000000100100061630206
|
||||
select hex(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer));
|
||||
hex(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer))
|
||||
0403000300000000000100100002002000616263020406
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "c"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "c"))
|
||||
0402000200000000000100100061620204
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "d"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "d"))
|
||||
0403000300000000000100100002002000616263020406
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "a"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "a"))
|
||||
0401000100000000006306
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "c"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "b", "c"))
|
||||
0401000100000000006102
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c"))
|
||||
0400000000
|
||||
select hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c", "e"));
|
||||
hex(column_delete(column_create("a", 1 as integer, "b", 2 as integer, "c", 3 as integer), "a", "b", "c", "e"))
|
||||
0400000000
|
||||
select hex(column_delete(column_create("a", 1), "a"));
|
||||
hex(column_delete(column_create("a", 1), "a"))
|
||||
0400000000
|
||||
select hex(column_delete("", "a"));
|
||||
hex(column_delete("", "a"))
|
||||
|
||||
#
|
||||
# MDEV-458 DNAMES: Server crashes on using an unquoted string
|
||||
# as a dynamic column name
|
||||
#
|
||||
select COLUMN_CREATE(color, "black");
|
||||
ERROR 42S22: Unknown column 'color' in 'field list'
|
||||
#
|
||||
# MDEV-489 Assertion `offset < 0x1f' failed in
|
||||
# type_and_offset_store on COLUMN_ADD
|
||||
#
|
||||
CREATE TABLE t1 (f1 tinyblob);
|
||||
INSERT INTO t1 VALUES (COLUMN_CREATE('col1', REPEAT('a',30)));
|
||||
select column_check(f1) from t1;
|
||||
column_check(f1)
|
||||
1
|
||||
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('b',211), 'val2' );
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'f1' at row 1
|
||||
select column_check(f1) from t1;
|
||||
column_check(f1)
|
||||
0
|
||||
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('c',211), 'val3' );
|
||||
Warnings:
|
||||
Warning 1265 Data truncated for column 'f1' at row 1
|
||||
select column_check(f1) from t1;
|
||||
column_check(f1)
|
||||
0
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-490/MDEV-491 null as arguments
|
||||
#
|
||||
SELECT COLUMN_GET( COLUMN_CREATE( 'col', 'val' ), NULL AS CHAR );
|
||||
COLUMN_GET( COLUMN_CREATE( 'col', 'val' ), NULL AS CHAR )
|
||||
NULL
|
||||
SELECT COLUMN_GET( NULL, 'col' as char );
|
||||
COLUMN_GET( NULL, 'col' as char )
|
||||
NULL
|
||||
SELECT COLUMN_EXISTS( COLUMN_CREATE( 'col', 'val' ), NULL);
|
||||
COLUMN_EXISTS( COLUMN_CREATE( 'col', 'val' ), NULL)
|
||||
NULL
|
||||
SELECT COLUMN_EXISTS( NULL, 'col');
|
||||
COLUMN_EXISTS( NULL, 'col')
|
||||
NULL
|
||||
SELECT COLUMN_CREATE( NULL, 'val' );
|
||||
COLUMN_CREATE( NULL, 'val' )
|
||||
NULL
|
||||
SELECT COLUMN_ADD( NULL, 'val', 'col');
|
||||
COLUMN_ADD( NULL, 'val', 'col')
|
||||
NULL
|
||||
#
|
||||
# MDEV-488: Assertion `column_name->length < 255' failed on a
|
||||
# column name with length 255 (precisely)
|
||||
#
|
||||
SELECT hex(COLUMN_CREATE(REPEAT('a',255),1));
|
||||
hex(COLUMN_CREATE(REPEAT('a',255),1))
|
||||
040100FF000000000061616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616102
|
||||
SELECT hex(COLUMN_CREATE(REPEAT('a',65536),1));
|
||||
ERROR 22007: Illegal value used as argument of dynamic column function
|
||||
#
|
||||
# JSON conversion
|
||||
#
|
||||
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));
|
||||
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"
|
||||
{"int":-1212,"date":"2011-04-05","time":"00:45:49.000001","uint":12334,"double":"1.23444e+50","string":"gdgd\\dhdjh\"dhdhd","decimal":23.344,"datetime":"2011-04-05 00:45:49.000001"}
|
||||
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));
|
||||
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))
|
||||
{"1":-1212,"2":12334,"3":23.344,"4":"1.23444e+50","5":"gdgd\\dhdjh\"dhdhd","6":"00:45:49.000001","7":"2011-04-05 00:45:49.000001","8":"2011-04-05"}
|
||||
#
|
||||
# CHECK test
|
||||
#
|
||||
SELECT COLUMN_CHECK(COLUMN_CREATE(1,'a'));
|
||||
COLUMN_CHECK(COLUMN_CREATE(1,'a'))
|
||||
1
|
||||
SELECT COLUMN_CHECK('abracadabra');
|
||||
COLUMN_CHECK('abracadabra')
|
||||
0
|
||||
SELECT COLUMN_CHECK('');
|
||||
COLUMN_CHECK('')
|
||||
1
|
||||
SELECT COLUMN_CHECK(NULL);
|
||||
COLUMN_CHECK(NULL)
|
||||
NULL
|
||||
#
|
||||
# escaping check
|
||||
#
|
||||
select column_json(column_create("string", "'\"/\\`.,whatever")),hex(column_create("string", "'\"/\\`.,whatever"));
|
||||
column_json(column_create("string", "'\"/\\`.,whatever")) hex(column_create("string", "'\"/\\`.,whatever"))
|
||||
{"string":"'\"/\\`.,whatever"} 040100060000000300737472696E670827222F5C602E2C7768617465766572
|
||||
#
|
||||
# embedding test
|
||||
#
|
||||
select column_json(column_create("val", "val", "emb", column_create("val2", "val2")));
|
||||
column_json(column_create("val", "val", "emb", column_create("val2", "val2")))
|
||||
{"emb":{"val2":"val2"},"val":"val"}
|
||||
select column_json(column_create(1, "val", 2, column_create(3, "val2")));
|
||||
column_json(column_create(1, "val", 2, column_create(3, "val2")))
|
||||
{"1":"val","2":{"3":"val2"}}
|
||||
#
|
||||
# Time encoding
|
||||
#
|
||||
select hex(column_create("t", "800:46:06.23434" AS time)) as hex,
|
||||
column_json(column_create("t", "800:46:06.23434" AS time)) as json;
|
||||
hex json
|
||||
04010001000000070074649363B82003 {"t":"800:46:06.234340"}
|
||||
select hex(column_create(1, "800:46:06.23434" AS time)) as hex,
|
||||
column_json(column_create(1, "800:46:06.23434" AS time)) as json;
|
||||
hex json
|
||||
000100010007649363B82003 {"1":"800:46:06.234340"}
|
||||
select hex(column_create("t", "800:46:06" AS time)) as hex,
|
||||
column_json(column_create("t", "800:46:06" AS time)) as json;
|
||||
hex json
|
||||
04010001000000070074860B32 {"t":"800:46:06"}
|
||||
select hex(column_create(1, "800:46:06" AS time)) as hex,
|
||||
column_json(column_create(1, "800:46:06" AS time)) as json;
|
||||
hex json
|
||||
000100010007000060B82003 {"1":"800:46:06"}
|
||||
select hex(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as hex,
|
||||
column_json(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as json;
|
||||
hex json
|
||||
0401000100000005007495B90F649363B80A00 {"t":"2012-12-21 10:46:06.234340"}
|
||||
select hex(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as hex,
|
||||
column_json(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as json;
|
||||
hex json
|
||||
00010001000595B90F649363B80A00 {"1":"2012-12-21 10:46:06.234340"}
|
||||
select hex(column_create("t", "2012-12-21 10:46:06" AS datetime)) as hex,
|
||||
column_json(column_create("t", "2012-12-21 10:46:06" AS datetime)) as json;
|
||||
hex json
|
||||
0401000100000005007495B90F86AB00 {"t":"2012-12-21 10:46:06"}
|
||||
select hex(column_create(1, "2012-12-21 10:46:06" AS datetime)) as hex,
|
||||
column_json(column_create(1, "2012-12-21 10:46:06" AS datetime)) as json;
|
||||
hex json
|
||||
00010001000595B90F000060B80A00 {"1":"2012-12-21 10:46:06"}
|
||||
|
719
mysql-test/t/cassandra.test
Normal file
719
mysql-test/t/cassandra.test
Normal file
File diff suppressed because one or more lines are too long
@ -550,3 +550,164 @@ 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)));
|
||||
select column_check(f1) from t1;
|
||||
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('b',211), 'val2' );
|
||||
# we can't detect last string cut with 100% probability,
|
||||
# because we detect it by string end
|
||||
select column_check(f1) from t1;
|
||||
UPDATE t1 SET f1 = COLUMN_ADD( f1, REPEAT('c',211), 'val3' );
|
||||
select column_check(f1) from t1;
|
||||
|
||||
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',65536),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);
|
||||
|
||||
--echo #
|
||||
--echo # escaping check
|
||||
--echo #
|
||||
select column_json(column_create("string", "'\"/\\`.,whatever")),hex(column_create("string", "'\"/\\`.,whatever"));
|
||||
|
||||
--echo #
|
||||
--echo # embedding test
|
||||
--echo #
|
||||
select column_json(column_create("val", "val", "emb", column_create("val2", "val2")));
|
||||
select column_json(column_create(1, "val", 2, column_create(3, "val2")));
|
||||
|
||||
--echo #
|
||||
--echo # Time encoding
|
||||
--echo #
|
||||
select hex(column_create("t", "800:46:06.23434" AS time)) as hex,
|
||||
column_json(column_create("t", "800:46:06.23434" AS time)) as json;
|
||||
select hex(column_create(1, "800:46:06.23434" AS time)) as hex,
|
||||
column_json(column_create(1, "800:46:06.23434" AS time)) as json;
|
||||
|
||||
select hex(column_create("t", "800:46:06" AS time)) as hex,
|
||||
column_json(column_create("t", "800:46:06" AS time)) as json;
|
||||
select hex(column_create(1, "800:46:06" AS time)) as hex,
|
||||
column_json(column_create(1, "800:46:06" AS time)) as json;
|
||||
|
||||
select hex(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as hex,
|
||||
column_json(column_create("t", "2012-12-21 10:46:06.23434" AS datetime)) as json;
|
||||
select hex(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as hex,
|
||||
column_json(column_create(1, "2012-12-21 10:46:06.23434" AS datetime)) as json;
|
||||
|
||||
select hex(column_create("t", "2012-12-21 10:46:06" AS datetime)) as hex,
|
||||
column_json(column_create("t", "2012-12-21 10:46:06" AS datetime)) as json;
|
||||
select hex(column_create(1, "2012-12-21 10:46:06" AS datetime)) as hex,
|
||||
column_json(column_create(1, "2012-12-21 10:46:06" AS datetime)) as json;
|
||||
|
3622
mysys/ma_dyncol.c
3622
mysys/ma_dyncol.c
File diff suppressed because it is too large
Load Diff
104
mysys/string.c
104
mysys/string.c
@ -175,6 +175,36 @@ 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,
|
||||
char quote)
|
||||
{
|
||||
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++]= quote;
|
||||
for (i= 0; i < len; i++)
|
||||
{
|
||||
register char c= append[i];
|
||||
if (c == quote || 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++]= quote;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void dynstr_free(DYNAMIC_STRING *str)
|
||||
{
|
||||
@ -193,3 +223,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;
|
||||
|
@ -6068,23 +6068,87 @@ Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item)
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
num= args[1]->val_int();
|
||||
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= mariadb_dyncol_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) ?
|
||||
mariadb_dyncol_exists(&col, (uint) num) :
|
||||
mariadb_dyncol_exists_named(&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:
|
||||
|
@ -526,6 +526,54 @@ protected:
|
||||
virtual ~Create_func_coercibility() {}
|
||||
};
|
||||
|
||||
class Create_func_dyncol_check : public Create_func_arg1
|
||||
{
|
||||
public:
|
||||
virtual Item *create_1_arg(THD *thd, Item *arg1);
|
||||
|
||||
static Create_func_dyncol_check s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_dyncol_check() {}
|
||||
virtual ~Create_func_dyncol_check() {}
|
||||
};
|
||||
|
||||
class Create_func_dyncol_exists : public Create_func_arg2
|
||||
{
|
||||
public:
|
||||
virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
|
||||
|
||||
static Create_func_dyncol_exists s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_dyncol_exists() {}
|
||||
virtual ~Create_func_dyncol_exists() {}
|
||||
};
|
||||
|
||||
class Create_func_dyncol_list : public Create_func_arg1
|
||||
{
|
||||
public:
|
||||
virtual Item *create_1_arg(THD *thd, Item *arg1);
|
||||
|
||||
static Create_func_dyncol_list s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_dyncol_list() {}
|
||||
virtual ~Create_func_dyncol_list() {}
|
||||
};
|
||||
|
||||
class Create_func_dyncol_json : public Create_func_arg1
|
||||
{
|
||||
public:
|
||||
virtual Item *create_1_arg(THD *thd, Item *arg1);
|
||||
|
||||
static Create_func_dyncol_json s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_dyncol_json() {}
|
||||
virtual ~Create_func_dyncol_json() {}
|
||||
};
|
||||
|
||||
|
||||
class Create_func_compress : public Create_func_arg1
|
||||
{
|
||||
@ -3108,6 +3156,38 @@ Create_func_coercibility::create_1_arg(THD *thd, Item *arg1)
|
||||
}
|
||||
|
||||
|
||||
Create_func_dyncol_check Create_func_dyncol_check::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_dyncol_check::create_1_arg(THD *thd, Item *arg1)
|
||||
{
|
||||
return new (thd->mem_root) Item_func_dyncol_check(arg1);
|
||||
}
|
||||
|
||||
Create_func_dyncol_exists Create_func_dyncol_exists::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_dyncol_exists::create_2_arg(THD *thd, Item *arg1, Item *arg2)
|
||||
{
|
||||
return new (thd->mem_root) Item_func_dyncol_exists(arg1, arg2);
|
||||
}
|
||||
|
||||
Create_func_dyncol_list Create_func_dyncol_list::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_dyncol_list::create_1_arg(THD *thd, Item *arg1)
|
||||
{
|
||||
return new (thd->mem_root) Item_func_dyncol_list(arg1);
|
||||
}
|
||||
|
||||
Create_func_dyncol_json Create_func_dyncol_json::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_dyncol_json::create_1_arg(THD *thd, Item *arg1)
|
||||
{
|
||||
return new (thd->mem_root) Item_func_dyncol_json(arg1);
|
||||
}
|
||||
|
||||
Create_func_concat Create_func_concat::s_singleton;
|
||||
|
||||
Item*
|
||||
@ -5252,6 +5332,10 @@ static Native_func_registry func_array[] =
|
||||
{ { C_STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)},
|
||||
{ { C_STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)},
|
||||
{ { C_STRING_WITH_LEN("COERCIBILITY") }, BUILDER(Create_func_coercibility)},
|
||||
{ { C_STRING_WITH_LEN("COLUMN_CHECK") }, BUILDER(Create_func_dyncol_check)},
|
||||
{ { C_STRING_WITH_LEN("COLUMN_EXISTS") }, BUILDER(Create_func_dyncol_exists)},
|
||||
{ { C_STRING_WITH_LEN("COLUMN_LIST") }, BUILDER(Create_func_dyncol_list)},
|
||||
{ { C_STRING_WITH_LEN("COLUMN_JSON") }, BUILDER(Create_func_dyncol_json)},
|
||||
{ { C_STRING_WITH_LEN("COMPRESS") }, BUILDER(Create_func_compress)},
|
||||
{ { C_STRING_WITH_LEN("CONCAT") }, BUILDER(Create_func_concat)},
|
||||
{ { C_STRING_WITH_LEN("CONCAT_WS") }, BUILDER(Create_func_concat_ws)},
|
||||
@ -5711,7 +5795,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;
|
||||
@ -5727,7 +5811,6 @@ 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_add(THD *thd, Item *str,
|
||||
List<DYNCALL_CREATE_DEF> &list)
|
||||
{
|
||||
@ -5747,7 +5830,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>;
|
||||
|
||||
@ -5757,12 +5840,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
|
||||
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
NOW_FUNC, TRIG_COND_FUNC,
|
||||
SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC,
|
||||
EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
|
||||
NEG_FUNC, GSYSVAR_FUNC };
|
||||
NEG_FUNC, GSYSVAR_FUNC, DYNCOL_FUNC };
|
||||
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
|
||||
OPTIMIZE_EQUAL };
|
||||
enum Type type() const { return FUNC_ITEM; }
|
||||
|
@ -3777,7 +3777,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_num(NULL), keys_str(NULL),
|
||||
names(FALSE), force_names(FALSE)
|
||||
{
|
||||
DBUG_ASSERT((args.elements & 0x1) == 0); // even number of arguments
|
||||
}
|
||||
@ -3785,14 +3786,28 @@ 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
|
||||
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));
|
||||
status_var_increment(thd->status_var.feature_dynamic_columns);
|
||||
return res || vals == 0 || nums == 0;
|
||||
if (!res)
|
||||
{
|
||||
vals= (DYNAMIC_COLUMN_VALUE *) alloc_root(thd->mem_root,
|
||||
sizeof(DYNAMIC_COLUMN_VALUE) *
|
||||
(arg_count / 2));
|
||||
for (i= 0; i + 1 < arg_count && args[i]->result_type() == INT_RESULT; i+= 2);
|
||||
if (i + 1 < arg_count)
|
||||
{
|
||||
names= TRUE;
|
||||
}
|
||||
|
||||
keys_num= (uint *) alloc_root(thd->mem_root,
|
||||
(sizeof(LEX_STRING) > sizeof(uint) ?
|
||||
sizeof(LEX_STRING) :
|
||||
sizeof(uint)) *
|
||||
(arg_count / 2));
|
||||
keys_str= (LEX_STRING *) keys_num;
|
||||
status_var_increment(thd->status_var.feature_dynamic_columns);
|
||||
}
|
||||
return res || vals == 0 || keys_num == 0;
|
||||
}
|
||||
|
||||
|
||||
@ -3803,13 +3818,49 @@ 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;
|
||||
|
||||
if (!(names || force_names))
|
||||
{
|
||||
for (i= 0; i < column_count; i++)
|
||||
{
|
||||
uint valpos= i * 2 + 1;
|
||||
DYNAMIC_COLUMN_TYPE type= defs[i].type;
|
||||
if (type == DYN_COL_NULL)
|
||||
switch (args[valpos]->field_type())
|
||||
{
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_SET:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
type= DYN_COL_STRING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == DYN_COL_STRING &&
|
||||
args[valpos]->type() == Item::FUNC_ITEM &&
|
||||
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
|
||||
{
|
||||
force_names= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get values */
|
||||
for (i= 0; i < column_count; i++)
|
||||
@ -3868,7 +3919,59 @@ void Item_func_dyncol_create::prepare_arguments()
|
||||
break;
|
||||
}
|
||||
}
|
||||
nums[i]= (uint) args[i * 2]->val_int();
|
||||
if (type == DYN_COL_STRING &&
|
||||
args[valpos]->type() == Item::FUNC_ITEM &&
|
||||
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
|
||||
{
|
||||
DBUG_ASSERT(names || force_names);
|
||||
type= DYN_COL_DYNCOL;
|
||||
}
|
||||
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))
|
||||
{
|
||||
keys_str[i].length= res->length();
|
||||
keys_str[i].str= sql_strmake(res->ptr(), res->length());
|
||||
}
|
||||
else
|
||||
{
|
||||
uint strlen;
|
||||
uint dummy_errors;
|
||||
char *str=
|
||||
(char *)sql_alloc((strlen= res->length() *
|
||||
my_charset_utf8_general_ci.mbmaxlen + 1));
|
||||
if (str)
|
||||
{
|
||||
keys_str[i].length=
|
||||
copy_and_convert(str, strlen, &my_charset_utf8_general_ci,
|
||||
res->ptr(), res->length(), res->charset(),
|
||||
&dummy_errors);
|
||||
keys_str[i].str= str;
|
||||
}
|
||||
else
|
||||
keys_str[i].length= 0;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
keys_str[i].length= 0;
|
||||
keys_str[i].str= NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
keys_num[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:
|
||||
@ -3883,11 +3986,11 @@ void Item_func_dyncol_create::prepare_arguments()
|
||||
case DYN_COL_DOUBLE:
|
||||
vals[i].x.double_value= args[valpos]->val_real();
|
||||
break;
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_STRING:
|
||||
res= args[valpos]->val_str(&tmp);
|
||||
if (res &&
|
||||
(vals[i].x.string.value.str= my_strndup(res->ptr(), res->length(),
|
||||
MYF(MY_WME))))
|
||||
(vals[i].x.string.value.str= sql_strmake(res->ptr(), res->length())))
|
||||
{
|
||||
vals[i].x.string.value.length= res->length();
|
||||
vals[i].x.string.charset= res->charset();
|
||||
@ -3902,7 +4005,7 @@ void Item_func_dyncol_create::prepare_arguments()
|
||||
case DYN_COL_DECIMAL:
|
||||
if ((dres= args[valpos]->val_decimal(&dtmp)))
|
||||
{
|
||||
dynamic_column_prepare_decimal(&vals[i]);
|
||||
mariadb_dyncol_prepare_decimal(&vals[i]);
|
||||
DBUG_ASSERT(vals[i].x.decimal.value.len == dres->len);
|
||||
vals[i].x.decimal.value.intg= dres->intg;
|
||||
vals[i].x.decimal.value.frac= dres->frac;
|
||||
@ -3912,7 +4015,7 @@ void Item_func_dyncol_create::prepare_arguments()
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamic_column_prepare_decimal(&vals[i]); // just to be safe
|
||||
mariadb_dyncol_prepare_decimal(&vals[i]); // just to be safe
|
||||
DBUG_ASSERT(args[valpos]->null_value);
|
||||
}
|
||||
break;
|
||||
@ -3931,24 +4034,12 @@ void Item_func_dyncol_create::prepare_arguments()
|
||||
}
|
||||
if (vals[i].type != DYN_COL_NULL && args[valpos]->null_value)
|
||||
{
|
||||
if (vals[i].type == DYN_COL_STRING)
|
||||
my_free(vals[i].x.string.value.str);
|
||||
vals[i].type= DYN_COL_NULL;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Item_func_dyncol_create::cleanup_arguments()
|
||||
{
|
||||
uint column_count= (arg_count / 2);
|
||||
uint i;
|
||||
|
||||
for (i= 0; i < column_count; i++)
|
||||
{
|
||||
if (vals[i].type == DYN_COL_STRING)
|
||||
my_free(vals[i].x.string.value.str);
|
||||
}
|
||||
}
|
||||
|
||||
String *Item_func_dyncol_create::val_str(String *str)
|
||||
{
|
||||
@ -3958,30 +4049,37 @@ 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))
|
||||
{
|
||||
dynamic_column_error_message(rc);
|
||||
dynamic_column_column_free(&col);
|
||||
res= NULL;
|
||||
null_value= TRUE;
|
||||
null_value= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move result from DYNAMIC_COLUMN to str_value */
|
||||
char *ptr;
|
||||
size_t length, alloc_length;
|
||||
dynamic_column_reassociate(&col, &ptr, &length, &alloc_length);
|
||||
str_value.reassociate(ptr, (uint32) length, (uint32) alloc_length,
|
||||
&my_charset_bin);
|
||||
res= &str_value;
|
||||
null_value= FALSE;
|
||||
if ((rc= ((names || force_names) ?
|
||||
mariadb_dyncol_create_many_named(&col, column_count, keys_str,
|
||||
vals, TRUE) :
|
||||
mariadb_dyncol_create_many(&col, column_count, keys_num,
|
||||
vals, TRUE))))
|
||||
{
|
||||
dynamic_column_error_message(rc);
|
||||
dynamic_column_column_free(&col);
|
||||
res= NULL;
|
||||
null_value= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Move result from DYNAMIC_COLUMN to str_value */
|
||||
char *ptr;
|
||||
size_t length, alloc_length;
|
||||
dynstr_reassociate(&col, &ptr, &length, &alloc_length);
|
||||
str_value.reassociate(ptr, (uint32) length, (uint32) alloc_length,
|
||||
&my_charset_bin);
|
||||
res= &str_value;
|
||||
null_value= FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
cleanup_arguments();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -4007,6 +4105,7 @@ void Item_func_dyncol_create::print_arguments(String *str,
|
||||
case DYN_COL_DOUBLE:
|
||||
str->append(STRING_WITH_LEN(" AS double"));
|
||||
break;
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_STRING:
|
||||
str->append(STRING_WITH_LEN(" AS char"));
|
||||
if (defs[i].cs)
|
||||
@ -4044,6 +4143,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= mariadb_dyncol_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)
|
||||
{
|
||||
@ -4055,21 +4188,25 @@ 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)
|
||||
if (args[arg_count - 1]->null_value ||
|
||||
init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
|
||||
STRING_BUFFER_USUAL_SIZE))
|
||||
goto null;
|
||||
init_dynamic_string(&col, NULL, res->length() + STRING_BUFFER_USUAL_SIZE,
|
||||
STRING_BUFFER_USUAL_SIZE);
|
||||
|
||||
col.length= res->length();
|
||||
memcpy(col.str, res->ptr(), col.length);
|
||||
|
||||
prepare_arguments();
|
||||
if (prepare_arguments(mariadb_dyncol_has_names(&col)))
|
||||
goto null;
|
||||
|
||||
if ((rc= dynamic_column_update_many(&col, column_count, nums, vals)))
|
||||
if ((rc= ((names || force_names) ?
|
||||
mariadb_dyncol_update_many_named(&col, column_count,
|
||||
keys_str, vals) :
|
||||
mariadb_dyncol_update_many(&col, column_count,
|
||||
keys_num, vals))))
|
||||
{
|
||||
dynamic_column_error_message(rc);
|
||||
dynamic_column_column_free(&col);
|
||||
cleanup_arguments();
|
||||
goto null;
|
||||
}
|
||||
|
||||
@ -4077,16 +4214,12 @@ String *Item_func_dyncol_add::val_str(String *str)
|
||||
/* Move result from DYNAMIC_COLUMN to str */
|
||||
char *ptr;
|
||||
size_t length, alloc_length;
|
||||
dynamic_column_reassociate(&col, &ptr, &length, &alloc_length);
|
||||
dynstr_reassociate(&col, &ptr, &length, &alloc_length);
|
||||
str->reassociate(ptr, (uint32) length, (uint32) alloc_length,
|
||||
&my_charset_bin);
|
||||
null_value= FALSE;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
dynamic_column_column_free(&col);
|
||||
cleanup_arguments();
|
||||
|
||||
return str;
|
||||
|
||||
null:
|
||||
@ -4118,10 +4251,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;
|
||||
|
||||
num= args[1]->val_int();
|
||||
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;
|
||||
@ -4137,7 +4308,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) ?
|
||||
mariadb_dyncol_get(&dyn_str, (uint) num, val) :
|
||||
mariadb_dyncol_get_named(&dyn_str, name, val))))
|
||||
{
|
||||
dynamic_column_error_message(rc);
|
||||
null_value= 1;
|
||||
@ -4169,6 +4342,7 @@ String *Item_dyncol_get::val_str(String *str_result)
|
||||
case DYN_COL_DOUBLE:
|
||||
str_result->set_real(val.x.double_value, NOT_FIXED_DEC, &my_charset_latin1);
|
||||
break;
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_STRING:
|
||||
if ((char*) tmp.ptr() <= val.x.string.value.str &&
|
||||
(char*) tmp.ptr() + tmp.length() >= val.x.string.value.str)
|
||||
@ -4245,6 +4419,7 @@ longlong Item_dyncol_get::val_int()
|
||||
return 0;
|
||||
|
||||
switch (val.type) {
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_NULL:
|
||||
goto null;
|
||||
case DYN_COL_UINT:
|
||||
@ -4325,6 +4500,7 @@ double Item_dyncol_get::val_real()
|
||||
return 0.0;
|
||||
|
||||
switch (val.type) {
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_NULL:
|
||||
goto null;
|
||||
case DYN_COL_UINT:
|
||||
@ -4382,6 +4558,7 @@ my_decimal *Item_dyncol_get::val_decimal(my_decimal *decimal_value)
|
||||
return NULL;
|
||||
|
||||
switch (val.type) {
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_NULL:
|
||||
goto null;
|
||||
case DYN_COL_UINT:
|
||||
@ -4441,6 +4618,7 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
|
||||
return 1; // Error
|
||||
|
||||
switch (val.type) {
|
||||
case DYN_COL_DYNCOL:
|
||||
case DYN_COL_NULL:
|
||||
goto null;
|
||||
case DYN_COL_INT:
|
||||
@ -4486,6 +4664,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)
|
||||
{
|
||||
@ -4501,7 +4681,8 @@ String *Item_func_dyncol_list::val_str(String *str)
|
||||
{
|
||||
uint i;
|
||||
enum enum_dyncol_func_result rc;
|
||||
DYNAMIC_ARRAY arr;
|
||||
LEX_STRING *names= 0;
|
||||
uint count;
|
||||
DYNAMIC_COLUMN col;
|
||||
String *res= args[0]->val_str(str);
|
||||
|
||||
@ -4510,33 +4691,37 @@ 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= mariadb_dyncol_list_named(&col, &count, &names)))
|
||||
{
|
||||
bzero(&col, sizeof(col));
|
||||
dynamic_column_error_message(rc);
|
||||
delete_dynamic(&arr);
|
||||
goto null;
|
||||
}
|
||||
bzero(&col, sizeof(col));
|
||||
|
||||
/*
|
||||
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(count * 13))
|
||||
goto null;
|
||||
|
||||
str->length(0);
|
||||
for (i= 0; i < arr.elements; i++)
|
||||
str->set_charset(&my_charset_utf8_general_ci);
|
||||
for (i= 0; i < count; i++)
|
||||
{
|
||||
str->qs_append(*dynamic_element(&arr, i, uint*));
|
||||
if (i < arr.elements - 1)
|
||||
append_identifier(current_thd, str, names[i].str, names[i].length);
|
||||
if (i < count - 1)
|
||||
str->qs_append(',');
|
||||
}
|
||||
|
||||
null_value= FALSE;
|
||||
delete_dynamic(&arr);
|
||||
if (names)
|
||||
my_free(names);
|
||||
return str;
|
||||
|
||||
null:
|
||||
null_value= TRUE;
|
||||
if (names)
|
||||
my_free(names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1001,9 +1001,10 @@ class Item_func_dyncol_create: public Item_str_func
|
||||
protected:
|
||||
DYNCALL_CREATE_DEF *defs;
|
||||
DYNAMIC_COLUMN_VALUE *vals;
|
||||
uint *nums;
|
||||
void prepare_arguments();
|
||||
void cleanup_arguments();
|
||||
uint *keys_num;
|
||||
LEX_STRING *keys_str;
|
||||
bool names, force_names;
|
||||
bool prepare_arguments(bool force_names);
|
||||
void print_arguments(String *str, enum_query_type query_type);
|
||||
public:
|
||||
Item_func_dyncol_create(List<Item> &args, DYNCALL_CREATE_DEF *dfs);
|
||||
@ -1012,6 +1013,7 @@ public:
|
||||
const char *func_name() const{ return "column_create"; }
|
||||
String *val_str(String *);
|
||||
virtual void print(String *str, enum_query_type query_type);
|
||||
virtual enum Functype functype() const { return DYNCOL_FUNC; }
|
||||
};
|
||||
|
||||
|
||||
@ -1026,6 +1028,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
|
||||
@ -1036,11 +1051,9 @@ class Item_dyncol_get: public Item_str_func
|
||||
public:
|
||||
Item_dyncol_get(Item *str, Item *num)
|
||||
:Item_str_func(str, num)
|
||||
{
|
||||
max_length= MAX_DYNAMIC_COLUMN_LENGTH;
|
||||
}
|
||||
{}
|
||||
void fix_length_and_dec()
|
||||
{ maybe_null= 1; }
|
||||
{ maybe_null= 1; max_length= MAX_BLOB_WIDTH; }
|
||||
/* Mark that collation can change between calls */
|
||||
bool dynamic_result() { return 1; }
|
||||
|
||||
@ -1067,3 +1080,4 @@ public:
|
||||
extern String my_empty_string;
|
||||
|
||||
#endif /* ITEM_STRFUNC_INCLUDED */
|
||||
|
||||
|
@ -123,11 +123,10 @@ 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_LIST", SYM(COLUMN_LIST_SYM)},
|
||||
{ "COMMENT", SYM(COMMENT_SYM)},
|
||||
{ "COMMIT", SYM(COMMIT_SYM)},
|
||||
{ "COMMITTED", SYM(COMMITTED_SYM)},
|
||||
|
@ -9888,6 +9888,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));
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -175,7 +175,8 @@ static struct
|
||||
/* we disable few other plugins by default */
|
||||
{ "ndbcluster", PLUGIN_OFF },
|
||||
{ "feedback", PLUGIN_OFF },
|
||||
{ "pbxt", PLUGIN_OFF }
|
||||
{ "pbxt", PLUGIN_OFF },
|
||||
{ "cassandra", PLUGIN_OFF }
|
||||
};
|
||||
|
||||
/* support for Services */
|
||||
|
@ -768,79 +768,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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -883,11 +883,10 @@ 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_LIST_SYM
|
||||
%token COLUMN_SYM /* SQL-2003-R */
|
||||
%token COLUMN_NAME_SYM /* SQL-2003-N */
|
||||
%token COMMENT_SYM
|
||||
@ -8403,7 +8402,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;
|
||||
@ -8957,16 +8956,9 @@ function_call_nonkeyword:
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
|
||||
COLUMN_EXISTS_SYM '(' expr ',' expr ')'
|
||||
COLUMN_CHECK_SYM '(' expr ')'
|
||||
{
|
||||
$$= new (YYTHD->mem_root) Item_func_dyncol_exists($3, $5);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
|
||||
COLUMN_LIST_SYM '(' expr ')'
|
||||
{
|
||||
$$= new (YYTHD->mem_root) Item_func_dyncol_list($3);
|
||||
$$= new (YYTHD->mem_root) Item_func_dyncol_check($3);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
@ -13114,11 +13106,10 @@ keyword:
|
||||
| CHECKPOINT_SYM {}
|
||||
| CLOSE_SYM {}
|
||||
| COLUMN_ADD_SYM {}
|
||||
| COLUMN_CHECK_SYM {}
|
||||
| COLUMN_CREATE_SYM {}
|
||||
| COLUMN_DELETE_SYM {}
|
||||
| COLUMN_EXISTS_SYM {}
|
||||
| COLUMN_GET_SYM {}
|
||||
| COLUMN_LIST_SYM {}
|
||||
| COMMENT_SYM {}
|
||||
| COMMIT_SYM {}
|
||||
| CONTAINS_SYM {}
|
||||
|
26
storage/cassandra/CMakeLists.txt
Normal file
26
storage/cassandra/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
SET(cassandra_sources
|
||||
ha_cassandra.cc
|
||||
ha_cassandra.h
|
||||
cassandra_se.h
|
||||
cassandra_se.cc
|
||||
gen-cpp/Cassandra.cpp
|
||||
gen-cpp/cassandra_types.h
|
||||
gen-cpp/cassandra_types.cpp
|
||||
gen-cpp/cassandra_constants.h
|
||||
gen-cpp/cassandra_constants.cpp
|
||||
gen-cpp/Cassandra.h)
|
||||
|
||||
#INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
|
||||
|
||||
INCLUDE_DIRECTORIES(AFTER /usr/local/include/thrift)
|
||||
#INCLUDE_DIRECTORIES(AFTER /home/buildbot/build/thrift-inst/include/thrift/)
|
||||
#INCLUDE_DIRECTORIES(AFTER /home/psergey/cassandra/thrift/include/thrift/)
|
||||
|
||||
#
|
||||
STRING(REPLACE "-fno-exceptions" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
#LINK_DIRECTORIES(/home/psergey/cassandra/thrift/lib)
|
||||
|
||||
MYSQL_ADD_PLUGIN(cassandra ${cassandra_sources} STORAGE_ENGINE MODULE_ONLY LINK_LIBRARIES thrift)
|
||||
# was: STORAGE_ENGINE MANDATORY
|
800
storage/cassandra/cassandra_se.cc
Normal file
800
storage/cassandra/cassandra_se.cc
Normal file
@ -0,0 +1,800 @@
|
||||
|
||||
// Cassandra includes:
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Thrift.h"
|
||||
#include "transport/TSocket.h"
|
||||
#include "transport/TTransport.h"
|
||||
#include "transport/TBufferTransports.h"
|
||||
#include "protocol/TProtocol.h"
|
||||
#include "protocol/TBinaryProtocol.h"
|
||||
#include "gen-cpp/Cassandra.h"
|
||||
// cassandra includes end
|
||||
|
||||
#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;
|
||||
using namespace apache::thrift::protocol;
|
||||
using namespace org::apache::cassandra;
|
||||
|
||||
|
||||
/*
|
||||
Implementation of connection to one Cassandra column family (ie., table)
|
||||
*/
|
||||
class Cassandra_se_impl: public Cassandra_se_interface
|
||||
{
|
||||
CassandraClient *cass; /* Connection to cassandra */
|
||||
|
||||
std::string column_family;
|
||||
std::string keyspace;
|
||||
|
||||
ConsistencyLevel::type write_consistency;
|
||||
ConsistencyLevel::type read_consistency;
|
||||
|
||||
/* How many times to retry an operation before giving up */
|
||||
int thrift_call_retries_to_do;
|
||||
|
||||
|
||||
/* DDL data */
|
||||
KsDef ks_def; /* KeySpace we're using (TODO: put this in table->share) */
|
||||
CfDef cf_def; /* Column family we're using (TODO: put in table->share)*/
|
||||
std::vector<ColumnDef>::iterator column_ddl_it;
|
||||
|
||||
/* The list that was returned by the last key lookup */
|
||||
std::vector<ColumnOrSuperColumn> column_data_vec;
|
||||
std::vector<ColumnOrSuperColumn>::iterator column_data_it;
|
||||
|
||||
/* Insert preparation */
|
||||
typedef std::map<std::string, std::vector<Mutation> > ColumnFamilyToMutation;
|
||||
typedef std::map<std::string, ColumnFamilyToMutation> KeyToCfMutationMap;
|
||||
|
||||
KeyToCfMutationMap batch_mutation; /* Prepare operation here */
|
||||
int64_t insert_timestamp;
|
||||
std::vector<Mutation>* insert_list;
|
||||
|
||||
/* Resultset we're reading */
|
||||
std::vector<KeySlice> key_slice_vec;
|
||||
std::vector<KeySlice>::iterator key_slice_it;
|
||||
|
||||
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:
|
||||
Cassandra_se_impl() : cass(NULL),
|
||||
write_consistency(ConsistencyLevel::ONE),
|
||||
read_consistency(ConsistencyLevel::ONE),
|
||||
thrift_call_retries_to_do(0) {}
|
||||
virtual ~Cassandra_se_impl(){ delete cass; }
|
||||
|
||||
/* Connection and DDL checks */
|
||||
bool connect(const char *host, int port, const char *keyspace);
|
||||
void set_column_family(const char *cfname) { column_family.assign(cfname); }
|
||||
|
||||
bool setup_ddl_checks();
|
||||
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);
|
||||
|
||||
/* Writes */
|
||||
void clear_insert_buffer();
|
||||
void start_row_insert(const char *key, int key_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,
|
||||
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, int *name_len,
|
||||
char **value, int *value_len );
|
||||
void get_read_rowkey(char **value, int *value_len);
|
||||
|
||||
/* Reads, multi-row scans */
|
||||
private:
|
||||
bool have_rowkey_to_skip;
|
||||
std::string rowkey_to_skip;
|
||||
|
||||
bool get_range_slices_param_last_key_as_start_key;
|
||||
public:
|
||||
bool get_range_slices(bool last_key_as_start_key);
|
||||
void finish_reading_range_slices();
|
||||
bool get_next_range_slice_row(bool *eof);
|
||||
|
||||
/* 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 */
|
||||
void new_lookup_keys();
|
||||
int add_lookup_key(const char *key, size_t key_len);
|
||||
bool multiget_slice();
|
||||
|
||||
bool get_next_multiget_row();
|
||||
|
||||
bool truncate();
|
||||
|
||||
bool remove_row();
|
||||
|
||||
private:
|
||||
bool retryable_truncate();
|
||||
bool retryable_do_insert();
|
||||
bool retryable_remove_row();
|
||||
bool retryable_setup_ddl_checks();
|
||||
bool retryable_multiget_slice();
|
||||
bool retryable_get_range_slices();
|
||||
bool retryable_get_slice();
|
||||
|
||||
std::vector<std::string> mrr_keys; /* can we use allocator to put these into MRR buffer? */
|
||||
std::map<std::string, std::vector<ColumnOrSuperColumn> > mrr_result;
|
||||
std::map<std::string, std::vector<ColumnOrSuperColumn> >::iterator mrr_result_it;
|
||||
|
||||
/* Non-inherited utility functions: */
|
||||
int64_t get_i64_timestamp();
|
||||
|
||||
typedef bool (Cassandra_se_impl::*retryable_func_t)();
|
||||
bool try_operation(retryable_func_t func);
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Connection and setup
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Cassandra_se_interface *create_cassandra_se()
|
||||
{
|
||||
return new Cassandra_se_impl;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::connect(const char *host, int port, const char *keyspace_arg)
|
||||
{
|
||||
bool res= true;
|
||||
|
||||
keyspace.assign(keyspace_arg);
|
||||
|
||||
try {
|
||||
boost::shared_ptr<TTransport> socket =
|
||||
boost::shared_ptr<TSocket>(new TSocket(host, port));
|
||||
boost::shared_ptr<TTransport> tr =
|
||||
boost::shared_ptr<TFramedTransport>(new TFramedTransport (socket));
|
||||
boost::shared_ptr<TProtocol> p =
|
||||
boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(tr));
|
||||
|
||||
cass= new CassandraClient(p);
|
||||
tr->open();
|
||||
cass->set_keyspace(keyspace_arg);
|
||||
|
||||
res= false; // success
|
||||
}catch(TTransportException te){
|
||||
print_error("%s [%d]", te.what(), te.getType());
|
||||
}catch(InvalidRequestException ire){
|
||||
print_error("%s [%s]", ire.what(), ire.why.c_str());
|
||||
}catch(NotFoundException nfe){
|
||||
print_error("%s", nfe.what());
|
||||
}catch(TException e){
|
||||
print_error("Thrift exception: %s", e.what());
|
||||
}catch (...) {
|
||||
print_error("Unknown exception");
|
||||
}
|
||||
|
||||
if (!res && setup_ddl_checks())
|
||||
res= true;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::set_consistency_levels(ulong read_cons_level,
|
||||
ulong write_cons_level)
|
||||
{
|
||||
write_cons_level= (ConsistencyLevel::type)(write_cons_level + 1);
|
||||
read_cons_level= (ConsistencyLevel::type)(read_cons_level + 1);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_setup_ddl_checks()
|
||||
{
|
||||
try {
|
||||
|
||||
cass->describe_keyspace(ks_def, keyspace);
|
||||
|
||||
} catch (NotFoundException nfe) {
|
||||
print_error("keyspace `%s` not found: %s", keyspace.c_str(), nfe.what());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<CfDef>::iterator it;
|
||||
for (it= ks_def.cf_defs.begin(); it < ks_def.cf_defs.end(); it++)
|
||||
{
|
||||
cf_def= *it;
|
||||
if (!cf_def.name.compare(column_family))
|
||||
return false;
|
||||
}
|
||||
|
||||
print_error("Column family %s not found in keyspace %s",
|
||||
column_family.c_str(),
|
||||
keyspace.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cassandra_se_impl::setup_ddl_checks()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_setup_ddl_checks);
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::first_ddl_column()
|
||||
{
|
||||
column_ddl_it= cf_def.column_metadata.begin();
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::next_ddl_column(char **name, int *name_len,
|
||||
char **type, int *type_len)
|
||||
{
|
||||
if (column_ddl_it == cf_def.column_metadata.end())
|
||||
return true;
|
||||
|
||||
*name= (char*)(*column_ddl_it).name.c_str();
|
||||
*name_len= (*column_ddl_it).name.length();
|
||||
|
||||
*type= (char*)(*column_ddl_it).validation_class.c_str();
|
||||
*type_len= (*column_ddl_it).validation_class.length();
|
||||
|
||||
column_ddl_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::get_rowkey_type(char **name, char **type)
|
||||
{
|
||||
if (cf_def.__isset.key_validation_class)
|
||||
*type= (char*)cf_def.key_validation_class.c_str();
|
||||
else
|
||||
*type= NULL;
|
||||
|
||||
if (cf_def.__isset.key_alias)
|
||||
*name= (char*)cf_def.key_alias.c_str();
|
||||
else
|
||||
*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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
int64_t Cassandra_se_impl::get_i64_timestamp()
|
||||
{
|
||||
struct timeval td;
|
||||
gettimeofday(&td, NULL);
|
||||
int64_t ms = td.tv_sec;
|
||||
ms = ms * 1000;
|
||||
int64_t usec = td.tv_usec;
|
||||
usec = usec / 1000;
|
||||
ms += usec;
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::clear_insert_buffer()
|
||||
{
|
||||
batch_mutation.clear();
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::start_row_insert(const char *key, int key_len)
|
||||
{
|
||||
std::string key_to_insert;
|
||||
key_to_insert.assign(key, key_len);
|
||||
batch_mutation[key_to_insert]= ColumnFamilyToMutation();
|
||||
ColumnFamilyToMutation& cf_mut= batch_mutation[key_to_insert];
|
||||
|
||||
cf_mut[column_family]= std::vector<Mutation>();
|
||||
insert_list= &cf_mut[column_family];
|
||||
|
||||
insert_timestamp= get_i64_timestamp();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
batch_mutation[key_to_delete]= ColumnFamilyToMutation();
|
||||
ColumnFamilyToMutation& cf_mut= batch_mutation[key_to_delete];
|
||||
|
||||
cf_mut[column_family]= std::vector<Mutation>();
|
||||
std::vector<Mutation> &mutation_list= cf_mut[column_family];
|
||||
|
||||
Mutation mut;
|
||||
mut.__isset.deletion= true;
|
||||
mut.deletion.__isset.timestamp= true;
|
||||
mut.deletion.timestamp= get_i64_timestamp();
|
||||
mut.deletion.__isset.predicate= true;
|
||||
|
||||
/*
|
||||
Attempting to delete columns with SliceRange causes exception with message
|
||||
"Deletion does not yet support SliceRange predicates".
|
||||
|
||||
Delete all columns individually.
|
||||
*/
|
||||
SlicePredicate slice_pred;
|
||||
slice_pred.__isset.column_names= true;
|
||||
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;
|
||||
|
||||
mutation_list.push_back(mut);
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::add_insert_column(const char *name,
|
||||
int name_len,
|
||||
const char *value,
|
||||
int value_len)
|
||||
{
|
||||
Mutation mut;
|
||||
mut.__isset.column_or_supercolumn= true;
|
||||
mut.column_or_supercolumn.__isset.column= true;
|
||||
|
||||
Column& col=mut.column_or_supercolumn.column;
|
||||
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;
|
||||
col.__isset.timestamp= true;
|
||||
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()
|
||||
{
|
||||
cass->batch_mutate(batch_mutation, write_consistency);
|
||||
|
||||
cassandra_counters.row_inserts+= batch_mutation.size();
|
||||
cassandra_counters.row_insert_batches++;
|
||||
|
||||
clear_insert_buffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::do_insert()
|
||||
{
|
||||
/*
|
||||
zero-size mutations are allowed by Cassandra's batch_mutate but lets not
|
||||
do them (we may attempt to do it if there is a bulk insert that stores
|
||||
exactly @@cassandra_insert_batch_size*n elements.
|
||||
*/
|
||||
if (batch_mutation.empty())
|
||||
return false;
|
||||
|
||||
return try_operation(&Cassandra_se_impl::retryable_do_insert);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Reading data
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
Make one key lookup. If the record is found, the result is stored locally and
|
||||
the caller should iterate over it.
|
||||
*/
|
||||
|
||||
bool Cassandra_se_impl::get_slice(char *key, size_t key_len, bool *found)
|
||||
{
|
||||
bool res;
|
||||
rowkey.assign(key, key_len);
|
||||
|
||||
if (!(res= try_operation(&Cassandra_se_impl::retryable_get_slice)))
|
||||
*found= get_slice_found_rows;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_get_slice()
|
||||
{
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
SliceRange sr;
|
||||
sr.start = "";
|
||||
sr.finish = "";
|
||||
slice_pred.__set_slice_range(sr);
|
||||
|
||||
cass->get_slice(column_data_vec, rowkey, cparent, slice_pred,
|
||||
read_consistency);
|
||||
|
||||
if (column_data_vec.size() == 0)
|
||||
{
|
||||
/*
|
||||
No columns found. Cassandra doesn't allow records without any column =>
|
||||
this means the seach key doesn't exist
|
||||
*/
|
||||
get_slice_found_rows= false;
|
||||
return false;
|
||||
}
|
||||
get_slice_found_rows= true;
|
||||
|
||||
column_data_it= column_data_vec.begin();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_next_read_column(char **name, int *name_len,
|
||||
char **value, int *value_len)
|
||||
{
|
||||
bool use_counter=false;
|
||||
while (1)
|
||||
{
|
||||
if (column_data_it == column_data_vec.end())
|
||||
return true;
|
||||
|
||||
if ((*column_data_it).__isset.column)
|
||||
break; /* Ok it's a real column. Should be always the case. */
|
||||
|
||||
if ((*column_data_it).__isset.counter_column)
|
||||
{
|
||||
use_counter= true;
|
||||
break;
|
||||
}
|
||||
|
||||
column_data_it++;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
column_data_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Return the rowkey for the record that was read */
|
||||
|
||||
void Cassandra_se_impl::get_read_rowkey(char **value, int *value_len)
|
||||
{
|
||||
*value= (char*)rowkey.c_str();
|
||||
*value_len= rowkey.length();
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_range_slices(bool last_key_as_start_key)
|
||||
{
|
||||
get_range_slices_param_last_key_as_start_key= last_key_as_start_key;
|
||||
|
||||
return try_operation(&Cassandra_se_impl::retryable_get_range_slices);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_get_range_slices()
|
||||
{
|
||||
bool last_key_as_start_key= get_range_slices_param_last_key_as_start_key;
|
||||
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
/* SlicePredicate can be used to limit columns we will retrieve */
|
||||
|
||||
KeyRange key_range;
|
||||
key_range.__isset.start_key= true;
|
||||
key_range.__isset.end_key= true;
|
||||
|
||||
if (last_key_as_start_key)
|
||||
{
|
||||
key_range.start_key= rowkey;
|
||||
|
||||
have_rowkey_to_skip= true;
|
||||
rowkey_to_skip= rowkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
have_rowkey_to_skip= false;
|
||||
key_range.start_key.assign("", 0);
|
||||
}
|
||||
|
||||
key_range.end_key.assign("", 0);
|
||||
key_range.count= read_batch_size;
|
||||
|
||||
cass->get_range_slices(key_slice_vec, cparent, slice_pred, key_range,
|
||||
read_consistency);
|
||||
|
||||
if (key_slice_vec.size() < (uint)read_batch_size)
|
||||
get_slices_returned_less= true;
|
||||
else
|
||||
get_slices_returned_less= false;
|
||||
|
||||
key_slice_it= key_slice_vec.begin();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Switch to next row. This may produce an error */
|
||||
bool Cassandra_se_impl::get_next_range_slice_row(bool *eof)
|
||||
{
|
||||
restart:
|
||||
if (key_slice_it == key_slice_vec.end())
|
||||
{
|
||||
if (get_slices_returned_less)
|
||||
{
|
||||
*eof= true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
We have read through all columns in this batch. Try getting the next
|
||||
batch.
|
||||
*/
|
||||
if (get_range_slices(true))
|
||||
return true;
|
||||
|
||||
if (key_slice_vec.empty())
|
||||
{
|
||||
*eof= true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
(1) - skip the last row that we have read in the previous batch.
|
||||
(2) - Rows that were deleted show up as rows without any columns. Skip
|
||||
them, like CQL does.
|
||||
*/
|
||||
if ((have_rowkey_to_skip && !rowkey_to_skip.compare(key_slice_it->key)) || // (1)
|
||||
key_slice_it->columns.size() == 0) // (2)
|
||||
{
|
||||
key_slice_it++;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
*eof= false;
|
||||
column_data_vec= key_slice_it->columns;
|
||||
rowkey= key_slice_it->key;
|
||||
column_data_it= column_data_vec.begin();
|
||||
key_slice_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Cassandra_se_impl::finish_reading_range_slices()
|
||||
{
|
||||
key_slice_vec.clear();
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
std::string name(name_arg);
|
||||
slice_pred.__isset.column_names= true;
|
||||
slice_pred.column_names.push_back(name);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::truncate()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_truncate);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_truncate()
|
||||
{
|
||||
cass->truncate(column_family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::remove_row()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_remove_row);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_remove_row()
|
||||
{
|
||||
ColumnPath column_path;
|
||||
column_path.column_family= column_family;
|
||||
cass->remove(rowkey, column_path, get_i64_timestamp(), write_consistency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Try calling a function, catching possible Cassandra errors, and re-trying
|
||||
for "transient" errors.
|
||||
*/
|
||||
bool Cassandra_se_impl::try_operation(retryable_func_t func_to_call)
|
||||
{
|
||||
bool res;
|
||||
int n_retries= thrift_call_retries_to_do;
|
||||
|
||||
do
|
||||
{
|
||||
res= true;
|
||||
|
||||
try {
|
||||
|
||||
if ((res= (this->*func_to_call)()))
|
||||
{
|
||||
/*
|
||||
The function call was made successfully (without timeouts, etc),
|
||||
but something inside it returned 'true'.
|
||||
This is supposedly a failure (or "not found" or other negative
|
||||
result). We need to return this to the caller.
|
||||
*/
|
||||
n_retries= 0;
|
||||
}
|
||||
|
||||
} catch (InvalidRequestException ire) {
|
||||
n_retries= 0; /* there is no point in retrying this operation */
|
||||
print_error("%s [%s]", ire.what(), ire.why.c_str());
|
||||
} catch (UnavailableException ue) {
|
||||
cassandra_counters.unavailable_exceptions++;
|
||||
if (!--n_retries)
|
||||
print_error("UnavailableException: %s", ue.what());
|
||||
} catch (TimedOutException te) {
|
||||
cassandra_counters.timeout_exceptions++;
|
||||
if (!--n_retries)
|
||||
print_error("TimedOutException: %s", te.what());
|
||||
}catch(TException e){
|
||||
/* todo: we may use retry for certain kinds of Thrift errors */
|
||||
n_retries= 0;
|
||||
print_error("Thrift exception: %s", e.what());
|
||||
} catch (...) {
|
||||
n_retries= 0; /* Don't retry */
|
||||
print_error("Unknown exception");
|
||||
}
|
||||
|
||||
} while (res && n_retries > 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// MRR reads
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Cassandra_se_impl::new_lookup_keys()
|
||||
{
|
||||
mrr_keys.clear();
|
||||
}
|
||||
|
||||
|
||||
int Cassandra_se_impl::add_lookup_key(const char *key, size_t key_len)
|
||||
{
|
||||
mrr_keys.push_back(std::string(key, key_len));
|
||||
return mrr_keys.size();
|
||||
}
|
||||
|
||||
bool Cassandra_se_impl::multiget_slice()
|
||||
{
|
||||
return try_operation(&Cassandra_se_impl::retryable_multiget_slice);
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::retryable_multiget_slice()
|
||||
{
|
||||
ColumnParent cparent;
|
||||
cparent.column_family= column_family;
|
||||
|
||||
SlicePredicate slice_pred;
|
||||
SliceRange sr;
|
||||
sr.start = "";
|
||||
sr.finish = "";
|
||||
slice_pred.__set_slice_range(sr);
|
||||
|
||||
cassandra_counters.multiget_reads++;
|
||||
cassandra_counters.multiget_keys_scanned += mrr_keys.size();
|
||||
cass->multiget_slice(mrr_result, mrr_keys, cparent, slice_pred,
|
||||
read_consistency);
|
||||
|
||||
cassandra_counters.multiget_rows_read += mrr_result.size();
|
||||
mrr_result_it= mrr_result.begin();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Cassandra_se_impl::get_next_multiget_row()
|
||||
{
|
||||
if (mrr_result_it == mrr_result.end())
|
||||
return true; /* EOF */
|
||||
|
||||
column_data_vec= mrr_result_it->second;
|
||||
rowkey= mrr_result_it->first;
|
||||
|
||||
column_data_it= column_data_vec.begin();
|
||||
mrr_result_it++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
123
storage/cassandra/cassandra_se.h
Normal file
123
storage/cassandra/cassandra_se.h
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
/*
|
||||
This file is a "bridge" interface between cassandra+Thrift and MariaDB.
|
||||
|
||||
It is #included by both sides, so it must itself include neither (including
|
||||
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
|
||||
{
|
||||
ONE = 1-1,
|
||||
QUORUM = 2-1,
|
||||
LOCAL_QUORUM = 3-1,
|
||||
EACH_QUORUM = 4-1,
|
||||
ALL = 5-1,
|
||||
ANY = 6-1,
|
||||
TWO = 7-1,
|
||||
THREE = 8-1,
|
||||
} enum_cassandra_consistency_level;
|
||||
|
||||
|
||||
class Column_name_enumerator
|
||||
{
|
||||
public:
|
||||
virtual const char* get_next_name()=0;
|
||||
virtual ~Column_name_enumerator(){}
|
||||
};
|
||||
|
||||
/*
|
||||
Interface to one cassandra column family, i.e. one 'table'
|
||||
*/
|
||||
class Cassandra_se_interface
|
||||
{
|
||||
public:
|
||||
Cassandra_se_interface() { err_buffer[0]=0; }
|
||||
|
||||
virtual ~Cassandra_se_interface(){};
|
||||
/* Init */
|
||||
virtual bool connect(const char *host, int port, const char *keyspace)=0;
|
||||
virtual void set_column_family(const char *cfname) = 0;
|
||||
|
||||
/* Settings */
|
||||
virtual void set_consistency_levels(ulong read_cons_level, ulong write_cons_level)=0;
|
||||
|
||||
/* Check underlying DDL */
|
||||
virtual bool setup_ddl_checks()=0;
|
||||
virtual void first_ddl_column()=0;
|
||||
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,
|
||||
LEX_STRING *names, uint nnames)=0;
|
||||
virtual void start_row_insert(const char *key, int key_len)=0;
|
||||
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, int *name_len,
|
||||
char **value, int *value_len)=0;
|
||||
virtual void get_read_rowkey(char **value, int *value_len)=0;
|
||||
|
||||
/* Reads, multi-row scans */
|
||||
int read_batch_size;
|
||||
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;
|
||||
virtual bool multiget_slice()=0;
|
||||
virtual bool get_next_multiget_row()=0;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Passing error messages up to ha_cassandra */
|
||||
char err_buffer[512];
|
||||
const char *error_str() { return err_buffer; }
|
||||
void print_error(const char *format, ...);
|
||||
};
|
||||
|
||||
|
||||
/* A structure with global counters */
|
||||
class Cassandra_status_vars
|
||||
{
|
||||
public:
|
||||
ulong row_inserts;
|
||||
ulong row_insert_batches;
|
||||
|
||||
ulong multiget_reads;
|
||||
ulong multiget_keys_scanned;
|
||||
ulong multiget_rows_read;
|
||||
|
||||
ulong timeout_exceptions;
|
||||
ulong unavailable_exceptions;
|
||||
};
|
||||
|
||||
|
||||
extern Cassandra_status_vars cassandra_counters;
|
||||
|
||||
|
||||
Cassandra_se_interface *create_cassandra_se();
|
||||
|
12871
storage/cassandra/gen-cpp/Cassandra.cpp
Normal file
12871
storage/cassandra/gen-cpp/Cassandra.cpp
Normal file
File diff suppressed because it is too large
Load Diff
5466
storage/cassandra/gen-cpp/Cassandra.h
Normal file
5466
storage/cassandra/gen-cpp/Cassandra.h
Normal file
File diff suppressed because it is too large
Load Diff
219
storage/cassandra/gen-cpp/Cassandra_server.skeleton.cpp
Normal file
219
storage/cassandra/gen-cpp/Cassandra_server.skeleton.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
// This autogenerated skeleton file illustrates how to build a server.
|
||||
// You should copy it to another filename to avoid overwriting it.
|
||||
|
||||
#include "Cassandra.h"
|
||||
#include <protocol/TBinaryProtocol.h>
|
||||
#include <server/TSimpleServer.h>
|
||||
#include <transport/TServerSocket.h>
|
||||
#include <transport/TBufferTransports.h>
|
||||
|
||||
using namespace ::apache::thrift;
|
||||
using namespace ::apache::thrift::protocol;
|
||||
using namespace ::apache::thrift::transport;
|
||||
using namespace ::apache::thrift::server;
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
using namespace ::org::apache::cassandra;
|
||||
|
||||
class CassandraHandler : virtual public CassandraIf {
|
||||
public:
|
||||
CassandraHandler() {
|
||||
// Your initialization goes here
|
||||
}
|
||||
|
||||
void login(const AuthenticationRequest& auth_request) {
|
||||
// Your implementation goes here
|
||||
printf("login\n");
|
||||
}
|
||||
|
||||
void set_keyspace(const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("set_keyspace\n");
|
||||
}
|
||||
|
||||
void get(ColumnOrSuperColumn& _return, const std::string& key, const ColumnPath& column_path, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get\n");
|
||||
}
|
||||
|
||||
void get_slice(std::vector<ColumnOrSuperColumn> & _return, const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_slice\n");
|
||||
}
|
||||
|
||||
int32_t get_count(const std::string& key, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_count\n");
|
||||
}
|
||||
|
||||
void multiget_slice(std::map<std::string, std::vector<ColumnOrSuperColumn> > & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("multiget_slice\n");
|
||||
}
|
||||
|
||||
void multiget_count(std::map<std::string, int32_t> & _return, const std::vector<std::string> & keys, const ColumnParent& column_parent, const SlicePredicate& predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("multiget_count\n");
|
||||
}
|
||||
|
||||
void get_range_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const SlicePredicate& predicate, const KeyRange& range, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_range_slices\n");
|
||||
}
|
||||
|
||||
void get_paged_slice(std::vector<KeySlice> & _return, const std::string& column_family, const KeyRange& range, const std::string& start_column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_paged_slice\n");
|
||||
}
|
||||
|
||||
void get_indexed_slices(std::vector<KeySlice> & _return, const ColumnParent& column_parent, const IndexClause& index_clause, const SlicePredicate& column_predicate, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("get_indexed_slices\n");
|
||||
}
|
||||
|
||||
void insert(const std::string& key, const ColumnParent& column_parent, const Column& column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("insert\n");
|
||||
}
|
||||
|
||||
void add(const std::string& key, const ColumnParent& column_parent, const CounterColumn& column, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("add\n");
|
||||
}
|
||||
|
||||
void remove(const std::string& key, const ColumnPath& column_path, const int64_t timestamp, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("remove\n");
|
||||
}
|
||||
|
||||
void remove_counter(const std::string& key, const ColumnPath& path, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("remove_counter\n");
|
||||
}
|
||||
|
||||
void batch_mutate(const std::map<std::string, std::map<std::string, std::vector<Mutation> > > & mutation_map, const ConsistencyLevel::type consistency_level) {
|
||||
// Your implementation goes here
|
||||
printf("batch_mutate\n");
|
||||
}
|
||||
|
||||
void truncate(const std::string& cfname) {
|
||||
// Your implementation goes here
|
||||
printf("truncate\n");
|
||||
}
|
||||
|
||||
void describe_schema_versions(std::map<std::string, std::vector<std::string> > & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_schema_versions\n");
|
||||
}
|
||||
|
||||
void describe_keyspaces(std::vector<KsDef> & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_keyspaces\n");
|
||||
}
|
||||
|
||||
void describe_cluster_name(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_cluster_name\n");
|
||||
}
|
||||
|
||||
void describe_version(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_version\n");
|
||||
}
|
||||
|
||||
void describe_ring(std::vector<TokenRange> & _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("describe_ring\n");
|
||||
}
|
||||
|
||||
void describe_token_map(std::map<std::string, std::string> & _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_token_map\n");
|
||||
}
|
||||
|
||||
void describe_partitioner(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_partitioner\n");
|
||||
}
|
||||
|
||||
void describe_snitch(std::string& _return) {
|
||||
// Your implementation goes here
|
||||
printf("describe_snitch\n");
|
||||
}
|
||||
|
||||
void describe_keyspace(KsDef& _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("describe_keyspace\n");
|
||||
}
|
||||
|
||||
void describe_splits(std::vector<std::string> & _return, const std::string& cfName, const std::string& start_token, const std::string& end_token, const int32_t keys_per_split) {
|
||||
// Your implementation goes here
|
||||
printf("describe_splits\n");
|
||||
}
|
||||
|
||||
void system_add_column_family(std::string& _return, const CfDef& cf_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_add_column_family\n");
|
||||
}
|
||||
|
||||
void system_drop_column_family(std::string& _return, const std::string& column_family) {
|
||||
// Your implementation goes here
|
||||
printf("system_drop_column_family\n");
|
||||
}
|
||||
|
||||
void system_add_keyspace(std::string& _return, const KsDef& ks_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_add_keyspace\n");
|
||||
}
|
||||
|
||||
void system_drop_keyspace(std::string& _return, const std::string& keyspace) {
|
||||
// Your implementation goes here
|
||||
printf("system_drop_keyspace\n");
|
||||
}
|
||||
|
||||
void system_update_keyspace(std::string& _return, const KsDef& ks_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_update_keyspace\n");
|
||||
}
|
||||
|
||||
void system_update_column_family(std::string& _return, const CfDef& cf_def) {
|
||||
// Your implementation goes here
|
||||
printf("system_update_column_family\n");
|
||||
}
|
||||
|
||||
void execute_cql_query(CqlResult& _return, const std::string& query, const Compression::type compression) {
|
||||
// Your implementation goes here
|
||||
printf("execute_cql_query\n");
|
||||
}
|
||||
|
||||
void prepare_cql_query(CqlPreparedResult& _return, const std::string& query, const Compression::type compression) {
|
||||
// Your implementation goes here
|
||||
printf("prepare_cql_query\n");
|
||||
}
|
||||
|
||||
void execute_prepared_cql_query(CqlResult& _return, const int32_t itemId, const std::vector<std::string> & values) {
|
||||
// Your implementation goes here
|
||||
printf("execute_prepared_cql_query\n");
|
||||
}
|
||||
|
||||
void set_cql_version(const std::string& version) {
|
||||
// Your implementation goes here
|
||||
printf("set_cql_version\n");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int port = 9090;
|
||||
shared_ptr<CassandraHandler> handler(new CassandraHandler());
|
||||
shared_ptr<TProcessor> processor(new CassandraProcessor(handler));
|
||||
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
|
||||
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
|
||||
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
|
||||
|
||||
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
|
||||
server.serve();
|
||||
return 0;
|
||||
}
|
||||
|
18
storage/cassandra/gen-cpp/cassandra_constants.cpp
Normal file
18
storage/cassandra/gen-cpp/cassandra_constants.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Autogenerated by Thrift Compiler (0.8.0)
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* @generated
|
||||
*/
|
||||
#include "cassandra_constants.h"
|
||||
|
||||
namespace org { namespace apache { namespace cassandra {
|
||||
|
||||
const cassandraConstants g_cassandra_constants;
|
||||
|
||||
cassandraConstants::cassandraConstants() {
|
||||
cassandra_const_VERSION = (char *)"19.32.0";
|
||||
}
|
||||
|
||||
}}} // namespace
|
||||
|
26
storage/cassandra/gen-cpp/cassandra_constants.h
Normal file
26
storage/cassandra/gen-cpp/cassandra_constants.h
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Autogenerated by Thrift Compiler (0.8.0)
|
||||
*
|
||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
* @generated
|
||||
*/
|
||||
#ifndef cassandra_CONSTANTS_H
|
||||
#define cassandra_CONSTANTS_H
|
||||
|
||||
#include "cassandra_types.h"
|
||||
|
||||
namespace org { namespace apache { namespace cassandra {
|
||||
|
||||
class cassandraConstants {
|
||||
public:
|
||||
cassandraConstants();
|
||||
|
||||
// std::string VERSION;
|
||||
char* cassandra_const_VERSION;
|
||||
};
|
||||
|
||||
extern const cassandraConstants g_cassandra_constants;
|
||||
|
||||
}}} // namespace
|
||||
|
||||
#endif
|
3512
storage/cassandra/gen-cpp/cassandra_types.cpp
Normal file
3512
storage/cassandra/gen-cpp/cassandra_types.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2149
storage/cassandra/gen-cpp/cassandra_types.h
Normal file
2149
storage/cassandra/gen-cpp/cassandra_types.h
Normal file
File diff suppressed because it is too large
Load Diff
2619
storage/cassandra/ha_cassandra.cc
Normal file
2619
storage/cassandra/ha_cassandra.cc
Normal file
File diff suppressed because it is too large
Load Diff
275
storage/cassandra/ha_cassandra.h
Normal file
275
storage/cassandra/ha_cassandra.h
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
Copyright (c) 2012, Monty Program Ab
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
|
||||
#include "my_global.h" /* ulonglong */
|
||||
#include "thr_lock.h" /* THR_LOCK, THR_LOCK_DATA */
|
||||
#include "handler.h" /* handler */
|
||||
#include "my_base.h" /* ha_rows */
|
||||
|
||||
#include "cassandra_se.h"
|
||||
|
||||
/** @brief
|
||||
CASSANDRA_SHARE is a structure that will be shared among all open handlers.
|
||||
This example implements the minimum of what you will probably need.
|
||||
*/
|
||||
typedef struct st_cassandra_share {
|
||||
char *table_name;
|
||||
uint table_name_length,use_count;
|
||||
mysql_mutex_t mutex;
|
||||
THR_LOCK lock;
|
||||
} CASSANDRA_SHARE;
|
||||
|
||||
class ColumnDataConverter;
|
||||
struct st_dynamic_column_value;
|
||||
typedef struct st_dynamic_column_value DYNAMIC_COLUMN_VALUE;
|
||||
|
||||
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,
|
||||
MEM_ROOT *mem_root);
|
||||
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
|
||||
*/
|
||||
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,
|
||||
char *cass_value, int cass_value_len);
|
||||
int connect_and_check_options(TABLE *table_arg);
|
||||
public:
|
||||
ha_cassandra(handlerton *hton, TABLE_SHARE *table_arg);
|
||||
~ha_cassandra()
|
||||
{
|
||||
free_field_converters();
|
||||
delete se;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
The name that will be used for display purposes.
|
||||
*/
|
||||
const char *table_type() const { return "CASSANDRA"; }
|
||||
|
||||
/** @brief
|
||||
The name of the index type that will be used for display.
|
||||
Don't implement this method unless you really have indexes.
|
||||
*/
|
||||
const char *index_type(uint inx) { return "HASH"; }
|
||||
|
||||
/** @brief
|
||||
The file extensions.
|
||||
*/
|
||||
const char **bas_ext() const;
|
||||
|
||||
/** @brief
|
||||
This is a list of flags that indicate what functionality the storage engine
|
||||
implements. The current table flags are documented in handler.h
|
||||
*/
|
||||
ulonglong table_flags() const
|
||||
{
|
||||
return HA_BINLOG_STMT_CAPABLE |
|
||||
HA_REC_NOT_IN_SEQ |
|
||||
HA_NO_TRANSACTIONS |
|
||||
HA_REQUIRE_PRIMARY_KEY |
|
||||
HA_PRIMARY_KEY_IN_READ_INDEX |
|
||||
HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
|
||||
HA_NO_AUTO_INCREMENT |
|
||||
HA_TABLE_SCAN_ON_INDEX;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
This is a bitmap of flags that indicates how the storage engine
|
||||
implements indexes. The current index flags are documented in
|
||||
handler.h. If you do not implement indexes, just return zero here.
|
||||
|
||||
@details
|
||||
part is the key part to check. First key part is 0.
|
||||
If all_parts is set, MySQL wants to know the flags for the combined
|
||||
index, up to and including 'part'.
|
||||
*/
|
||||
ulong index_flags(uint inx, uint part, bool all_parts) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call max_supported_record_length(), max_supported_keys(),
|
||||
max_supported_key_parts(), uint max_supported_key_length()
|
||||
to make sure that the storage engine can handle the data it is about to
|
||||
send. Return *real* limits of your storage engine here; MySQL will do
|
||||
min(your_limits, MySQL_limits) automatically.
|
||||
*/
|
||||
uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
|
||||
|
||||
/* Support only one Primary Key, for now */
|
||||
uint max_supported_keys() const { return 1; }
|
||||
uint max_supported_key_parts() const { return 1; }
|
||||
|
||||
/** @brief
|
||||
unireg.cc will call this to make sure that the storage engine can handle
|
||||
the data it is about to send. Return *real* limits of your storage engine
|
||||
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
||||
|
||||
@details
|
||||
There is no need to implement ..._key_... methods if your engine doesn't
|
||||
support indexes.
|
||||
*/
|
||||
uint max_supported_key_length() const { return 16*1024; /* just to return something*/ }
|
||||
|
||||
int index_init(uint idx, bool sorted);
|
||||
|
||||
int index_read_map(uchar * buf, const uchar * key,
|
||||
key_part_map keypart_map,
|
||||
enum ha_rkey_function find_flag);
|
||||
|
||||
/** @brief
|
||||
Called in test_quick_select to determine if indexes should be used.
|
||||
*/
|
||||
virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
|
||||
|
||||
/** @brief
|
||||
This method will never be called if you do not implement indexes.
|
||||
*/
|
||||
virtual double read_time(uint, uint, ha_rows rows)
|
||||
{ return (double) rows / 20.0+1; }
|
||||
|
||||
virtual void start_bulk_insert(ha_rows rows, uint flags);
|
||||
virtual int end_bulk_insert();
|
||||
|
||||
virtual int reset();
|
||||
|
||||
|
||||
int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
|
||||
uint n_ranges, uint mode, HANDLER_BUFFER *buf);
|
||||
int multi_range_read_next(range_id_t *range_info);
|
||||
ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
|
||||
void *seq_init_param,
|
||||
uint n_ranges, uint *bufsz,
|
||||
uint *flags, COST_VECT *cost);
|
||||
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
|
||||
uint key_parts, uint *bufsz,
|
||||
uint *flags, COST_VECT *cost);
|
||||
int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
|
||||
|
||||
private:
|
||||
bool source_exhausted;
|
||||
bool mrr_start_read();
|
||||
int check_field_options(Field **fields);
|
||||
int read_dyncol(uint *count,
|
||||
DYNAMIC_COLUMN_VALUE **vals, LEX_STRING **names,
|
||||
String *valcol);
|
||||
int write_dynamic_row(uint count,
|
||||
DYNAMIC_COLUMN_VALUE *vals,
|
||||
LEX_STRING *names);
|
||||
void static free_dynamic_row(DYNAMIC_COLUMN_VALUE **vals,
|
||||
LEX_STRING **names);
|
||||
CASSANDRA_TYPE_DEF * get_cassandra_field_def(char *cass_name,
|
||||
int cass_name_length);
|
||||
public:
|
||||
int open(const char *name, int mode, uint test_if_locked);
|
||||
int close(void);
|
||||
|
||||
int write_row(uchar *buf);
|
||||
int update_row(const uchar *old_data, uchar *new_data);
|
||||
int delete_row(const uchar *buf);
|
||||
|
||||
/** @brief
|
||||
Unlike index_init(), rnd_init() can be called two consecutive times
|
||||
without rnd_end() in between (it only makes sense if scan=1). In this
|
||||
case, the second call should prepare for the new table scan (e.g if
|
||||
rnd_init() allocates the cursor, the second call should position the
|
||||
cursor to the start of the table; no need to deallocate and allocate
|
||||
it again. This is a required method.
|
||||
*/
|
||||
int rnd_init(bool scan); //required
|
||||
int rnd_end();
|
||||
int rnd_next(uchar *buf); ///< required
|
||||
int rnd_pos(uchar *buf, uchar *pos); ///< required
|
||||
void position(const uchar *record); ///< required
|
||||
int info(uint); ///< required
|
||||
int delete_all_rows(void);
|
||||
ha_rows records_in_range(uint inx, key_range *min_key,
|
||||
key_range *max_key);
|
||||
int create(const char *name, TABLE *form,
|
||||
HA_CREATE_INFO *create_info); ///< required
|
||||
bool check_if_incompatible_data(HA_CREATE_INFO *info,
|
||||
uint table_changes);
|
||||
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type); ///< required
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user