diff --git a/src/box/alter.cc b/src/box/alter.cc index bb3686d6efee5c5cfb5b905e829ce17c5b12228e..941b638ea0eb26eb1a97ac2351769cf2d83fc84b 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -4595,9 +4595,12 @@ ck_constraint_def_new_from_tuple(struct tuple *tuple) const char *expr_str = tuple_field_str_xc(tuple, BOX_CK_CONSTRAINT_FIELD_CODE, &expr_str_len); + bool is_enabled = + tuple_field_count(tuple) <= BOX_CK_CONSTRAINT_FIELD_IS_ENABLED || + tuple_field_bool_xc(tuple, BOX_CK_CONSTRAINT_FIELD_IS_ENABLED); struct ck_constraint_def *ck_def = ck_constraint_def_new(name, name_len, expr_str, expr_str_len, - space_id, language); + space_id, language, is_enabled); if (ck_def == NULL) diag_raise(); return ck_def; @@ -4697,6 +4700,30 @@ on_replace_dd_ck_constraint(struct trigger * /* trigger*/, void *event) auto ck_def_guard = make_scoped_guard([=] { ck_constraint_def_delete(ck_def); }); + /* + * A corner case: enabling/disabling an existent + * ck constraint doesn't require the object + * rebuilding. + * FIXME: here we need to re-run check constraint + * in case it is turned on after insertion of new + * tuples. Otherwise, data in space can turn out to + * be inconsistent (i.e. violate existing constraints). + */ + const char *name = ck_def->name; + struct ck_constraint *old_ck_constraint = + space_ck_constraint_by_name(space, name, strlen(name)); + if (old_ck_constraint != NULL) { + struct ck_constraint_def *old_def = + old_ck_constraint->def; + assert(old_def->space_id == ck_def->space_id); + assert(strcmp(old_def->name, ck_def->name) == 0); + if (old_def->language == ck_def->language && + strcmp(old_def->expr_str, ck_def->expr_str) == 0) { + old_def->is_enabled = ck_def->is_enabled; + trigger_run_xc(&on_alter_space, space); + return; + } + } /* * FIXME: Ck constraint creation on non-empty * space is not implemented yet. @@ -4704,8 +4731,7 @@ on_replace_dd_ck_constraint(struct trigger * /* trigger*/, void *event) struct index *pk = space_index(space, 0); if (pk != NULL && index_size(pk) > 0) { tnt_raise(ClientError, ER_CREATE_CK_CONSTRAINT, - ck_def->name, - "referencing space must be empty"); + name, "referencing space must be empty"); } struct ck_constraint *new_ck_constraint = ck_constraint_new(ck_def, space->def); @@ -4715,9 +4741,6 @@ on_replace_dd_ck_constraint(struct trigger * /* trigger*/, void *event) auto ck_guard = make_scoped_guard([=] { ck_constraint_delete(new_ck_constraint); }); - const char *name = new_ck_constraint->def->name; - struct ck_constraint *old_ck_constraint = - space_ck_constraint_by_name(space, name, strlen(name)); if (old_ck_constraint != NULL) rlist_del_entry(old_ck_constraint, link); if (space_add_ck_constraint(space, new_ck_constraint) != 0) diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index 4c9aea7f50f8ac86be32ca9f126fea9a3d2d182f..59f6cc16bb48841fa99b4e13590b8e0677433b35 100644 Binary files a/src/box/bootstrap.snap and b/src/box/bootstrap.snap differ diff --git a/src/box/ck_constraint.c b/src/box/ck_constraint.c index 1cde270224e509fc5cbbb9e4c178a06f70c4dd5d..d21717f947b3a25f1daa5f784aa3d3123aea933d 100644 --- a/src/box/ck_constraint.c +++ b/src/box/ck_constraint.c @@ -44,7 +44,7 @@ const char *ck_constraint_language_strs[] = {"SQL"}; struct ck_constraint_def * ck_constraint_def_new(const char *name, uint32_t name_len, const char *expr_str, uint32_t expr_str_len, uint32_t space_id, - enum ck_constraint_language language) + enum ck_constraint_language language, bool is_enabled) { uint32_t expr_str_offset; uint32_t ck_def_sz = ck_constraint_def_sizeof(name_len, expr_str_len, @@ -55,6 +55,7 @@ ck_constraint_def_new(const char *name, uint32_t name_len, const char *expr_str, diag_set(OutOfMemory, ck_def_sz, "malloc", "ck_def"); return NULL; } + ck_def->is_enabled = is_enabled; ck_def->expr_str = (char *)ck_def + expr_str_offset; ck_def->language = language; ck_def->space_id = space_id; @@ -201,7 +202,8 @@ ck_constraint_on_replace_trigger(struct trigger *trigger, void *event) struct ck_constraint *ck_constraint; rlist_foreach_entry(ck_constraint, &space->ck_constraint, link) { - if (ck_constraint_program_run(ck_constraint, field_ref) != 0) + if (ck_constraint->def->is_enabled && + ck_constraint_program_run(ck_constraint, field_ref) != 0) diag_raise(); } } diff --git a/src/box/ck_constraint.h b/src/box/ck_constraint.h index f26f77a389ff76e473c87a57c4d3c9e90f76d0a7..6761318d69e3d5efb211a2ad9ace426042af86a2 100644 --- a/src/box/ck_constraint.h +++ b/src/box/ck_constraint.h @@ -71,6 +71,11 @@ struct ck_constraint_def { * defined for. */ uint32_t space_id; + /** + * Per constraint option regulating its execution: it is + * disabled (set to false) contraint won't be fired. + */ + bool is_enabled; /** The language of ck constraint. */ enum ck_constraint_language language; /** @@ -140,6 +145,7 @@ ck_constraint_def_sizeof(uint32_t name_len, uint32_t expr_str_len, * @param expr_str_len The length of the @a expr string. * @param space_id The identifier of the target space. * @param language The language of the @a expr string. + * @param is_enabled Whether this ck constraint should be fired. * @retval not NULL Check constraint definition object pointer * on success. * @retval NULL Otherwise. The diag message is set. @@ -147,7 +153,7 @@ ck_constraint_def_sizeof(uint32_t name_len, uint32_t expr_str_len, struct ck_constraint_def * ck_constraint_def_new(const char *name, uint32_t name_len, const char *expr, uint32_t expr_str_len, uint32_t space_id, - enum ck_constraint_language language); + enum ck_constraint_language language, bool is_enabled); /** * Destroy check constraint definition memory, release acquired diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 98067f79558272a699b1705042668ce013d3ea7f..e898c3aa6b0e43c3c57b3311a5eae3b9b2c2c3ef 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1706,7 +1706,7 @@ space_mt.create_check_constraint = function(space, name, code) box.error(box.error.PROC_LUA, "Usage: space:create_constraint(name, code)") end - box.space._ck_constraint:insert({space.id, name, false, 'SQL', code}) + box.space._ck_constraint:insert({space.id, name, false, 'SQL', code, true}) return space.ck_constraint[name] end space_mt.pairs = function(space, key, opts) @@ -1759,6 +1759,20 @@ ck_constraint_mt.drop = function(ck_constraint) check_ck_constraint_arg(ck_constraint, 'drop') box.space._ck_constraint:delete({ck_constraint.space_id, ck_constraint.name}) end +ck_constraint_mt.enable = function(ck_constraint, yesno) + check_ck_constraint_arg(ck_constraint, 'enable') + local s = builtin.space_by_id(ck_constraint.space_id) + if s == nil then + box.error(box.error.NO_SUCH_SPACE, tostring(ck_constraint.space_id)) + end + local t = box.space._ck_constraint:get({ck_constraint.space_id, + ck_constraint.name}) + if t == nil then + box.error(box.error.NO_SUCH_CONSTRAINT, tostring(ck_constraint.name)) + end + box.space._ck_constraint:update({ck_constraint.space_id, ck_constraint.name}, + {{'=', 6, yesno}}) +end box.schema.index_mt = base_index_mt box.schema.memtx_index_mt = memtx_index_mt diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index d0a7e7815fd6ec5304ff0fc8715e3b3110edaeb7..8b84e1fb29750334ed2f7893bdaf7bc67abf325c 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -205,6 +205,9 @@ lbox_push_ck_constraint(struct lua_State *L, struct space *space, int i) lua_pushstring(L, ck_constraint->def->expr_str); lua_setfield(L, -2, "expr"); + lua_pushboolean(L, ck_constraint->def->is_enabled); + lua_setfield(L, -2, "is_enabled"); + lua_setfield(L, -2, ck_constraint->def->name); } lua_pop(L, 1); diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index 2abd75dffdde4d86eeb282a9d3d0a743ea134315..e71b7fb418701e560be51c49eaae9f8ab7f8766a 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -927,6 +927,19 @@ local function upgrade_to_2_3_0() datetime, datetime}) _priv:replace{ADMIN, PUBLIC, 'function', t.id, box.priv.X} end + + log.info("Extend _ck_constraint space format with is_enabled field") + local _ck_constraint = box.space._ck_constraint + for _, tuple in _ck_constraint:pairs() do + _ck_constraint:update({tuple[1], tuple[2]}, {{'=', 6, true}}) + end + local format = {{name='space_id', type='unsigned'}, + {name='name', type='string'}, + {name='is_deferred', type='boolean'}, + {name='language', type='str'}, + {name='code', type='str'}, + {name='is_enabled', type='boolean'}} + _ck_constraint:format(format) end -------------------------------------------------------------------------------- diff --git a/src/box/schema_def.h b/src/box/schema_def.h index 85f652d5203e714881b30828ed55cc68c5111b3a..ba870ff4254e417a0697e9c9b49f2fe0a17dfd4c 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -267,6 +267,7 @@ enum { BOX_CK_CONSTRAINT_FIELD_DEFERRED = 2, BOX_CK_CONSTRAINT_FIELD_LANGUAGE = 3, BOX_CK_CONSTRAINT_FIELD_CODE = 4, + BOX_CK_CONSTRAINT_FIELD_IS_ENABLED = 5, }; /** _func_index fields. */ diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 233f567340e588ff599396c5d813087dbf078998..51cd7ce63d18862b5eb781a48dd1398572e8e04f 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -982,7 +982,7 @@ vdbe_emit_ck_constraint_create(struct Parse *parser, * Occupy registers for 5 fields: each member in * _ck_constraint space plus one for final msgpack tuple. */ - int ck_constraint_reg = sqlGetTempRange(parser, 6); + int ck_constraint_reg = sqlGetTempRange(parser, 7); sqlVdbeAddOp2(v, OP_SCopy, reg_space_id, ck_constraint_reg); sqlVdbeAddOp4(v, OP_String8, 0, ck_constraint_reg + 1, 0, sqlDbStrDup(db, ck_def->name), P4_DYNAMIC); @@ -991,8 +991,9 @@ vdbe_emit_ck_constraint_create(struct Parse *parser, ck_constraint_language_strs[ck_def->language], P4_STATIC); sqlVdbeAddOp4(v, OP_String8, 0, ck_constraint_reg + 4, 0, sqlDbStrDup(db, ck_def->expr_str), P4_DYNAMIC); - sqlVdbeAddOp3(v, OP_MakeRecord, ck_constraint_reg, 5, - ck_constraint_reg + 5); + sqlVdbeAddOp2(v, OP_Bool, true, ck_constraint_reg + 5); + sqlVdbeAddOp3(v, OP_MakeRecord, ck_constraint_reg, 6, + ck_constraint_reg + 6); const char *error_msg = tt_sprintf(tnt_errcode_desc(ER_CONSTRAINT_EXISTS), ck_def->name); @@ -1002,9 +1003,9 @@ vdbe_emit_ck_constraint_create(struct Parse *parser, false, OP_NoConflict) != 0) return; sqlVdbeAddOp2(v, OP_SInsert, BOX_CK_CONSTRAINT_ID, - ck_constraint_reg + 5); + ck_constraint_reg + 6); VdbeComment((v, "Create CK constraint %s", ck_def->name)); - sqlReleaseTempRange(parser, ck_constraint_reg, 6); + sqlReleaseTempRange(parser, ck_constraint_reg, 7); } /** diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result index a59979e6286cb8b23b17dba90dd4c47a04fb2346..123aa2feb558ee2cb33de8378be39d7838f6c225 100644 --- a/test/box-py/bootstrap.result +++ b/test/box-py/bootstrap.result @@ -92,7 +92,8 @@ box.space._space:select{} {'name': 'child_cols', 'type': 'array'}, {'name': 'parent_cols', 'type': 'array'}]] - [364, 1, '_ck_constraint', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'is_deferred', 'type': 'boolean'}, - {'name': 'language', 'type': 'str'}, {'name': 'code', 'type': 'str'}]] + {'name': 'language', 'type': 'str'}, {'name': 'code', 'type': 'str'}, {'name': 'is_enabled', + 'type': 'boolean'}]] - [372, 1, '_func_index', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, {'name': 'index_id', 'type': 'unsigned'}, {'name': 'func_id', 'type': 'unsigned'}]] ... diff --git a/test/box/access_misc.result b/test/box/access_misc.result index a1b6435bcf882764dceb6ef4606da57bfefaeb1f..27eb47aa06bc31f24c75632cc1785a349eed6596 100644 --- a/test/box/access_misc.result +++ b/test/box/access_misc.result @@ -832,147 +832,148 @@ box.space._space:select() {'name': 'child_cols', 'type': 'array'}, {'name': 'parent_cols', 'type': 'array'}]] - [364, 1, '_ck_constraint', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, {'name': 'name', 'type': 'string'}, {'name': 'is_deferred', 'type': 'boolean'}, - {'name': 'language', 'type': 'str'}, {'name': 'code', 'type': 'str'}]] + {'name': 'language', 'type': 'str'}, {'name': 'code', 'type': 'str'}, {'name': 'is_enabled', + 'type': 'boolean'}]] - [372, 1, '_func_index', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, {'name': 'index_id', 'type': 'unsigned'}, {'name': 'func_id', 'type': 'unsigned'}]] ... box.space._func:select() --- - - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'function', [], 'any', 'none', 'none', - false, false, true, ['LUA'], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, ['LUA'], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [2, 1, 'TRIM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [3, 1, 'TYPEOF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [4, 1, 'PRINTF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [5, 1, 'UNICODE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [6, 1, 'CHAR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [7, 1, 'HEX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [8, 1, 'VERSION', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [9, 1, 'QUOTE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [10, 1, 'REPLACE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [11, 1, 'SUBSTR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [12, 1, 'GROUP_CONCAT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [13, 1, 'JULIANDAY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [14, 1, 'DATE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [15, 1, 'TIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [16, 1, 'DATETIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [17, 1, 'STRFTIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [18, 1, 'CURRENT_TIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [19, 1, 'CURRENT_TIMESTAMP', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + 'none', false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [20, 1, 'CURRENT_DATE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [21, 1, 'LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [22, 1, 'POSITION', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [23, 1, 'ROUND', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [24, 1, 'UPPER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [25, 1, 'LOWER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [26, 1, 'IFNULL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [27, 1, 'RANDOM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [28, 1, 'CEIL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [29, 1, 'CEILING', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [30, 1, 'CHARACTER_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + 'none', false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [31, 1, 'CHAR_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [32, 1, 'FLOOR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [33, 1, 'MOD', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [34, 1, 'OCTET_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [35, 1, 'ROW_COUNT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [36, 1, 'COUNT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [37, 1, 'LIKE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [38, 1, 'ABS', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [39, 1, 'EXP', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [40, 1, 'LN', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [41, 1, 'POWER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [42, 1, 'SQRT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [43, 1, 'SUM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [44, 1, 'TOTAL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [45, 1, 'AVG', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [46, 1, 'RANDOMBLOB', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [47, 1, 'NULLIF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [48, 1, 'ZEROBLOB', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [49, 1, 'MIN', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [50, 1, 'MAX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [51, 1, 'COALESCE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [52, 1, 'EVERY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [53, 1, 'EXISTS', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [54, 1, 'EXTRACT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [55, 1, 'SOME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [56, 1, 'GREATER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [57, 1, 'LESSER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [58, 1, 'SOUNDEX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [59, 1, 'LIKELIHOOD', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [60, 1, 'LIKELY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [61, 1, 'UNLIKELY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [62, 1, '_sql_stat_get', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + 'none', false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [63, 1, '_sql_stat_push', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + 'none', false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [64, 1, '_sql_stat_init', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + 'none', false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [65, 1, 'LUA', 1, 'LUA', 'function(code) return assert(loadstring(code))() end', 'function', ['string'], 'any', 'none', 'none', false, false, true, ['LUA', 'SQL'], - {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [66, 1, 'GREATEST', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] - [67, 1, 'LEAST', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] + false, false, true, [], {}, '', '2019-10-07 13:46:37', '2019-10-07 13:46:37'] ... session = nil --- diff --git a/test/sql/checks.result b/test/sql/checks.result index 50347bc3a929ec3199100ae4a8ad300444212b5d..72b1fa26f73040290733914026e82a1a90618693 100644 --- a/test/sql/checks.result +++ b/test/sql/checks.result @@ -37,35 +37,35 @@ _ = box.space.test:create_index('pk') --- ... -- Invalid expression test. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5', true}) --- - error: 'Failed to create check constraint ''CK_CONSTRAINT_01'': Syntax error near ''<''' ... -- Non-existent space test. -box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) --- - error: Space '550' does not exist ... -- Pass integer instead of expression. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 666}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 666, true}) --- - error: 'Tuple field 5 type does not match one required by operation: expected string' ... -- Deferred CK constraints are not supported. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', true, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', true, 'SQL', 'X<5', true}) --- - error: Tarantool does not support deferred ck constraints ... -- The only supported language is SQL. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'LUA', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'LUA', 'X<5', true}) --- - error: Unsupported language 'LUA' specified for function 'CK_CONSTRAINT_01' ... -- Check constraints LUA creation test. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) --- -- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'] +- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true] ... box.space._ck_constraint:count({}) --- @@ -80,9 +80,9 @@ box.space.test:insert({5}) --- - error: 'Check constraint failed ''CK_CONSTRAINT_01'': X<5' ... -box.space._ck_constraint:replace({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +box.space._ck_constraint:replace({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) --- -- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'] +- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true] ... box.execute("INSERT INTO \"test\" VALUES(5);") --- @@ -111,7 +111,7 @@ box.space._space:delete({513}) ... box.space._ck_constraint:delete({513, 'CK_CONSTRAINT_01'}) --- -- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'] +- [513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true] ... box.space._space:delete({513}) --- @@ -177,14 +177,14 @@ s = box.schema.create_space('test', {engine = engine}) _ = s:create_index('pk') --- ... -_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'}) +_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y', true}) --- - error: Tarantool does not support CK constraint for space without format ... s:format({{name='X', type='integer'}, {name='Y', type='integer'}}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'}) +_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y', true}) --- ... box.execute("INSERT INTO \"test\" VALUES(2, 1);") @@ -229,7 +229,7 @@ s:insert({2, 1}) --- - [2, 1] ... -_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'}) +_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10', true}) --- - error: 'Failed to create check constraint ''conflict'': referencing space must be empty' @@ -237,7 +237,7 @@ _ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'}) s:truncate() --- ... -_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'}) +_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10', true}) --- ... box.execute("INSERT INTO \"test\" VALUES(1, 2);") @@ -332,7 +332,7 @@ _ = s:create_index('pk') s:format({{name='X', type='any'}, {name='Y', type='integer'}, {name='Z', type='integer', is_nullable=true}}) --- ... -ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'X = 1 AND Z IS NOT NULL'}) +ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'X = 1 AND Z IS NOT NULL', true}) --- ... s:insert({2, 1}) @@ -374,7 +374,7 @@ _ = s:create_index('pk') s:format({{name='X', type='any'}, {name='Y', type='integer'}, {name='Z', type='integer', is_nullable=true}}) --- ... -ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'Z IS NOT NULL'}) +ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'Z IS NOT NULL', true}) --- ... s:insert({1, 2, box.NULL}) @@ -388,7 +388,7 @@ s:insert({1, 2}) _ = box.space._ck_constraint:delete({s.id, 'ZnotNULL'}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y and Y < Z'}) +_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y and Y < Z', true}) --- ... s:insert({'1', 2}) @@ -464,7 +464,7 @@ _ = s:create_index('pk', {parts = {3, 'integer'}}) _ = s:create_index('unique', {parts = {1, 'integer'}}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'complex1', false, 'SQL', 'x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x == y+10'}) +_ = box.space._ck_constraint:insert({s.id, 'complex1', false, 'SQL', 'x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x == y+10', true}) --- ... s:insert({1, 10, 1}) @@ -513,7 +513,7 @@ s:format({{name='X', type='integer'}, {name='Z', type='any'}}) _ = s:create_index('pk', {parts = {1, 'integer'}}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\''}) +_ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\'', true}) --- ... s:insert({1, 'string'}) @@ -564,7 +564,7 @@ test_run:cmd("setopt delimiter ''"); s:format(format65) --- ... -_ = box.space._ck_constraint:insert({s.id, 'X1is666andX65is666', false, 'SQL', 'X1 == 666 and X65 == 666 and X63 IS NOT NULL'}) +_ = box.space._ck_constraint:insert({s.id, 'X1is666andX65is666', false, 'SQL', 'X1 == 666 and X65 == 666 and X63 IS NOT NULL', true}) --- ... s:insert(s:frommap({X1 = 1, X65 = 1})) @@ -642,24 +642,28 @@ _ = s2:create_check_constraint('greater', 'X > 20') s1.ck_constraint.physics --- - space_id: <ID> + is_enabled: true name: physics expr: X < Y ... s1.ck_constraint.greater --- - space_id: <ID> + is_enabled: true name: greater expr: X > 20 ... s2.ck_constraint.physics --- - space_id: <ID> + is_enabled: true name: physics expr: X > Y ... s2.ck_constraint.greater --- - space_id: <ID> + is_enabled: true name: greater expr: X > 20 ... @@ -685,6 +689,7 @@ s2.ck_constraint.greater:drop() s2.ck_constraint.physics --- - space_id: <ID> + is_enabled: true name: physics expr: X > Y ... @@ -716,12 +721,75 @@ s2:drop() physics_ck --- - space_id: <ID> + is_enabled: true name: physics expr: X > Y ... physics_ck:drop() --- ... +-- +-- gh-4244: Add an ability to disable CK constraints +-- Make sure that ck constraints are turned on/off with +-- :enable configurator. +-- +engine = test_run:get_cfg('engine') +--- +... +box.execute('pragma sql_default_engine=\''..engine..'\'') +--- +- row_count: 0 +... +box.execute("CREATE TABLE test(a INT PRIMARY KEY);"); +--- +- row_count: 1 +... +box.execute('ALTER TABLE test ADD CONSTRAINT CK CHECK(a < 5);') +--- +- row_count: 1 +... +box.space.TEST:insert({10}) +--- +- error: 'Check constraint failed ''CK'': a < 5' +... +box.space.TEST.ck_constraint.CK:enable(false) +--- +... +assert(box.space.TEST.ck_constraint.CK.is_enabled == false) +--- +- true +... +box.space.TEST:insert({11}) +--- +- [11] +... +-- Test is_enabled state persistency. +test_run:cmd("restart server default") +test_run = require('test_run').new() +--- +... +test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '") +--- +- true +... +box.space.TEST:insert({12}) +--- +- [12] +... +box.space.TEST.ck_constraint.CK:enable(true) +--- +... +assert(box.space.TEST.ck_constraint.CK.is_enabled == true) +--- +- true +... +box.space.TEST:insert({13}) +--- +- error: 'Check constraint failed ''CK'': a < 5' +... +box.space.TEST:drop() +--- +... test_run:cmd("clear filter") --- - true diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua index cde213f8b6586a08c0a6931324f35bdc2eaf3ab1..11918dceddae8fc4f3ef8116f52696ac530dba6a 100644 --- a/test/sql/checks.test.lua +++ b/test/sql/checks.test.lua @@ -18,23 +18,23 @@ s = box.space._space:insert(t) _ = box.space.test:create_index('pk') -- Invalid expression test. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X><5', true}) -- Non-existent space test. -box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({550, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) -- Pass integer instead of expression. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 666}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 666, true}) -- Deferred CK constraints are not supported. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', true, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', true, 'SQL', 'X<5', true}) -- The only supported language is SQL. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'LUA', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'LUA', 'X<5', true}) -- Check constraints LUA creation test. -box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +box.space._ck_constraint:insert({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) box.space._ck_constraint:count({}) box.execute("INSERT INTO \"test\" VALUES(5);") box.space.test:insert({5}) -box.space._ck_constraint:replace({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +box.space._ck_constraint:replace({513, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) box.execute("INSERT INTO \"test\" VALUES(5);") box.execute("INSERT INTO \"test\" VALUES(6);") box.space.test:insert({6}) @@ -64,9 +64,9 @@ box.space._ck_constraint:count() == 0 -- Ck constraints are disallowed for spaces having no format. s = box.schema.create_space('test', {engine = engine}) _ = s:create_index('pk') -_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'}) +_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y', true}) s:format({{name='X', type='integer'}, {name='Y', type='integer'}}) -_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y'}) +_ = box.space._ck_constraint:insert({s.id, 'physics', false, 'SQL', 'X<Y', true}) box.execute("INSERT INTO \"test\" VALUES(2, 1);") s:format({{name='Y', type='integer'}, {name='X', type='integer'}}) box.execute("INSERT INTO \"test\" VALUES(1, 2);") @@ -78,9 +78,9 @@ s:format() s:format({{name='Y1', type='integer'}, {name='X1', type='integer'}}) -- Ck constraint creation is forbidden for non-empty space s:insert({2, 1}) -_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'}) +_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10', true}) s:truncate() -_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10'}) +_ = box.space._ck_constraint:insert({s.id, 'conflict', false, 'SQL', 'X>10', true}) box.execute("INSERT INTO \"test\" VALUES(1, 2);") box.execute("INSERT INTO \"test\" VALUES(11, 11);") box.execute("INSERT INTO \"test\" VALUES(12, 11);") @@ -114,7 +114,7 @@ box.execute("DROP TABLE t1") s = box.schema.create_space('test', {engine = engine}) _ = s:create_index('pk') s:format({{name='X', type='any'}, {name='Y', type='integer'}, {name='Z', type='integer', is_nullable=true}}) -ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'X = 1 AND Z IS NOT NULL'}) +ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'X = 1 AND Z IS NOT NULL', true}) s:insert({2, 1}) s:insert({1, 1}) s:insert({1, 1, box.NULL}) @@ -129,11 +129,11 @@ s:drop() s = box.schema.create_space('test', {engine = engine}) _ = s:create_index('pk') s:format({{name='X', type='any'}, {name='Y', type='integer'}, {name='Z', type='integer', is_nullable=true}}) -ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'Z IS NOT NULL'}) +ck_not_null = box.space._ck_constraint:insert({s.id, 'ZnotNULL', false, 'SQL', 'Z IS NOT NULL', true}) s:insert({1, 2, box.NULL}) s:insert({1, 2}) _ = box.space._ck_constraint:delete({s.id, 'ZnotNULL'}) -_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y and Y < Z'}) +_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y and Y < Z', true}) s:insert({'1', 2}) s:insert({}) s:insert({2, 1}) @@ -157,7 +157,7 @@ s = box.schema.create_space('test', {engine = engine}) s:format({{name='X', type='integer'}, {name='Y', type='integer'}, {name='Z', type='integer'}}) _ = s:create_index('pk', {parts = {3, 'integer'}}) _ = s:create_index('unique', {parts = {1, 'integer'}}) -_ = box.space._ck_constraint:insert({s.id, 'complex1', false, 'SQL', 'x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x == y+10'}) +_ = box.space._ck_constraint:insert({s.id, 'complex1', false, 'SQL', 'x+y==11 OR x*y==12 OR x/y BETWEEN 5 AND 8 OR -x == y+10', true}) s:insert({1, 10, 1}) s:update({1}, {{'=', 1, 4}, {'=', 2, 3}}) s:update({1}, {{'=', 1, 12}, {'=', 2, 2}}) @@ -171,7 +171,7 @@ s:drop() s = box.schema.create_space('test', {engine = engine}) s:format({{name='X', type='integer'}, {name='Z', type='any'}}) _ = s:create_index('pk', {parts = {1, 'integer'}}) -_ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\''}) +_ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\'', true}) s:insert({1, 'string'}) s:insert({1, {map=true}}) s:insert({1, {'a', 'r','r','a','y'}}) @@ -191,7 +191,7 @@ for i = 1,66 do end test_run:cmd("setopt delimiter ''"); s:format(format65) -_ = box.space._ck_constraint:insert({s.id, 'X1is666andX65is666', false, 'SQL', 'X1 == 666 and X65 == 666 and X63 IS NOT NULL'}) +_ = box.space._ck_constraint:insert({s.id, 'X1is666andX65is666', false, 'SQL', 'X1 == 666 and X65 == 666 and X63 IS NOT NULL', true}) s:insert(s:frommap({X1 = 1, X65 = 1})) s:insert(s:frommap({X1 = 666, X65 = 1})) s:insert(s:frommap({X1 = 1, X65 = 666})) @@ -234,4 +234,27 @@ s2:drop() physics_ck physics_ck:drop() +-- +-- gh-4244: Add an ability to disable CK constraints +-- Make sure that ck constraints are turned on/off with +-- :enable configurator. +-- +engine = test_run:get_cfg('engine') +box.execute('pragma sql_default_engine=\''..engine..'\'') +box.execute("CREATE TABLE test(a INT PRIMARY KEY);"); +box.execute('ALTER TABLE test ADD CONSTRAINT CK CHECK(a < 5);') +box.space.TEST:insert({10}) +box.space.TEST.ck_constraint.CK:enable(false) +assert(box.space.TEST.ck_constraint.CK.is_enabled == false) +box.space.TEST:insert({11}) +-- Test is_enabled state persistency. +test_run:cmd("restart server default") +test_run = require('test_run').new() +test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '") +box.space.TEST:insert({12}) +box.space.TEST.ck_constraint.CK:enable(true) +assert(box.space.TEST.ck_constraint.CK.is_enabled == true) +box.space.TEST:insert({13}) +box.space.TEST:drop() + test_run:cmd("clear filter") diff --git a/test/sql/errinj.result b/test/sql/errinj.result index ecc194fb88bb23eacb73495f80b3a79fa176b971..7ab522f493eb2a6e20394e84ed40ade7f8aca4ae 100644 --- a/test/sql/errinj.result +++ b/test/sql/errinj.result @@ -410,7 +410,7 @@ errinj.set("ERRINJ_WAL_IO", true) --- - ok ... -_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) --- - error: Failed to write to disk ... @@ -418,7 +418,7 @@ errinj.set("ERRINJ_WAL_IO", false) --- - ok ... -_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) --- ... box.execute("INSERT INTO \"test\" VALUES(5);") @@ -430,7 +430,7 @@ errinj.set("ERRINJ_WAL_IO", true) --- - ok ... -_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) --- - error: Failed to write to disk ... @@ -438,7 +438,7 @@ errinj.set("ERRINJ_WAL_IO", false) --- - ok ... -_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) --- ... box.execute("INSERT INTO \"test\" VALUES(5);") @@ -484,10 +484,10 @@ _ = s:create_index('pk') s:format({{name='X', type='integer'}, {name='Y', type='integer'}}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y'}) +_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y', true}) --- ... -_ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10'}) +_ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10', true}) --- ... box.execute("INSERT INTO \"test\" VALUES(1, 2);") diff --git a/test/sql/errinj.test.lua b/test/sql/errinj.test.lua index 2b4f74a8220a7cf23ad5f03501885ffb64dfffce..b978767ada6f6cf6d46994f1f302a0883897d6ec 100644 --- a/test/sql/errinj.test.lua +++ b/test/sql/errinj.test.lua @@ -126,14 +126,14 @@ s = box.schema.space.create('test', {format = {{name = 'X', type = 'unsigned'}}} pk = box.space.test:create_index('pk') errinj.set("ERRINJ_WAL_IO", true) -_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) errinj.set("ERRINJ_WAL_IO", false) -_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5'}) +_ = box.space._ck_constraint:insert({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<5', true}) box.execute("INSERT INTO \"test\" VALUES(5);") errinj.set("ERRINJ_WAL_IO", true) -_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) errinj.set("ERRINJ_WAL_IO", false) -_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5'}) +_ = box.space._ck_constraint:replace({s.id, 'CK_CONSTRAINT_01', false, 'SQL', 'X<=5', true}) box.execute("INSERT INTO \"test\" VALUES(5);") errinj.set("ERRINJ_WAL_IO", true) _ = box.space._ck_constraint:delete({s.id, 'CK_CONSTRAINT_01'}) @@ -149,8 +149,8 @@ s:drop() s = box.schema.create_space('test') _ = s:create_index('pk') s:format({{name='X', type='integer'}, {name='Y', type='integer'}}) -_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y'}) -_ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10'}) +_ = box.space._ck_constraint:insert({s.id, 'XlessY', false, 'SQL', 'X < Y', true}) +_ = box.space._ck_constraint:insert({s.id, 'Xgreater10', false, 'SQL', 'X > 10', true}) box.execute("INSERT INTO \"test\" VALUES(1, 2);") box.execute("INSERT INTO \"test\" VALUES(20, 10);") box.execute("INSERT INTO \"test\" VALUES(20, 100);")