[tarantool-patches] [PATCH v3 1/4] box: an ability to disable CK constraints

Kirill Shcherbatov kshcherbatov at tarantool.org
Mon Sep 16 15:47:09 MSK 2019


Now it is possible to disable and enable ck constraints in LUA.
This option is not persistent. All ck constraints are enabled
by default when Tarantool is configured. Ck constraints checks
are not performed during standard recovery, but performed during
force_recovery - all conflicting tuples are skipped in case of
ck_constraint conflict.

Part of #4244
---
 extra/exports            |  1 +
 src/box/ck_constraint.c  | 19 ++++++++++++++++++-
 src/box/ck_constraint.h  | 18 ++++++++++++++++++
 src/box/lua/schema.lua   | 12 ++++++++++++
 src/box/lua/space.cc     |  3 +++
 src/box/memtx_engine.c   |  1 +
 test/sql/checks.result   | 40 ++++++++++++++++++++++++++++++++++++++++
 test/sql/checks.test.lua | 14 ++++++++++++++
 8 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/extra/exports b/extra/exports
index 7b84a1452..a24ace4b8 100644
--- a/extra/exports
+++ b/extra/exports
@@ -78,6 +78,7 @@ tarantool_exit
 log_pid
 space_by_id
 space_run_triggers
+space_ck_constraint_set_state
 space_bsize
 box_schema_version
 
diff --git a/src/box/ck_constraint.c b/src/box/ck_constraint.c
index 1cde27022..b422c2f3e 100644
--- a/src/box/ck_constraint.c
+++ b/src/box/ck_constraint.c
@@ -28,6 +28,7 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+#include "memtx_engine.h"
 #include "box/session.h"
 #include "bind.h"
 #include "ck_constraint.h"
@@ -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->is_enabled &&
+		    ck_constraint_program_run(ck_constraint, field_ref) != 0)
 			diag_raise();
 	}
 }
@@ -223,6 +225,8 @@ ck_constraint_new(struct ck_constraint_def *ck_constraint_def,
 	}
 	ck_constraint->def = NULL;
 	ck_constraint->stmt = NULL;
+	ck_constraint->is_enabled = true;
+
 	rlist_create(&ck_constraint->link);
 	struct Expr *expr =
 		sql_expr_compile(sql_get(), ck_constraint_def->expr_str,
@@ -269,3 +273,16 @@ space_ck_constraint_by_name(struct space *space, const char *name,
 	}
 	return NULL;
 }
+
+int
+space_ck_constraint_set_state(struct space *space, const char *name,
+			      bool new_state)
+{
+	struct ck_constraint *ck =
+		space_ck_constraint_by_name(space, name, strlen(name));
+	if (ck == NULL)
+		return -1;
+	ck->is_enabled = new_state;
+	(void) trigger_run(&on_alter_space, space);
+	return 0;
+}
diff --git a/src/box/ck_constraint.h b/src/box/ck_constraint.h
index f26f77a38..8fc2c5789 100644
--- a/src/box/ck_constraint.h
+++ b/src/box/ck_constraint.h
@@ -93,6 +93,11 @@ struct ck_constraint {
 	 * message when ck condition unsatisfied.
 	 */
 	struct sql_stmt *stmt;
+	/**
+	 * Per constraint option regulating its execution: it is
+	 * disabled (set to false) contraint won't be fired.
+	 */
+	bool is_enabled;
 	/**
 	 * Organize check constraint structs into linked list
 	 * with space::ck_constraint.
@@ -214,6 +219,19 @@ struct ck_constraint *
 space_ck_constraint_by_name(struct space *space, const char *name,
 			    uint32_t name_len);
 
+/**
+ * Find check constraint object in a given space by a given name
+ * and change it's is_enabled state.
+ * @param space The space to lookup check constraint.
+ * @param name The check constraint name.
+ * @param new_state The new is_enabled state for ck constraint.
+ * @return 0 if ck constraint is successfully found and new
+ *         is_enabled value is set, -1 otherwise.
+ */
+int
+space_ck_constraint_set_state(struct space *space, const char *name,
+			      bool new_state);
+
 #if defined(__cplusplus)
 } /* extern "C" { */
 #endif
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 98067f795..3154e4df3 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -29,6 +29,8 @@ ffi.cdef[[
     struct space *space_by_id(uint32_t id);
     extern uint32_t box_schema_version();
     void space_run_triggers(struct space *space, bool yesno);
+    void space_ck_constraint_set_state(struct space *space, const char *name,
+                                       bool new_state);
     size_t space_bsize(struct space *space);
 
     typedef struct tuple box_tuple_t;
@@ -1759,6 +1761,16 @@ 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
+    if builtin.space_ck_constraint_set_state(s, ck_constraint.name, yesno) ~= nil then
+        box.error(box.error.NO_SUCH_CONSTRAINT, tostring(ck_constraint.name))
+    end
+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 d0a7e7815..2c686e818 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->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/memtx_engine.c b/src/box/memtx_engine.c
index eb11346c1..b78034217 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -35,6 +35,7 @@
 #include <small/small.h>
 #include <small/mempool.h>
 
+#include "ck_constraint.h"
 #include "fiber.h"
 #include "errinj.h"
 #include "coio_file.h"
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 50347bc3a..0ca49203c 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -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,47 @@ 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 CHECK (a < 5) primary key);");
+---
+- row_count: 1
+...
+box.space.TEST:insert({10})
+---
+- error: 'Check constraint failed ''ck_unnamed_TEST_1'': a < 5'
+...
+box.space.TEST.ck_constraint.ck_unnamed_TEST_1:enable(false)
+---
+...
+box.space.TEST:insert({11})
+---
+- [11]
+...
+box.space.TEST.ck_constraint.ck_unnamed_TEST_1:enable(true)
+---
+...
+box.space.TEST:insert({12})
+---
+- error: 'Check constraint failed ''ck_unnamed_TEST_1'': a < 5'
+...
 test_run:cmd("clear filter")
 ---
 - true
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index cde213f8b..db5d0b05f 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -234,4 +234,18 @@ 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 CHECK (a < 5) primary key);");
+box.space.TEST:insert({10})
+box.space.TEST.ck_constraint.ck_unnamed_TEST_1:enable(false)
+box.space.TEST:insert({11})
+box.space.TEST.ck_constraint.ck_unnamed_TEST_1:enable(true)
+box.space.TEST:insert({12})
+
 test_run:cmd("clear filter")
-- 
2.23.0





More information about the Tarantool-patches mailing list