[tarantool-patches] [PATCH v6 4/4] sql: remove Checks to server
Kirill Shcherbatov
kshcherbatov at tarantool.org
Tue May 15 20:03:21 MSK 2018
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 <stdlib.h>
#include <stdbool.h>
@@ -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 <id>" 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(
);
]], {
-- <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 +371,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 +395,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 +556,8 @@ 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 +569,8 @@ 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
More information about the Tarantool-patches
mailing list