From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 09D0E43A26F for ; Fri, 25 Oct 2019 18:45:43 +0300 (MSK) From: imeevma@tarantool.org Date: Fri, 25 Oct 2019 18:45:43 +0300 Message-Id: In-Reply-To: References: Subject: [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview List-Id: Tarantool development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org Cc: tarantool-patches@freelists.org, tarantool-patches@dev.tarantool.org Thank you for review! My answers, one question and new patch below. On 10/19/19 1:08 AM, Vladislav Shpilevoy wrote: > Thanks for the patch! > > See 14 comments below. > > On 17/10/2019 16:40, imeevma@tarantool.org wrote: >> This patch creates the _vsql_settings sysview. This system view >> has custom methods get() and create_iterator(). This allows us >> to get SQL settings by creating a tuple on the fly without having >> to save it anywhere. >> >> Part of #4511 >> >> @TarantoolBot document > > 1. I think, it is worth to create one doc request for the > whole feature - both SET command and _vsql_settings space. > They are useless without each other. > Fixed. However, do I need to write a doc-bot request now when the sysview purpose has changed? >> Title: The _vsql_settings sysview >> Sysview _vsql_settings allows the user to get the current SQL >> parameters. >> >> Currently available SQL settings: >> 'defer_foreign_keys' >> 'full_column_names' >> 'recursive_triggers' >> 'reverse_unordered_selects' >> 'sql_compound_select_limit' >> 'sql_default_engine' >> >> In addition, SQL debugging settings can also be obtained from this >> system view in the debug build: >> 'parser_trace' >> 'select_trace' >> 'sql_trace' >> 'vdbe_addoptrace' >> 'vdbe_debug' >> 'vdbe_eqp' >> 'vdbe_listing' >> 'vdbe_trace' >> 'where_trace' >> >> Example of usage: >> box.space._vsql_settings:get{'full_column_names'} >> box.space._vsql_settings:select{'defer_foreign_keys'} >> box.space._vsql_settings:select{'full_column_names', {iterator = 'LE'}} > > 2. There is a problem with having generic iterators. Because if > you allow to iterate over multiple settings, then you have > to do it like normal indexes do, with a strict order. Currently > you return settings without an order. > > There is 2 options what to do: > > - Ban all iterator types except =, and ban an empty key; > > - Keep the settings sorted and return them like a tree > index does. That might be useful in case we will agree > to create a generic space _vsession_storage. Then by a > prefix a user could select all settings of a specific > subsystem. Like 'sql_', 'vinyl_', etc. > > I am ok with both. Or maybe you will be able to find a third > solution. > Fixed. I changed the order, now it works as the second option suggested. > Another problem is that: pairs() and select() somewhy return > different results. > > tarantool> t = {} > --- > ... > > tarantool> for k, v in box.space._vsql_settings:pairs() do table.insert(t, {k, v}) end > --- > ... > > tarantool> t > --- > - - - > - ['defer_foreign_keys', false] > ... > > tarantool> box.space._vsql_settings:select() > --- > - - ['defer_foreign_keys', false] > - ['full_column_names', false] > - ['recursive_triggers', true] > - ['reverse_unordered_selects', false] > - ['sql_compound_select_limit', 30] > - ['sql_default_engine', 'memtx'] > - ['parser_trace', false] > - ['select_trace', false] > - ['sql_trace', false] > - ['vdbe_addoptrace', false] > - ['vdbe_debug', false] > - ['vdbe_eqp', false] > - ['vdbe_listing', false] > - ['vdbe_trace', false] > - ['where_trace', false] > ... > > As you see, pairs() stops after a first tuple. For other spaces > empty pairs and select work the same. > I fixed this, still not sure why it was like this - after I rewritten the patch, it worked as it should. >> --- >> src/box/bootstrap.snap | Bin 5934 -> 5973 bytes >> src/box/lua/space.cc | 2 + >> src/box/lua/upgrade.lua | 23 +++++ >> src/box/schema_def.h | 2 + >> src/box/sql.c | 203 +++++++++++++++++++++++++++++++++++++ >> src/box/sql.h | 66 ++++++++++++ >> src/box/sql/sqlInt.h | 14 +-- >> src/box/sysview.c | 19 +++- >> test/app-tap/tarantoolctl.test.lua | 4 +- >> test/box-py/bootstrap.result | 5 +- >> test/box/access_misc.result | 136 +++++++++++++------------ >> test/box/access_sysview.result | 6 +- >> test/box/alter.result | 5 +- >> test/box/sql.result | 111 ++++++++++++++++++++ >> test/box/sql.test.lua | 38 +++++++ >> test/wal_off/alter.result | 2 +- >> 16 files changed, 542 insertions(+), 94 deletions(-) >> >> diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua >> index 2abd75d..f105db8 100644 >> --- a/src/box/lua/upgrade.lua >> +++ b/src/box/lua/upgrade.lua >> @@ -930,6 +930,28 @@ local function upgrade_to_2_3_0() >> end >> >> -------------------------------------------------------------------------------- >> +-- Tarantool 2.3.1 >> +-------------------------------------------------------------------------------- >> + >> +local function create_vsql_settings_sysview() >> + local _space = box.space[box.schema.SPACE_ID] >> + local _index = box.space[box.schema.INDEX_ID] >> + local format = {} >> + format[1] = {name='name', type='string'} >> + format[2] = {name='value', type='any'} >> + log.info("create space _vsql_settings") >> + _space:insert{box.schema.VSQL_SETTINGS_ID, ADMIN, '_vsql_settings', >> + 'sysview', 0, setmap({}), format} >> + log.info("create index _sql_settings:primary") > > 3. _vsql, not _sql > Fixed. >> + _index:insert{box.schema.VSQL_SETTINGS_ID, 0, 'primary', 'tree', > > 4. See? You said it is 'tree' and the key is string, but select() returns > tuples in a mixed order: > > - ['sql_default_engine', 'memtx'] > - ['parser_trace', false] > - ['select_trace', false] > > 's', 'p', 's' - clearly not an alphabetical order. > Fixed. >> + {unique = true}, {{0, 'string'}}} >> +end >> + >> diff --git a/src/box/schema_def.h b/src/box/schema_def.h >> index 85f652d..04e1e33 100644 >> --- a/src/box/schema_def.h >> +++ b/src/box/schema_def.h >> @@ -114,6 +114,8 @@ enum { >> BOX_CK_CONSTRAINT_ID = 364, >> /** Space id of _func_index. */ >> BOX_FUNC_INDEX_ID = 372, >> + /** Space id of _vsql_settings. */ >> + BOX_VSQL_SETTINGS_ID = 380, > > 5. Usually system views are the original space ID + 1. > So here it would be 381. Sorry for the nit. > Fixed. >> /** End of the reserved range of system spaces. */ >> BOX_SYSTEM_ID_MAX = 511, >> BOX_ID_NIL = 2147483647 >> diff --git a/src/box/sql.c b/src/box/sql.c >> index f1df555..0c73caf 100644 >> --- a/src/box/sql.c >> +++ b/src/box/sql.c >> @@ -1265,3 +1265,206 @@ vdbe_field_ref_prepare_tuple(struct vdbe_field_ref *field_ref, >> vdbe_field_ref_create(field_ref, tuple, tuple_data(tuple), >> tuple->bsize); >> } >> + >> +struct sql_option_metadata sql_options[] = { >> + /* SQL_OPTION_DEFER_FOREIGN_KEYS */ >> + {"defer_foreign_keys", FIELD_TYPE_BOOLEAN, SQL_DeferFKs}, >> + /* SQL_OPTION_DEFER_FOREIGN_KEYS */ > > 6. Double SQL_OPTION_DEFER_FOREIGN_KEYS. > Fixed. >> + {"full_column_names", FIELD_TYPE_BOOLEAN, SQL_FullColNames}, >> + /* SQL_OPTION_RECURSIVE_TRIGGERS */ >> + {"recursive_triggers", FIELD_TYPE_BOOLEAN, SQL_RecTriggers}, >> + /* SQL_OPTION_REVERSE_UNORDERED_SELECTS */ >> + {"reverse_unordered_selects", FIELD_TYPE_BOOLEAN, SQL_ReverseOrder}, >> + /* SQL_OPTION_COMPOUND_SELECT_LIMIT */ >> + {"sql_compound_select_limit", FIELD_TYPE_INTEGER, 0}, >> + /* SQL_OPTION_DEFAULT_ENGINE */ >> + {"sql_default_engine", FIELD_TYPE_STRING, 0}, >> + /* SQL_OPTION_PARSER_TRACE */ >> + {"parser_trace", FIELD_TYPE_BOOLEAN, PARSER_TRACE_FLAG}, >> + /* SQL_OPTION_SELECT_TRACE */ >> + {"select_trace", FIELD_TYPE_BOOLEAN, SQL_SelectTrace}, >> + /* SQL_OPTION_TRACE */ >> + {"sql_trace", FIELD_TYPE_BOOLEAN, SQL_SqlTrace}, >> + /* SQL_OPTION_VDBE_ADDOPTRACE */ >> + {"vdbe_addoptrace", FIELD_TYPE_BOOLEAN, SQL_VdbeAddopTrace}, >> + /* SQL_OPTION_VDBE_DEBUG */ >> + {"vdbe_debug", FIELD_TYPE_BOOLEAN, >> + SQL_SqlTrace | SQL_VdbeListing | SQL_VdbeTrace}, >> + /* SQL_OPTION_VDBE_EQP */ >> + {"vdbe_eqp", FIELD_TYPE_BOOLEAN, SQL_VdbeEQP}, >> + /* SQL_OPTION_VDBE_LISTING */ >> + {"vdbe_listing", FIELD_TYPE_BOOLEAN, SQL_VdbeListing}, >> + /* SQL_OPTION_VDBE_TRACE */ >> + {"vdbe_trace", FIELD_TYPE_BOOLEAN, SQL_VdbeTrace}, >> + /* SQL_OPTION_WHERE_TRACE */ >> + {"where_trace", FIELD_TYPE_BOOLEAN, SQL_WhereTrace}, >> +}; >> + >> +static inline int >> +sql_option_id_by_key(const char *key) > > 7. From the API it looks like the key is a normal string, > but in fact it is a MessagePack encoded string. Please, > say it somewhere in the function name/comment/parameter name. > Fixed. Now it takes name as string. >> +{ >> + uint32_t len; >> + struct region *region = &fiber()->gc; >> + size_t svp = region_used(region); >> + const char *tmp = mp_decode_str(&key, &len); >> + char *str = region_alloc(region, len + 1); > > 8. Please, use tt_cstr. It is much faster and simpler. > Thanks, fixed. >> + strncpy(str, tmp, len); >> + str[len] = '\0'; >> + int id; >> + for (id = 0; id < SQL_OPTION_max; ++id) { >> + if (strcmp(str, sql_options[id].name) == 0) >> + break; >> + } >> + region_truncate(region, svp); >> + return id; >> +} >> + >> +/** >> + * Create tuple that contains name and value of the option. >> + * >> + * @param format format for new tuple. >> + * @param option_id id of option to return. >> + * @param result[out] new tuple. > > 9. Please, use capital letters in the sentences beginning. > Fixed. > 10. [out] modifier stands right after param: > > @param[out] > Fixed. >> + */ >> +static int >> +sql_option_tuple(struct tuple_format *format, int option_id, >> + struct tuple **result) >> +{ >> + if (option_id < 0 || option_id >= SQL_OPTION_max) { >> + *result = NULL; >> + return 0; >> + } >> + int limit = 0; >> + const char *engine = NULL; >> + struct region *region = &fiber()->gc; >> + struct session *session = current_session(); >> + uint32_t flags = session->sql_flags; >> + uint32_t option_flag = sql_options[option_id].flag; >> + /* Change to format->*_field_count */ > > 11. Sorry, I didn't understand the comment. Change what? Why > not to change now? > Sorry, I wrote this comment for myself but forgot about it. >> + uint32_t column_count = 2; >> + size_t size = mp_sizeof_array(column_count) + >> + mp_sizeof_str(strlen(sql_options[option_id].name)); >> + if (sql_options[option_id].field_type == FIELD_TYPE_BOOLEAN) { >> + size += mp_sizeof_bool(true); >> + } else if (option_id == SQL_OPTION_DEFAULT_ENGINE) { >> + engine = sql_storage_engine_strs[session->sql_default_engine]; >> + size += mp_sizeof_str(strlen(engine)); >> + } else { >> + assert(option_id == SQL_OPTION_COMPOUND_SELECT_LIMIT); >> + limit = sql_get()->aLimit[SQL_LIMIT_COMPOUND_SELECT]; >> + size += mp_sizeof_uint(limit); >> + } >> + >> + size_t svp = region_used(region); >> + char *pos_ret = region_alloc(region, size); >> + if (pos_ret == NULL) { >> + diag_set(OutOfMemory, size, "region_alloc", "pos_ret"); >> + return -1; >> + } >> + char *pos = mp_encode_array(pos_ret, column_count); >> + pos = mp_encode_str(pos, sql_options[option_id].name, >> + strlen(sql_options[option_id].name)); >> + if (sql_options[option_id].field_type == FIELD_TYPE_BOOLEAN) >> + pos = mp_encode_bool(pos, (flags & option_flag) == option_flag); >> + else if (option_id == SQL_OPTION_DEFAULT_ENGINE) >> + pos = mp_encode_str(pos, engine, strlen(engine)); >> + else >> + pos = mp_encode_uint(pos, limit); >> + struct tuple *tuple = tuple_new(format, pos_ret, pos_ret + size); >> + region_truncate(region, svp); >> + if (tuple == NULL) >> + return -1; >> + *result = tuple; >> + return 0; >> +} >> + >> +int> +sql_options_get(struct index *index, const char *key, uint32_t part_count, >> + struct tuple **result) >> +{ >> + assert(part_count == 1); >> + (void)part_count; >> + struct space *space = space_cache_find(index->def->space_id); >> + uint32_t option_id = sql_option_id_by_key(key); >> + if (option_id == SQL_OPTION_max) { >> + *result = NULL; >> + return 0; >> + } >> + return sql_option_tuple(space->format, option_id, result); >> +} >> + >> +struct sql_options_iterator { >> + struct iterator base; >> + struct tuple_format *format; >> + int option_id; >> + bool is_eq_type; >> + size_t svp; >> +}; >> + >> +static int >> +sql_options_iterator_next(struct iterator *itr, struct tuple **ret) >> +{ >> + struct sql_options_iterator *it = (struct sql_options_iterator *)itr; >> + int rc = sql_option_tuple(it->format, it->option_id++, ret); >> + if (it->is_eq_type) >> + it->option_id = SQL_OPTION_max; >> + return rc; >> +} >> + >> +static int >> +sql_options_iterator_prev(struct iterator *itr, struct tuple **ret) >> +{ >> + struct sql_options_iterator *it = (struct sql_options_iterator *)itr; >> + int rc = sql_option_tuple(it->format, it->option_id--, ret); >> + if (it->is_eq_type) >> + it->option_id = -1; >> + return rc; >> +} >> + >> +static void >> +sql_options_iterator_free(struct iterator *itr) >> +{ >> + struct sql_options_iterator *it = (struct sql_options_iterator *)itr; >> + region_truncate(&fiber()->gc, it->svp); >> +} >> + >> +struct iterator * >> +sql_options_create_iterator(struct index *index, enum iterator_type type, >> + const char *key, uint32_t part_count) >> +{ >> + bool is_eq_type = false; >> + uint32_t option_id; >> + if (part_count > 0) { >> + assert(part_count == 1); >> + option_id = sql_option_id_by_key(key); >> + if (type == ITER_EQ || type == ITER_REQ) >> + is_eq_type = true; >> + else if (type == ITER_LT) >> + --option_id; >> + else if (type == ITER_GT) >> + ++option_id; >> + if (option_id == SQL_OPTION_max && type == ITER_LE) >> + --option_id; >> + } else { >> + option_id = iterator_type_is_reverse(type) ? >> + SQL_OPTION_max - 1 : 0; >> + } >> + struct space *space = space_cache_find(index->def->space_id); >> + struct region *region = &fiber()->gc; >> + size_t svp = region_used(region); >> + struct sql_options_iterator *it = region_alloc(region, sizeof(*it)); > > 12. Unfortunately, you can't allocate iterators on a > region - iterators should survive fiber garbage > collection. > Fixed, replaced by malloc. >> + if (it == NULL) { >> + diag_set(OutOfMemory, sizeof(*it), "region_alloc", "it"); >> + return NULL; >> + } >> + iterator_create(&it->base, index); >> + it->base.next = iterator_type_is_reverse(type) ? >> + sql_options_iterator_prev : >> + sql_options_iterator_next; >> + it->base.free = sql_options_iterator_free; >> + it->option_id = option_id; >> + it->is_eq_type = is_eq_type; >> + it->format = space->format; >> + it->svp = svp; >> + return (struct iterator *)it; >> +} >> diff --git a/src/box/sql.h b/src/box/sql.h >> index 0fa52fc..5c23748 100644 >> --- a/src/box/sql.h >> +++ b/src/box/sql.h >> @@ -33,11 +33,68 @@ >> >> #include >> #include >> +#include "iterator_type.h" >> >> #if defined(__cplusplus) >> extern "C" { >> #endif >> >> +/** SQL options flags. */ >> +/** True to trace VDBE execution */ >> +#define SQL_VdbeTrace 0x00000001 >> +/** Debug print info about SQL query as it parsed */ >> +#define PARSER_TRACE_FLAG 0x00000002 >> +/** Show full column names on SELECT */ >> +#define SQL_FullColNames 0x00000004 >> +/** Debug print SQL as it executes */ >> +#define SQL_SqlTrace 0x00000200 >> +/** Debug info about select statement */ >> +#define SQL_SelectTrace 0x00000800 >> +/** Debug info about optimizer's work */ >> +#define SQL_WhereTrace 0x00008000 >> +/** Debug listings of VDBE programs */ >> +#define SQL_VdbeListing 0x00000400 >> +/** Trace sqlVdbeAddOp() calls */ >> +#define SQL_VdbeAddopTrace 0x00001000 >> +/** Reverse unordered SELECTs */ >> +#define SQL_ReverseOrder 0x00020000 >> +/** Enable recursive triggers */ >> +#define SQL_RecTriggers 0x00040000 >> +/** Defer all FK constraints */ >> +#define SQL_DeferFKs 0x02000000 >> +/** Debug EXPLAIN QUERY PLAN */ >> +#define SQL_VdbeEQP 0x08000000 > > 13. Why have you moved these macros from their old > place? > Fixed. >> + >> +enum { >> + SQL_OPTION_DEFER_FOREIGN_KEYS = 0, >> + SQL_OPTION_FULL_COLUMN_NAMES, >> + SQL_OPTION_RECURSIVE_TRIGGERS, >> + SQL_OPTION_REVERSE_UNORDERED_SELECTS, >> + SQL_OPTION_COMPOUND_SELECT_LIMIT, >> + SQL_OPTION_DEFAULT_ENGINE, >> +#ifndef NDEBUG> diff --git a/test/box/access_misc.result b/test/box/access_misc.result >> index a1b6435..66469e1 100644 >> --- a/test/box/access_misc.result >> +++ b/test/box/access_misc.result >> @@ -835,144 +835,146 @@ box.space._space:select() >> {'name': 'language', 'type': 'str'}, {'name': 'code', 'type': 'str'}]] >> - [372, 1, '_func_index', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, >> {'name': 'index_id', 'type': 'unsigned'}, {'name': 'func_id', 'type': 'unsigned'}]] >> + - [380, 1, '_vsql_settings', 'sysview', 0, {}, [{'name': 'name', 'type': 'string'}, >> + {'name': 'value', 'type': 'any'}]] >> ... >> box.space._func:select() >> --- >> - - [1, 1, 'box.schema.user.info', 1, 'LUA', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, ['LUA'], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, ['LUA'], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [2, 1, 'TRIM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [3, 1, 'TYPEOF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [4, 1, 'PRINTF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [5, 1, 'UNICODE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [6, 1, 'CHAR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [7, 1, 'HEX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [8, 1, 'VERSION', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [9, 1, 'QUOTE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [10, 1, 'REPLACE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [11, 1, 'SUBSTR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [12, 1, 'GROUP_CONCAT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [13, 1, 'JULIANDAY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [14, 1, 'DATE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [15, 1, 'TIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [16, 1, 'DATETIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [17, 1, 'STRFTIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [18, 1, 'CURRENT_TIME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [19, 1, 'CURRENT_TIMESTAMP', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', >> - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + 'none', false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [20, 1, 'CURRENT_DATE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [21, 1, 'LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [22, 1, 'POSITION', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [23, 1, 'ROUND', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [24, 1, 'UPPER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [25, 1, 'LOWER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [26, 1, 'IFNULL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [27, 1, 'RANDOM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [28, 1, 'CEIL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [29, 1, 'CEILING', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [30, 1, 'CHARACTER_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', >> - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + 'none', false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [31, 1, 'CHAR_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [32, 1, 'FLOOR', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [33, 1, 'MOD', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [34, 1, 'OCTET_LENGTH', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [35, 1, 'ROW_COUNT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [36, 1, 'COUNT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [37, 1, 'LIKE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [38, 1, 'ABS', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [39, 1, 'EXP', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [40, 1, 'LN', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [41, 1, 'POWER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [42, 1, 'SQRT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [43, 1, 'SUM', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [44, 1, 'TOTAL', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [45, 1, 'AVG', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [46, 1, 'RANDOMBLOB', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [47, 1, 'NULLIF', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [48, 1, 'ZEROBLOB', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [49, 1, 'MIN', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [50, 1, 'MAX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [51, 1, 'COALESCE', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [52, 1, 'EVERY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [53, 1, 'EXISTS', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [54, 1, 'EXTRACT', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [55, 1, 'SOME', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', false, >> - false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [56, 1, 'GREATER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [57, 1, 'LESSER', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [58, 1, 'SOUNDEX', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [59, 1, 'LIKELIHOOD', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [60, 1, 'LIKELY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [61, 1, 'UNLIKELY', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [62, 1, '_sql_stat_get', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', >> - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + 'none', false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [63, 1, '_sql_stat_push', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', >> - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + 'none', false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [64, 1, '_sql_stat_init', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', >> - 'none', false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + 'none', false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [65, 1, 'LUA', 1, 'LUA', 'function(code) return assert(loadstring(code))() end', >> 'function', ['string'], 'any', 'none', 'none', false, false, true, ['LUA', 'SQL'], >> - {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [66, 1, 'GREATEST', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> - [67, 1, 'LEAST', 1, 'SQL_BUILTIN', '', 'function', [], 'any', 'none', 'none', >> - false, false, true, [], {}, '', '2019-08-14 14:09:37', '2019-08-14 14:09:37'] >> + false, false, true, [], {}, '', '2019-10-16 15:38:07', '2019-10-16 15:38:07'] >> ... > > 14. Could we somehow refactor that test so as it would not change > so much on each change of the schema? In a separate commit/branch. > Send a patch. New patch: >From da4508c0b2f0b6af680163e6ae517200e7a9949f Mon Sep 17 00:00:00 2001 From: Mergen Imeev Date: Thu, 24 Oct 2019 15:18:09 +0300 Subject: [PATCH] box: introdice _vsession_settings sysview This patch creates the _vsession_settings sysview. This sysview contains names and values of the session-local options. This sysview creates tuples on the fly using its own get() and create_iterator() methods. This allows us to get a tuple without having to save it anywhere. Currently, only SQL options can be extracted from this sysview, since the only session-local options are SQL options. Part of #4511 diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap index 59f6cc1..6b4b96a 100644 Binary files a/src/box/bootstrap.snap and b/src/box/bootstrap.snap differ diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index 8b84e1f..77f245c 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -652,6 +652,8 @@ box_lua_space_init(struct lua_State *L) lua_setfield(L, -2, "SPACE_SEQUENCE_ID"); lua_pushnumber(L, BOX_FUNC_INDEX_ID); lua_setfield(L, -2, "FUNC_INDEX_ID"); + lua_pushnumber(L, BOX_VSESSION_SETTINGS_ID); + lua_setfield(L, -2, "VSESSION_SETTINGS_ID"); lua_pushnumber(L, BOX_SYSTEM_ID_MIN); lua_setfield(L, -2, "SYSTEM_ID_MIN"); lua_pushnumber(L, BOX_SYSTEM_ID_MAX); diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua index e71b7fb..94e4118 100644 --- a/src/box/lua/upgrade.lua +++ b/src/box/lua/upgrade.lua @@ -943,6 +943,28 @@ local function upgrade_to_2_3_0() end -------------------------------------------------------------------------------- +-- Tarantool 2.3.1 +-------------------------------------------------------------------------------- + +local function create_vsession_settings_sysview() + local _space = box.space[box.schema.SPACE_ID] + local _index = box.space[box.schema.INDEX_ID] + local format = {} + format[1] = {name='name', type='string'} + format[2] = {name='value', type='any'} + log.info("create space _vsession_settings") + _space:insert{box.schema.VSESSION_SETTINGS_ID, ADMIN, '_vsession_settings', + 'sysview', 0, setmap({}), format} + log.info("create index _vsession_settings:primary") + _index:insert{box.schema.VSESSION_SETTINGS_ID, 0, 'primary', 'tree', + {unique = true}, {{0, 'string'}}} +end + +local function upgrade_to_2_3_1() + create_vsession_settings_sysview() +end + +-------------------------------------------------------------------------------- local function get_version() local version = box.space._schema:get{'version'} @@ -977,6 +999,7 @@ local function upgrade(options) {version = mkversion(2, 1, 3), func = upgrade_to_2_1_3, auto = true}, {version = mkversion(2, 2, 1), func = upgrade_to_2_2_1, auto = true}, {version = mkversion(2, 3, 0), func = upgrade_to_2_3_0, auto = true}, + {version = mkversion(2, 3, 1), func = upgrade_to_2_3_1, auto = true}, } for _, handler in ipairs(handlers) do diff --git a/src/box/schema_def.h b/src/box/schema_def.h index ba870ff..b9824cb 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -114,6 +114,8 @@ enum { BOX_CK_CONSTRAINT_ID = 364, /** Space id of _func_index. */ BOX_FUNC_INDEX_ID = 372, + /** Space id of _vsession_settings. */ + BOX_VSESSION_SETTINGS_ID = 381, /** End of the reserved range of system spaces. */ BOX_SYSTEM_ID_MAX = 511, BOX_ID_NIL = 2147483647 diff --git a/src/box/session.cc b/src/box/session.cc index 59bf226..32dc87a 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -36,6 +36,9 @@ #include "user.h" #include "error.h" #include "tt_static.h" +#include "index.h" +#include "schema.h" +#include "sql.h" const char *session_type_strs[] = { "background", @@ -360,3 +363,116 @@ generic_session_sync(struct session *session) (void) session; return 0; } + +int +session_options_get(struct index *index, const char *key, uint32_t part_count, + struct tuple **result) +{ + assert(part_count == 1); + (void)part_count; + struct space *space = space_cache_find(index->def->space_id); + uint32_t len; + const char *name = mp_decode_str(&key, &len); + name = tt_cstr(name, len); + /* + * Currently, the only session local options are SQL + * options. + */ + uint32_t sql_option_id = sql_option_id_by_name(name); + return sql_option_tuple(space->format, sql_option_id, result); +} + +/** + * An iterator that iterates over current session options. + */ +struct session_options_iterator { + /** Base iterator. Must be the first member. */ + struct iterator base; + /** Format of the tuples this iterator returns. */ + struct tuple_format *format; + /** Id of SQL option this iterator should return. */ + uint32_t sql_option_id; + /** + * The number of tuples left to show. If we did not get + * the key when creating the iterator, then the value of + * the field is < 0. Otherwise, it should be either 1 or 0 + * in the normal case. + */ + int max_tuples_to_show; +}; + +static int +session_options_iterator_next(struct iterator *itr, struct tuple **ret) +{ + struct session_options_iterator *it = + (struct session_options_iterator *)itr; + if (it->max_tuples_to_show == 0) { + *ret = NULL; + return 0; + } + if (it->max_tuples_to_show > 0) + it->max_tuples_to_show--; + return sql_option_tuple(it->format, it->sql_option_id++, ret); +} + +static int +session_options_iterator_prev(struct iterator *itr, struct tuple **ret) +{ + struct session_options_iterator *it = + (struct session_options_iterator *)itr; + if (it->max_tuples_to_show == 0) { + *ret = NULL; + return 0; + } else if (it->max_tuples_to_show > 0) { + it->max_tuples_to_show--; + } + return sql_option_tuple(it->format, it->sql_option_id--, ret); +} + +static void +session_options_iterator_free(struct iterator *itr) +{ + free(itr); +} + +struct iterator * +session_options_create_iterator(struct index *index, enum iterator_type type, + const char *key, uint32_t part_count) +{ + int max_tuples_to_show = -1; + uint32_t sql_option_id; + if (part_count > 0) { + assert(part_count == 1); + uint32_t len; + const char *name = mp_decode_str(&key, &len); + name = tt_cstr(name, len); + sql_option_id = sql_option_id_by_name(name); + if (type == ITER_EQ || type == ITER_REQ) + max_tuples_to_show = 1; + else if (type == ITER_LT) + --sql_option_id; + else if (type == ITER_GT) + ++sql_option_id; + if (sql_option_id == sql_option_id_max() && type == ITER_LE) + --sql_option_id; + } else { + sql_option_id = iterator_type_is_reverse(type) ? + sql_option_id_max() - 1 : 0; + } + struct space *space = space_cache_find(index->def->space_id); + struct session_options_iterator *it = + (session_options_iterator *)malloc(sizeof(*it)); + if (it == NULL) { + diag_set(OutOfMemory, sizeof(*it), "malloc", "it"); + return NULL; + } + iterator_create(&it->base, index); + it->base.next = iterator_type_is_reverse(type) ? + session_options_iterator_prev : + session_options_iterator_next; + it->base.free = session_options_iterator_free; + it->sql_option_id = sql_option_id; + it->max_tuples_to_show = max_tuples_to_show; + it->format = space->format; + return (struct iterator *)it; +} diff --git a/src/box/session.h b/src/box/session.h index 85a2d94..96d9ad0 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -36,12 +36,15 @@ #include "fiber.h" #include "user.h" #include "authentication.h" +#include "iterator_type.h" #if defined(__cplusplus) extern "C" { #endif /* defined(__cplusplus) */ struct port; +struct index; +struct tuple; struct session_vtab; void @@ -355,6 +358,16 @@ generic_session_fd(struct session *session); int64_t generic_session_sync(struct session *session); +/** Method get() for _vsession_settings sysview. */ +int +session_options_get(struct index *index, const char *key, uint32_t part_count, + struct tuple **result); + +/** Method create_iterator() for _vsession_settings sysview. */ +struct iterator * +session_options_create_iterator(struct index *index, enum iterator_type type, + const char *key, uint32_t part_count); + #if defined(__cplusplus) } /* extern "C" */ diff --git a/src/box/sql.h b/src/box/sql.h index 0fa52fc..fe7cb08 100644 --- a/src/box/sql.h +++ b/src/box/sql.h @@ -70,6 +70,7 @@ struct Select; struct Table; struct sql_trigger; struct space_def; +struct tuple_format; /** * Perform parsing of provided expression. This is done by @@ -420,6 +421,39 @@ void vdbe_field_ref_prepare_tuple(struct vdbe_field_ref *field_ref, struct tuple *tuple); +/** + * Return the next number after the last SQL option. + * + * @retval Next number after the last SQL option. + */ +uint32_t +sql_option_id_max(); + +/** + * Return the SQL option ID with the given name. If there is no + * option with this name, a number is returned that is equal to + * the one returned by sql_option_id_max(). + * + * @param name The name of the option. + * @retval Option ID. + */ +int +sql_option_id_by_name(const char *name); + +/** + * Create a tuple that contains the name and value of the SQL + * option. + * + * @param format Format of the tuple. + * @param option_id ID of SQL option. + * @param[out] result New tuple or NULL. + * @retval 0 On success. + * @retval < 0 On error. + */ +int +sql_option_tuple(struct tuple_format *format, int option_id, + struct tuple **result); + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 51cd7ce..cb97106 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -48,6 +48,7 @@ #include "vdbeInt.h" #include "tarantoolInt.h" #include "box/box.h" +#include "box/tuple.h" #include "box/ck_constraint.h" #include "box/fk_constraint.h" #include "box/sequence.h" @@ -3242,3 +3243,160 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name, *fieldno = i; return 0; } + +/** + * Identifiers of all SQL options that can be viewed. The + * identifier of the option is equal to its place in the sorted + * list of options, which starts at 0. + * + * It is IMPORTANT that SQL options are sorted by name. If this is + * not the case, the result returned by the _vsession_settings + * space iterator will not be sorted properly. + */ +enum { + SQL_OPTION_COMPOUND_SELECT_LIMIT = 0, + SQL_OPTION_DEFAULT_ENGINE, + SQL_OPTION_DEFER_FOREIGN_KEYS, + SQL_OPTION_FULL_COLUMN_NAMES, +#ifndef NDEBUG + SQL_OPTION_PARSER_TRACE, +#endif + SQL_OPTION_RECURSIVE_TRIGGERS, + SQL_OPTION_REVERSE_UNORDERED_SELECTS, +#ifndef NDEBUG + SQL_OPTION_SELECT_TRACE, + SQL_OPTION_TRACE, + SQL_OPTION_VDBE_ADDOPTRACE, + SQL_OPTION_VDBE_DEBUG, + SQL_OPTION_VDBE_EQP, + SQL_OPTION_VDBE_LISTING, + SQL_OPTION_VDBE_TRACE, + SQL_OPTION_WHERE_TRACE, +#endif + SQL_OPTION_max, +}; + +/** + * A local structure that allows to establish a connection between + * the name of the parameter, its field type and mask, if it have + * one. + */ +struct sql_option_metadata +{ + const char *name; + uint32_t field_type; + uint32_t mask; +}; + +/** + * Variable that contains names of the SQL options, their field + * types and mask if they have one or 0 if don't have. + * + * It is IMPORTANT that these options sorted by name. + */ +static struct sql_option_metadata sql_options[] = { + /** SQL_OPTION_COMPOUND_SELECT_LIMIT */ + {"sql_compound_select_limit", FIELD_TYPE_INTEGER, 0}, + /** SQL_OPTION_DEFAULT_ENGINE */ + {"sql_default_engine", FIELD_TYPE_STRING, 0}, + /** SQL_OPTION_DEFER_FOREIGN_KEYS */ + {"sql_defer_foreign_keys", FIELD_TYPE_BOOLEAN, SQL_DeferFKs}, + /** SQL_OPTION_FULL_COLUMN_NAMES */ + {"sql_full_column_names", FIELD_TYPE_BOOLEAN, SQL_FullColNames}, +#ifndef NDEBUG + /** SQL_OPTION_PARSER_TRACE */ + {"sql_parser_trace", FIELD_TYPE_BOOLEAN, PARSER_TRACE_FLAG}, +#endif + /** SQL_OPTION_RECURSIVE_TRIGGERS */ + {"sql_recursive_triggers", FIELD_TYPE_BOOLEAN, SQL_RecTriggers}, + /** SQL_OPTION_REVERSE_UNORDERED_SELECTS */ + {"sql_reverse_unordered_selects", FIELD_TYPE_BOOLEAN, SQL_ReverseOrder}, +#ifndef NDEBUG + /** SQL_OPTION_SELECT_TRACE */ + {"sql_select_trace", FIELD_TYPE_BOOLEAN, SQL_SelectTrace}, + /** SQL_OPTION_TRACE */ + {"sql_trace", FIELD_TYPE_BOOLEAN, SQL_SqlTrace}, + /** SQL_OPTION_VDBE_ADDOPTRACE */ + {"sql_vdbe_addoptrace", FIELD_TYPE_BOOLEAN, SQL_VdbeAddopTrace}, + /** SQL_OPTION_VDBE_DEBUG */ + {"sql_vdbe_debug", FIELD_TYPE_BOOLEAN, + SQL_SqlTrace | SQL_VdbeListing | SQL_VdbeTrace}, + /** SQL_OPTION_VDBE_EQP */ + {"sql_vdbe_eqp", FIELD_TYPE_BOOLEAN, SQL_VdbeEQP}, + /** SQL_OPTION_VDBE_LISTING */ + {"sql_vdbe_listing", FIELD_TYPE_BOOLEAN, SQL_VdbeListing}, + /** SQL_OPTION_VDBE_TRACE */ + {"sql_vdbe_trace", FIELD_TYPE_BOOLEAN, SQL_VdbeTrace}, + /** SQL_OPTION_WHERE_TRACE */ + {"sql_where_trace", FIELD_TYPE_BOOLEAN, SQL_WhereTrace}, +#endif +}; + +uint32_t +sql_option_id_max() +{ + return SQL_OPTION_max; +} + +int +sql_option_id_by_name(const char *name) +{ + for (uint32_t id = 0; id < SQL_OPTION_max; ++id) { + if (strcmp(name, sql_options[id].name) == 0) + return id; + } + return SQL_OPTION_max; +} + +int +sql_option_tuple(struct tuple_format *format, int option_id, + struct tuple **result) +{ + if (option_id < 0 || option_id >= SQL_OPTION_max) { + *result = NULL; + return 0; + } + int limit = 0; + const char *engine = NULL; + struct region *region = &fiber()->gc; + struct session *session = current_session(); + uint32_t flags = session->sql_flags; + uint32_t mask = sql_options[option_id].mask; + /* Tuple format contains two fields - name and value. */ + uint32_t column_count = format->min_field_count; + assert(column_count == 2); + size_t size = mp_sizeof_array(column_count) + + mp_sizeof_str(strlen(sql_options[option_id].name)); + if (sql_options[option_id].field_type == FIELD_TYPE_BOOLEAN) { + size += mp_sizeof_bool(true); + } else if (option_id == SQL_OPTION_DEFAULT_ENGINE) { + engine = sql_storage_engine_strs[session->sql_default_engine]; + size += mp_sizeof_str(strlen(engine)); + } else { + assert(option_id == SQL_OPTION_COMPOUND_SELECT_LIMIT); + limit = sql_get()->aLimit[SQL_LIMIT_COMPOUND_SELECT]; + size += mp_sizeof_uint(limit); + } + + size_t svp = region_used(region); + char *pos_ret = region_alloc(region, size); + if (pos_ret == NULL) { + diag_set(OutOfMemory, size, "region_alloc", "pos_ret"); + return -1; + } + char *pos = mp_encode_array(pos_ret, column_count); + pos = mp_encode_str(pos, sql_options[option_id].name, + strlen(sql_options[option_id].name)); + if (sql_options[option_id].field_type == FIELD_TYPE_BOOLEAN) + pos = mp_encode_bool(pos, (flags & mask) == mask); + else if (option_id == SQL_OPTION_DEFAULT_ENGINE) + pos = mp_encode_str(pos, engine, strlen(engine)); + else + pos = mp_encode_uint(pos, limit); + struct tuple *tuple = tuple_new(format, pos_ret, pos_ret + size); + region_truncate(region, svp); + if (tuple == NULL) + return -1; + *result = tuple; + return 0; +} diff --git a/src/box/sysview.c b/src/box/sysview.c index 745cf09..83a8ccc 100644 --- a/src/box/sysview.c +++ b/src/box/sysview.c @@ -411,7 +411,7 @@ vsequence_filter(struct space *source, struct tuple *tuple) } static bool -vcollation_filter(struct space *source, struct tuple *tuple) +generic_filter(struct space *source, struct tuple *tuple) { (void) source; (void) tuple; @@ -481,10 +481,17 @@ sysview_space_create_index(struct space *space, struct index_def *def) case BOX_VCOLLATION_ID: source_space_id = BOX_COLLATION_ID; source_index_id = def->iid; - filter = vcollation_filter; + filter = generic_filter; get = index_get; create_iterator = index_create_iterator; break; + case BOX_VSESSION_SETTINGS_ID: + source_space_id = BOX_VSESSION_SETTINGS_ID; + source_index_id = def->iid; + filter = generic_filter; + get = session_options_get; + create_iterator = session_options_create_iterator; + break; default: diag_set(ClientError, ER_MODIFY_INDEX, def->name, space_name(space), @@ -569,9 +576,10 @@ sysview_engine_create_space(struct engine *engine, struct space_def *def, return NULL; } struct tuple_format *format = - tuple_format_new(NULL, NULL, keys, key_count, def->fields, - def->field_count, def->exact_field_count, - def->dict, def->opts.is_temporary, + tuple_format_new(&tuple_format_runtime->vtab, NULL, keys, + key_count, def->fields, def->field_count, + def->exact_field_count, def->dict, + def->opts.is_temporary, def->opts.is_ephemeral); if (format == NULL) { free(space); diff --git a/test/app-tap/tarantoolctl.test.lua b/test/app-tap/tarantoolctl.test.lua index f388208..a41fad3 100755 --- a/test/app-tap/tarantoolctl.test.lua +++ b/test/app-tap/tarantoolctl.test.lua @@ -410,8 +410,8 @@ do check_ctlcat_xlog(test_i, dir, "--from=3 --to=6 --format=json --show-system --replica 1", "\n", 3) check_ctlcat_xlog(test_i, dir, "--from=3 --to=6 --format=json --show-system --replica 1 --replica 2", "\n", 3) check_ctlcat_xlog(test_i, dir, "--from=3 --to=6 --format=json --show-system --replica 2", "\n", 0) - check_ctlcat_snap(test_i, dir, "--space=280", "---\n", 24) - check_ctlcat_snap(test_i, dir, "--space=288", "---\n", 52) + check_ctlcat_snap(test_i, dir, "--space=280", "---\n", 25) + check_ctlcat_snap(test_i, dir, "--space=288", "---\n", 53) end) end) diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result index 123aa2f..54b43ec 100644 --- a/test/box-py/bootstrap.result +++ b/test/box-py/bootstrap.result @@ -4,7 +4,7 @@ box.internal.bootstrap() box.space._schema:select{} --- - - ['max_id', 511] - - ['version', 2, 3, 0] + - ['version', 2, 3, 1] ... box.space._cluster:select{} --- @@ -96,6 +96,8 @@ box.space._space:select{} 'type': 'boolean'}]] - [372, 1, '_func_index', 'memtx', 0, {}, [{'name': 'space_id', 'type': 'unsigned'}, {'name': 'index_id', 'type': 'unsigned'}, {'name': 'func_id', 'type': 'unsigned'}]] + - [381, 1, '_vsession_settings', 'sysview', 0, {}, [{'name': 'name', 'type': 'string'}, + {'name': 'value', 'type': 'any'}]] ... box.space._index:select{} --- @@ -153,6 +155,7 @@ box.space._index:select{} - [364, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'string']]] - [372, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]] - [372, 1, 'fid', 'tree', {'unique': false}, [[2, 'unsigned']]] + - [381, 0, 'primary', 'tree', {'unique': true}, [[0, 'string']]] ... box.space._user:select{} --- diff --git a/test/box/access_sysview.result b/test/box/access_sysview.result index 3072b73..5a41526 100644 --- a/test/box/access_sysview.result +++ b/test/box/access_sysview.result @@ -246,11 +246,11 @@ box.session.su('guest') ... #box.space._vspace:select{} --- -- 25 +- 26 ... #box.space._vindex:select{} --- -- 53 +- 54 ... #box.space._vuser:select{} --- @@ -282,7 +282,7 @@ box.session.su('guest') ... #box.space._vindex:select{} --- -- 53 +- 54 ... #box.space._vuser:select{} --- diff --git a/test/box/alter.result b/test/box/alter.result index 46ce868..2a0eaca 100644 --- a/test/box/alter.result +++ b/test/box/alter.result @@ -92,7 +92,7 @@ space = box.space[t[1]] ... space.id --- -- 373 +- 382 ... space.field_count --- @@ -137,7 +137,7 @@ space_deleted ... space:replace{0} --- -- error: Space '373' does not exist +- error: Space '382' does not exist ... _index:insert{_space.id, 0, 'primary', 'tree', {unique=true}, {{0, 'unsigned'}}} --- @@ -220,6 +220,7 @@ _index:select{} - [364, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'string']]] - [372, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned'], [1, 'unsigned']]] - [372, 1, 'fid', 'tree', {'unique': false}, [[2, 'unsigned']]] + - [381, 0, 'primary', 'tree', {'unique': true}, [[0, 'string']]] ... -- modify indexes of a system space _index:delete{_index.id, 0} diff --git a/test/box/misc.result b/test/box/misc.result index b293051..b41ffa4 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -1330,3 +1330,124 @@ test_run:grep_log('default', 'test log') --- - test log ... +-- +-- gh-4511: make sure that _vsession_settings sysview works as +-- intended. +-- +v = box.space._vsession_settings +--- +... +option_count = v:count() +--- +... +v:format() +--- +- [{'name': 'name', 'type': 'string'}, {'name': 'value', 'type': 'any'}] +... +(#v:select()) == option_count +--- +- true +... +(#v:select({}, {iterator = 'ALL'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'REQ'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'EQ'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'GE'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'GT'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'LE'})) == option_count +--- +- true +... +(#v:select({}, {iterator = 'LT'})) == option_count +--- +- true +... +(#v:select({'abcde'}, {iterator = 'ALL'})) == 0 +--- +- true +... +(#v:select({'abcde'}, {iterator = 'REQ'})) == 0 +--- +- true +... +(#v:select({'abcde'}, {iterator = 'EQ'})) == 0 +--- +- true +... +(#v:select({'abcde'}, {iterator = 'GE'})) == 0 +--- +- true +... +(#v:select({'abcde'}, {iterator = 'GT'})) == 0 +--- +- true +... +(#v:select({'abcde'}, {iterator = 'LE'})) == option_count +--- +- true +... +(#v:select({'abcde'}, {iterator = 'LT'})) == option_count +--- +- true +... +v:select({'sql_defer_foreign_keys'}) +--- +- - ['sql_defer_foreign_keys', false] +... +v:select({'sql_recursive_triggers'}) +--- +- - ['sql_recursive_triggers', true] +... +v:select({'sql_reverse_unordered_selects'}) +--- +- - ['sql_reverse_unordered_selects', false] +... +v:select({'sql_compound_select_limit'}) +--- +- - ['sql_compound_select_limit', 30] +... +v:select({'sql_default_engine'}) +--- +- - ['sql_default_engine', 'memtx'] +... +new_record = v:frommap({name='abs', value=123}) +--- +... +v:insert(new_record) +--- +- error: View '_vsession_settings' is read-only +... +t = {} +--- +... +for k, v in box.space._vsession_settings:pairs() do table.insert(t, {k, v}) end +--- +... +#t == option_count +--- +- true +... +box.execute([[SELECT * from "_vsession_settings" WHERE "name" = 'sql_default_engine']]) +--- +- metadata: + - name: name + type: string + - name: value + type: any + rows: + - ['sql_default_engine', 'memtx'] +... diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index cc223b2..50c89df 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -383,3 +383,45 @@ tuple_format = box.internal.new_tuple_format(format) box.cfg{} local ffi = require'ffi' ffi.C._say(ffi.C.S_WARN, nil, 0, nil, "%s", "test log") test_run:grep_log('default', 'test log') + +-- +-- gh-4511: make sure that _vsession_settings sysview works as +-- intended. +-- + +v = box.space._vsession_settings +option_count = v:count() + +v:format() + +(#v:select()) == option_count +(#v:select({}, {iterator = 'ALL'})) == option_count +(#v:select({}, {iterator = 'REQ'})) == option_count +(#v:select({}, {iterator = 'EQ'})) == option_count +(#v:select({}, {iterator = 'GE'})) == option_count +(#v:select({}, {iterator = 'GT'})) == option_count +(#v:select({}, {iterator = 'LE'})) == option_count +(#v:select({}, {iterator = 'LT'})) == option_count + +(#v:select({'abcde'}, {iterator = 'ALL'})) == 0 +(#v:select({'abcde'}, {iterator = 'REQ'})) == 0 +(#v:select({'abcde'}, {iterator = 'EQ'})) == 0 +(#v:select({'abcde'}, {iterator = 'GE'})) == 0 +(#v:select({'abcde'}, {iterator = 'GT'})) == 0 +(#v:select({'abcde'}, {iterator = 'LE'})) == option_count +(#v:select({'abcde'}, {iterator = 'LT'})) == option_count + +v:select({'sql_defer_foreign_keys'}) +v:select({'sql_recursive_triggers'}) +v:select({'sql_reverse_unordered_selects'}) +v:select({'sql_compound_select_limit'}) +v:select({'sql_default_engine'}) + +new_record = v:frommap({name='abs', value=123}) +v:insert(new_record) + +t = {} +for k, v in box.space._vsession_settings:pairs() do table.insert(t, {k, v}) end +#t == option_count + +box.execute([[SELECT * from "_vsession_settings" WHERE "name" = 'sql_default_engine']]) diff --git a/test/wal_off/alter.result b/test/wal_off/alter.result index 62cb11d..97f7e6f 100644 --- a/test/wal_off/alter.result +++ b/test/wal_off/alter.result @@ -28,7 +28,7 @@ end; ... #spaces; --- -- 65502 +- 65501 ... -- cleanup for k, v in pairs(spaces) do -- 2.7.4