From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (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 62BA841D0BD for ; Thu, 17 Oct 2019 17:40:18 +0300 (MSK) From: imeevma@tarantool.org Date: Thu, 17 Oct 2019 17:40:17 +0300 Message-Id: In-Reply-To: References: Subject: [Tarantool-patches] [PATCH v1 3/5] sql: create SET command 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 This patch creates the SET command for SQL, which will be used instead of pragmas that modify SQL settings. Part of #4511 @TarantoolBot document Title: SET SQL command The SET SQL command is used to change SQL settings. 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 changed using this command 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: SET full_column_names = true; SET sql_compound_select_limit(10); SET sql_default_engine = 'memtx'; --- src/box/sql/build.c | 60 +++++++++++++++++++++ src/box/sql/parse.y | 8 +++ src/box/sql/sqlInt.h | 14 +++++ test/sql/sql-debug.result | 127 ++++++++++++++++++++++++++++++++++++++++++++ test/sql/sql-debug.test.lua | 26 +++++++++ 5 files changed, 235 insertions(+) diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 233f567..45bd3c0 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -3241,3 +3241,63 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name, *fieldno = i; return 0; } + +void +sql_set_settings(struct Parse *parse_context, struct Token *name, + struct Expr *value) +{ + int option_id; + struct session *session = current_session(); + char *name_str = sql_name_from_token(sql_get(), name); + if (name_str == NULL) { + parse_context->is_aborted = true; + return; + } + for (option_id = 0; option_id < SQL_OPTION_max; ++option_id) { + if (strcasecmp(sql_options[option_id].name, name_str) == 0) + break; + } + if (option_id == SQL_OPTION_max) { + diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Setting is " + "not found"); + parse_context->is_aborted = true; + return; + } + struct sql_option_metadata *option = &sql_options[option_id]; + if (value->type != option->field_type) { + diag_set(ClientError, ER_INCONSISTENT_TYPES, + field_type_strs[option->field_type], + field_type_strs[value->type]); + parse_context->is_aborted = true; + return; + } + if (value->type == FIELD_TYPE_BOOLEAN) { + bool is_set = value->op == TK_TRUE; + if (is_set) + session->sql_flags |= option->flag; + else + session->sql_flags &= ~option->flag; +#ifndef NDEBUG + if (option_id == SQL_OPTION_PARSER_TRACE) { + if (is_set) + sqlParserTrace(stdout, "parser: "); + else + sqlParserTrace(NULL, NULL); + } +#endif + } else if (option_id == SQL_OPTION_DEFAULT_ENGINE) { + enum sql_storage_engine engine = + STR2ENUM(sql_storage_engine, value->u.zToken); + if (engine == sql_storage_engine_MAX) { + parse_context->is_aborted = true; + diag_set(ClientError, ER_NO_SUCH_ENGINE, + value->u.zToken); + return; + } + current_session()->sql_default_engine = engine; + } else { + assert(option_id == SQL_OPTION_COMPOUND_SELECT_LIMIT); + sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, + value->u.iValue); + } +} diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index ed59a87..7bea68d 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -1535,6 +1535,14 @@ cmd ::= DROP INDEX ifexists(E) nm(X) ON fullname(Y). { sql_drop_index(pParse); } +///////////////////////////// The SET command //////////////////////////////// +cmd ::= SET nm(X) EQ term(Y). { + sql_set_settings(pParse,&X,Y.pExpr); +} +cmd ::= SET nm(X) LP term(Y) RP. { + sql_set_settings(pParse,&X,Y.pExpr); +} + ///////////////////////////// The PRAGMA command ///////////////////////////// // cmd ::= PRAGMA nm(X). { diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index a87590e..9a2b5c8 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -4436,4 +4436,18 @@ int sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name, uint32_t *fieldno); +/** + * Set new value for SQL setting. + * + * @param parse_context Parsing context. + * @param name Name of SQL setting to change. + * @param value New values of SQL setting. + * + * @retval 0 on success. + * @retval -1 on error. + */ +void +sql_set_settings(struct Parse *parse_context, struct Token *name, + struct Expr *value); + #endif /* sqlINT_H */ diff --git a/test/sql/sql-debug.result b/test/sql/sql-debug.result index 2dba684..07542e3 100644 --- a/test/sql/sql-debug.result +++ b/test/sql/sql-debug.result @@ -54,3 +54,130 @@ box.execute('PRAGMA') - ['vdbe_trace', 0] - ['where_trace', 0] ... +-- +-- gh-4511: make sure that SET works. +-- +box.execute('SELECT "name" FROM "_vsql_settings";') +--- +- metadata: + - name: name + type: string + rows: + - ['defer_foreign_keys'] + - ['full_column_names'] + - ['recursive_triggers'] + - ['reverse_unordered_selects'] + - ['sql_compound_select_limit'] + - ['sql_default_engine'] + - ['parser_trace'] + - ['select_trace'] + - ['sql_trace'] + - ['vdbe_addoptrace'] + - ['vdbe_debug'] + - ['vdbe_eqp'] + - ['vdbe_listing'] + - ['vdbe_trace'] + - ['where_trace'] +... +engine = box.space._vsql_settings:get{'sql_default_engine'}[2] +--- +... +order = box.space._vsql_settings:get{'reverse_unordered_selects'}[2] +--- +... +box.execute('SET sql_default_engine = 1;') +--- +- null +- 'Inconsistent types: expected string got integer' +... +box.execute("SET sql_default_engine = 'some_engine';") +--- +- null +- Space engine 'some_engine' does not exist +... +box.execute("SET engine = 'vinyl';") +--- +- null +- Setting is not found +... +box.execute("SET defer_foreign_keys('vinyl');") +--- +- null +- 'Inconsistent types: expected boolean got string' +... +engine == box.space._vsql_settings:get{'sql_default_engine'}[2] +--- +- true +... +order == box.space._vsql_settings:get{'reverse_unordered_selects'}[2] +--- +- true +... +box.execute("SET sql_default_engine = 'vinyl';") +--- +- row_count: 0 +... +box.execute("SET reverse_unordered_selects(true);") +--- +- row_count: 0 +... +box.execute('SELECT "name" FROM "_vsql_settings";') +--- +- metadata: + - name: name + type: string + rows: + - ['where_trace'] + - ['vdbe_trace'] + - ['vdbe_listing'] + - ['vdbe_eqp'] + - ['vdbe_debug'] + - ['vdbe_addoptrace'] + - ['sql_trace'] + - ['select_trace'] + - ['parser_trace'] + - ['sql_default_engine'] + - ['sql_compound_select_limit'] + - ['reverse_unordered_selects'] + - ['recursive_triggers'] + - ['full_column_names'] + - ['defer_foreign_keys'] +... +box.execute("SET sql_default_engine('memtx');") +--- +- row_count: 0 +... +box.execute("SET reverse_unordered_selects = false;") +--- +- row_count: 0 +... +box.execute('SELECT "name" FROM "_vsql_settings";') +--- +- metadata: + - name: name + type: string + rows: + - ['defer_foreign_keys'] + - ['full_column_names'] + - ['recursive_triggers'] + - ['reverse_unordered_selects'] + - ['sql_compound_select_limit'] + - ['sql_default_engine'] + - ['parser_trace'] + - ['select_trace'] + - ['sql_trace'] + - ['vdbe_addoptrace'] + - ['vdbe_debug'] + - ['vdbe_eqp'] + - ['vdbe_listing'] + - ['vdbe_trace'] + - ['where_trace'] +... +box.execute("SET sql_default_engine = '"..engine.."';") +--- +- row_count: 0 +... +box.execute("SET reverse_unordered_selects = "..tostring(order)..";") +--- +- row_count: 0 +... diff --git a/test/sql/sql-debug.test.lua b/test/sql/sql-debug.test.lua index edd0ef4..60d7fdd 100644 --- a/test/sql/sql-debug.test.lua +++ b/test/sql/sql-debug.test.lua @@ -15,3 +15,29 @@ box.execute('PRAGMA parser_trace = '.. result[1][1]) -- Make PRAGMA command return the result as a result set. -- box.execute('PRAGMA') + +-- +-- gh-4511: make sure that SET works. +-- +box.execute('SELECT "name" FROM "_vsql_settings";') + +engine = box.space._vsql_settings:get{'sql_default_engine'}[2] +order = box.space._vsql_settings:get{'reverse_unordered_selects'}[2] + +box.execute('SET sql_default_engine = 1;') +box.execute("SET sql_default_engine = 'some_engine';") +box.execute("SET engine = 'vinyl';") +box.execute("SET defer_foreign_keys('vinyl');") +engine == box.space._vsql_settings:get{'sql_default_engine'}[2] +order == box.space._vsql_settings:get{'reverse_unordered_selects'}[2] + +box.execute("SET sql_default_engine = 'vinyl';") +box.execute("SET reverse_unordered_selects(true);") +box.execute('SELECT "name" FROM "_vsql_settings";') + +box.execute("SET sql_default_engine('memtx');") +box.execute("SET reverse_unordered_selects = false;") +box.execute('SELECT "name" FROM "_vsql_settings";') + +box.execute("SET sql_default_engine = '"..engine.."';") +box.execute("SET reverse_unordered_selects = "..tostring(order)..";") -- 2.7.4