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 E9CA246970E for ; Thu, 30 Jan 2020 14:10:10 +0300 (MSK) From: Chris Sosnin Date: Thu, 30 Jan 2020 14:10:09 +0300 Message-Id: <20200130111009.35857-1-k.sosnin@tarantool.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH] sql: provide a user friendly frontend for accessing session settings List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org, tarantool-patches@dev.tarantool.org Currently if a user wants to change session setting with sql, he has to execute non-obvious query, thus, we introduce a more native way to do this. Part of #4711 --- This patch is a follow-up for session settings patchset. issue:https://github.com/tarantool/tarantool/issues/4711 branch:https://github.com/tarantool/tarantool/tree/ksosnin/gh-4712-search-settings src/box/sql/build.c | 31 ++++++++++++ src/box/sql/parse.y | 5 ++ src/box/sql/sqlInt.h | 11 +++++ src/box/sql/vdbe.c | 45 +++++++++++++++++ ...1-access-settings-from-any-frontend.result | 49 +++++++++++++++++++ ...access-settings-from-any-frontend.test.lua | 13 +++++ 6 files changed, 154 insertions(+) diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 7dcf7b858..cb7733cfc 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -3474,3 +3474,34 @@ sql_session_settings_init() setting->set = sql_session_setting_set; } } + +void +sql_set_setting(struct Parse *parse_context, struct Token *name, + struct Expr *value) +{ + struct Vdbe *vdbe = sqlGetVdbe(parse_context); + assert(vdbe != NULL); + sqlVdbeCountChanges(vdbe); + char *key = sql_name_from_token(sql_get(), name); + if (key == NULL) + goto abort; + int low = 0, high = session_setting_MAX - 1; + while (low <= high) { + int index = (high + low) / 2; + int cmp = strcasecmp(session_settings[index].name, key); + if (cmp == 0) { + sqlVdbeAddOp4(vdbe, OP_Set, index, 0, 0, + (const char *)value, P4_PTR); + return; + } + if (cmp < 0) + low = index + 1; + else + high = index - 1; + } + diag_set(ClientError, ER_SQL_PARSER_GENERIC, + tt_sprintf("Session setting %s doesn't exist", key)); +abort: + parse_context->is_aborted = true; + return; +} diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index cfe1c0012..9d9b498a7 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -1541,6 +1541,11 @@ 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_setting(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 d1fcf4761..5e192a7bb 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -4510,4 +4510,15 @@ int sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name, uint32_t *fieldno); +/** + * Create VDBE instructions to set new value of session setting. + * + * @param parse_context Parsing context. + * @param name Name of the session setting. + * @param value New value of the session setting. + */ +void +sql_set_setting(struct Parse *parse_context, struct Token *name, + struct Expr *value); + #endif /* sqlINT_H */ diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index eab74db4a..0ee90de47 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -55,6 +55,7 @@ #include "box/schema.h" #include "box/space.h" #include "box/sequence.h" +#include "box/session_settings.h" /* * Invoke this macro on memory cells just prior to changing the @@ -5261,6 +5262,50 @@ case OP_IncMaxid: { break; } +/* Opcode: Set P1 * * P4 * + * + * Set new value to session setting. P1 is ID of the setting. + * P4 is actually of type "struct Expr *" and contains value + * of the setting. + */ +case OP_Set: { + assert(pOp->p4type == P4_PTR); + struct Expr *expr = (struct Expr *)pOp->p4.p; + int sid = pOp->p1; + assert(sid >= 0 && sid < session_setting_MAX); + struct session_setting *setting = &session_settings[sid]; + switch (expr->type) { + case FIELD_TYPE_BOOLEAN: { + bool value = expr->op == TK_TRUE; + size_t size = mp_sizeof_bool(value); + char *mp_value = (char *)region_alloc(&fiber()->gc, + size); + mp_encode_bool(mp_value, value); + if (setting->set(sid, mp_value) != 0) + goto abort_due_to_error; + break; + } + case FIELD_TYPE_STRING: { + const char *str = expr->u.zToken; + size_t len = strlen(str); + uint32_t size = mp_sizeof_str(len); + char *mp_value = (char *)region_alloc(&fiber()->gc, + size); + mp_encode_str(mp_value, str, len); + if (setting->set(sid, mp_value) != 0) + goto abort_due_to_error; + break; + } + default: + diag_set(ClientError, ER_SESSION_SETTING_INVALID_VALUE, + setting->name, + field_type_strs[setting->metadata.field_type]); + goto abort_due_to_error; + } + p->nChange++; + break; +} + /* Opcode: Noop * * * * * * * Do nothing. This instruction is often useful as a jump diff --git a/test/box/gh-4511-access-settings-from-any-frontend.result b/test/box/gh-4511-access-settings-from-any-frontend.result index 1c3ca7661..0597365a1 100644 --- a/test/box/gh-4511-access-settings-from-any-frontend.result +++ b/test/box/gh-4511-access-settings-from-any-frontend.result @@ -343,6 +343,39 @@ settings.sql_defer_foreign_keys | - false | ... +box.execute([[set sql_default_engine = 'vinyl']]) + | --- + | - row_count: 1 + | ... +assert(s:get('sql_default_engine').value == 'vinyl') + | --- + | - true + | ... +box.execute([[set sql_default_engine = 'memtx']]) + | --- + | - row_count: 1 + | ... +assert(s:get('sql_default_engine').value == 'memtx') + | --- + | - true + | ... +box.execute([[set sql_defer_foreign_keys = true]]) + | --- + | - row_count: 1 + | ... +assert(s:get('sql_defer_foreign_keys').value == true) + | --- + | - true + | ... +box.execute([[set sql_defer_foreign_keys = false]]) + | --- + | - row_count: 1 + | ... +assert(s:get('sql_defer_foreign_keys').value == false) + | --- + | - true + | ... + settings.sql_default_engine:set(true) | --- | - error: Session setting sql_default_engine expected a value of type string @@ -355,3 +388,19 @@ settings.sql_parser_debug:set('string') | --- | - error: Session setting sql_parser_debug expected a value of type boolean | ... + +box.execute([[set sql_def_engine = true]]) + | --- + | - null + | - Session setting SQL_DEF_ENGINE doesn't exist + | ... +box.execute([[set sql_default_engine = true]]) + | --- + | - null + | - Session setting sql_default_engine expected a value of type string + | ... +box.execute([[set sql_defer_foreign_keys = 'true']]) + | --- + | - null + | - Session setting sql_defer_foreign_keys expected a value of type boolean + | ... diff --git a/test/box/gh-4511-access-settings-from-any-frontend.test.lua b/test/box/gh-4511-access-settings-from-any-frontend.test.lua index 53f03450d..e93edaf98 100644 --- a/test/box/gh-4511-access-settings-from-any-frontend.test.lua +++ b/test/box/gh-4511-access-settings-from-any-frontend.test.lua @@ -132,6 +132,19 @@ assert(s:get('sql_defer_foreign_keys').value == true) s:update('sql_defer_foreign_keys', {{'=', 2, false}}) settings.sql_defer_foreign_keys +box.execute([[set sql_default_engine = 'vinyl']]) +assert(s:get('sql_default_engine').value == 'vinyl') +box.execute([[set sql_default_engine = 'memtx']]) +assert(s:get('sql_default_engine').value == 'memtx') +box.execute([[set sql_defer_foreign_keys = true]]) +assert(s:get('sql_defer_foreign_keys').value == true) +box.execute([[set sql_defer_foreign_keys = false]]) +assert(s:get('sql_defer_foreign_keys').value == false) + settings.sql_default_engine:set(true) settings.sql_defer_foreign_keys:set(false, 1, 2, 3) settings.sql_parser_debug:set('string') + +box.execute([[set sql_def_engine = true]]) +box.execute([[set sql_default_engine = true]]) +box.execute([[set sql_defer_foreign_keys = 'true']]) -- 2.21.1 (Apple Git-122.3)