From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 1B92720747 for ; Wed, 23 May 2018 10:05:49 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id K13afJKQteWF for ; Wed, 23 May 2018 10:05:49 -0400 (EDT) Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id A6AF02070C for ; Wed, 23 May 2018 10:05:48 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v7 7/7] sql: remove Checks to server Date: Wed, 23 May 2018 17:05:34 +0300 Message-Id: <2baee418a3799c91c5a8b92ac62e59de3456da0d.1527084287.git.kshcherbatov@tarantool.org> In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, Kirill Shcherbatov 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( ); ]], { -- - 1, "subqueries prohibited in CHECK constraints" + 1, "Failed to create space 'T3': subqueries prohibited in CHECK constraints" -- }) @@ -370,7 +370,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "no such column: Q" + 1, "Failed to create space 'T3': no such column: Q" -- }) @@ -394,7 +394,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "no such column: T2.X" + 1, "Failed to create space 'T3': no such column: T2.X" -- }) @@ -555,7 +555,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "parameters prohibited in CHECK constraints" + 1, "Failed to create space 'T5': parameters prohibited in CHECK constraints" -- }) @@ -567,7 +567,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "parameters prohibited in CHECK constraints" + 1, "Failed to create space 'T5': parameters prohibited in CHECK constraints" -- }) -- 2.7.4