[tarantool-patches] [PATCH v2 1/2] Introduce 'view' space option

Nikita Pettik korablev at tarantool.org
Tue Mar 27 02:03:32 MSK 2018


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





More information about the Tarantool-patches mailing list