[tarantool-patches] [PATCH] sql: enable basic SELECTs for Lua created tables
Kirill Yukhin
kyukhin at tarantool.org
Tue Jun 26 10:40:04 MSK 2018
Branch: https://github.com/tarantool/tarantool/tree/kyukhin/gh-3369-lua-select
Issue: https://github.com/tarantool/tarantool/issues/3369
Update expander of SELECT statement to search for space if
corresponding table wasn't found in table hash. Create dummy
table if so and fill def field only.
Also fix a leak in VIEW creation.
Part of #3369
---
src/box/sql.c | 8 +--
src/box/sql/build.c | 4 +-
src/box/sql/insert.c | 9 ++-
src/box/sql/select.c | 21 ++++++-
test/sql-tap/lua-tables.test.lua | 117 +++++++++++++++++++++++++++++++++++++++
5 files changed, 148 insertions(+), 11 deletions(-)
create mode 100755 test/sql-tap/lua-tables.test.lua
diff --git a/src/box/sql.c b/src/box/sql.c
index 1135315..6e5c1b3 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1740,14 +1740,14 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno)
}
struct space_def *
-sql_ephemeral_space_def_new(Parse *parser, const char *name)
+sql_ephemeral_space_def_new(struct Parse *parser, const char *name)
{
struct space_def *def = NULL;
- struct region *region = &fiber()->gc;
size_t name_len = name != NULL ? strlen(name) : 0;
uint32_t dummy;
- size_t size = space_def_sizeof(name_len, NULL, 0, &dummy, &dummy, &dummy);
- def = (struct space_def *)region_alloc(region, size);
+ size_t size = space_def_sizeof(name_len, NULL, 0, &dummy, &dummy,
+ &dummy);
+ def = (struct space_def *)region_alloc(&parser->region, size);
if (def == NULL) {
diag_set(OutOfMemory, size, "region_alloc",
"sql_ephemeral_space_def_new");
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 0da7d80..748fb51 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -1970,6 +1970,7 @@ sql_create_view(struct Parse *parse_context, struct Token *begin,
struct Select *select, bool if_exists)
{
struct sqlite3 *db = parse_context->db;
+ struct Table *sel_tab = NULL;
if (parse_context->nVar > 0) {
sqlite3ErrorMsg(parse_context,
"parameters are not allowed in views");
@@ -1979,7 +1980,7 @@ sql_create_view(struct Parse *parse_context, struct Token *begin,
struct Table *p = parse_context->pNewTable;
if (p == NULL || parse_context->nErr != 0)
goto create_view_fail;
- struct Table *sel_tab = sqlite3ResultSetOfSelect(parse_context, select);
+ sel_tab = sqlite3ResultSetOfSelect(parse_context, select);
if (sel_tab == NULL)
goto create_view_fail;
if (aliases != NULL) {
@@ -2032,6 +2033,7 @@ sql_create_view(struct Parse *parse_context, struct Token *begin,
sqlite3EndTable(parse_context, 0, &end, 0);
create_view_fail:
+ sqlite3DbFree(db, sel_tab);
sql_expr_list_delete(db, aliases);
sql_select_delete(db, select);
return;
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index a43f7b5..6a8cc69 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -51,11 +51,10 @@ sqlite3OpenTable(Parse * pParse, /* Generate code into this VDBE */
Vdbe *v;
v = sqlite3GetVdbe(pParse);
assert(opcode == OP_OpenWrite || opcode == OP_OpenRead);
- Index *pPk = sqlite3PrimaryKeyIndex(pTab);
- assert(pPk != 0);
- assert(pPk->tnum == pTab->tnum);
- struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(pPk->tnum));
- vdbe_emit_open_cursor(pParse, iCur, pPk->tnum, space);
+
+ struct space *space = space_by_id(pTab->def->id);
+ assert(space->index_count > 0);
+ vdbe_emit_open_cursor(pParse, iCur, 0, space);
VdbeComment((v, "%s", pTab->def->name));
}
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 368bcd6..dd847aa 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -36,6 +36,7 @@
#include "coll.h"
#include "sqliteInt.h"
#include "tarantoolInt.h"
+#include "box/box.h"
#include "box/coll_id_cache.h"
#include "box/schema.h"
#include "box/session.h"
@@ -4798,7 +4799,25 @@ selectExpander(Walker * pWalker, Select * p)
/* An ordinary table or view name in the FROM clause */
assert(pFrom->pTab == 0);
pFrom->pTab = pTab =
- sqlite3LocateTable(pParse, 0, pFrom->zName);
+ sqlite3LocateTable(pParse, LOCATE_NOERR, pFrom->zName);
+ if (pTab == NULL) {
+ struct Table *tab = sqlite3DbMallocZero(db,
+ sizeof(Table));
+ tab->nTabRef = 1;
+ const char *t_name = pFrom->zName;
+ int space_id = box_space_id_by_name(t_name,
+ strlen(t_name));
+ if (space_id == BOX_ID_NIL) {
+ sqlite3ErrorMsg(pParse,
+ "no such table: %s",
+ t_name);
+ pParse->checkSchema = 1;
+ return WRC_Abort;
+ }
+ struct space *space = space_by_id(space_id);
+ tab->def = space->def;
+ pFrom->pTab = pTab = tab;
+ }
if (pTab == NULL)
return WRC_Abort;
if (pTab->nTabRef >= 0xffff) {
diff --git a/test/sql-tap/lua-tables.test.lua b/test/sql-tap/lua-tables.test.lua
new file mode 100755
index 0000000..3096cd7
--- /dev/null
+++ b/test/sql-tap/lua-tables.test.lua
@@ -0,0 +1,117 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(7)
+
+test:do_test(
+ "lua-tables-repare-1",
+ function()
+ format = {}
+ format[1] = { name = 'id', type = 'scalar'}
+ format[2] = { name = 'f2', type = 'scalar'}
+ s = box.schema.create_space('t', {format = format})
+ i = s:create_index('i', {parts={1, 'scalar'}})
+
+ s:replace{1, 4}
+ s:replace{2, 2}
+ s:replace{3, 3}
+ s:replace{4, 3}
+
+ s1 = box.schema.create_space('t1')
+ s1:create_index('i', {parts={1, 'scalar'}})
+ s1:replace{1, 1}
+ end,
+ {})
+
+test:do_execsql_test(
+ "lua-tables-2",
+ [[SELECT *, count(*)
+ FROM "t" as t1, "t" as t2
+ WHERE t1."id" = t2."f2"
+ ]],
+ {4, 3, 1, 4, 4})
+
+test:do_execsql_test(
+ "lua-tables-3",
+ [[create view v as SELECT * FROM "t";
+ select * from v;
+ ]],
+ {1, 4, 2, 2, 3, 3, 4, 3})
+
+test:do_catchsql_test(
+ "lua-tables-4",
+ [[SELECT * from "t1"]],
+ {1, "no tables specified"}
+)
+
+-- Extract from tkt3527.test.lua
+test:do_test(
+ "lua-tables-prepare-5",
+ function()
+ format = {{name = "CODE", type = "integer"},
+ {name = "NAME", type = "scalar"}}
+ s = box.schema.create_space("ELEMENT", {format = format})
+ s:create_index('pk', {parts = {1, 'scalar'}})
+ s:replace{1, 'Elem1'}
+ s:replace{2, 'Elem2'}
+ s:replace{3, 'Elem3'}
+ s:replace{4, 'Elem4'}
+ s:replace{5, 'Elem5'}
+
+ format = {{name = "CODEOR", type = "scalar"},
+ {name = "CODE", type = "scalar"}}
+ s = box.schema.create_space("ELEMOR", {format = format})
+ s:create_index('pk', {parts = {1, 'scalar', 2, 'scalar'}})
+ s:replace{3, 4}
+ s:replace{4, 5}
+
+ format = {{name = "CODEAND", type = "scalar"},
+ {name = "CODE", type = "scalar"},
+ {name = "ATTR1", type = "scalar"},
+ {name = "ATTR2", type = "scalar"},
+ {name = "ATTR3", type = "scalar"}}
+ s = box.schema.create_space("ELEMAND", {format = format})
+ s:create_index('pk', {parts = {1, "scalar", 2, "scalar"}})
+ s:replace{1, 3, 'a', 'b', 'c'}
+ s:replace{1, 2, 'x', 'y', 'z'}
+ end,
+ {})
+
+test:do_execsql_test(
+ "lua-tables-6",
+ [[CREATE VIEW ElemView1 AS
+ SELECT
+ CAST(Element.Code AS VARCHAR(50)) AS ElemId,
+ Element.Code AS ElemCode,
+ Element.Name AS ElemName,
+ ElemAnd.Code AS InnerCode,
+ ElemAnd.Attr1 AS Attr1,
+ ElemAnd.Attr2 AS Attr2,
+ ElemAnd.Attr3 AS Attr3,
+ 0 AS Level,
+ 0 AS IsOrElem
+ FROM Element JOIN ElemAnd ON ElemAnd.CodeAnd=Element.Code
+ WHERE ElemAnd.CodeAnd NOT IN (SELECT CodeOr FROM ElemOr)
+ UNION ALL
+ SELECT
+ CAST(ElemOr.CodeOr AS VARCHAR(50)) AS ElemId,
+ Element.Code AS ElemCode,
+ Element.Name AS ElemName,
+ ElemOr.Code AS InnerCode,
+ NULL AS Attr1,
+ NULL AS Attr2,
+ NULL AS Attr3,
+ 0 AS Level,
+ 1 AS IsOrElem
+ FROM ElemOr JOIN Element ON Element.Code=ElemOr.CodeOr
+ ORDER BY ElemId, InnerCode;]],
+ {})
+
+test:do_execsql_test(
+ "lua-tables-7",
+ [[SELECT * FROM ElemView1]],
+ {"1",1,"Elem1",2,"x","y","z",0,0,
+ "1",1,"Elem1",3,"a","b","c",0,0,
+ "3",3,"Elem3",4,"","","",0,1,
+ "4",4,"Elem4",5,"","","",0,1})
+
+test:finish_test()
--
2.16.2
More information about the Tarantool-patches
mailing list