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 E60422AA4D for ; Mon, 26 Mar 2018 19:03:45 -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 C1WTxQtG7e-J for ; Mon, 26 Mar 2018 19:03:45 -0400 (EDT) Received: from smtp29.i.mail.ru (smtp29.i.mail.ru [94.100.177.89]) (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 2F6722A9BB for ; Mon, 26 Mar 2018 19:03:44 -0400 (EDT) From: Nikita Pettik Subject: [tarantool-patches] [PATCH v2 1/2] Introduce 'view' space option Date: Tue, 27 Mar 2018 02:03:32 +0300 Message-Id: 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@freelist.org Cc: tarantool-patches@freelists.org, Nikita Pettik Now, space can feature SQL specific option 'view'. In SQL view is a space without any functional parts except for 'SELECT' statement. In this respect, creation of any indexes is prohibited on views; views must have SQL statement; transofrmation from space to view is also banned. It is worth mentioning, that setting 'view' option isn't available via Lua interface function 'space_create', but possible by straight insertion in _space space. Closes #3268 --- src/box/alter.cc | 7 ++++ src/box/errcode.h | 3 +- src/box/space_def.c | 7 ++++ src/box/space_def.h | 6 ++++ src/box/sql.c | 9 ++++- test/box/misc.result | 1 + test/sql/view.result | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/sql/view.test.lua | 46 ++++++++++++++++++++++++ 8 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 test/sql/view.result create mode 100644 test/sql/view.test.lua diff --git a/src/box/alter.cc b/src/box/alter.cc index bd87d2f54..a93ea5918 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -496,6 +496,9 @@ space_def_new_from_tuple(struct tuple *tuple, uint32_t errcode, } struct space_opts opts; space_opts_decode(&opts, space_opts, region); + if (opts.view && opts.sql == NULL) { + tnt_raise(ClientError, ER_VIEW_MISSING_SQL); + } struct space_def *def = space_def_new_xc(id, uid, exact_field_count, name, name_len, engine_name, engine_name_len, &opts, fields, @@ -1590,6 +1593,10 @@ on_replace_dd_index(struct trigger * /* trigger */, void *event) uint32_t iid = tuple_field_u32_xc(old_tuple ? old_tuple : new_tuple, BOX_INDEX_FIELD_ID); struct space *old_space = space_cache_find_xc(id); + if (old_space->def->opts.view) { + tnt_raise(ClientError, ER_ALTER_SPACE, space_name(old_space), + "can not alter indexes on view"); + } enum priv_type priv_type = new_tuple ? PRIV_C : PRIV_D; if (old_tuple && new_tuple) priv_type = PRIV_A; diff --git a/src/box/errcode.h b/src/box/errcode.h index beb37aa2f..e5d882df8 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -212,7 +212,8 @@ struct errcode_record { /*157 */_(ER_SQL_EXECUTE, "Failed to execute SQL statement: %s") \ /*158 */_(ER_SQL, "SQL error: %s") \ /*159 */_(ER_SQL_BIND_NOT_FOUND, "Parameter %s was not found in the statement") \ - /*160 */_(ER_ACTION_MISMATCH, "Field %d contains %s on conflict action, but %s in index parts") + /*160 */_(ER_ACTION_MISMATCH, "Field %d contains %s on conflict action, but %s in index parts") \ + /*161 */_(ER_VIEW_MISSING_SQL, "Space declared as a view must have SQL statement") \ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/space_def.c b/src/box/space_def.c index 340cf27f2..304f904a6 100644 --- a/src/box/space_def.c +++ b/src/box/space_def.c @@ -35,11 +35,13 @@ const struct space_opts space_opts_default = { /* .temporary = */ false, + /* .view = */ false, /* .sql = */ 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, view), OPT_DEF("sql", OPT_STRPTR, struct space_opts, sql), OPT_END, }; @@ -177,6 +179,11 @@ space_def_check_compatibility(const struct space_def *old_def, "space id is immutable"); return -1; } + if (new_def->opts.view != old_def->opts.view) { + diag_set(ClientError, ER_ALTER_SPACE, old_def->name, + "can not transform space to view and visa versa"); + return -1; + } if (is_space_empty) return 0; diff --git a/src/box/space_def.h b/src/box/space_def.h index 8425ff6d3..bdf697437 100644 --- a/src/box/space_def.h +++ b/src/box/space_def.h @@ -49,6 +49,12 @@ struct space_opts { * - changes are not part of a snapshot */ bool temporary; + /** + * If the space is a view, then it can't feature any + * indexes, and must have SQL statement. Moreover, + * this flag can't be changed after space creation. + */ + bool view; /** * SQL statement that produced this space. */ diff --git a/src/box/sql.c b/src/box/sql.c index 224747157..1e5f551ae 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -1592,9 +1592,16 @@ int tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, void *buf) const struct Enc *enc = get_enc(buf); char *base = buf, *p; - p = enc->encode_map(base, 1); + bool is_view = false; + if (pTable != NULL) + is_view = pTable->pSelect != NULL; + p = enc->encode_map(base, is_view ? 2 : 1); 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); + } return (int)(p - base); } diff --git a/test/box/misc.result b/test/box/misc.result index aeee42930..298e6a9ba 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -329,6 +329,7 @@ t; - 'box.error.ROLE_LOOP : 87' - 'box.error.TUPLE_NOT_FOUND : 4' - 'box.error.LOADING : 116' + - 'box.error.VIEW_MISSING_SQL : 161' - 'box.error.BACKUP_IN_PROGRESS : 129' - 'box.error.DROP_USER : 44' - 'box.error.MODIFY_INDEX : 14' diff --git a/test/sql/view.result b/test/sql/view.result new file mode 100644 index 000000000..aa65dfb28 --- /dev/null +++ b/test/sql/view.result @@ -0,0 +1,98 @@ +test_run = require('test_run').new() +--- +... +-- Verify that constraints on 'view' option are working. +-- box.cfg() +-- Create space and view. +box.sql.execute("CREATE TABLE t1(a, b, PRIMARY KEY(a, b));"); +--- +... +box.sql.execute("CREATE VIEW v1 AS SELECT a+b FROM t1;"); +--- +... +-- View can't have any indexes. +box.sql.execute("CREATE INDEX i1 on v1(a);"); +--- +- error: views may not be indexed +... +v1 = box.space.V1; +--- +... +v1:create_index('primary', {parts = {1, 'string'}}) +--- +- error: 'Can''t modify space ''V1'': can not alter indexes on view' +... +v1:create_index('secondary', {parts = {1, 'string'}}) +--- +- error: 'Can''t modify space ''V1'': can not alter indexes on view' +... +-- View option can't be changed. +v1 = box.space._space.index[2]:select('V1')[1]:totable(); +--- +... +v1[6]['view'] = false; +--- +... +box.space._space:replace(v1); +--- +- error: 'Can''t modify space ''V1'': can not transform space to view and visa versa' +... +t1 = box.space._space.index[2]:select('T1')[1]:totable(); +--- +... +t1[6]['view'] = true; +--- +... +box.space._space:replace(t1); +--- +- error: 'Can''t modify space ''T1'': can not transform space to view and visa versa' +... +-- View can't exist without SQL statement. +v1[6] = {}; +--- +... +v1[6]['view'] = true; +--- +... +box.space._space:replace(v1); +--- +- error: Space declared as a view must have SQL statement +... +-- Views can't be created via space_create(). +box.schema.create_space('view', {view = true}) +--- +- error: Illegal parameters, unexpected option 'view' +... +-- View can be created via straight insertion into _space. +sp = box.schema.create_space('test'); +--- +... +raw_sp = box.space._space:get(sp.id):totable(); +--- +... +sp:drop(); +--- +... +raw_sp[6].sql = 'fake'; +--- +... +raw_sp[6].view = true; +--- +... +sp = box.space._space:replace(raw_sp); +--- +... +box.space._space:select(sp['id'])[1]['name'] +--- +- test +... +-- Cleanup +box.space.test:drop(); +--- +... +box.sql.execute("DROP TABLE t1;"); +--- +... +box.sql.execute("DROP VIEW v1;"); +--- +... diff --git a/test/sql/view.test.lua b/test/sql/view.test.lua new file mode 100644 index 000000000..ab2843cb6 --- /dev/null +++ b/test/sql/view.test.lua @@ -0,0 +1,46 @@ +test_run = require('test_run').new() + +-- Verify that constraints on 'view' option are working. + +-- box.cfg() + +-- Create space and view. +box.sql.execute("CREATE TABLE t1(a, b, PRIMARY KEY(a, b));"); +box.sql.execute("CREATE VIEW v1 AS SELECT a+b FROM t1;"); + +-- View can't have any indexes. +box.sql.execute("CREATE INDEX i1 on v1(a);"); +v1 = box.space.V1; +v1:create_index('primary', {parts = {1, 'string'}}) +v1:create_index('secondary', {parts = {1, 'string'}}) + +-- View option can't be changed. +v1 = box.space._space.index[2]:select('V1')[1]:totable(); +v1[6]['view'] = false; +box.space._space:replace(v1); + +t1 = box.space._space.index[2]:select('T1')[1]:totable(); +t1[6]['view'] = true; +box.space._space:replace(t1); + +-- View can't exist without SQL statement. +v1[6] = {}; +v1[6]['view'] = true; +box.space._space:replace(v1); + +-- Views can't be created via space_create(). +box.schema.create_space('view', {view = true}) + +-- View can be created via straight insertion into _space. +sp = box.schema.create_space('test'); +raw_sp = box.space._space:get(sp.id):totable(); +sp:drop(); +raw_sp[6].sql = 'fake'; +raw_sp[6].view = true; +sp = box.space._space:replace(raw_sp); +box.space._space:select(sp['id'])[1]['name'] + +-- Cleanup +box.space.test:drop(); +box.sql.execute("DROP TABLE t1;"); +box.sql.execute("DROP VIEW v1;"); -- 2.15.1