Skip to content

Commit

Permalink
sql: do not reset region on select
Browse files Browse the repository at this point in the history
Prior to this patch, region on fiber was reset during select(), get(),
count(), max(), or min(). This would result in an error if one of these
operations was used in a user-defined function in SQL. After this patch,
these functions truncate region instead of resetting it.

Closes #5427
  • Loading branch information
ImeevMA committed Nov 2, 2020
1 parent 42c64d0 commit de3a354
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 6 deletions.
5 changes: 4 additions & 1 deletion src/box/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,8 @@ box_select(uint32_t space_id, uint32_t index_id,
struct port *port)
{
(void)key_end;

struct region *region = &fiber()->gc;
size_t used = region_used(region);
rmean_collect(rmean_box, IPROTO_SELECT, 1);

if (iterator < 0 || iterator >= iterator_type_MAX) {
Expand Down Expand Up @@ -1453,6 +1454,8 @@ box_select(uint32_t space_id, uint32_t index_id,
return -1;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
return 0;
}

Expand Down
20 changes: 20 additions & 0 deletions src/box/index.cc
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
mp_tuple_assert(key, key_end);
struct space *space;
struct index *index;
struct region *region = &fiber()->gc;
size_t used = region_used(region);
if (check_index(space_id, index_id, &space, &index) != 0)
return -1;
if (!index->def->opts.is_unique) {
Expand All @@ -246,6 +248,8 @@ box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
return -1;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
/* Count statistics. */
rmean_collect(rmean_box, IPROTO_SELECT, 1);
if (*result != NULL)
Expand All @@ -261,6 +265,8 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
mp_tuple_assert(key, key_end);
struct space *space;
struct index *index;
struct region *region = &fiber()->gc;
size_t used = region_used(region);
if (check_index(space_id, index_id, &space, &index) != 0)
return -1;
if (index->def->type != TREE) {
Expand All @@ -280,6 +286,8 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
return -1;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
if (*result != NULL)
tuple_bless(*result);
return 0;
Expand All @@ -293,6 +301,8 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
assert(result != NULL);
struct space *space;
struct index *index;
struct region *region = &fiber()->gc;
size_t used = region_used(region);
if (check_index(space_id, index_id, &space, &index) != 0)
return -1;
if (index->def->type != TREE) {
Expand All @@ -312,6 +322,8 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
return -1;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
if (*result != NULL)
tuple_bless(*result);
return 0;
Expand All @@ -331,6 +343,8 @@ box_index_count(uint32_t space_id, uint32_t index_id, int type,
enum iterator_type itype = (enum iterator_type) type;
struct space *space;
struct index *index;
struct region *region = &fiber()->gc;
size_t used = region_used(region);
if (check_index(space_id, index_id, &space, &index) != 0)
return -1;
uint32_t part_count = mp_decode_array(&key);
Expand All @@ -346,6 +360,8 @@ box_index_count(uint32_t space_id, uint32_t index_id, int type,
return -1;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
return count;
}

Expand All @@ -367,6 +383,8 @@ box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
enum iterator_type itype = (enum iterator_type) type;
struct space *space;
struct index *index;
struct region *region = &fiber()->gc;
size_t used = region_used(region);
if (check_index(space_id, index_id, &space, &index) != 0)
return NULL;
assert(mp_typeof(*key) == MP_ARRAY); /* checked by Lua */
Expand All @@ -383,6 +401,8 @@ box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
return NULL;
}
txn_commit_ro_stmt(txn);
if (txn == NULL)
region_truncate(region, used);
rmean_collect(rmean_box, IPROTO_SELECT, 1);
return it;
}
Expand Down
6 changes: 1 addition & 5 deletions src/box/txn.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,7 @@ static inline void
txn_commit_ro_stmt(struct txn *txn)
{
assert(txn == in_txn());
if (txn) {
/* nothing to do */
} else {
fiber_gc();
}
(void)txn;
}

/**
Expand Down
153 changes: 153 additions & 0 deletions test/sql/gh-5427-lua-func-changes-result.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
-- test-run result file version 2
test_run = require('test_run').new()
| ---
| ...
engine = test_run:get_cfg('engine')
| ---
| ...
_ = box.space._session_settings:update('sql_default_engine', {{'=', 2, engine}})
| ---
| ...

box.execute([[CREATE TABLE t (b STRING PRIMARY KEY);]])
| ---
| - row_count: 1
| ...
box.execute([[INSERT INTO t VALUES ('aaaaaaaaaaaa');]])
| ---
| - row_count: 1
| ...
test_run:cmd("setopt delimiter ';'");
| ---
| - true
| ...
box.schema.func.create('CORRUPT_SELECT', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:select()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
| ---
| ...
box.schema.func.create('CORRUPT_GET', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:get('aaaaaaaaaaaa')
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
| ---
| ...
box.schema.func.create('CORRUPT_COUNT', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:count()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
| ---
| ...
box.schema.func.create('CORRUPT_MAX', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T.index[0]:max()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
| ---
| ...
box.schema.func.create('CORRUPT_MIN', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T.index[0]:min()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
| ---
| ...
test_run:cmd("setopt delimiter ''");
| ---
| - true
| ...

box.execute([[select CORRUPT_SELECT(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
| ---
| - metadata:
| - name: COLUMN_1
| type: integer
| rows:
| - [1]
| ...
box.execute([[select CORRUPT_GET(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
| ---
| - metadata:
| - name: COLUMN_1
| type: integer
| rows:
| - [1]
| ...
box.execute([[select CORRUPT_COUNT(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
| ---
| - metadata:
| - name: COLUMN_1
| type: integer
| rows:
| - [1]
| ...
box.execute([[select CORRUPT_MAX(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
| ---
| - metadata:
| - name: COLUMN_1
| type: integer
| rows:
| - [1]
| ...
box.execute([[select CORRUPT_MIN(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
| ---
| - metadata:
| - name: COLUMN_1
| type: integer
| rows:
| - [1]
| ...

box.execute([[DROP TABLE t;]])
| ---
| - row_count: 1
| ...
86 changes: 86 additions & 0 deletions test/sql/gh-5427-lua-func-changes-result.test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
test_run = require('test_run').new()
engine = test_run:get_cfg('engine')
_ = box.space._session_settings:update('sql_default_engine', {{'=', 2, engine}})

box.execute([[CREATE TABLE t (b STRING PRIMARY KEY);]])
box.execute([[INSERT INTO t VALUES ('aaaaaaaaaaaa');]])
test_run:cmd("setopt delimiter ';'");
box.schema.func.create('CORRUPT_SELECT', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:select()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
box.schema.func.create('CORRUPT_GET', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:get('aaaaaaaaaaaa')
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
box.schema.func.create('CORRUPT_COUNT', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T:count()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
box.schema.func.create('CORRUPT_MAX', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T.index[0]:max()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
box.schema.func.create('CORRUPT_MIN', {
language = 'LUA',
returns = 'integer',
body = [[
function(x)
box.space.T.index[0]:min()
return 1
end]],
is_sandboxed = false,
param_list = { "string" },
exports = { 'LUA', 'SQL' },
is_deterministic = false,
if_not_exists = true
});
test_run:cmd("setopt delimiter ''");

box.execute([[select CORRUPT_SELECT(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
box.execute([[select CORRUPT_GET(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
box.execute([[select CORRUPT_COUNT(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
box.execute([[select CORRUPT_MAX(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})
box.execute([[select CORRUPT_MIN(t.b) from t where t.b = ? and t.b <= ? order by t.b;]], {"aaaaaaaaaaaa", "aaaaaaaaaaaa"})

box.execute([[DROP TABLE t;]])

0 comments on commit de3a354

Please sign in to comment.