Commit 4cda5407 authored by Rich Prohaska's avatar Rich Prohaska

merge upsert19 to master

parents 9652dac4 05bdfcbc
...@@ -2,14 +2,22 @@ set default_storage_engine='tokudb'; ...@@ -2,14 +2,22 @@ set default_storage_engine='tokudb';
drop table if exists t; drop table if exists t;
set tokudb_disable_slow_upsert=1; set tokudb_disable_slow_upsert=1;
create table t (id int primary key, x int not null); create table t (id int primary key, x int not null);
insert noar into t values (1,42); insert noar into t values (1,1);
insert noar into t values (1,42) on duplicate key update x=x+1; insert noar into t values (1,1) on duplicate key update x=x+1;
select * from t; select * from t;
id x id x
1 43 1 2
insert noar into t values (1,42) on duplicate key update x=values(x)+1; insert noar into t values (1,10) on duplicate key update x=values(x)+1;
ERROR 42000: Table 't' uses an extension that doesn't exist in this XYZ version ERROR 42000: Table 't' uses an extension that doesn't exist in this XYZ version
select * from t; select * from t;
id x id x
1 43 1 2
insert noar into t values (1,10) on duplicate key update x=x+values(x);
select * from t;
id x
1 12
insert noar into t values (1,100) on duplicate key update x=x+values(x);
select * from t;
id x
1 112
drop table t; drop table t;
...@@ -12,13 +12,19 @@ set tokudb_disable_slow_upsert=1; ...@@ -12,13 +12,19 @@ set tokudb_disable_slow_upsert=1;
create table t (id int primary key, x int not null); create table t (id int primary key, x int not null);
insert noar into t values (1,42); insert noar into t values (1,1);
insert noar into t values (1,42) on duplicate key update x=x+1; insert noar into t values (1,1) on duplicate key update x=x+1;
select * from t; select * from t;
replace_regex /MariaDB/XYZ/ /MySQL/XYZ/; replace_regex /MariaDB/XYZ/ /MySQL/XYZ/;
error ER_UNSUPPORTED_EXTENSION; error ER_UNSUPPORTED_EXTENSION;
insert noar into t values (1,42) on duplicate key update x=values(x)+1; insert noar into t values (1,10) on duplicate key update x=values(x)+1;
select * from t;
insert noar into t values (1,10) on duplicate key update x=x+values(x);
select * from t;
insert noar into t values (1,100) on duplicate key update x=x+values(x);
select * from t; select * from t;
drop table t; drop table t;
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
// Restrictions: // Restrictions:
// No triggers // No triggers
// Statement or mixed replication // Statement or mixed replication
// Does not support row based replication
// Primary key must be defined // Primary key must be defined
// Simple and compound primary key // Simple and compound primary key
// Int, char and varchar primary key types // Int, char and varchar primary key types
...@@ -14,10 +13,10 @@ ...@@ -14,10 +13,10 @@
// Integer and char field updates // Integer and char field updates
// Update expressions: // Update expressions:
// x = constant // x = constant
// x = x+constant // x = x + constant
// x = x-constant // x = x - constant
// x = if(x=0,0,x-1) // x = if (x=0,0,x-1)
// Session variable enables fast updates and fast upserts // x = x + values(x)
// Session variable disables slow updates and slow upserts // Session variable disables slow updates and slow upserts
// Future features: // Future features:
...@@ -72,7 +71,14 @@ static void dump_item(Item *item) { ...@@ -72,7 +71,14 @@ static void dump_item(Item *item) {
fprintf(stderr, ")\n"); fprintf(stderr, ")\n");
break; break;
} }
case Item::INSERT_VALUE_ITEM: {
Item_insert_value *value_item = static_cast<Item_insert_value*>(item);
fprintf(stderr, ":insert_value");
dump_item(value_item->arg);
break;
}
default: default:
fprintf(stderr, ":unsupported\n");
break; break;
} }
} }
...@@ -197,9 +203,9 @@ return_error: ...@@ -197,9 +203,9 @@ return_error:
// Return true if an expression is a simple int expression or a simple function of +- int expression. // Return true if an expression is a simple int expression or a simple function of +- int expression.
static bool check_int_result(Item *item) { static bool check_int_result(Item *item) {
Item::Type t = item->type(); Item::Type t = item->type();
if (t == Item::INT_ITEM) if (t == Item::INT_ITEM) {
return true; return true;
else if (t == Item::FUNC_ITEM) { } else if (t == Item::FUNC_ITEM) {
Item_func *item_func = static_cast<Item_func*>(item); Item_func *item_func = static_cast<Item_func*>(item);
if (strcmp(item_func->func_name(), "+") != 0 && strcmp(item_func->func_name(), "-") != 0) if (strcmp(item_func->func_name(), "+") != 0 && strcmp(item_func->func_name(), "-") != 0)
return false; return false;
...@@ -213,8 +219,21 @@ static bool check_int_result(Item *item) { ...@@ -213,8 +219,21 @@ static bool check_int_result(Item *item) {
return false; return false;
} }
// check that an item is an insert value item with the same field name
static bool check_insert_value(Item *item, const char *field_name) {
if (item->type() != Item::INSERT_VALUE_ITEM)
return false;
Item_insert_value *value_item = static_cast<Item_insert_value*>(item);
if (value_item->arg->type() != Item::FIELD_ITEM)
return false;
Item_field *arg = static_cast<Item_field*>(value_item->arg);
if (strcmp(field_name, arg->field_name) != 0)
return false;
return true;
}
// Return true if an expression looks like field_name op constant. // Return true if an expression looks like field_name op constant.
static bool check_x_op_constant(const char *field_name, Item *item, const char *op, Item **item_constant) { static bool check_x_op_constant(const char *field_name, Item *item, const char *op, Item **item_constant, bool allow_insert_value) {
if (item->type() != Item::FUNC_ITEM) if (item->type() != Item::FUNC_ITEM)
return false; return false;
Item_func *item_func = static_cast<Item_func*>(item); Item_func *item_func = static_cast<Item_func*>(item);
...@@ -230,6 +249,7 @@ static bool check_x_op_constant(const char *field_name, Item *item, const char * ...@@ -230,6 +249,7 @@ static bool check_x_op_constant(const char *field_name, Item *item, const char *
if (strcmp(field_name, arg0->field_name) != 0) if (strcmp(field_name, arg0->field_name) != 0)
return false; return false;
if (!check_int_result(arguments[1])) if (!check_int_result(arguments[1]))
if (!(allow_insert_value && check_insert_value(arguments[1], field_name)))
return false; return false;
*item_constant = arguments[1]; *item_constant = arguments[1];
return true; return true;
...@@ -238,9 +258,9 @@ static bool check_x_op_constant(const char *field_name, Item *item, const char * ...@@ -238,9 +258,9 @@ static bool check_x_op_constant(const char *field_name, Item *item, const char *
// Return true if an expression looks like field_name = constant // Return true if an expression looks like field_name = constant
static bool check_x_equal_0(const char *field_name, Item *item) { static bool check_x_equal_0(const char *field_name, Item *item) {
Item *item_constant; Item *item_constant;
if (!check_x_op_constant(field_name, item, "=", &item_constant)) if (!check_x_op_constant(field_name, item, "=", &item_constant, false))
return false; return false;
if (item_constant->val_int() != 0) if (item_constant->type() != Item::INT_ITEM || item_constant->val_int() != 0)
return false; return false;
return true; return true;
} }
...@@ -248,9 +268,9 @@ static bool check_x_equal_0(const char *field_name, Item *item) { ...@@ -248,9 +268,9 @@ static bool check_x_equal_0(const char *field_name, Item *item) {
// Return true if an expression looks like fieldname - 1 // Return true if an expression looks like fieldname - 1
static bool check_x_minus_1(const char *field_name, Item *item) { static bool check_x_minus_1(const char *field_name, Item *item) {
Item *item_constant; Item *item_constant;
if (!check_x_op_constant(field_name, item, "-", &item_constant)) if (!check_x_op_constant(field_name, item, "-", &item_constant, false))
return false; return false;
if (item_constant->val_int() != 1) if (item_constant->type() != Item::INT_ITEM || item_constant->val_int() != 1)
return false; return false;
return true; return true;
} }
...@@ -279,7 +299,7 @@ static bool check_decr_floor_expression(Field *lhs_field, Item *item) { ...@@ -279,7 +299,7 @@ static bool check_decr_floor_expression(Field *lhs_field, Item *item) {
} }
// Check if lhs = rhs expression is simple. Return true if it is. // Check if lhs = rhs expression is simple. Return true if it is.
static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table) { static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table, bool allow_insert_value) {
Field *lhs_field = find_field_by_name(table, lhs_item); Field *lhs_field = find_field_by_name(table, lhs_item);
if (lhs_field == NULL) if (lhs_field == NULL)
return false; return false;
...@@ -296,9 +316,9 @@ static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table ...@@ -296,9 +316,9 @@ static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table
if (check_int_result(rhs_item)) if (check_int_result(rhs_item))
return true; return true;
Item *item_constant; Item *item_constant;
if (check_x_op_constant(lhs_field->field_name, rhs_item, "+", &item_constant)) if (check_x_op_constant(lhs_field->field_name, rhs_item, "+", &item_constant, allow_insert_value))
return true; return true;
if (check_x_op_constant(lhs_field->field_name, rhs_item, "-", &item_constant)) if (check_x_op_constant(lhs_field->field_name, rhs_item, "-", &item_constant, allow_insert_value))
return true; return true;
if (check_decr_floor_expression(lhs_field, rhs_item)) if (check_decr_floor_expression(lhs_field, rhs_item))
return true; return true;
...@@ -319,7 +339,7 @@ static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table ...@@ -319,7 +339,7 @@ static bool check_update_expression(Item *lhs_item, Item *rhs_item, TABLE *table
} }
// Check that all update expressions are simple. Return true if they are. // Check that all update expressions are simple. Return true if they are.
static bool check_all_update_expressions(List<Item> &fields, List<Item> &values, TABLE *table) { static bool check_all_update_expressions(List<Item> &fields, List<Item> &values, TABLE *table, bool allow_insert_value) {
List_iterator<Item> lhs_i(fields); List_iterator<Item> lhs_i(fields);
List_iterator<Item> rhs_i(values); List_iterator<Item> rhs_i(values);
while (1) { while (1) {
...@@ -327,9 +347,8 @@ static bool check_all_update_expressions(List<Item> &fields, List<Item> &values, ...@@ -327,9 +347,8 @@ static bool check_all_update_expressions(List<Item> &fields, List<Item> &values,
if (lhs_item == NULL) if (lhs_item == NULL)
break; break;
Item *rhs_item = rhs_i++; Item *rhs_item = rhs_i++;
if (rhs_item == NULL) assert(rhs_item != NULL);
assert(0); // can not happen if (!check_update_expression(lhs_item, rhs_item, table, allow_insert_value))
if (!check_update_expression(lhs_item, rhs_item, table))
return false; return false;
} }
return true; return true;
...@@ -472,7 +491,7 @@ bool ha_tokudb::check_fast_update(THD *thd, List<Item> &fields, List<Item> &valu ...@@ -472,7 +491,7 @@ bool ha_tokudb::check_fast_update(THD *thd, List<Item> &fields, List<Item> &valu
if (clustering_keys_exist(table)) if (clustering_keys_exist(table))
return false; return false;
if (!check_all_update_expressions(fields, values, table)) if (!check_all_update_expressions(fields, values, table, false))
return false; return false;
if (!check_point_update(conds, table)) if (!check_point_update(conds, table))
...@@ -503,7 +522,17 @@ static void marshall_blobs_descriptor(tokudb::buffer &b, TABLE *table, KEY_AND_C ...@@ -503,7 +522,17 @@ static void marshall_blobs_descriptor(tokudb::buffer &b, TABLE *table, KEY_AND_C
static inline uint32_t get_null_bit_position(uint32_t null_bit); static inline uint32_t get_null_bit_position(uint32_t null_bit);
// Marshall update operatins to a buffer. // evaluate the int value of an item
static longlong item_val_int(Item *item) {
Item::Type t = item->type();
if (t == Item::INSERT_VALUE_ITEM) {
Item_insert_value *value_item = static_cast<Item_insert_value*>(item);
return value_item->arg->val_int();
} else
return item->val_int();
}
// Marshall update operations to a buffer.
static void marshall_update(tokudb::buffer &b, Item *lhs_item, Item *rhs_item, TABLE *table, TOKUDB_SHARE *share) { static void marshall_update(tokudb::buffer &b, Item *lhs_item, Item *rhs_item, TABLE *table, TOKUDB_SHARE *share) {
// figure out the update operation type (again) // figure out the update operation type (again)
Field *lhs_field = find_field_by_name(table, lhs_item); Field *lhs_field = find_field_by_name(table, lhs_item);
...@@ -544,14 +573,14 @@ static void marshall_update(tokudb::buffer &b, Item *lhs_item, Item *rhs_item, T ...@@ -544,14 +573,14 @@ static void marshall_update(tokudb::buffer &b, Item *lhs_item, Item *rhs_item, T
Item_func *rhs_func = static_cast<Item_func*>(rhs_item); Item_func *rhs_func = static_cast<Item_func*>(rhs_item);
Item **arguments = rhs_func->arguments(); Item **arguments = rhs_func->arguments();
if (strcmp(rhs_func->func_name(), "if") == 0) { if (strcmp(rhs_func->func_name(), "if") == 0) {
update_operation = '-'; // we only support one if function for now, and it is a descrement with floor. update_operation = '-'; // we only support one if function for now, and it is a decrement with floor.
v_ll = 1; v_ll = 1;
} else if (rhs_func->argument_count() == 1) { } else if (rhs_func->argument_count() == 1) {
update_operation = '='; update_operation = '=';
v_ll = rhs_func->val_int(); v_ll = rhs_func->val_int();
} else { } else {
update_operation = rhs_func->func_name()[0]; update_operation = rhs_func->func_name()[0];
v_ll = arguments[1]->val_int(); v_ll = item_val_int(arguments[1]);
} }
v_length = lhs_field->pack_length(); v_length = lhs_field->pack_length();
v_ptr = &v_ll; v_ptr = &v_ll;
...@@ -712,8 +741,7 @@ int ha_tokudb::send_update_message(List<Item> &update_fields, List<Item> &update ...@@ -712,8 +741,7 @@ int ha_tokudb::send_update_message(List<Item> &update_fields, List<Item> &update
if (lhs_item == NULL) if (lhs_item == NULL)
break; break;
Item *rhs_item = rhs_i++; Item *rhs_item = rhs_i++;
if (rhs_item == NULL) assert(rhs_item != NULL);
assert(0); // can not happen
marshall_update(update_message, lhs_item, rhs_item, table, share); marshall_update(update_message, lhs_item, rhs_item, table, share);
} }
...@@ -801,7 +829,7 @@ bool ha_tokudb::check_upsert(THD *thd, List<Item> &update_fields, List<Item> &up ...@@ -801,7 +829,7 @@ bool ha_tokudb::check_upsert(THD *thd, List<Item> &update_fields, List<Item> &up
!(thd->variables.binlog_format == BINLOG_FORMAT_STMT || thd->variables.binlog_format == BINLOG_FORMAT_MIXED)) !(thd->variables.binlog_format == BINLOG_FORMAT_STMT || thd->variables.binlog_format == BINLOG_FORMAT_MIXED))
return false; return false;
if (!check_all_update_expressions(update_fields, update_values, table)) if (!check_all_update_expressions(update_fields, update_values, table, true))
return false; return false;
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment