diff --git a/src/box/errcode.h b/src/box/errcode.h index 444171778bd02f4e8ef9f92233754f9071184dc6..d1e4d02a95b0dac217779657bb2ec750a4f74195 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -265,6 +265,7 @@ struct errcode_record { /*210 */_(ER_SQL_PREPARE, "Failed to prepare SQL statement: %s") \ /*211 */_(ER_WRONG_QUERY_ID, "Prepared statement with id %u does not exist") \ /*212 */_(ER_SEQUENCE_NOT_STARTED, "Sequence '%s' is not started") \ + /*213 */_(ER_NO_SUCH_SESSION_SETTING, "Session setting %s doesn't exist") \ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/lua/session.c b/src/box/lua/session.c index c6a600f6f26e917d0f0311409163ea35662404a7..64453463aa26506f93bde9c0fe47801aeb2e5d35 100644 --- a/src/box/lua/session.c +++ b/src/box/lua/session.c @@ -42,6 +42,8 @@ #include "box/user.h" #include "box/schema.h" #include "box/port.h" +#include "box/session_settings.h" +#include "tt_static.h" static const char *sessionlib_name = "box.session"; @@ -411,6 +413,113 @@ lbox_session_on_access_denied(struct lua_State *L) lbox_push_on_access_denied_event, NULL); } +static int +lbox_session_setting_get_by_id(struct lua_State *L, int sid) +{ + assert(sid >= 0 && sid < SESSION_SETTING_COUNT); + const char *mp_pair, *mp_pair_end; + session_settings[sid].get(sid, &mp_pair, &mp_pair_end); + uint32_t len; + mp_decode_array(&mp_pair); + mp_decode_str(&mp_pair, &len); + enum field_type field_type = session_settings[sid].field_type; + if (field_type == FIELD_TYPE_BOOLEAN) { + bool value = mp_decode_bool(&mp_pair); + lua_pushboolean(L, value); + } else { + assert(field_type == FIELD_TYPE_STRING); + const char *str = mp_decode_str(&mp_pair, &len); + lua_pushlstring(L, str, len); + } + return 1; +} + +static int +lbox_session_setting_get(struct lua_State *L) +{ + assert(lua_gettop(L) == 2); + const char *setting_name = lua_tostring(L, -1); + int sid = session_setting_find(setting_name); + if (sid < 0) { + diag_set(ClientError, ER_PROC_LUA, tt_sprintf("Session "\ + "setting %s doesn't exist", setting_name)); + return luaT_error(L); + } + return lbox_session_setting_get_by_id(L, sid); +} + +static int +lbox_session_setting_set(struct lua_State *L) +{ + assert(lua_gettop(L) == 3); + int arg_type = lua_type(L, -1); + const char *setting_name = lua_tostring(L, -2); + int sid = session_setting_find(setting_name); + if (sid < 0) { + diag_set(ClientError, ER_NO_SUCH_SESSION_SETTING, setting_name); + return luaT_error(L); + } + struct session_setting *setting = &session_settings[sid]; + switch (arg_type) { + case LUA_TBOOLEAN: { + bool value = lua_toboolean(L, -1); + size_t size = mp_sizeof_bool(value); + char *mp_value = (char *) static_alloc(size); + mp_encode_bool(mp_value, value); + if (setting->set(sid, mp_value) != 0) + return luaT_error(L); + break; + } + case LUA_TSTRING: { + const char *str = lua_tostring(L, -1); + size_t len = strlen(str); + uint32_t size = mp_sizeof_str(len); + char *mp_value = (char *) static_alloc(size); + if (mp_value == NULL) { + diag_set(OutOfMemory, size, "static_alloc", + "mp_value"); + return luaT_error(L); + } + mp_encode_str(mp_value, str, len); + if (setting->set(sid, mp_value) != 0) + return luaT_error(L); + break; + } + default: + diag_set(ClientError, ER_SESSION_SETTING_INVALID_VALUE, + session_setting_strs[sid], + field_type_strs[setting->field_type]); + return luaT_error(L); + } + return 0; +} + +static int +lbox_session_settings_serialize(struct lua_State *L) +{ + lua_newtable(L); + for (int id = 0; id < SESSION_SETTING_COUNT; ++id) { + lbox_session_setting_get_by_id(L, id); + lua_setfield(L, -2, session_setting_strs[id]); + } + return 1; +} + +static void +lbox_session_settings_init(struct lua_State *L) +{ + lua_newtable(L); + lua_createtable(L, 0, 3); + lua_pushcfunction(L, lbox_session_settings_serialize); + lua_setfield(L, -2, "__serialize"); + lua_pushcfunction(L, lbox_session_setting_get); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, lbox_session_setting_set); + lua_setfield(L, -2, "__newindex"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "settings"); +} + void session_storage_cleanup(int sid) { @@ -478,5 +587,6 @@ box_lua_session_init(struct lua_State *L) {NULL, NULL} }; luaL_register_module(L, sessionlib_name, sessionlib); + lbox_session_settings_init(L); lua_pop(L, 1); } diff --git a/src/box/session.cc b/src/box/session.cc index 881318252a33116fbd22cbb7bb5a9de5f26fd19d..b557eed621c37f63b7c2c0b65cfc3ee68da2bd0e 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -283,6 +283,7 @@ session_init() panic("out of memory"); mempool_create(&session_pool, &cord()->slabc, sizeof(struct session)); credentials_create(&admin_credentials, admin_user); + sql_session_settings_init(); } void diff --git a/src/box/session.h b/src/box/session.h index 6dfc7cba56da6f6badb76e514d01884e03662306..1c47b898696f40810880d277baad15dbfab9492f 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -41,6 +41,8 @@ extern "C" { #endif /* defined(__cplusplus) */ +extern void sql_session_settings_init(); + struct port; struct session_vtab; diff --git a/src/box/session_settings.c b/src/box/session_settings.c index 2ecf71f2d92f6901402e4bb50d0e44b78497920b..79c4b8d3cb505abb9570574830873589f4dc4342 100644 --- a/src/box/session_settings.c +++ b/src/box/session_settings.c @@ -243,8 +243,8 @@ session_settings_index_get(struct index *base, const char *key, uint32_t len; key = mp_decode_str(&key, &len); key = tt_cstr(key, len); - int sid = 0; - if (session_settings_next(&sid, key, true, true) != 0) { + int sid = session_setting_find(key); + if (sid < 0) { *result = NULL; return 0; } @@ -345,7 +345,8 @@ session_settings_space_execute_update(struct space *space, struct txn *txn, } key = mp_decode_str(&key, &key_len); key = tt_cstr(key, key_len); - if (session_settings_next(&sid, key, true, true) != 0) { + sid = session_setting_find(key); + if (sid < 0) { *result = NULL; return 0; } @@ -439,3 +440,12 @@ const struct space_vtab session_settings_space_vtab = { /* .prepare_alter = */ generic_space_prepare_alter, /* .invalidate = */ generic_space_invalidate, }; + +int +session_setting_find(const char *name) { + int sid = 0; + if (session_settings_next(&sid, name, true, true) == 0) + return sid; + else + return -1; +} diff --git a/src/box/session_settings.h b/src/box/session_settings.h index de24e3c6fff10d50d67572e3dbc70eb5c4df9d85..e2adc52899070a226ed3447cca7f926c081352ee 100644 --- a/src/box/session_settings.h +++ b/src/box/session_settings.h @@ -84,3 +84,6 @@ struct session_setting { extern struct session_setting session_settings[SESSION_SETTING_COUNT]; extern const char *session_setting_strs[SESSION_SETTING_COUNT]; + +int +session_setting_find(const char *name); diff --git a/src/box/sql.c b/src/box/sql.c index fa41b45179399a002089913bbc5a717bf58e875a..6afb308b1b7af976d1ff3dfe926bd8da92fec755 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -63,14 +63,9 @@ static const uint32_t default_sql_flags = SQL_EnableTrigger | SQL_AutoIndex | SQL_RecTriggers; -extern void -sql_session_settings_init(); - void sql_init() { - sql_session_settings_init(); - default_flags |= default_sql_flags; current_session()->sql_flags |= default_sql_flags; diff --git a/test/box/error.result b/test/box/error.result index 234c26371de3b54a79a7d06c8e64ac86559b91f0..df6d0ebc0f71b31f785afe5647af7b222ca45041 100644 --- a/test/box/error.result +++ b/test/box/error.result @@ -430,6 +430,7 @@ t; | 210: box.error.SQL_PREPARE | 211: box.error.WRONG_QUERY_ID | 212: box.error.SEQUENCE_NOT_STARTED + | 213: box.error.NO_SUCH_SESSION_SETTING | ... test_run:cmd("setopt delimiter ''"); diff --git a/test/box/gh-4511-access-settings-from-any-frontend.result b/test/box/session_settings.result similarity index 85% rename from test/box/gh-4511-access-settings-from-any-frontend.result rename to test/box/session_settings.result index ed340d053f560acec86efb640c1c0ca194133f30..823bcc6c6d3018ee134b9cca3ebaab0be33d2a8f 100644 --- a/test/box/gh-4511-access-settings-from-any-frontend.result +++ b/test/box/session_settings.result @@ -287,3 +287,64 @@ s:update('sql_defer_foreign_keys', {{'=', 'value', '1'}}) | --- | - error: Session setting sql_defer_foreign_keys expected a value of type boolean | ... + +-- gh-4711: Provide a user-friendly frontend for accessing session settings. +settings = box.session.settings + | --- + | ... +assert(settings ~= nil) + | --- + | - true + | ... + +s:update('sql_default_engine', {{'=', 2, 'vinyl'}}) + | --- + | - ['sql_default_engine', 'vinyl'] + | ... +settings.sql_default_engine + | --- + | - vinyl + | ... +settings.sql_default_engine = 'memtx' + | --- + | ... +s:get('sql_default_engine').value + | --- + | - memtx + | ... +settings.sql_defer_foreign_keys = true + | --- + | ... +s:get('sql_defer_foreign_keys').value + | --- + | - true + | ... +s:update('sql_defer_foreign_keys', {{'=', 2, false}}) + | --- + | - ['sql_defer_foreign_keys', false] + | ... +settings.sql_defer_foreign_keys + | --- + | - false + | ... + +settings.sql_default_engine = true + | --- + | - error: Session setting sql_default_engine expected a value of type string + | ... +settings.sql_defer_foreign_keys = 'false' + | --- + | - error: Session setting sql_defer_foreign_keys expected a value of type boolean + | ... +settings.sql_parser_debug = 'string' + | --- + | - error: Session setting sql_parser_debug expected a value of type boolean + | ... + +str = string.rep('a', 20 * 1024) + | --- + | ... +box.session.settings.sql_default_engine = str + | --- + | - error: Failed to allocate 20483 bytes in static_alloc for mp_value + | ... diff --git a/test/box/gh-4511-access-settings-from-any-frontend.test.lua b/test/box/session_settings.test.lua similarity index 85% rename from test/box/gh-4511-access-settings-from-any-frontend.test.lua rename to test/box/session_settings.test.lua index 3668749985f362611e4224b05274187710f79251..7d6903e3ec7f5765974e53a8cc998c964c289a62 100644 --- a/test/box/gh-4511-access-settings-from-any-frontend.test.lua +++ b/test/box/session_settings.test.lua @@ -106,3 +106,23 @@ s:update('sql_defer_foreign_keys', {{'=', 'some text', true}}) s:update('sql_defer_foreign_keys', {{'=', 'value', 1}}) s:update('sql_defer_foreign_keys', {{'=', 'value', {1}}}) s:update('sql_defer_foreign_keys', {{'=', 'value', '1'}}) + +-- gh-4711: Provide a user-friendly frontend for accessing session settings. +settings = box.session.settings +assert(settings ~= nil) + +s:update('sql_default_engine', {{'=', 2, 'vinyl'}}) +settings.sql_default_engine +settings.sql_default_engine = 'memtx' +s:get('sql_default_engine').value +settings.sql_defer_foreign_keys = true +s:get('sql_defer_foreign_keys').value +s:update('sql_defer_foreign_keys', {{'=', 2, false}}) +settings.sql_defer_foreign_keys + +settings.sql_default_engine = true +settings.sql_defer_foreign_keys = 'false' +settings.sql_parser_debug = 'string' + +str = string.rep('a', 20 * 1024) +box.session.settings.sql_default_engine = str