Cassandra SE merge

This commit is contained in:
unknown 2013-01-10 00:58:36 +02:00
commit f54a4819b6
38 changed files with 33956 additions and 1396 deletions

View File

@ -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}})

View File

@ -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

View File

@ -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);

View 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.
}

View File

@ -0,0 +1 @@
--plugin-load=$HA_CASSANDRA_SO --cassandra=on

View 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;

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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);
}

View File

@ -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

View File

@ -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; }

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)},

View File

@ -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));

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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);
}
/*

View File

@ -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 {}

View 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

View 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;
}

View 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();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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
};