diff --git a/src/box/alter.cc b/src/box/alter.cc index 87f926dd900c41ad3f590a66d297867a67d4e291..a1780983c47abddbb59b700a006d17833e8f7bf2 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -1898,19 +1898,15 @@ alter_space_move_indexes(struct alter_space *alter, uint32_t begin, * * @param select Tables from this select to be updated. * @param update_value +1 on view creation, -1 on drop. - * @param suppress_error If true, silently skip nonexistent - * spaces from 'FROM' clause. - * @param[out] not_found_space Name of a disappeared space. - * @retval 0 on success, -1 if suppress_error is false and space - * from 'FROM' clause doesn't exist. + * @retval 0 on success, -1 on error (diag is set). */ static int -update_view_references(struct Select *select, int update_value, - bool suppress_error, const char **not_found_space) +update_view_references(struct Select *select, int update_value) { assert(update_value == 1 || update_value == -1); struct SrcList *list = sql_select_expand_from_tables(select); int from_tables_count = sql_src_list_entry_count(list); + /* Firstly check that everything is correct. */ for (int i = 0; i < from_tables_count; ++i) { const char *space_name = sql_src_list_entry_name(list, i); assert(space_name != NULL); @@ -1926,19 +1922,25 @@ update_view_references(struct Select *select, int update_value, continue; struct space *space = space_by_name(space_name); if (space == NULL) { - if (! suppress_error) { - assert(not_found_space != NULL); - *not_found_space = tt_sprintf("%s", space_name); - sqlSrcListDelete(list); - return -1; - } - continue; + diag_set(ClientError, ER_NO_SUCH_SPACE, space_name); + goto error; } + } + /* Secondly do the job. */ + for (int i = 0; i < from_tables_count; ++i) { + const char *space_name = sql_src_list_entry_name(list, i); + /* See comment before sql_select_constains_cte call above. */ + if (sql_select_constains_cte(select, space_name)) + continue; + struct space *space = space_by_name(space_name); assert(space->def->view_ref_count > 0 || update_value > 0); space->def->view_ref_count += update_value; } sqlSrcListDelete(list); return 0; +error: + sqlSrcListDelete(list); + return -1; } /** @@ -1964,7 +1966,8 @@ on_create_view_rollback(struct trigger *trigger, void *event) { (void) event; struct Select *select = (struct Select *)trigger->data; - update_view_references(select, -1, true, NULL); + int rc = update_view_references(select, -1); + assert(rc == 0); (void)rc; sql_select_delete(select); return 0; } @@ -1993,7 +1996,8 @@ on_drop_view_rollback(struct trigger *trigger, void *event) { (void) event; struct Select *select = (struct Select *)trigger->data; - update_view_references(select, 1, true, NULL); + int rc = update_view_references(select, 1); + assert(rc == 0); (void)rc; sql_select_delete(select); return 0; } @@ -2223,19 +2227,8 @@ on_replace_dd_space(struct trigger * /* trigger */, void *event) auto select_guard = make_scoped_guard([=] { sql_select_delete(select); }); - const char *disappeared_space; - if (update_view_references(select, 1, false, - &disappeared_space) != 0) { - /* - * Decrement counters which have - * been increased by previous call. - */ - update_view_references(select, -1, false, - &disappeared_space); - diag_set(ClientError, ER_NO_SUCH_SPACE, - disappeared_space); + if (update_view_references(select, 1) != 0) return -1; - } struct trigger *on_commit_view = txn_alter_trigger_new(on_create_view_commit, select); @@ -2337,7 +2330,8 @@ on_replace_dd_space(struct trigger * /* trigger */, void *event) if (on_rollback_view == NULL) return -1; txn_stmt_on_rollback(stmt, on_rollback_view); - update_view_references(select, -1, true, NULL); + int rc = update_view_references(select, -1); + assert(rc == 0); (void)rc; select_guard.is_active = false; } } else { /* UPDATE, REPLACE */ diff --git a/test/sql/view.result b/test/sql/view.result index d0c3f94a7b6d9c01b33bc9ef564c0e4f83f379f2..6fa8520ba4067e014ef421471cead319ee86d1a5 100644 --- a/test/sql/view.result +++ b/test/sql/view.result @@ -271,6 +271,23 @@ box.execute("DROP TABLE c;") - null - 'Can''t drop space ''C'': other views depend on this space' ... +-- Try to create invalid view using direct insert to space _space. +space_tuple = box.space._space.index[0]:max():totable() +--- +... +space_tuple[1] = space_tuple[1] + 1 -- id +--- +... +space_tuple[3] = space_tuple[3] .. '1' -- name +--- +... +space_tuple[6].sql = string.gsub(space_tuple[6].sql, 'FROM c', 'FROM ccc') +--- +... +box.space._space:insert(space_tuple) +--- +- error: Space 'CCC' does not exist +... box.space.BCV:drop() --- ... diff --git a/test/sql/view.test.lua b/test/sql/view.test.lua index 2ff7ab3451be7a753473436c92979dbc3be9a2d5..8c370959baacf9e20fd684c02d2ec4b7eccc9437 100644 --- a/test/sql/view.test.lua +++ b/test/sql/view.test.lua @@ -101,6 +101,14 @@ box.execute("DROP TABLE c;") box.execute("CREATE TABLE c (s1 INT PRIMARY KEY);") box.execute("CREATE VIEW bcv(x, y) AS VALUES((SELECT 'k' FROM b), (VALUES((SELECT 1 FROM b WHERE s1 IN (VALUES((SELECT 1 + c.s1 FROM c)))))))") box.execute("DROP TABLE c;") + +-- Try to create invalid view using direct insert to space _space. +space_tuple = box.space._space.index[0]:max():totable() +space_tuple[1] = space_tuple[1] + 1 -- id +space_tuple[3] = space_tuple[3] .. '1' -- name +space_tuple[6].sql = string.gsub(space_tuple[6].sql, 'FROM c', 'FROM ccc') +box.space._space:insert(space_tuple) + box.space.BCV:drop() box.execute("DROP TABLE c;") box.execute("DROP TABLE b;")