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 EA70624720 for ; Tue, 15 May 2018 13:03:29 -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 aLp0BFoKGV3z for ; Tue, 15 May 2018 13:03:29 -0400 (EDT) Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (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 22AF6246D9 for ; Tue, 15 May 2018 13:03:29 -0400 (EDT) From: Kirill Shcherbatov Subject: [tarantool-patches] [PATCH v6 4/4] sql: remove Checks to server Date: Tue, 15 May 2018 20:03:21 +0300 Message-Id: <4898952651385c13e1d4458e7020a23353bd4446.1526403792.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_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 | 11 +++++ src/box/key_def.cc | 2 +- src/box/opt_def.c | 16 +++++++- src/box/opt_def.h | 8 +++- src/box/space_def.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/box/space_def.h | 6 +++ src/box/sql.c | 83 ++++++++++++++++++++++++++++++++++++- src/box/sql.h | 93 +++++++++++++++++++++++++++++++++++++++++- src/box/sql/build.c | 99 ++++++++++++++++++++++++++------------------- src/box/sql/delete.c | 6 +-- src/box/sql/expr.c | 53 ++++++++++-------------- src/box/sql/fkey.c | 15 +++---- src/box/sql/insert.c | 22 +++++----- src/box/sql/parse.y | 86 +++++++++++++++++++-------------------- src/box/sql/pragma.h | 2 - src/box/sql/prepare.c | 10 ++++- src/box/sql/resolve.c | 39 ++++++------------ src/box/sql/select.c | 45 +++++++++++---------- src/box/sql/sqliteInt.h | 39 +++++------------- src/box/sql/tokenize.c | 7 ++-- src/box/sql/trigger.c | 13 +++--- src/box/sql/update.c | 2 +- src/box/sql/wherecode.c | 14 ++++--- src/box/sql/whereexpr.c | 7 ++-- test/sql-tap/check.test.lua | 13 +++--- 25 files changed, 542 insertions(+), 246 deletions(-) diff --git a/src/box/alter.cc b/src/box/alter.cc index c446b10..f1c2394 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -407,6 +407,7 @@ field_def_decode(struct field_def *field, const char **data, if (field->default_value != NULL && sql_expr_compile(sql_get(), field->default_value, + strlen(field->default_value), &field->default_value_expr) != 0) diag_raise(); } @@ -521,6 +522,16 @@ 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) { + int rc = + sql_resolve_checks_space_def_reference(def->opts.checks, + def); + if (rc != 0) + tnt_raise(ClientError, errcode, + tt_cstr(name, name_len), + diag_last_error(diag_get())->errmsg); + } + 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/key_def.cc b/src/box/key_def.cc index 98719c2..a5ce15d 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -58,7 +58,7 @@ part_type_by_name_wrapper(const char *str, uint32_t len) const struct opt_def part_def_reg[] = { OPT_DEF_ENUM(PART_OPT_TYPE, field_type, struct key_part_def, type, - part_type_by_name_wrapper), + (void *)part_type_by_name_wrapper), OPT_DEF(PART_OPT_FIELD, OPT_UINT32, struct key_part_def, fieldno), OPT_DEF(PART_OPT_COLLATION, OPT_UINT32, struct key_part_def, coll_id), OPT_DEF(PART_OPT_NULLABILITY, OPT_BOOL, struct key_part_def, diff --git a/src/box/opt_def.c b/src/box/opt_def.c index cd93c23..4987654 100644 --- a/src/box/opt_def.c +++ b/src/box/opt_def.c @@ -44,6 +44,7 @@ const char *opt_type_strs[] = { /* [OPT_STR] = */ "string", /* [OPT_STRPTR] = */ "string", /* [OPT_ENUM] = */ "enum", + /* [OPT_ARRAY] = */ "array", }; static int @@ -112,11 +113,12 @@ opt_set(void *opts, const struct opt_def *def, const char **val, if (mp_typeof(**val) != MP_STR) return -1; str = mp_decode_str(val, &str_len); - if (def->to_enum == NULL) { + if (def->callback == NULL) { ival = strnindex(def->enum_strs, str, str_len, def->enum_max); } else { - ival = def->to_enum(str, str_len); + opt_def_to_enum_cb to_enum = def->callback; + ival = to_enum(str, str_len); } switch(def->enum_size) { case sizeof(uint8_t): @@ -135,6 +137,16 @@ opt_set(void *opts, const struct opt_def *def, const char **val, unreachable(); }; break; + case OPT_ARRAY: + if (mp_typeof(**val) != MP_ARRAY) + return -1; + ival = mp_decode_array(val); + opt_def_action_cb array_parse_cb = def->callback; + assert(array_parse_cb); + *(const char **)opt = array_parse_cb(val, ival); + if (*(const char **)opt == NULL) + return -1; + break; default: unreachable(); } diff --git a/src/box/opt_def.h b/src/box/opt_def.h index 633832a..d5500d7 100644 --- a/src/box/opt_def.h +++ b/src/box/opt_def.h @@ -47,12 +47,14 @@ enum opt_type { OPT_STR, /* char[] */ OPT_STRPTR, /* char* */ OPT_ENUM, /* enum */ + OPT_ARRAY, /* array */ opt_type_MAX, }; extern const char *opt_type_strs[]; typedef int64_t (*opt_def_to_enum_cb)(const char *str, uint32_t len); +typedef void *(*opt_def_action_cb)(void *data, uint32_t k); struct opt_def { const char *name; @@ -65,7 +67,7 @@ struct opt_def { const char **enum_strs; uint32_t enum_max; /** If not NULL, used to get a enum value by a string. */ - opt_def_to_enum_cb to_enum; + void *callback; }; #define OPT_DEF(key, type, opts, field) \ @@ -76,6 +78,10 @@ struct opt_def { { key, OPT_ENUM, offsetof(opts, field), sizeof(int), #enum_name, \ sizeof(enum enum_name), enum_name##_strs, enum_name##_MAX, to_enum } +#define OPT_DEF_ARRAY(key, opts, field, action) \ + { key, OPT_ARRAY, offsetof(opts, field), sizeof(((opts *)0)->field), \ + NULL, 0, NULL, 0, action } + #define OPT_END {NULL, opt_type_MAX, 0, 0, NULL, 0, NULL, 0, NULL} struct region; diff --git a/src/box/space_def.c b/src/box/space_def.c index 1fa3345..2dbcac5 100644 --- a/src/box/space_def.c +++ b/src/box/space_def.c @@ -29,21 +29,29 @@ * SUCH DAMAGE. */ +#include "sqliteInt.h" #include "space_def.h" #include "diag.h" #include "error.h" #include "sql.h" +#include "msgpuck.h" + +void * +checks_array_decode(void *data, uint32_t array_items); 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, + (void *)checks_array_decode), OPT_END, }; @@ -123,6 +131,18 @@ 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"); + free(ret->opts.sql); + free(ret); + return NULL; + } + sql_update_checks_space_def_reference(ret->opts.checks, ret); + } tuple_dictionary_ref(ret->dict); return ret; } @@ -209,6 +229,16 @@ 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.pCheck"); + free(def); + return NULL; + } + sql_update_checks_space_def_reference(def->opts.checks, def); + } return def; } @@ -233,3 +263,70 @@ space_def_delete(struct space_def *def) TRASH(def); free(def); } + +/** + * Decode checks from msgpack. + * @param data pointer to array of maps + * e.g. [{"expr_str": "x < y", "name": "ONE"}, ..]. + * @param array_items array items count. + * @retval not NULL Checks pointer on success. + * @retval NULL on error. + */ +void * +checks_array_decode(void *data, uint32_t array_items) +{ + struct ExprList *pChecks = NULL; + const char **map = (const char **)data; + struct sqlite3 *db = sql_get(); + for (unsigned i = 0; i < array_items; i++) { + pChecks = sql_expr_list_append(db, pChecks, NULL); + if (pChecks == NULL) { + diag_set(OutOfMemory, 0, "sql_expr_list_append", + "pChecks"); + goto error; + } + struct ExprList_item *pItem = + &pChecks->a[pChecks->nExpr - 1]; + 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) { + uint32_t expr_str_len = 0; + const char *expr_str = + mp_decode_str(map, &expr_str_len); + struct Expr *check_expr = NULL; + if (sql_expr_compile(db, expr_str, expr_str_len, + &check_expr) != 0) + goto error; + pItem->pExpr = check_expr; + } else if (strncmp(key, "name", key_len) == 0) { + uint32_t name_str_len = 0; + const char *name_str = + mp_decode_str(map, &name_str_len); + assert(pItem->zName == NULL); + pItem->zName = sqlite3DbStrNDup(db, name_str, + name_str_len); + if (pItem->zName == NULL) { + diag_set(OutOfMemory, 0, + "checks_array_decode", + "pItem->zName"); + goto error; + } + } else { + diag_set(ClientError, ER_WRONG_INDEX_OPTIONS, 0, + "pItem->zName"); + goto error; + } + } + } + return pChecks; +error: + sql_expr_list_free(db, pChecks); + return NULL; +} diff --git a/src/box/space_def.h b/src/box/space_def.h index 52447b6..0d2b9e6 100644 --- a/src/box/space_def.h +++ b/src/box/space_def.h @@ -33,6 +33,7 @@ #include "trivia/util.h" #include "tuple_dictionary.h" #include "schema_def.h" +#include "sql.h" #include #include @@ -59,6 +60,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; @@ -81,6 +86,7 @@ static inline void space_opts_destroy(struct space_opts *opts) { free(opts->sql); + sql_expr_list_free(sql_get(), opts->checks); TRASH(opts); } diff --git a/src/box/sql.c b/src/box/sql.c index 357cbf9..bdb7e5b 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1510,13 +1510,45 @@ 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 && + pTable->def->opts.checks->nExpr > 0); + int checks_cnt = has_checks ? pTable->def->opts.checks->nExpr : 0; + + int map_fields = 1; + map_fields += (is_view == true); + map_fields += (has_checks == true); + 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 (!has_checks || checks_cnt == 0) + return (int)(p - base); + + 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); + 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); } @@ -1739,6 +1771,52 @@ sql_ephemeral_table_new(Parse *parser, const char *name) return table; } +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_update_checks_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_resolve_checks_space_def_reference(ExprList *expr_list, + struct space_def *def) +{ + Parse parser; + sql_parser_create(&parser); + parser.db = 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; +} + int sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable) { @@ -1755,5 +1833,8 @@ sql_table_def_rebuild(struct sqlite3 *db, struct Table *pTable) } pTable->def = new_def; pTable->def->opts.temporary = false; + if (new_def->opts.checks != NULL) + sql_update_checks_space_def_reference(new_def->opts.checks, + new_def); return 0; } diff --git a/src/box/sql.h b/src/box/sql.h index 3c26492..6399c79 100644 --- a/src/box/sql.h +++ b/src/box/sql.h @@ -74,12 +74,14 @@ struct Table; * stuct Select and return it. * @param db SQL context handle. * @param expr Expression to parse. + * @param expr_len Expression to parse length (optional). * @param[out] result Result: AST structure. * * @retval Error code if any. */ int -sql_expr_compile(struct sqlite3 *db, const char *expr, struct Expr **result); +sql_expr_compile(struct sqlite3 *db, const char *expr, int expr_len, + struct Expr **result); /** * Store duplicate of a parsed expression into @a parser. @@ -175,6 +177,95 @@ sql_ephemeral_space_def_new(struct Parse *parser, const char *name); int sql_table_def_rebuild(struct sqlite3 *db, struct Table *table); +/** + * Duplicate Expr list. + * The flags parameter contains a combination of the EXPRDUP_XXX flags. + * If the EXPRDUP_REDUCE flag is set, then the structure returned is a + * truncated version of the usual Expr structure that will be stored as + * part of the in-memory representation of the database schema. + * @param db The database connection. + * @param p The ExprList to duplicate. + * @param flags EXPRDUP_XXX flags. + * @retval NULL on memory allocation error. + * @retval not NULL on success. + */ +struct ExprList * +sql_expr_list_dup(struct sqlite3 * db, struct ExprList * p, int flags); + +/** + * Free AST pointed by expr list. + * @param db SQL handle. + * @param expr_list Root pointer of ExprList. + */ +void +sql_expr_list_free(struct sqlite3 * db, struct ExprList *expr_list); + +/** + * Add a new element to the end of an expression list. If pList is + * initially NULL, then create a new expression list. + * + * If a memory allocation error occurs, the entire list is freed and + * NULL is returned. If non-NULL is returned, then it is guaranteed + * that the new entry was successfully appended. + * @param db SQL handle. + * @param expr_list List to which to append. Might be NULL. + * @param expr Expression to be appended. Might be NULL. + * @retval NULL on memory allocation error. + * @retval not NULL on success. + */ +struct ExprList * +sql_expr_list_append(struct sqlite3 * db, struct ExprList *expr_list, struct Expr *expr); + +/** + * Resolve names in expressions that can only reference a single table: + * * CHECK constraints + * * WHERE clauses on partial indices + * The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression + * is set to -1 and the Expr.iColumn value is set to the column number. + * Any errors cause an error message to be set in pParse. + * @param pParse Parsing context. + * @param pTab The table being referenced. + * @param type NC_IsCheck or NC_PartIdx or NC_IdxExpr. + * @param pExpr Expression to resolve. May be NULL. + * @param pList Expression list to resolve. May be NUL. + */ +void +sql_resolve_self_reference(struct Parse *parser, struct Table *table, int type, + struct Expr *expr, struct ExprList *expr_list); + +/** + * Resolve space_def references checks for expr_list. + * @param expr_list to modify. + * @param def to refer to. + */ +int +sql_resolve_checks_space_def_reference(struct ExprList *expr_list, + struct space_def *def); + +/** + * Update space_def references for checks expr_list. + * @param expr_list to modify. + * @param def to refer to. + */ +void +sql_update_checks_space_def_reference(struct ExprList *expr_list, + struct space_def *def); + +/** + * Initialize a new parser object. + * @param parser object to initialize. + */ +void +sql_parser_create(struct Parse *parser); + +/** + * Release the parser object resources. + * @param parser object to release. + */ +void +sql_parser_destroy(struct Parse *parser); + + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 718809d..60f1a50 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -218,7 +218,7 @@ freeIndex(sqlite3 * db, Index * p) sqlite3DeleteIndexSamples(db, p); #endif sql_expr_free(db, p->pPartIdxWhere, false); - sqlite3ExprListDelete(db, p->aColExpr); + sql_expr_list_free(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); sqlite3_free(p->aiRowEst); sqlite3DbFree(db, p); @@ -373,7 +373,6 @@ deleteTable(sqlite3 * db, Table * pTable) sqlite3DbFree(db, pTable->aCol); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); - sqlite3ExprListDelete(db, pTable->pCheck); /* Do not delete pTable->def allocated not on region. */ assert(pTable->def != NULL); if (!pTable->def->opts.temporary) @@ -973,7 +972,7 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ } primary_key_exit: - sqlite3ExprListDelete(pParse->db, pList); + sql_expr_list_free(pParse->db, pList); return; } @@ -981,22 +980,25 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ * Add a new CHECK constraint to the table currently under construction. */ void -sqlite3AddCheckConstraint(Parse * pParse, /* Parsing context */ - Expr * pCheckExpr /* The check expression */ - ) +sqlite3AddCheckConstraint(Parse *parser, Expr *expr, ExprSpan *span) { #ifndef SQLITE_OMIT_CHECK - Table *pTab = pParse->pNewTable; + Table *pTab = parser->pNewTable; if (pTab) { - pTab->pCheck = - sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); - if (pParse->constraintName.n) { - sqlite3ExprListSetName(pParse, pTab->pCheck, - &pParse->constraintName, 1); + sqlite3 *db = parser->db; + expr->u.zToken = + sqlite3DbStrNDup(db, (char *)span->zStart, + (int)(span->zEnd - span->zStart)); + pTab->def->opts.checks = + sql_expr_list_append(parser->db, pTab->def->opts.checks, + expr); + if (parser->constraintName.n) { + sqlite3ExprListSetName(parser, pTab->def->opts.checks, + &parser->constraintName, 1); } } else #endif - sql_expr_free(pParse->db, pCheckExpr, false); + sql_expr_free(parser->db, expr, false); } /* @@ -1088,6 +1090,22 @@ space_is_view(Table *table) { } /** + * Get 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) +{ + 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, * which is passes to OP_OpenWrite as an argument. @@ -1395,9 +1413,9 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab) ExprList *pList; Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->def->fields[pTab->iPKey].name); - pList = sqlite3ExprListAppend(pParse, 0, - sqlite3ExprAlloc(db, TK_ID, - &ipkToken, 0)); + pList = sql_expr_list_append(pParse->db, 0, + sqlite3ExprAlloc(db, TK_ID, + &ipkToken, 0)); if (pList == 0) return; pList->a[0].sortOrder = pParse->iPkSortOrder; @@ -1826,15 +1844,6 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ if (sql_table_def_rebuild(db, p) != 0) return; -#ifndef SQLITE_OMIT_CHECK - /* Resolve names in all CHECK constraint expressions. - */ - if (p->pCheck) { - sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, - p->pCheck); - } -#endif /* !defined(SQLITE_OMIT_CHECK) */ - /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); for (pIdx = p->pIndex; pIdx; pIdx = pIdx->pNext) { @@ -1964,6 +1973,12 @@ sqlite3EndTable(Parse * pParse, /* Parse context */ } #endif } + + /* We don't need Checks in SQL anymore. */ + if (p->def->opts.checks != NULL) { + sql_expr_list_free(db, p->def->opts.checks); + p->def->opts.checks = NULL; + } } #ifndef SQLITE_OMIT_VIEW @@ -2005,7 +2020,7 @@ sqlite3CreateView(Parse * pParse, /* The parsing context */ */ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); p->def->opts.is_view = true; - p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); + p->def->opts.checks = sql_expr_list_dup(db, pCNames, EXPRDUP_REDUCE); if (db->mallocFailed) goto create_view_fail; @@ -2032,7 +2047,7 @@ sqlite3CreateView(Parse * pParse, /* The parsing context */ create_view_fail: sqlite3SelectDelete(db, pSelect); - sqlite3ExprListDelete(db, pCNames); + sql_expr_list_free(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ @@ -2100,7 +2115,8 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable) db->lookaside.bDisable++; pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); pParse->nTab = n; - if (pTable->pCheck) { + ExprList *checks = space_checks_expr_list(pTable->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 pTable->pCheck. The pCheck field @@ -2108,8 +2124,7 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable) * a VIEW it holds the list of column names. */ struct space_def *old_def = pTable->def; - sqlite3ColumnsFromExprList(pParse, pTable->pCheck, - pTable); + sqlite3ColumnsFromExprList(pParse, checks, pTable); if (sql_table_def_rebuild(db, pTable) != 0) { nErr++; } else { @@ -2562,8 +2577,8 @@ sqlite3CreateForeignKey(Parse * pParse, /* Parsing context */ fk_end: sqlite3DbFree(db, pFKey); #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ - sqlite3ExprListDelete(db, pFromCol); - sqlite3ExprListDelete(db, pToCol); + sql_expr_list_free(db, pFromCol); + sql_expr_list_free(db, pToCol); } /* @@ -2971,7 +2986,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ struct field_def *field = &pTab->def->fields[pTab->def->field_count - 1]; sqlite3TokenInit(&prevCol, field->name); - pList = sqlite3ExprListAppend(pParse, 0, + pList = sql_expr_list_append(pParse->db, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if (pList == 0) @@ -3024,8 +3039,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ pIndex->nColumn = pList->nExpr; /* Tarantool have access to each column by any index */ if (pPIWhere) { - sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, - 0); + sql_resolve_self_reference(pParse, pTab, NC_PartIdx, pPIWhere, + 0); pIndex->pPartIdxWhere = pPIWhere; pPIWhere = 0; } @@ -3042,8 +3057,8 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ for (i = 0, pListItem = pList->a; i < pList->nExpr; i++, pListItem++) { Expr *pCExpr; /* The i-th index expression */ int requestedSortOrder; /* ASC or DESC on the i-th expression */ - sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, - pListItem->pExpr, 0); + sql_resolve_self_reference(pParse, pTab, NC_IdxExpr, + pListItem->pExpr, 0); if (pParse->nErr) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); @@ -3258,7 +3273,7 @@ sqlite3CreateIndex(Parse * pParse, /* All information about this parse */ if (pIndex) freeIndex(db, pIndex); sql_expr_free(db, pPIWhere, false); - sqlite3ExprListDelete(db, pList); + sql_expr_list_free(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } @@ -3733,7 +3748,7 @@ sqlite3SrcListDelete(sqlite3 * db, SrcList * pList) if (pItem->fg.isIndexedBy) sqlite3DbFree(db, pItem->u1.zIndexedBy); if (pItem->fg.isTabFunc) - sqlite3ExprListDelete(db, pItem->u1.pFuncArg); + sql_expr_list_free(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); sqlite3SelectDelete(db, pItem->pSelect); sql_expr_free(db, pItem->pOn, false); @@ -3839,7 +3854,7 @@ sqlite3SrcListFuncArgs(Parse * pParse, SrcList * p, ExprList * pList) pItem->u1.pFuncArg = pList; pItem->fg.isTabFunc = 1; } else { - sqlite3ExprListDelete(pParse->db, pList); + sql_expr_list_free(pParse->db, pList); } } @@ -4255,7 +4270,7 @@ sqlite3WithAdd(Parse * pParse, /* Parsing context */ assert((pNew != 0 && zName != 0) || db->mallocFailed); if (db->mallocFailed) { - sqlite3ExprListDelete(db, pArglist); + sql_expr_list_free(db, pArglist); sqlite3SelectDelete(db, pQuery); sqlite3DbFree(db, zName); pNew = pWith; @@ -4280,7 +4295,7 @@ sqlite3WithDelete(sqlite3 * db, With * pWith) int i; for (i = 0; i < pWith->nCte; i++) { struct Cte *pCte = &pWith->a[i]; - sqlite3ExprListDelete(db, pCte->pCols); + sql_expr_list_free(db, pCte->pCols); sqlite3SelectDelete(db, pCte->pSelect); sqlite3DbFree(db, pCte->zName); } diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index 5056005..476993d 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -182,7 +182,7 @@ sqlite3LimitWhere(Parse * pParse, /* The parser context */ pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0); if (pSelectRowid == 0) goto limit_where_cleanup; - pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid); + pEList = sql_expr_list_append(pParse->db, 0, pSelectRowid); if (pEList == 0) goto limit_where_cleanup; @@ -191,7 +191,7 @@ sqlite3LimitWhere(Parse * pParse, /* The parser context */ */ pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0); if (pSelectSrc == 0) { - sqlite3ExprListDelete(pParse->db, pEList); + sql_expr_list_free(pParse->db, pEList); goto limit_where_cleanup; } @@ -210,7 +210,7 @@ sqlite3LimitWhere(Parse * pParse, /* The parser context */ limit_where_cleanup: sql_expr_free(pParse->db, pWhere); - sqlite3ExprListDelete(pParse->db, pOrderBy); + sql_expr_list_free(pParse->db, pOrderBy); sql_expr_free(pParse->db, pLimit); sql_expr_free(pParse->db, pOffset); return 0; diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index 9a8f045..9f874a1 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -1061,7 +1061,8 @@ sqlite3ExprFunction(Parse * pParse, ExprList * pList, Token * pToken) assert(pToken); pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); if (pNew == 0) { - sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ + /* Avoid memory leak when malloc fails. */ + sql_expr_list_free(db, pList); return 0; } pNew->x.pList = pList; @@ -1180,7 +1181,7 @@ sqlite3ExprDeleteNN(sqlite3 * db, Expr * p, bool extern_alloc) if (ExprHasProperty(p, EP_xIsSelect)) { sqlite3SelectDelete(db, p->x.pSelect); } else { - sqlite3ExprListDelete(db, p->x.pList); + sql_expr_list_free(db, p->x.pList); } } if (ExprHasProperty(p, EP_MemToken)) @@ -1368,8 +1369,8 @@ sql_expr_dup(struct sqlite3 *db, struct Expr *p, int flags, char **buffer) flags); } else { pNew->x.pList = - sqlite3ExprListDup(db, p->x.pList, - flags); + sql_expr_list_dup(db, p->x.pList, + flags); } } @@ -1426,7 +1427,7 @@ withDup(sqlite3 * db, With * p) pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0); pRet->a[i].pCols = - sqlite3ExprListDup(db, p->a[i].pCols, 0); + sql_expr_list_dup(db, p->a[i].pCols, 0); pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName); } @@ -1444,7 +1445,7 @@ withDup(sqlite3 * db, With * p) * be deleted (by being passed to their respective ...Delete() routines) * without effecting the originals. * - * The expression list, ID, and source lists return by sqlite3ExprListDup(), + * The expression list, ID, and source lists return by sql_expr_list_dup(), * sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded * by subsequent calls to sqlite*ListAppend() routines. * @@ -1463,7 +1464,7 @@ sqlite3ExprDup(sqlite3 * db, Expr * p, int flags) } ExprList * -sqlite3ExprListDup(sqlite3 * db, ExprList * p, int flags) +sql_expr_list_dup(sqlite3 *db, ExprList *p, int flags) { ExprList *pNew; struct ExprList_item *pItem, *pOldItem; @@ -1556,8 +1557,8 @@ sqlite3SrcListDup(sqlite3 * db, SrcList * p, int flags) pNewItem->pIBIndex = pOldItem->pIBIndex; if (pNewItem->fg.isTabFunc) { pNewItem->u1.pFuncArg = - sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, - flags); + sql_expr_list_dup(db, pOldItem->u1.pFuncArg, + flags); } pTab = pNewItem->pTab = pOldItem->pTab; if (pTab) { @@ -1612,12 +1613,12 @@ sqlite3SelectDup(sqlite3 * db, Select * p, int flags) pNew = sqlite3DbMallocRawNN(db, sizeof(*p)); if (pNew == 0) return 0; - pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags); + pNew->pEList = sql_expr_list_dup(db, p->pEList, flags); pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags); pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags); - pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags); + pNew->pGroupBy = sql_expr_list_dup(db, p->pGroupBy, flags); pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags); - pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags); + pNew->pOrderBy = sql_expr_list_dup(db, p->pOrderBy, flags); pNew->op = p->op; pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags); if (pPrior) @@ -1636,21 +1637,9 @@ sqlite3SelectDup(sqlite3 * db, Select * p, int flags) return pNew; } -/* - * Add a new element to the end of an expression list. If pList is - * initially NULL, then create a new expression list. - * - * If a memory allocation error occurs, the entire list is freed and - * NULL is returned. If non-NULL is returned, then it is guaranteed - * that the new entry was successfully appended. - */ ExprList * -sqlite3ExprListAppend(Parse * pParse, /* Parsing context */ - ExprList * pList, /* List to which to append. Might be NULL */ - Expr * pExpr /* Expression to be appended. Might be NULL */ - ) +sql_expr_list_append(sqlite3 * db, ExprList *pList, Expr *pExpr) { - sqlite3 *db = pParse->db; assert(db != 0); if (pList == 0) { pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)); @@ -1680,7 +1669,7 @@ sqlite3ExprListAppend(Parse * pParse, /* Parsing context */ no_mem: /* Avoid leaking memory if malloc has failed. */ sql_expr_free(db, pExpr, false); - sqlite3ExprListDelete(db, pList); + sql_expr_list_free(db, pList); return 0; } @@ -1728,7 +1717,7 @@ sqlite3ExprListAppendVector(Parse * pParse, /* Parsing context */ for (i = 0; i < pColumns->nId; i++) { Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i); - pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); + pList = sql_expr_list_append(pParse->db, pList, pSubExpr); if (pList) { assert(pList->nExpr == iFirst + i + 1); pList->a[pList->nExpr - 1].zName = pColumns->a[i].zName; @@ -1742,7 +1731,7 @@ sqlite3ExprListAppendVector(Parse * pParse, /* Parsing context */ assert(pFirst->op == TK_SELECT_COLUMN); /* Store the SELECT statement in pRight so it will be deleted when - * sqlite3ExprListDelete() is called + * sql_expr_list_free() is called */ pFirst->pRight = pExpr; pExpr = 0; @@ -1870,10 +1859,10 @@ exprListDeleteNN(sqlite3 * db, ExprList * pList) } void -sqlite3ExprListDelete(sqlite3 * db, ExprList * pList) +sql_expr_list_free(sqlite3 *db, ExprList *expr_list) { - if (pList) - exprListDeleteNN(db, pList); + if (expr_list) + exprListDeleteNN(db, expr_list); } /* @@ -4440,7 +4429,7 @@ sqlite3ExprCodeAtInit(Parse * pParse, /* Parsing context */ assert(ConstFactorOk(pParse)); p = pParse->pConstExpr; pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); - p = sqlite3ExprListAppend(pParse, p, pExpr); + p = sql_expr_list_append(pParse->db, p, pExpr); if (p) { struct ExprList_item *pItem = &p->a[p->nExpr - 1]; pItem->u.iConstExprReg = regDest; diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index c7b1cda..0a28943 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -737,7 +737,7 @@ fkTriggerDelete(sqlite3 * dbMem, Trigger * p) if (p) { TriggerStep *pStep = p->step_list; sql_expr_free(dbMem, pStep->pWhere, false); - sqlite3ExprListDelete(dbMem, pStep->pExprList); + sql_expr_list_free(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); sql_expr_free(dbMem, p->pWhen, false); sqlite3DbFree(dbMem, p); @@ -1367,7 +1367,8 @@ fkActionTrigger(Parse * pParse, /* Parse context */ sqlite3ExprAlloc(db, TK_NULL, 0, 0); } pList = - sqlite3ExprListAppend(pParse, pList, pNew); + sql_expr_list_append(pParse->db, pList, + pNew); sqlite3ExprListSetName(pParse, pList, &tFromCol, 0); } @@ -1390,9 +1391,9 @@ fkActionTrigger(Parse * pParse, /* Parse context */ pRaise->affinity = ON_CONFLICT_ACTION_ABORT; } pSelect = sqlite3SelectNew(pParse, - sqlite3ExprListAppend(pParse, - 0, - pRaise), + sql_expr_list_append(pParse->db, + 0, + pRaise), sqlite3SrcListAppend(db, 0, &tFrom), pWhere, 0, 0, 0, 0, 0, 0); @@ -1415,7 +1416,7 @@ fkActionTrigger(Parse * pParse, /* Parse context */ pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = - sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); + sql_expr_list_dup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); if (pWhen) { @@ -1430,7 +1431,7 @@ fkActionTrigger(Parse * pParse, /* Parse context */ sql_expr_free(db, pWhere, false); sql_expr_free(db, pWhen, false); - sqlite3ExprListDelete(db, pList); + sql_expr_list_free(db, pList); sqlite3SelectDelete(db, pSelect); if (db->mallocFailed == 1) { fkTriggerDelete(db, pTrigger); diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 1a883e2..32ad806 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -922,7 +922,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */ insert_cleanup: sqlite3SrcListDelete(db, pTabList); - sqlite3ExprListDelete(db, pList); + sql_expr_list_free(db, pList); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); @@ -1183,10 +1183,10 @@ sqlite3GenerateConstraintChecks(Parse * pParse, /* The parser context */ /* Test all CHECK constraints */ -#ifndef SQLITE_OMIT_CHECK - if (pTab->pCheck && (user_session->sql_flags & + uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum); + ExprList *pCheck = space_checks_expr_list(space_id); + if (pCheck && (user_session->sql_flags & SQLITE_IgnoreChecks) == 0) { - ExprList *pCheck = pTab->pCheck; pParse->ckBase = regNewData + 1; onError = overrideError != ON_CONFLICT_ACTION_DEFAULT ? overrideError @@ -1217,7 +1217,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. @@ -1853,12 +1852,15 @@ 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 */ + 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/parse.y b/src/box/sql/parse.y index b078e20..b7f2f45 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -286,7 +286,7 @@ ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} -ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);} +ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr,&X);} ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} @@ -337,7 +337,7 @@ tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,X,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} tcons ::= CHECK LP expr(E) RP onconf. - {sqlite3AddCheckConstraint(pParse,E.pExpr);} + {sqlite3AddCheckConstraint(pParse,E.pExpr,&E);} tcons ::= FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); @@ -529,25 +529,25 @@ distinct(A) ::= . {A = 0;} // opcode of TK_ASTERISK. // %type selcollist {ExprList*} -%destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor selcollist {sql_expr_list_free(pParse->db, $$);} %type sclp {ExprList*} -%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);} +%destructor sclp {sql_expr_list_free(pParse->db, $$);} sclp(A) ::= selcollist(A) COMMA. sclp(A) ::= . {A = 0;} selcollist(A) ::= sclp(A) expr(X) as(Y). { - A = sqlite3ExprListAppend(pParse, A, X.pExpr); + A = sql_expr_list_append(pParse->db, A, X.pExpr); if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1); sqlite3ExprListSetSpan(pParse,A,&X); } selcollist(A) ::= sclp(A) STAR. { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - A = sqlite3ExprListAppend(pParse, A, p); + A = sql_expr_list_append(pParse->db, A, p); } selcollist(A) ::= sclp(A) nm(X) DOT STAR. { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - A = sqlite3ExprListAppend(pParse,A, pDot); + A = sql_expr_list_append(pParse->db,A, pDot); } // An option "AS " phrase that can follow one of the expressions that @@ -662,23 +662,23 @@ using_opt(U) ::= . {U = 0;} %type orderby_opt {ExprList*} -%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} +%destructor orderby_opt {sql_expr_list_free(pParse->db, $$);} // the sortlist non-terminal stores a list of expression where each // expression is optionally followed by ASC or DESC to indicate the // sort order. // %type sortlist {ExprList*} -%destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor sortlist {sql_expr_list_free(pParse->db, $$);} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). { - A = sqlite3ExprListAppend(pParse,A,Y.pExpr); + A = sql_expr_list_append(pParse->db,A,Y.pExpr); sqlite3ExprListSetSortOrder(A,Z); } sortlist(A) ::= expr(Y) sortorder(Z). { - A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/ + A = sql_expr_list_append(pParse->db,0,Y.pExpr); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(A,Z); } @@ -689,7 +689,7 @@ sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} %type groupby_opt {ExprList*} -%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} +%destructor groupby_opt {sql_expr_list_free(pParse->db, $$);} groupby_opt(A) ::= . {A = 0;} groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;} @@ -778,17 +778,17 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) %endif %type setlist {ExprList*} -%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor setlist {sql_expr_list_free(pParse->db, $$);} setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). { - A = sqlite3ExprListAppend(pParse, A, Y.pExpr); + A = sql_expr_list_append(pParse->db, A, Y.pExpr); sqlite3ExprListSetName(pParse, A, &X, 1); } setlist(A) ::= setlist(A) COMMA LP idlist(X) RP EQ expr(Y). { A = sqlite3ExprListAppendVector(pParse, A, X, Y.pExpr); } setlist(A) ::= nm(X) EQ expr(Y). { - A = sqlite3ExprListAppend(pParse, 0, Y.pExpr); + A = sql_expr_list_append(pParse->db, 0, Y.pExpr); sqlite3ExprListSetName(pParse, A, &X, 1); } setlist(A) ::= LP idlist(X) RP EQ expr(Y). { @@ -970,13 +970,13 @@ term(A) ::= CTIME_KW(OP). { } expr(A) ::= LP(L) nexprlist(X) COMMA expr(Y) RP(R). { - ExprList *pList = sqlite3ExprListAppend(pParse, X, Y.pExpr); + ExprList *pList = sql_expr_list_append(pParse->db, X, Y.pExpr); A.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( A.pExpr ){ A.pExpr->x.pList = pList; spanSet(&A, &L, &R); }else{ - sqlite3ExprListDelete(pParse->db, pList); + sql_expr_list_free(pParse->db, pList); } } @@ -999,8 +999,8 @@ expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] { ExprList *pList; int bNot = OP.n & 0x80000000; OP.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, Y.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, A.pExpr); + pList = sql_expr_list_append(pParse->db,0, Y.pExpr); + pList = sql_expr_list_append(pParse->db,pList, A.pExpr); A.pExpr = sqlite3ExprFunction(pParse, pList, &OP); exprNot(pParse, bNot, &A); A.zEnd = Y.zEnd; @@ -1010,9 +1010,9 @@ expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { ExprList *pList; int bNot = OP.n & 0x80000000; OP.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, Y.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, A.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, E.pExpr); + pList = sql_expr_list_append(pParse->db,0, Y.pExpr); + pList = sql_expr_list_append(pParse->db,pList, A.pExpr); + pList = sql_expr_list_append(pParse->db,pList, E.pExpr); A.pExpr = sqlite3ExprFunction(pParse, pList, &OP); exprNot(pParse, bNot, &A); A.zEnd = E.zEnd; @@ -1095,14 +1095,14 @@ expr(A) ::= PLUS(B) expr(X). [BITNOT] between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= NOT BETWEEN. {A = 1;} expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { - ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr); - pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr); + ExprList *pList = sql_expr_list_append(pParse->db,0, X.pExpr); + pList = sql_expr_list_append(pParse->db,pList, Y.pExpr); A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, A.pExpr, 0); if( A.pExpr ){ A.pExpr->x.pList = pList; }else{ - sqlite3ExprListDelete(pParse->db, pList); - } + sql_expr_list_free(pParse->db, pList); + } exprNot(pParse, N, &A); A.zEnd = Y.zEnd; } @@ -1140,7 +1140,7 @@ expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] { */ Expr *pRHS = Y->a[0].pExpr; Y->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, Y); + sql_expr_list_free(pParse->db, Y); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ @@ -1154,7 +1154,7 @@ expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] { A.pExpr->x.pList = Y; sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ - sqlite3ExprListDelete(pParse->db, Y); + sql_expr_list_free(pParse->db, Y); } exprNot(pParse, N, &A); } @@ -1192,22 +1192,22 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { spanSet(&A,&C,&E); /*A-overwrites-C*/ A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0); if( A.pExpr ){ - A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; + A.pExpr->x.pList = Z ? sql_expr_list_append(pParse->db,Y,Z) : Y; sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); }else{ - sqlite3ExprListDelete(pParse->db, Y); + sql_expr_list_free(pParse->db, Y); sql_expr_free(pParse->db, Z, false); } } %type case_exprlist {ExprList*} -%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor case_exprlist {sql_expr_list_free(pParse->db, $$);} case_exprlist(A) ::= case_exprlist(A) WHEN expr(Y) THEN expr(Z). { - A = sqlite3ExprListAppend(pParse,A, Y.pExpr); - A = sqlite3ExprListAppend(pParse,A, Z.pExpr); + A = sql_expr_list_append(pParse->db,A, Y.pExpr); + A = sql_expr_list_append(pParse->db,A, Z.pExpr); } case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). { - A = sqlite3ExprListAppend(pParse,0, Y.pExpr); - A = sqlite3ExprListAppend(pParse,A, Z.pExpr); + A = sql_expr_list_append(pParse->db,0, Y.pExpr); + A = sql_expr_list_append(pParse->db,A, Z.pExpr); } %type case_else {Expr*} %destructor case_else {sql_expr_free(pParse->db, $$, false);} @@ -1219,21 +1219,21 @@ case_operand(A) ::= expr(X). {A = X.pExpr; /*A-overwrites-X*/} case_operand(A) ::= . {A = 0;} %type exprlist {ExprList*} -%destructor exprlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor exprlist {sql_expr_list_free(pParse->db, $$);} %type nexprlist {ExprList*} -%destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor nexprlist {sql_expr_list_free(pParse->db, $$);} exprlist(A) ::= nexprlist(A). exprlist(A) ::= . {A = 0;} nexprlist(A) ::= nexprlist(A) COMMA expr(Y). - {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);} + {A = sql_expr_list_append(pParse->db,A,Y.pExpr);} nexprlist(A) ::= expr(Y). - {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/} + {A = sql_expr_list_append(pParse->db,0,Y.pExpr); /*A-overwrites-Y*/} /* A paren_exprlist is an optional expression list contained inside ** of parenthesis */ %type paren_exprlist {ExprList*} -%destructor paren_exprlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor paren_exprlist {sql_expr_list_free(pParse->db, $$);} paren_exprlist(A) ::= . {A = 0;} paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;} @@ -1261,9 +1261,9 @@ uniqueflag(A) ::= . {A = ON_CONFLICT_ACTION_NONE;} // used for the arguments to an index. That is just an historical accident. // %type eidlist {ExprList*} -%destructor eidlist {sqlite3ExprListDelete(pParse->db, $$);} +%destructor eidlist {sql_expr_list_free(pParse->db, $$);} %type eidlist_opt {ExprList*} -%destructor eidlist_opt {sqlite3ExprListDelete(pParse->db, $$);} +%destructor eidlist_opt {sql_expr_list_free(pParse->db, $$);} %include { /* Add a single new term to an ExprList that is used to store a @@ -1278,7 +1278,7 @@ uniqueflag(A) ::= . {A = ON_CONFLICT_ACTION_NONE;} int hasCollate, int sortOrder ){ - ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); + ExprList *p = sql_expr_list_append(pParse->db, pPrior, 0); if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) && pParse->db->init.busy==0 ){ 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/prepare.c b/src/box/sql/prepare.c index f949709..5c7e0c8 100644 --- a/src/box/sql/prepare.c +++ b/src/box/sql/prepare.c @@ -437,12 +437,20 @@ sqlite3_prepare_v2(sqlite3 * db, /* Database handle. */ } void +sql_parser_create(struct Parse *parser) +{ + memset(parser, 0, sizeof(struct Parse)); + struct region *region = &fiber()->gc; + parser->region_initial_size = region_used(region); +} + +void sql_parser_destroy(Parse *parser) { assert(parser != NULL); sqlite3 *db = parser->db; sqlite3DbFree(db, parser->aLabel); - sqlite3ExprListDelete(db, parser->pConstExpr); + sql_expr_list_free(db, parser->pConstExpr); if (db != NULL) { assert(db->lookaside.bDisable >= parser->disableLookaside); diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c index bf729b7..3c2cd63 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); } } @@ -1578,40 +1576,27 @@ sqlite3ResolveSelectNames(Parse * pParse, /* The parser context */ sqlite3WalkSelect(&w, p); } -/* - * Resolve names in expressions that can only reference a single table: - * - * * CHECK constraints - * * WHERE clauses on partial indices - * - * The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression - * is set to -1 and the Expr.iColumn value is set to the column number. - * - * Any errors cause an error message to be set in pParse. - */ void -sqlite3ResolveSelfReference(Parse * pParse, /* Parsing context */ - Table * pTab, /* The table being referenced */ - int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ - Expr * pExpr, /* Expression to resolve. May be NULL. */ - ExprList * pList /* Expression list to resolve. May be NUL. */ - ) +sql_resolve_self_reference(struct Parse *parser, struct Table *table, int type, + struct Expr *expr, struct ExprList *expr_list) { - SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ - NameContext sNC; /* Name context for pParse->pNewTable */ + /* Fake SrcList for pParse->pNewTable */ + SrcList sSrc; + /* Name context for pParse->pNewTable */ + NameContext sNC; assert(type == NC_IsCheck || type == NC_PartIdx || type == NC_IdxExpr); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; - sSrc.a[0].zName = pTab->def->name; - sSrc.a[0].pTab = pTab; + sSrc.a[0].zName = table->def->name; + sSrc.a[0].pTab = table; sSrc.a[0].iCursor = -1; - sNC.pParse = pParse; + sNC.pParse = parser; sNC.pSrcList = &sSrc; sNC.ncFlags = type; - if (sqlite3ResolveExprNames(&sNC, pExpr)) + if (sqlite3ResolveExprNames(&sNC, expr)) return; - if (pList) - sqlite3ResolveExprListNames(&sNC, pList); + if (expr_list) + sqlite3ResolveExprListNames(&sNC, expr_list); } diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 48aaffc..cadebf7 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -92,12 +92,12 @@ clearSelect(sqlite3 * db, Select * p, int bFree) { while (p) { Select *pPrior = p->pPrior; - sqlite3ExprListDelete(db, p->pEList); + sql_expr_list_free(db, p->pEList); sqlite3SrcListDelete(db, p->pSrc); sql_expr_free(db, p->pWhere, false); - sqlite3ExprListDelete(db, p->pGroupBy); + sql_expr_list_free(db, p->pGroupBy); sql_expr_free(db, p->pHaving, false); - sqlite3ExprListDelete(db, p->pOrderBy); + sql_expr_list_free(db, p->pOrderBy); sql_expr_free(db, p->pLimit, false); sql_expr_free(db, p->pOffset, false); if (p->pWith) @@ -148,8 +148,8 @@ sqlite3SelectNew(Parse * pParse, /* Parsing context */ } if (pEList == 0) { pEList = - sqlite3ExprListAppend(pParse, 0, - sqlite3Expr(db, TK_ASTERISK, 0)); + sql_expr_list_append(pParse->db, 0, + sqlite3Expr(db, TK_ASTERISK, 0)); } struct session MAYBE_UNUSED *user_session; user_session = current_session(); @@ -2372,7 +2372,7 @@ generateWithRecursiveQuery(Parse * pParse, /* Parsing context */ sqlite3VdbeResolveLabel(v, addrBreak); end_of_recursive_query: - sqlite3ExprListDelete(pParse->db, p->pOrderBy); + sql_expr_list_free(pParse->db, p->pOrderBy); p->pOrderBy = pOrderBy; p->pLimit = pLimit; p->pOffset = pOffset; @@ -2667,7 +2667,7 @@ multiSelect(Parse * pParse, /* Parsing context */ /* Query flattening in sqlite3Select() might refill p->pOrderBy. * Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ - sqlite3ExprListDelete(db, p->pOrderBy); + sql_expr_list_free(db, p->pOrderBy); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; @@ -3216,8 +3216,8 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */ pNew->flags |= EP_IntValue; pNew->u.iValue = i; pOrderBy = - sqlite3ExprListAppend(pParse, pOrderBy, - pNew); + sql_expr_list_append(pParse->db, pOrderBy, + pNew); if (pOrderBy) pOrderBy->a[nOrderBy++].u.x. iOrderByCol = (u16) i; @@ -3249,7 +3249,7 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */ /* Reattach the ORDER BY clause to the query. */ p->pOrderBy = pOrderBy; - pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); + pPrior->pOrderBy = sql_expr_list_dup(pParse->db, pOrderBy, 0); /* Allocate a range of temporary registers and the KeyInfo needed * for the logic that removes duplicate result rows when the @@ -4106,7 +4106,7 @@ flattenSubquery(Parse * pParse, /* Parsing context */ pParent->pHaving); assert(pParent->pGroupBy == 0); pParent->pGroupBy = - sqlite3ExprListDup(db, pSub->pGroupBy, 0); + sql_expr_list_dup(db, pSub->pGroupBy, 0); } else { pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); @@ -4396,7 +4396,8 @@ convertCompoundSelectToSubquery(Walker * pWalker, Select * p) *pNew = *p; p->pSrc = pNewSrc; p->pEList = - sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); + sql_expr_list_append(pParse->db, 0, + sqlite3Expr(db, TK_ASTERISK, 0)); p->op = TK_SELECT; p->pWhere = 0; pNew->pGroupBy = 0; @@ -4837,8 +4838,8 @@ selectExpander(Walker * pWalker, Select * p) /* This particular expression does not need to be expanded. */ pNew = - sqlite3ExprListAppend(pParse, pNew, - a[k].pExpr); + sql_expr_list_append(pParse->db, pNew, + a[k].pExpr); if (pNew) { pNew->a[pNew->nExpr - 1].zName = a[k].zName; @@ -4942,7 +4943,8 @@ selectExpander(Walker * pWalker, Select * p) } else { pExpr = pRight; } - pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); + pNew = sql_expr_list_append( + pParse->db, pNew, pExpr); sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, @@ -4984,7 +4986,7 @@ selectExpander(Walker * pWalker, Select * p) } } } - sqlite3ExprListDelete(db, pEList); + sql_expr_list_free(db, pEList); p->pEList = pNew; } #if SQLITE_MAX_COLUMN @@ -5385,7 +5387,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ /* If ORDER BY makes no difference in the output then neither does * DISTINCT so it can be removed too. */ - sqlite3ExprListDelete(db, p->pOrderBy); + sql_expr_list_free(db, p->pOrderBy); p->pOrderBy = 0; p->selFlags &= ~SF_Distinct; } @@ -5632,7 +5634,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ if ((p->selFlags & (SF_Distinct | SF_Aggregate)) == SF_Distinct && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1) == 0) { p->selFlags &= ~SF_Distinct; - pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0); + pGroupBy = p->pGroupBy = sql_expr_list_dup(db, pEList, 0); /* Notice that even thought SF_Distinct has been cleared from p->selFlags, * the sDistinct.isTnct is still set. Hence, isTnct represents the * original setting of the SF_Distinct flag, not the current setting @@ -6222,7 +6224,8 @@ sqlite3Select(Parse * pParse, /* The parser context */ if (flag) { pMinMax = - sqlite3ExprListDup(db, pMinMax, 0); + sql_expr_list_dup(db, pMinMax, + 0); pDel = pMinMax; assert(db->mallocFailed || pMinMax != 0); @@ -6244,7 +6247,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax, 0, flag, 0); if (pWInfo == 0) { - sqlite3ExprListDelete(db, pDel); + sql_expr_list_free(db, pDel); goto select_end; } updateAccumulator(pParse, &sAggInfo); @@ -6267,7 +6270,7 @@ sqlite3Select(Parse * pParse, /* The parser context */ SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, pDest, addrEnd, addrEnd); - sqlite3ExprListDelete(db, pDel); + sql_expr_list_free(db, pDel); } sqlite3VdbeResolveLabel(v, addrEnd); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 75699ae..44897af 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -1911,7 +1911,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 */ @@ -2894,10 +2893,8 @@ struct Parse { Token constraintName; /* Name of the constraint currently being parsed */ int regRoot; /* Register holding root page number for new objects */ int nMaxArg; /* Max args passed to user function by sub-program */ -#ifdef SELECTTRACE_ENABLED int nSelect; /* Number of SELECT statements seen */ int nSelectIndent; /* How far to indent SELECTTRACE() output */ -#endif Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ @@ -3472,12 +3469,10 @@ void sqlite3PExprAddSelect(Parse *, Expr *, Select *); Expr *sqlite3ExprAnd(sqlite3 *, Expr *, Expr *); Expr *sqlite3ExprFunction(Parse *, ExprList *, Token *); void sqlite3ExprAssignVarNumber(Parse *, Expr *, u32); -ExprList *sqlite3ExprListAppend(Parse *, ExprList *, Expr *); ExprList *sqlite3ExprListAppendVector(Parse *, ExprList *, IdList *, Expr *); void sqlite3ExprListSetSortOrder(ExprList *, int); void sqlite3ExprListSetName(Parse *, ExprList *, Token *, int); void sqlite3ExprListSetSpan(Parse *, ExprList *, ExprSpan *); -void sqlite3ExprListDelete(sqlite3 *, ExprList *); u32 sqlite3ExprListFlags(const ExprList *); int sqlite3Init(sqlite3 *); int sqlite3InitCallback(void *, int, char **, char **); @@ -3493,10 +3488,18 @@ void sqlite3StartTable(Parse *, Token *, int); void sqlite3AddColumn(Parse *, Token *, Token *); void sqlite3AddNotNull(Parse *, int); void sqlite3AddPrimaryKey(Parse *, ExprList *, int, int, int); -void sqlite3AddCheckConstraint(Parse *, Expr *); void sqlite3AddDefaultValue(Parse *, ExprSpan *); void sqlite3AddCollateType(Parse *, Token *); + +/** + * Add a new CHECK constraint to the table currently under construction. + * @param parser Parsing context. + * @param expr The check expression. + * @param span The check expression string. + */ +void sqlite3AddCheckConstraint(Parse *parser, Expr *expr, ExprSpan *span); + const char * column_collation_name(Table *, uint32_t); const char * @@ -3507,6 +3510,8 @@ struct coll * sql_default_coll(); bool space_is_view(Table *); +struct ExprList * +space_checks_expr_list(uint32_t space_id); void sqlite3EndTable(Parse *, Token *, Token *, Select *); int @@ -3673,7 +3678,6 @@ void sqlite3MayAbort(Parse *); void sqlite3HaltConstraint(Parse *, int, int, char *, i8, u8); void sqlite3UniqueConstraint(Parse *, int, Index *); Expr *sqlite3ExprDup(sqlite3 *, Expr *, int); -ExprList *sqlite3ExprListDup(sqlite3 *, ExprList *, int); SrcList *sqlite3SrcListDup(sqlite3 *, SrcList *, int); IdList *sqlite3IdListDup(sqlite3 *, IdList *); Select *sqlite3SelectDup(sqlite3 *, Select *, int); @@ -3866,7 +3870,6 @@ int sqlite3MatchSpanName(const char *, const char *, const char *); int sqlite3ResolveExprNames(NameContext *, Expr *); int sqlite3ResolveExprListNames(NameContext *, ExprList *); void sqlite3ResolveSelectNames(Parse *, Select *, NameContext *); -void sqlite3ResolveSelfReference(Parse *, Table *, int, Expr *, ExprList *); int sqlite3ResolveOrderGroupBy(Parse *, Select *, ExprList *, const char *); void sqlite3ColumnDefault(Vdbe *, struct space_def *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); @@ -4117,24 +4120,4 @@ extern int sqlite3InitDatabase(sqlite3 * db); enum on_conflict_action table_column_nullable_action(struct Table *tab, uint32_t column); -/** - * Initialize a new parser object. - * @param parser object to initialize. - */ -static inline void -sql_parser_create(struct Parse *parser) -{ - memset(parser, 0, PARSE_HDR_SZ); - memset(PARSE_TAIL(parser), 0, PARSE_TAIL_SZ); - struct region *region = &fiber()->gc; - parser->region_initial_size = region_used(region); -} - -/** - * Release the parser object resources. - * @param parser object to release. - */ -void -sql_parser_destroy(struct Parse *parser); - #endif /* SQLITEINT_H */ diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c index 279c3af..afd202a 100644 --- a/src/box/sql/tokenize.c +++ b/src/box/sql/tokenize.c @@ -649,16 +649,17 @@ sqlite3RunParser(Parse * pParse, const char *zSql, char **pzErrMsg) } int -sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result) +sql_expr_compile(sqlite3 *db, const char *expr, int expr_len, + struct Expr **result) { const char *outer = "SELECT "; - int len = strlen(outer) + strlen(expr); + int len = strlen(outer) + expr_len; char *stmt = (char *) region_alloc(&fiber()->gc, len + 1); if (stmt == NULL) { diag_set(OutOfMemory, len + 1, "region_alloc", "stmt"); return -1; } - sprintf(stmt, "%s%s", outer, expr); + sprintf(stmt, "%s%.*s", outer, expr_len, expr); struct Parse parser; sql_parser_create(&parser); diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 0845d22..e81f8c7 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -53,7 +53,7 @@ sqlite3DeleteTriggerStep(sqlite3 * db, TriggerStep * pTriggerStep) pTriggerStep = pTriggerStep->pNext; sql_expr_free(db, pTmp->pWhere, false); - sqlite3ExprListDelete(db, pTmp->pExprList); + sql_expr_list_free(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); @@ -438,12 +438,12 @@ sqlite3TriggerUpdateStep(sqlite3 * db, /* The database connection */ pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName); if (pTriggerStep) { pTriggerStep->pExprList = - sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); + sql_expr_list_dup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pTriggerStep->orconf = orconf; } - sqlite3ExprListDelete(db, pEList); + sql_expr_list_free(db, pEList); sql_expr_free(db, pWhere, false); return pTriggerStep; } @@ -724,9 +724,10 @@ codeTriggerProgram(Parse * pParse, /* The parser context */ case TK_UPDATE:{ sqlite3Update(pParse, targetSrcList(pParse, pStep), - sqlite3ExprListDup(db, - pStep-> - pExprList, 0), + sql_expr_list_dup(db, + pStep-> + pExprList, + 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf); diff --git a/src/box/sql/update.c b/src/box/sql/update.c index 635b2d6..121db6e 100644 --- a/src/box/sql/update.c +++ b/src/box/sql/update.c @@ -681,7 +681,7 @@ sqlite3Update(Parse * pParse, /* The parser context */ update_cleanup: sqlite3DbFree(db, aXRef); /* Also frees aRegIdx[] and aToOpen[] */ sqlite3SrcListDelete(db, pTabList); - sqlite3ExprListDelete(db, pChanges); + sql_expr_list_free(db, pChanges); sql_expr_free(db, pWhere, false); return; } diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c index a3db23b..7b55f3e 100644 --- a/src/box/sql/wherecode.c +++ b/src/box/sql/wherecode.c @@ -510,11 +510,13 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ pExpr, 0); pRhs = - sqlite3ExprListAppend(pParse, pRhs, - pNewRhs); + sql_expr_list_append(pParse->db, + pRhs, + pNewRhs); pLhs = - sqlite3ExprListAppend(pParse, pLhs, - pNewLhs); + sql_expr_list_append(pParse->db, + pLhs, + pNewLhs); } } if (!db->mallocFailed) { @@ -561,8 +563,8 @@ codeEqualityTerm(Parse * pParse, /* The parsing context */ pLeft->x.pList = pOrigLhs; pX->pLeft = pLeft; } - sqlite3ExprListDelete(pParse->db, pLhs); - sqlite3ExprListDelete(pParse->db, pRhs); + sql_expr_list_free(pParse->db, pLhs); + sql_expr_list_free(pParse->db, pRhs); } if (eType == IN_INDEX_INDEX_DESC) { diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c index 2636cd5..9fc62d8 100644 --- a/src/box/sql/whereexpr.c +++ b/src/box/sql/whereexpr.c @@ -782,8 +782,9 @@ exprAnalyzeOrTerm(SrcList * pSrc, /* the FROM clause */ sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = - sqlite3ExprListAppend(pWInfo->pParse, pList, - pDup); + sql_expr_list_append(pWInfo->pParse->db, + pList, + pDup); pLeft = pOrTerm->pExpr->pLeft; } assert(pLeft != 0); @@ -803,7 +804,7 @@ exprAnalyzeOrTerm(SrcList * pSrc, /* the FROM clause */ pTerm = &pWC->a[idxTerm]; markTermAsChild(pWC, idxNew, idxTerm); } else { - sqlite3ExprListDelete(db, pList); + sql_expr_list_free(db, pList); } pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ } diff --git a/test/sql-tap/check.test.lua b/test/sql-tap/check.test.lua index 9e21c55..3443879 100755 --- a/test/sql-tap/check.test.lua +++ b/test/sql-tap/check.test.lua @@ -345,7 +345,8 @@ test:do_catchsql_test( ); ]], { -- - 1, "subqueries prohibited in CHECK constraints" + 1, "Failed to create space 'T3': subqueries prohibited in CHECK ".. + "constraints" -- }) @@ -370,7 +371,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "no such column: Q" + 1, "Failed to create space 'T3': no such column: Q" -- }) @@ -394,7 +395,7 @@ test:do_catchsql_test( ); ]], { -- - 1, "no such column: T2.X" + 1, "Failed to create space 'T3': no such column: T2.X" -- }) @@ -555,7 +556,8 @@ test:do_catchsql_test( ); ]], { -- - 1, "parameters prohibited in CHECK constraints" + 1, "Failed to create space 'T5': parameters prohibited in CHECK ".. + "constraints" -- }) @@ -567,7 +569,8 @@ test:do_catchsql_test( ); ]], { -- - 1, "parameters prohibited in CHECK constraints" + 1, "Failed to create space 'T5': parameters prohibited in CHECK ".. + "constraints" -- }) -- 2.7.4