Tarantool development patches archive
 help / color / mirror / Atom feed
From: Kirill Shcherbatov <kshcherbatov@tarantool.org>
To: tarantool-patches@freelists.org
Cc: v.shpilevoy@tarantool.org,
	Kirill Shcherbatov <kshcherbatov@tarantool.org>
Subject: [tarantool-patches] [PATCH v7 7/7] sql: remove Checks to server
Date: Wed, 23 May 2018 17:05:34 +0300	[thread overview]
Message-ID: <2baee418a3799c91c5a8b92ac62e59de3456da0d.1527084287.git.kshcherbatov@tarantool.org> (raw)
In-Reply-To: <cover.1527084286.git.kshcherbatov@tarantool.org>
In-Reply-To: <cover.1527084286.git.kshcherbatov@tarantool.org>

New server checks stored in space_opts. For ExprList transfering
to server data is packed in msgpack as array of maps:
[{"expr_str": "x < y", "name" : "FIRST"}, ..]
Introduced checks_array_decode aimed to unpack this
complex package.
Introduced sql_checks_update_space_def_reference to update space
references as space_def pointer changes over the time,
i.e. resolved checks refer released memory.

Resolves #3272.
---
 src/box/alter.cc            |   5 +++
 src/box/opt_def.h           |   5 ++-
 src/box/space_def.c         |  96 +++++++++++++++++++++++++++++++++++++++
 src/box/space_def.h         |  12 ++---
 src/box/sql.c               | 107 +++++++++++++++++++++++++++++++++++++++++++-
 src/box/sql.h               |  43 ++++++++++++++++++
 src/box/sql/build.c         |  65 +++++++++++++++++++--------
 src/box/sql/insert.c        |  33 ++++++++------
 src/box/sql/pragma.h        |   2 -
 src/box/sql/resolve.c       |   2 -
 src/box/sql/sqliteInt.h     |   1 -
 test/sql-tap/check.test.lua |  10 ++---
 12 files changed, 329 insertions(+), 52 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index e4780da..b379da2 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -523,6 +523,11 @@ space_def_new_from_tuple(struct tuple *tuple, uint32_t errcode,
 		space_def_new_xc(id, uid, exact_field_count, name, name_len,
 				 engine_name, engine_name_len, &opts, fields,
 				 field_count);
+	if (def->opts.checks != NULL &&
+	    sql_checks_resolve_space_def_reference(def->opts.checks, def) != 0){
+		tnt_raise(ClientError, errcode, def->name,
+			  box_error_message(box_error_last()));
+	}
 	auto def_guard = make_scoped_guard([=] { space_def_delete(def); });
 	struct engine *engine = engine_find_xc(def->engine_name);
 	engine_check_space_def_xc(engine, def);
diff --git a/src/box/opt_def.h b/src/box/opt_def.h
index 71fef3a..91e4f0b 100644
--- a/src/box/opt_def.h
+++ b/src/box/opt_def.h
@@ -79,11 +79,12 @@ struct opt_def {
 
 #define OPT_DEF_ENUM(key, enum_name, opts, field, to_enum) \
 	{ key, OPT_ENUM, offsetof(opts, field), sizeof(int), #enum_name, \
-	  sizeof(enum enum_name), enum_name##_strs, enum_name##_MAX, {to_enum} }
+	  sizeof(enum enum_name), enum_name##_strs, enum_name##_MAX, \
+	  { to_enum } }
 
 #define OPT_DEF_ARRAY(key, opts, field, to_array) \
 	 { key, OPT_ARRAY, offsetof(opts, field), sizeof(((opts *)0)->field), \
-	   NULL, 0, NULL, 0, {to_array} }
+	   NULL, 0, NULL, 0, { (void *)to_array} }
 
 #define OPT_END {NULL, opt_type_MAX, 0, 0, NULL, 0, NULL, 0, {NULL}}
 
diff --git a/src/box/space_def.c b/src/box/space_def.c
index 9e0e7e3..7bff86f 100644
--- a/src/box/space_def.c
+++ b/src/box/space_def.c
@@ -33,17 +33,33 @@
 #include "diag.h"
 #include "error.h"
 #include "sql.h"
+#include "msgpuck.h"
+
+/**
+ * Make checks from msgpack.
+ * @param str pointer to array of maps
+ *         e.g. [{"expr_str": "x < y", "name": "ONE"}, ..].
+ * @param len array items count.
+ * @param opt pointer to store parsing result.
+ * @retval not NULL Checks pointer on success.
+ * @retval NULL on error.
+ */
+static int
+checks_array_decode(const char **str, uint32_t len, char *opt);
 
 const struct space_opts space_opts_default = {
 	/* .temporary = */ false,
 	/* .view = */ false,
 	/* .sql        = */ NULL,
+	/* .checks     = */ NULL,
 };
 
 const struct opt_def space_opts_reg[] = {
 	OPT_DEF("temporary", OPT_BOOL, struct space_opts, temporary),
 	OPT_DEF("view", OPT_BOOL, struct space_opts, is_view),
 	OPT_DEF("sql", OPT_STRPTR, struct space_opts, sql),
+	OPT_DEF_ARRAY("checks", struct space_opts, checks,
+		checks_array_decode),
 	OPT_END,
 };
 
@@ -122,6 +138,19 @@ space_def_dup(const struct space_def *src)
 			}
 		}
 	}
+	if (src->opts.checks != NULL) {
+		ret->opts.checks =
+			sql_expr_list_dup(sql_get(), src->opts.checks, 0);
+		if (ret->opts.checks == NULL) {
+			diag_set(OutOfMemory, 0, "sql_expr_list_dup",
+				 "ret->opts.checks");
+			space_def_destroy_fields(ret->fields, ret->field_count);
+			free(ret->opts.sql);
+			free(ret);
+			return NULL;
+		}
+		sql_checks_update_space_def_reference(ret->opts.checks, ret);
+	}
 	tuple_dictionary_ref(ret->dict);
 	return ret;
 }
@@ -207,6 +236,18 @@ space_def_new(uint32_t id, uint32_t uid, uint32_t exact_field_count,
 			}
 		}
 	}
+	if (opts->checks != NULL) {
+		def->opts.checks = sql_expr_list_dup(sql_get(), opts->checks, 0);
+		if (def->opts.checks == NULL) {
+			diag_set(OutOfMemory, 0, "sql_expr_list_dup",
+				 "def->opts.checks");
+			space_def_destroy_fields(def->fields, def->field_count);
+			free(def->opts.sql);
+			free(def);
+			return NULL;
+		}
+		sql_checks_update_space_def_reference(def->opts.checks, def);
+	}
 	return def;
 }
 
@@ -231,3 +272,58 @@ space_def_delete(struct space_def *def)
 	TRASH(def);
 	free(def);
 }
+
+void
+space_opts_destroy(struct space_opts *opts)
+{
+	free(opts->sql);
+	sql_expr_list_delete(sql_get(), opts->checks);
+	TRASH(opts);
+}
+
+static int
+checks_array_decode(const char **str, uint32_t len, char *opt)
+{
+	struct ExprList *checks = NULL;
+	const char **map = str;
+	struct sqlite3 *db = sql_get();
+	for (unsigned i = 0; i < len; i++) {
+		checks = sql_expr_list_append(db, checks, NULL);
+		if (checks == NULL) {
+			diag_set(OutOfMemory, 0, "sql_expr_list_append",
+				 "pChecks");
+			goto error;
+		}
+		const char *expr_name = NULL;
+		const char *expr_str = NULL;
+		uint32_t expr_name_len = 0;
+		uint32_t expr_str_len = 0;
+		uint32_t map_size = mp_decode_map(map);
+		for (unsigned j = 0; j < map_size; j++) {
+			if (mp_typeof(**map) != MP_STR) {
+				diag_set(ClientError, ER_WRONG_INDEX_OPTIONS, 0,
+					 "key must be a string");
+				goto error;
+			}
+			uint32_t key_len;
+			const char *key = mp_decode_str(map, &key_len);
+			if (strncmp(key, "expr_str", key_len) == 0) {
+				expr_str = mp_decode_str(map, &expr_str_len);
+			} else if (strncmp(key, "name", key_len) == 0) {
+				expr_name = mp_decode_str(map, &expr_name_len);
+			} else {
+				diag_set(ClientError, ER_WRONG_INDEX_OPTIONS, 0,
+					 "invalid MsgPack");
+				goto error;
+			}
+		}
+		sql_check_list_item_init(checks, i, expr_name,
+					 expr_name_len, expr_str,
+					 expr_str_len);
+	}
+	*(void **)opt = checks;
+	return 0;
+error:
+	sql_expr_list_delete(db, checks);
+	return  -1;
+}
diff --git a/src/box/space_def.h b/src/box/space_def.h
index 5328203..e9bd283 100644
--- a/src/box/space_def.h
+++ b/src/box/space_def.h
@@ -61,6 +61,10 @@ struct space_opts {
 	 * SQL statement that produced this space.
 	 */
 	char *sql;
+	/**
+	* SQL Checks expressions list.
+	*/
+	struct ExprList *checks;
 };
 
 extern const struct space_opts space_opts_default;
@@ -79,12 +83,8 @@ space_opts_create(struct space_opts *opts)
 /**
  * Destroy space options
  */
-static inline void
-space_opts_destroy(struct space_opts *opts)
-{
-	free(opts->sql);
-	TRASH(opts);
-}
+void
+space_opts_destroy(struct space_opts *opts);
 
 /** Space metadata. */
 struct space_def {
diff --git a/src/box/sql.c b/src/box/sql.c
index 0845e65..d62e14c 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1508,13 +1508,49 @@ int tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, void *buf)
 	bool is_view = false;
 	if (pTable != NULL)
 		is_view = pTable->def->opts.is_view;
-	p = enc->encode_map(base, is_view ? 2 : 1);
+
+	bool has_checks = (pTable != NULL && pTable->def->opts.checks != NULL);
+	int checks_cnt = has_checks ? pTable->def->opts.checks->nExpr : 0;
+
+	int map_fields = 1;
+	map_fields += is_view == true;
+	map_fields += (checks_cnt > 0);
+	p = enc->encode_map(base, map_fields);
+
 	p = enc->encode_str(p, "sql", 3);
 	p = enc->encode_str(p, zSql, strlen(zSql));
 	if (is_view) {
 		p = enc->encode_str(p, "view", 4);
 		p = enc->encode_bool(p, true);
 	}
+	if (checks_cnt == 0)
+		return (int)(p - base);
+	/* Encode checks. */
+	struct ExprList_item *a = pTable->def->opts.checks->a;
+	p = enc->encode_str(p, "checks", 6);
+	p = enc->encode_array(p, checks_cnt);
+	for (int i = 0; i < checks_cnt; ++i) {
+		int items = 0;
+		items += a[i].pExpr != NULL;
+		items += a[i].zName != NULL;
+		p = enc->encode_map(p, items);
+		/*
+		 * a[i].pExpr could be NULL for VIEW column names
+		 * represented as checks.
+		 */
+		if (a[i].pExpr != NULL) {
+			Expr *pExpr = a[i].pExpr;
+			assert(pExpr->u.zToken != NULL);
+			p = enc->encode_str(p, "expr_str", 8);
+			p = enc->encode_str(p, pExpr->u.zToken,
+					    strlen(pExpr->u.zToken));
+		}
+		if (a[i].zName != NULL) {
+			p = enc->encode_str(p, "name", 10);
+			p = enc->encode_str(p, a[i].zName,
+					    strlen(a[i].zName));
+		}
+	}
 	return (int)(p - base);
 }
 
@@ -1761,3 +1797,72 @@ sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable)
 	pTable->def->opts.temporary = false;
 	return 0;
 }
+
+int
+sql_check_list_item_init(struct ExprList *expr_list, int idx,
+			 const char *expr_name, uint32_t expr_name_len,
+			 const char *expr_str, uint32_t expr_str_len)
+{
+	assert(idx < expr_list->nExpr);
+	struct ExprList_item *item = &expr_list->a[idx];
+	memset(item, 0, sizeof(struct ExprList_item));
+	if (expr_name != NULL) {
+		item->zName = sqlite3DbStrNDup(db, expr_name, expr_name_len);
+		if (item->zName == NULL)
+			return -1;
+	}
+	struct Expr *check = NULL;
+	if (expr_str != NULL &&
+	    sql_expr_compile(db, expr_str, expr_str_len,
+			     &check) != 0) {
+		sqlite3DbFree(db, item->zName);
+		return -1;
+	}
+	item->pExpr = check;
+	return 0;
+}
+
+static int
+update_space_def_callback(Walker *pWalker, Expr *pExpr)
+{
+	if (pExpr->op == TK_COLUMN && ExprHasProperty(pExpr, EP_Resolved))
+		pExpr->space_def = (struct space_def *) pWalker->pParse;
+	return WRC_Continue;
+}
+
+void
+sql_checks_update_space_def_reference(ExprList *expr_list,
+				      struct space_def *def)
+{
+	assert(expr_list != NULL);
+	Walker w;
+	memset(&w, 0, sizeof(w));
+	w.xExprCallback = update_space_def_callback;
+	w.pParse = (void *)def;
+
+	for (int i = 0; i < expr_list->nExpr; i++)
+		sqlite3WalkExpr(&w, expr_list->a[i].pExpr);
+}
+
+int
+sql_checks_resolve_space_def_reference(ExprList *expr_list,
+				       struct space_def *def)
+{
+	Parse parser;
+	sql_parser_create(&parser, sql_get());
+	parser.parse_only = true;
+
+	Table dummy_table;
+	memset(&dummy_table, 0, sizeof(dummy_table));
+	dummy_table.def = def;
+
+	sql_resolve_self_reference(&parser, &dummy_table, NC_IsCheck, NULL,
+				   expr_list);
+	int rc = parser.rc;
+	if (rc != SQLITE_OK)
+		diag_set(IllegalParams, parser.zErrMsg);
+
+	sql_parser_destroy(&parser);
+
+	return rc == SQLITE_OK ? 0 : -1;
+}
diff --git a/src/box/sql.h b/src/box/sql.h
index d031d9b..e626f76 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -103,6 +103,15 @@ struct Expr*
 space_column_default_expr(uint32_t space_id, uint32_t fieldno);
 
 /**
+ * Get server checks list by space_id.
+ * @param space_id Space ID.
+ * @retval NULL on error.
+ * @param not NULL on success.
+ */
+struct ExprList *
+space_checks_expr_list(uint32_t space_id);
+
+/**
  * Return the number of bytes required to create a duplicate of the
  * expression passed as the first argument. The second argument is a
  * mask containing EXPRDUP_XXX flags.
@@ -235,6 +244,40 @@ sql_resolve_self_reference(struct Parse *parser, struct Table *table, int type,
 			   struct Expr *expr, struct ExprList *expr_list);
 
 /**
+ * Initialize check_list_item.
+ * @param expr_list ExprList with item.
+ * @param idx item index.
+ * @param expr_name expression name (optional).
+ * @param expr_name_len expresson name length (optional).
+ * @param expr_str expression to build string.
+ * @param expr_str_len expression to build string length.
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+int
+sql_check_list_item_init(struct ExprList *expr_list, int idx,
+			 const char *expr_name, uint32_t expr_name_len,
+			 const char *expr_str, uint32_t expr_str_len);
+
+/**
+ * Resolve space_def references checks for expr_list.
+ * @param expr_list to modify.
+ * @param def to refer to.
+ */
+int
+sql_checks_resolve_space_def_reference(struct ExprList *expr_list,
+				       struct space_def *def);
+
+/**
+ * Update space_def references for expr_list.
+ * @param expr_list to modify.
+ * @param def to refer to.
+ */
+void
+sql_checks_update_space_def_reference(struct ExprList *expr_list,
+					struct space_def *def);
+
+/**
  * Initialize a new parser object.
  * A number of service allocations are performed on the region, which is also
  * cleared in the destroy function.
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index d00bb1d..f5bb54d 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -406,7 +406,6 @@ deleteTable(sqlite3 * db, Table * pTable)
 	sqlite3DbFree(db, pTable->aCol);
 	sqlite3DbFree(db, pTable->zColAff);
 	sqlite3SelectDelete(db, pTable->pSelect);
-	sql_expr_list_delete(db, pTable->pCheck);
 	assert(pTable->def != NULL);
 	/* Do not delete pTable->def allocated on region. */
 	if (!pTable->def->opts.temporary)
@@ -1022,19 +1021,29 @@ sqlite3AddPrimaryKey(Parse * pParse,	/* Parsing context */
 void
 sql_add_check_constraint(Parse *parser, ExprSpan *span)
 {
-#ifndef SQLITE_OMIT_CHECK
 	struct Expr *expr = span->pExpr;
 	Table *table = parser->pNewTable;
 	if (table != NULL) {
-		table->pCheck =
-			sql_expr_list_append(parser->db, table->pCheck, expr);
+		expr->u.zToken =
+			sqlite3DbStrNDup(parser->db, (char *)span->zStart,
+					 (int)(span->zEnd - span->zStart));
+		if (expr->u.zToken == NULL)
+			goto release_expr;
+		table->def->opts.checks =
+			sql_expr_list_append(parser->db,
+					     table->def->opts.checks, expr);
+		if (table->def->opts.checks == NULL) {
+			sqlite3DbFree(parser->db, expr->u.zToken);
+			goto release_expr;
+		}
 		if (parser->constraintName.n) {
-			sqlite3ExprListSetName(parser, table->pCheck,
+			sqlite3ExprListSetName(parser, table->def->opts.checks,
 					       &parser->constraintName, 1);
 		}
-	} else
-#endif
+	} else {
+release_expr:
 		sql_expr_delete(parser->db, expr, false);
+	}
 }
 
 /*
@@ -1177,6 +1186,16 @@ space_is_view(Table *table) {
 	return space->def->opts.is_view;
 }
 
+struct ExprList *
+space_checks_expr_list(uint32_t space_id)
+{
+	struct space *space;
+	space = space_by_id(space_id);
+	assert(space != NULL);
+	assert(space->def != NULL);
+	return space->def->opts.checks;
+}
+
 /**
  * Create cursor which will be positioned to the space/index.
  * It makes space lookup and loads pointer to it into register,
@@ -1848,17 +1867,14 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 		return;
 	}
 
+	/*
+	 * As rebuild creates a new ExpList tree and old_def
+	 * is allocated on region release old tree manually.
+	 */
+	struct ExprList *old_checks = p->def->opts.checks;
 	if (sql_table_def_rebuild(db, p) != 0)
 		return;
-
-#ifndef SQLITE_OMIT_CHECK
-	/* Resolve names in all CHECK constraint expressions.
-	 */
-	if (p->pCheck) {
-		sql_resolve_self_reference(pParse, p, NC_IsCheck, NULL,
-					    p->pCheck);
-	}
-#endif				/* !defined(SQLITE_OMIT_CHECK) */
+	sql_expr_list_delete(db, old_checks);
 
 	/* If not initializing, then create new Tarantool space.
 	 *
@@ -1979,6 +1995,15 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 		}
 #endif
 	}
+
+	/*
+	 * Checks are useless for now as all operations process with
+	 * the server checks instance. Remove to do not consume extra memory,
+	 * don't require make a copy on space_def_dup and to improve
+	 * debuggability.
+	 */
+	sql_expr_list_delete(db, p->def->opts.checks);
+	p->def->opts.checks = NULL;
 }
 
 #ifndef SQLITE_OMIT_VIEW
@@ -2020,7 +2045,7 @@ sqlite3CreateView(Parse * pParse,	/* The parsing context */
 	 */
 	p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
 	p->def->opts.is_view = true;
-	p->pCheck = sql_expr_list_dup(db, pCNames, EXPRDUP_REDUCE);
+	p->def->opts.checks = sql_expr_list_dup(db, pCNames, EXPRDUP_REDUCE);
 	if (db->mallocFailed)
 		goto create_view_fail;
 
@@ -2106,7 +2131,9 @@ sql_view_column_names(struct Parse *parse, struct Table *table)
 	struct Table *sel_tab = sqlite3ResultSetOfSelect(parse, select);
 	parse->nTab = n;
 	int rc = 0;
-	if (table->pCheck != NULL) {
+	/* Get server checks. */
+	ExprList *checks = space_checks_expr_list(table->def->id);
+	if (checks != NULL) {
 		/* CREATE VIEW name(arglist) AS ...
 		 * The names of the columns in the table are taken
 		 * from arglist which is stored in table->pCheck.
@@ -2115,7 +2142,7 @@ sql_view_column_names(struct Parse *parse, struct Table *table)
 		 * VIEW it holds the list of column names.
 		 */
 		struct space_def *old_def = table->def;
-		sqlite3ColumnsFromExprList(parse, table->pCheck, table);
+		sqlite3ColumnsFromExprList(parse, checks, table);
 		if (sql_table_def_rebuild(db, table) != 0) {
 			rc = -1;
 		} else {
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 6e7144c..f78f679 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -1164,21 +1164,23 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 		}
 	}
 
-	/* Test all CHECK constraints
+	/*
+	 * Get server checks.
+	 * Test all CHECK constraints.
 	 */
-#ifndef SQLITE_OMIT_CHECK
-	if (pTab->pCheck && (user_session->sql_flags &
-			     SQLITE_IgnoreChecks) == 0) {
-		ExprList *pCheck = pTab->pCheck;
+	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
+	ExprList *checks = space_checks_expr_list(space_id);
+	if (checks != NULL && (user_session->sql_flags &
+		       SQLITE_IgnoreChecks) == 0) {
 		pParse->ckBase = regNewData + 1;
 		if (override_error != ON_CONFLICT_ACTION_DEFAULT)
 			on_error = override_error;
 		else
 			on_error = ON_CONFLICT_ACTION_ABORT;
 
-		for (i = 0; i < pCheck->nExpr; i++) {
+		for (i = 0; i < checks->nExpr; i++) {
 			int allOk;
-			Expr *pExpr = pCheck->a[i].pExpr;
+			Expr *pExpr = checks->a[i].pExpr;
 			if (aiChng
 			    && checkConstraintUnchanged(pExpr, aiChng))
 				continue;
@@ -1188,7 +1190,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			if (on_error == ON_CONFLICT_ACTION_IGNORE) {
 				sqlite3VdbeGoto(v, ignoreDest);
 			} else {
-				char *zName = pCheck->a[i].zName;
+				char *zName = checks->a[i].zName;
 				if (zName == 0)
 					zName = pTab->def->name;
 				if (on_error == ON_CONFLICT_ACTION_REPLACE)
@@ -1202,7 +1204,6 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			sqlite3VdbeResolveLabel(v, allOk);
 		}
 	}
-#endif				/* !defined(SQLITE_OMIT_CHECK) */
 
 	/* Test all UNIQUE constraints by creating entries for each UNIQUE
 	 * index and making sure that duplicate entries do not already exist.
@@ -1886,12 +1887,16 @@ xferOptimization(Parse * pParse,	/* Parser context */
 			return 0;	/* pDestIdx has no corresponding index in pSrc */
 		}
 	}
-#ifndef SQLITE_OMIT_CHECK
-	if (pDest->pCheck
-	    && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck, -1)) {
-		return 0;	/* Tables have different CHECK constraints.  Ticket #2252 */
+	/* Get server checks. */
+	ExprList *pCheck_src = space_checks_expr_list(
+		SQLITE_PAGENO_TO_SPACEID(pSrc->tnum));
+	ExprList *pCheck_dest = space_checks_expr_list(
+		SQLITE_PAGENO_TO_SPACEID(pDest->tnum));
+	if (pCheck_dest
+	    && sqlite3ExprListCompare(pCheck_src, pCheck_dest, -1)) {
+		/* Tables have different CHECK constraints.  Ticket #2252 */
+		return 0;
 	}
-#endif
 #ifndef SQLITE_OMIT_FOREIGN_KEY
 	/* Disallow the transfer optimization if the destination table constains
 	 * any foreign key constraints.  This is more restrictive than necessary.
diff --git a/src/box/sql/pragma.h b/src/box/sql/pragma.h
index eb7c93b..f966018 100644
--- a/src/box/sql/pragma.h
+++ b/src/box/sql/pragma.h
@@ -166,14 +166,12 @@ static const PragmaName aPragmaName[] = {
 	 /* iArg:      */ SQLITE_FullColNames},
 #endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_CHECK)
 	{ /* zName:     */ "ignore_check_constraints",
 	 /* ePragTyp:  */ PragTyp_FLAG,
 	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
 	 /* ColNames:  */ 0, 0,
 	 /* iArg:      */ SQLITE_IgnoreChecks},
 #endif
-#endif
 #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 	{ /* zName:     */ "index_info",
 	 /* ePragTyp:  */ PragTyp_INDEX_INFO,
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index fd82119..0523b4e 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -530,10 +530,8 @@ notValid(Parse * pParse,	/* Leave error message here */
 		const char *zIn = "partial index WHERE clauses";
 		if (pNC->ncFlags & NC_IdxExpr)
 			zIn = "index expressions";
-#ifndef SQLITE_OMIT_CHECK
 		else if (pNC->ncFlags & NC_IsCheck)
 			zIn = "CHECK constraints";
-#endif
 		sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
 	}
 }
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 5746cb4..7611b4c 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1924,7 +1924,6 @@ struct Table {
 	Select *pSelect;	/* NULL for tables.  Points to definition if a view. */
 	FKey *pFKey;		/* Linked list of all foreign keys in this table */
 	char *zColAff;		/* String defining the affinity of each column */
-	ExprList *pCheck;	/* All CHECK constraints */
 	/*   ... also used as column name list in a VIEW */
 	Hash idxHash;		/* All (named) indices indexed by name */
 	int tnum;		/* Root BTree page for this table */
diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua
index 9e21c55..82d0fb7 100755
--- a/test/sql-tap/check.test.lua
+++ b/test/sql-tap/check.test.lua
@@ -345,7 +345,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-3.1>
-        1, "subqueries prohibited in CHECK constraints"
+        1, "Failed to create space 'T3': subqueries prohibited in CHECK constraints"
         -- </check-3.1>
     })
 
@@ -370,7 +370,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-3.3>
-        1, "no such column: Q"
+        1, "Failed to create space 'T3': no such column: Q"
         -- </check-3.3>
     })
 
@@ -394,7 +394,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-3.5>
-        1, "no such column: T2.X"
+        1, "Failed to create space 'T3': no such column: T2.X"
         -- </check-3.5>
     })
 
@@ -555,7 +555,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-5.1>
-        1, "parameters prohibited in CHECK constraints"
+        1, "Failed to create space 'T5': parameters prohibited in CHECK constraints"
         -- </check-5.1>
     })
 
@@ -567,7 +567,7 @@ test:do_catchsql_test(
         );
     ]], {
         -- <check-5.2>
-        1, "parameters prohibited in CHECK constraints"
+        1, "Failed to create space 'T5': parameters prohibited in CHECK constraints"
         -- </check-5.2>
     })
 
-- 
2.7.4

  parent reply	other threads:[~2018-05-23 14:05 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-23 14:05 [tarantool-patches] [PATCH v7 0/7] " Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 1/7] sql: remove parser construct, destruct to sql.h Kirill Shcherbatov
2018-05-23 17:46   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 19:26   ` Vladislav Shpilevoy
2018-05-25 12:05     ` Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 2/7] box: introduce OPT_ARRAY opt_type to decode arrays Kirill Shcherbatov
2018-05-23 17:53   ` [tarantool-patches] " Konstantin Osipov
2018-05-24  7:32     ` Kirill Shcherbatov
2018-05-24 19:26   ` Vladislav Shpilevoy
2018-05-25 11:54     ` Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 3/7] sql: introduce expr_len for sql_expr_compile Kirill Shcherbatov
2018-05-24 19:26   ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-25 11:54     ` Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 4/7] sql: rename sql_expr_free to sql_expr_delete Kirill Shcherbatov
2018-05-23 18:00   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 19:26   ` Vladislav Shpilevoy
2018-05-25 11:54     ` Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 5/7] sql: change sqlite3AddCheckConstraint signature Kirill Shcherbatov
2018-05-23 18:01   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 19:26   ` Vladislav Shpilevoy
2018-05-25 11:53     ` Kirill Shcherbatov
2018-05-29 11:51   ` n.pettik
2018-05-30  8:32     ` Kirill Shcherbatov
2018-05-23 14:05 ` [tarantool-patches] [PATCH v7 6/7] sql: export funcs defined on Expr, ExprList to sql.h Kirill Shcherbatov
2018-05-23 18:15   ` [tarantool-patches] " Konstantin Osipov
2018-05-24  7:33     ` Kirill Shcherbatov
2018-05-24 19:26   ` Vladislav Shpilevoy
2018-05-25 11:53     ` Kirill Shcherbatov
2018-05-28 11:19       ` Vladislav Shpilevoy
2018-05-28 14:59         ` Kirill Shcherbatov
2018-05-23 14:05 ` Kirill Shcherbatov [this message]
2018-05-24 19:26   ` [tarantool-patches] Re: [PATCH v7 7/7] sql: remove Checks to server Vladislav Shpilevoy
2018-05-25 11:53     ` Kirill Shcherbatov
2018-05-28 11:19       ` Vladislav Shpilevoy
2018-05-28 14:59         ` Kirill Shcherbatov
2018-05-28 18:50           ` Vladislav Shpilevoy
2018-05-29 11:49   ` n.pettik
2018-05-30  8:32     ` Kirill Shcherbatov
2018-05-30 10:42       ` n.pettik
2018-05-25 12:04 ` [tarantool-patches] Re: [PATCH v7 0/7] " Kirill Shcherbatov
2018-05-28 11:19   ` Vladislav Shpilevoy
2018-05-30 11:03 ` n.pettik
2018-05-31 17:44   ` Kirill Yukhin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2baee418a3799c91c5a8b92ac62e59de3456da0d.1527084287.git.kshcherbatov@tarantool.org \
    --to=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [tarantool-patches] [PATCH v7 7/7] sql: remove Checks to server' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox