Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET
@ 2019-10-25 15:45 imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 1/5] sysview: make get() and create_iterator() methods virtual imeevma
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

Hi! Thank you review. My answers and new patch-set description
below.

On 10/19/19 1:08 AM, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patchset!
>
> Mostly the design is ok. Consider a question below.
>
> What about having a more general settings space? For all
> session settings. Named like '_vsession_settings'. Or
> '_vsession_storage'. It will be exactly like in your
> patchset, but all SQL settings will have 'sql_' prefix.
> And then we could reuse that space for other settings,
> even from not SQL, like Kostja planned.
>
Thank you for suggestion. I did as you suggested and send a letter
to server-dev with this suggestion.

> I am just afraid, that number of system spaces grows
> without a control. With current pace we have only 16
> free IDs left for system spaces. Next are user space.
> See, now we've used 380. The last is 511. Interval is 8.
> 131 / 8 = 16. And we can't put them tighter. We
> need 8-width gaps to be able to insert new spaces
> between existing ones when a certain recovery order will
> be needed.
>
> 16 is not really many, taking into account a pile of
> information schema views going to be added.
>
I understand that this is a problem. Nevertheless, when I asked
about this at scrum, it was decided to leave the problem for the
future.

> On 17/10/2019 16:40, imeevma@tarantool.org wrote:
>> This patch0set created a new SQL command: SET. This command is
>> used to change SQL settings, including debugging settings.
>>
>> The main goal of this fix pack version is to choose a design to
>> solve the problem.
>>
>> https://github.com/tarantool/tarantool/issues/4511
>> https://github.com/tarantool/tarantool/tree/imeevma/gh-4511-pragma-replaced-by-set
>>
>

New description:

The main goal of this set of patches is to replace control pragmas
with the SET operator. Control pragmas are those that change SQL
settings. Along with this, we will allow to see SQL settings in
unified way.

https://github.com/tarantool/tarantool/issues/4511
https://github.com/tarantool/tarantool/tree/imeevma/gh-4511-pragma-replaced-by-set

Changes in v2:
1) Sysview _vsql_settings was changed to _session_settings.
2) Code refactoring.
3) Fixed comments and descriptions.
4) Fixed showed in review bugs.

Mergen Imeev (5):
  sysview: make get() and create_iterator() methods virtual
  box: introdice _vsession_settings sysview
  sql: introduce SET statement
  temporary: disable boolean.test.sql
  sql: replace control pragmas

 src/box/bootstrap.snap                             | Bin 5944 -> 5982 bytes
 src/box/lua/space.cc                               |   2 +
 src/box/lua/upgrade.lua                            |  23 +++
 src/box/schema_def.h                               |   2 +
 src/box/session.cc                                 | 116 +++++++++++
 src/box/session.h                                  |  13 ++
 src/box/sql.c                                      |   3 +-
 src/box/sql.h                                      |  34 ++++
 src/box/sql/build.c                                | 218 +++++++++++++++++++++
 src/box/sql/delete.c                               |  26 ---
 src/box/sql/insert.c                               |  35 +---
 src/box/sql/parse.y                                |   8 +-
 src/box/sql/pragma.c                               | 203 +------------------
 src/box/sql/pragma.h                               | 150 --------------
 src/box/sql/select.c                               |  16 +-
 src/box/sql/sqlInt.h                               |  16 +-
 src/box/sql/update.c                               |  26 ---
 src/box/sql/vdbe.c                                 |  26 +--
 src/box/sysview.c                                  |  48 ++++-
 test/app-tap/tarantoolctl.test.lua                 |   4 +-
 test/box-py/bootstrap.result                       |   5 +-
 test/box/access_sysview.result                     |   6 +-
 test/box/alter.result                              |   5 +-
 test/box/misc.result                               | 121 ++++++++++++
 test/box/misc.test.lua                             |  42 ++++
 test/sql-tap/analyze4.test.lua                     |   4 +-
 test/sql-tap/autoinc.test.lua                      |   2 +-
 test/sql-tap/colname.test.lua                      |  37 ++--
 test/sql-tap/fkey2.test.lua                        |   4 +-
 test/sql-tap/gh2548-select-compound-limit.test.lua |   8 +-
 test/sql-tap/lua/sqltester.lua                     |   2 +-
 test/sql-tap/misc1.test.lua                        |   2 +-
 test/sql-tap/pragma.test.lua                       | 135 +------------
 test/sql-tap/select1.test.lua                      |  35 ++--
 test/sql-tap/tkt3731.test.lua                      |   2 +-
 test/sql-tap/trigger2.test.lua                     |   2 +-
 test/sql-tap/triggerC.test.lua                     |  51 +----
 test/sql-tap/update.test.lua                       |  17 +-
 test/sql-tap/whereA.test.lua                       |  24 +--
 test/sql/check-clear-ephemeral.result              |   4 +-
 test/sql/check-clear-ephemeral.test.lua            |   4 +-
 test/sql/checks.result                             |   4 +-
 test/sql/checks.test.lua                           |   4 +-
 test/sql/clear.result                              |   4 +-
 test/sql/clear.test.lua                            |   4 +-
 test/sql/collation.result                          |   2 +-
 test/sql/collation.test.lua                        |   2 +-
 test/sql/ddl.result                                |   2 +-
 test/sql/ddl.test.lua                              |   2 +-
 test/sql/delete-multiple-idx.result                |   4 +-
 test/sql/delete-multiple-idx.test.lua              |   4 +-
 test/sql/delete.result                             |   4 +-
 test/sql/delete.test.lua                           |   4 +-
 test/sql/drop-index.result                         |   4 +-
 test/sql/drop-index.test.lua                       |   4 +-
 test/sql/drop-table.result                         |   4 +-
 test/sql/drop-table.test.lua                       |   4 +-
 test/sql/engine.result                             |   6 +-
 test/sql/engine.test.lua                           |   6 +-
 test/sql/errinj.result                             |   2 +-
 test/sql/errinj.test.lua                           |   2 +-
 test/sql/func-recreate.result                      |   2 +-
 test/sql/func-recreate.test.lua                    |   2 +-
 test/sql/gh-2362-select-access-rights.result       |   2 +-
 test/sql/gh-2362-select-access-rights.test.lua     |   2 +-
 test/sql/gh-2929-primary-key.result                |   2 +-
 test/sql/gh-2929-primary-key.test.lua              |   2 +-
 test/sql/gh-2981-check-autoinc.result              |   2 +-
 test/sql/gh-2981-check-autoinc.test.lua            |   2 +-
 test/sql/gh-3199-no-mem-leaks.result               |   2 +-
 test/sql/gh-3199-no-mem-leaks.test.lua             |   2 +-
 test/sql/gh-3613-idx-alter-update-2.result         |   2 +-
 test/sql/gh-3613-idx-alter-update-2.test.lua       |   2 +-
 test/sql/gh-3613-idx-alter-update.result           |   2 +-
 test/sql/gh-3613-idx-alter-update.test.lua         |   2 +-
 test/sql/gh-3888-values-blob-assert.result         |   2 +-
 test/sql/gh-3888-values-blob-assert.test.lua       |   2 +-
 test/sql/gh2141-delete-trigger-drop-table.result   |   2 +-
 test/sql/gh2141-delete-trigger-drop-table.test.lua |   2 +-
 test/sql/gh2251-multiple-update.result             |   2 +-
 test/sql/gh2251-multiple-update.test.lua           |   2 +-
 test/sql/gh2483-remote-persistency-check.result    |   2 +-
 test/sql/gh2483-remote-persistency-check.test.lua  |   2 +-
 .../gh2808-inline-unique-persistency-check.result  |   2 +-
 ...gh2808-inline-unique-persistency-check.test.lua |   2 +-
 test/sql/icu-upper-lower.result                    |   2 +-
 test/sql/icu-upper-lower.test.lua                  |   2 +-
 test/sql/insert-unique.result                      |   4 +-
 test/sql/insert-unique.test.lua                    |   4 +-
 test/sql/integer-overflow.result                   |   2 +-
 test/sql/integer-overflow.test.lua                 |   2 +-
 test/sql/iproto.result                             |  33 +---
 test/sql/iproto.test.lua                           |  10 +-
 test/sql/max-on-index.result                       |   4 +-
 test/sql/max-on-index.test.lua                     |   4 +-
 test/sql/message-func-indexes.result               |   2 +-
 test/sql/message-func-indexes.test.lua             |   2 +-
 test/sql/misc.result                               |   2 +-
 test/sql/misc.test.lua                             |   2 +-
 test/sql/no-pk-space.result                        |   2 +-
 test/sql/no-pk-space.test.lua                      |   2 +-
 test/sql/on-conflict.result                        |   2 +-
 test/sql/on-conflict.test.lua                      |   2 +-
 test/sql/persistency.result                        |   2 +-
 test/sql/persistency.test.lua                      |   2 +-
 test/sql/row-count.result                          |  10 +-
 test/sql/row-count.test.lua                        |   4 +-
 test/sql/savepoints.result                         |   2 +-
 test/sql/savepoints.test.lua                       |   2 +-
 test/sql/select-null.result                        |   4 +-
 test/sql/select-null.test.lua                      |   4 +-
 test/sql/sql-debug.result                          | 147 ++++++++++----
 test/sql/sql-debug.test.lua                        |  33 ++--
 test/sql/sql-statN-index-drop.result               |   2 +-
 test/sql/sql-statN-index-drop.test.lua             |   2 +-
 test/sql/suite.ini                                 |   2 +-
 test/sql/tokenizer.result                          |   2 +-
 test/sql/tokenizer.test.lua                        |   2 +-
 test/sql/transition.result                         |   2 +-
 test/sql/transition.test.lua                       |   2 +-
 test/sql/transitive-transactions.result            |   8 +-
 test/sql/transitive-transactions.test.lua          |   8 +-
 test/sql/triggers.result                           |  14 +-
 test/sql/triggers.test.lua                         |  14 +-
 test/sql/update-with-nested-select.result          |   4 +-
 test/sql/update-with-nested-select.test.lua        |   4 +-
 test/sql/upgrade.result                            |   2 +-
 test/sql/upgrade.test.lua                          |   2 +-
 test/sql/view.result                               |   2 +-
 test/sql/view.test.lua                             |   2 +-
 test/sql/view_delayed_wal.result                   |   2 +-
 test/sql/view_delayed_wal.test.lua                 |   2 +-
 test/sql/vinyl-opts.result                         |   2 +-
 test/sql/vinyl-opts.test.lua                       |   2 +-
 test/wal_off/alter.result                          |   2 +-
 135 files changed, 990 insertions(+), 988 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Tarantool-patches] [PATCH v2 1/5] sysview: make get() and create_iterator() methods virtual
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
@ 2019-10-25 15:45 ` imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview imeevma
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

This patch makes get() and create_iterator() virtual for sysview
index. This will allow us to create custom version of these
functions.

Needed for #4511
---
 src/box/sysview.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/src/box/sysview.c b/src/box/sysview.c
index 00c320b..745cf09 100644
--- a/src/box/sysview.c
+++ b/src/box/sysview.c
@@ -49,6 +49,12 @@
 #include "session.h"
 
 typedef bool (*sysview_filter_f)(struct space *, struct tuple *);
+typedef int (*sysview_get_f)(struct index *index, const char *key,
+			     uint32_t part_count, struct tuple **result);
+typedef struct iterator *(*sysview_create_iterator_f)(struct index *index,
+						      enum iterator_type type,
+						      const char *key,
+						      uint32_t part_count);
 
 struct sysview_engine {
 	struct engine base;
@@ -61,6 +67,8 @@ struct sysview_index {
 	uint32_t source_space_id;
 	uint32_t source_index_id;
 	sysview_filter_f filter;
+	sysview_get_f get;
+	sysview_create_iterator_f create_iterator;
 };
 
 struct sysview_iterator {
@@ -140,7 +148,7 @@ sysview_index_create_iterator(struct index *base, enum iterator_type type,
 	it->base.next = sysview_iterator_next;
 	it->base.free = sysview_iterator_free;
 
-	it->source = index_create_iterator(pk, type, key, part_count);
+	it->source = index->create_iterator(pk, type, key, part_count);
 	if (it->source == NULL) {
 		mempool_free(&sysview->iterator_pool, it);
 		return NULL;
@@ -167,7 +175,7 @@ sysview_index_get(struct index *base, const char *key,
 	if (exact_key_validate(pk->def->key_def, key, part_count) != 0)
 		return -1;
 	struct tuple *tuple;
-	if (index_get(pk, key, part_count, &tuple) != 0)
+	if (index->get(pk, key, part_count, &tuple) != 0)
 		return -1;
 	if (tuple == NULL || !index->filter(source, tuple))
 		*result = NULL;
@@ -424,42 +432,58 @@ sysview_space_create_index(struct space *space, struct index_def *def)
 	uint32_t source_space_id;
 	uint32_t source_index_id;
 	sysview_filter_f filter;
+	sysview_get_f get;
+	sysview_create_iterator_f create_iterator;
 
 	switch (def->space_id) {
 	case BOX_VSPACE_ID:
 		source_space_id = BOX_SPACE_ID;
 		source_index_id = def->iid;
 		filter = vspace_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VINDEX_ID:
 		source_space_id = BOX_INDEX_ID;
 		source_index_id = def->iid;
 		filter = vspace_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VUSER_ID:
 		source_space_id = BOX_USER_ID;
 		source_index_id = def->iid;
 		filter = vuser_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VFUNC_ID:
 		source_space_id = BOX_FUNC_ID;
 		source_index_id = def->iid;
 		filter = vfunc_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VPRIV_ID:
 		source_space_id = BOX_PRIV_ID;
 		source_index_id = def->iid;
 		filter = vpriv_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VSEQUENCE_ID:
 		source_space_id = BOX_SEQUENCE_ID;
 		source_index_id = def->iid;
 		filter = vsequence_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	case BOX_VCOLLATION_ID:
 		source_space_id = BOX_COLLATION_ID;
 		source_index_id = def->iid;
 		filter = vcollation_filter;
+		get = index_get;
+		create_iterator = index_create_iterator;
 		break;
 	default:
 		diag_set(ClientError, ER_MODIFY_INDEX,
@@ -484,6 +508,8 @@ sysview_space_create_index(struct space *space, struct index_def *def)
 	index->source_space_id = source_space_id;
 	index->source_index_id = source_index_id;
 	index->filter = filter;
+	index->get = get;
+	index->create_iterator = create_iterator;
 	return &index->base;
 }
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 1/5] sysview: make get() and create_iterator() methods virtual imeevma
@ 2019-10-25 15:45 ` imeevma
  2019-10-26 17:35   ` Vladislav Shpilevoy
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 3/5] sql: introduce SET statement imeevma
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

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
> ---
> - - - <iterator state>
>     - ['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 <stdbool.h>
>>  #include <stdint.h>
>> +#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 <imeevma@gmail.com>
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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Tarantool-patches] [PATCH v2 3/5] sql: introduce SET statement
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 1/5] sysview: make get() and create_iterator() methods virtual imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview imeevma
@ 2019-10-25 15:45 ` imeevma
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql imeevma
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

Thank you for review! My answers and new patch below.


On 10/19/19 1:08 AM, Vladislav Shpilevoy wrote:
> Thanks for the patch!
>
> See 3 comments below.
>
> On 17/10/2019 16:40, imeevma@tarantool.org wrote:
>> 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.
>
> 1. Please, provide SET syntax description. And say, that pragmas
> are dropped. And which of them are dropped, which are converted
> into SET.
>
Fixed.

>>
>> 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/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);
>
> 2. Do we really need both syntax variants?
>
No, I think. Fixed.

>> 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]
>
> 3. Does field access by name work?
>
Yes, fixed.


New patch:

From 8444f08e9a52ec809208ae7e85a69b44014dc215 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Wed, 16 Oct 2019 16:43:10 +0300
Subject: [PATCH] sql: introduce SET statement

This patch creates an SQL SET statement. This statement replaces
pragmas that can modify SQL settings. List of pragmas that will
have the corresponding option in SET:
'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'

All these pragmas along with the pragmas 'short_column_names' and
'count_changes' will be removed in the next patch.

Part of #4511

@TarantoolBot document
Title: SQL SET statement
SQL SET statement is used to change SQL settings. To change the
value of an SQL parameter, use the following syntax:

SET <name of the setting> = <value of the setting>;

Currently available SQL settings:
'sql_defer_foreign_keys'
'sql_full_column_names'
'sql_recursive_triggers'
'sql_reverse_unordered_selects'
'sql_compound_select_limit'
'sql_default_engine'

In addition, SQL debugging settings can also be changed using this
statement in the debug build:
'sql_parser_trace'
'sql_select_trace'
'sql_trace'
'sql_vdbe_addoptrace'
'sql_vdbe_debug'
'sql_vdbe_eqp'
'sql_vdbe_listing'
'sql_vdbe_trace'
'sql_where_trace'

Example of usage:
SET full_column_names = true;
SET sql_compound_select_limit = 10;
SET sql_default_engine = 'memtx';

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index cb97106..3eef4dc 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -3400,3 +3400,63 @@ sql_option_tuple(struct tuple_format *format, int option_id,
 	*result = tuple;
 	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->mask;
+		else
+			session->sql_flags &= ~option->mask;
+#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 1d0c95f..d0702d7 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -1539,6 +1539,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_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 c32cacc..0bc8bbd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4458,4 +4458,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..bfcc046 100644
--- a/test/sql/sql-debug.result
+++ b/test/sql/sql-debug.result
@@ -54,3 +54,134 @@ box.execute('PRAGMA')
   - ['vdbe_trace', 0]
   - ['where_trace', 0]
 ...
+--
+-- gh-4511: make sure that SET works.
+--
+box.execute('SELECT "name" FROM "_vsession_settings";')
+---
+- metadata:
+  - name: name
+    type: string
+  rows:
+  - ['sql_compound_select_limit']
+  - ['sql_default_engine']
+  - ['sql_defer_foreign_keys']
+  - ['sql_full_column_names']
+  - ['sql_parser_trace']
+  - ['sql_recursive_triggers']
+  - ['sql_reverse_unordered_selects']
+  - ['sql_select_trace']
+  - ['sql_trace']
+  - ['sql_vdbe_addoptrace']
+  - ['sql_vdbe_debug']
+  - ['sql_vdbe_eqp']
+  - ['sql_vdbe_listing']
+  - ['sql_vdbe_trace']
+  - ['sql_where_trace']
+...
+engine = box.space._vsession_settings:get{'sql_default_engine'}.value
+---
+...
+order = box.space._vsession_settings:get{'sql_reverse_unordered_selects'}.value
+---
+...
+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 sql_defer_foreign_keys = 'vinyl';")
+---
+- null
+- 'Inconsistent types: expected boolean got string'
+...
+engine == box.space._vsession_settings:get{'sql_default_engine'}.value
+---
+- true
+...
+order == box.space._vsession_settings:get{'sql_reverse_unordered_selects'}.value
+---
+- true
+...
+box.execute("SET sql_default_engine = 'vinyl';")
+---
+- row_count: 0
+...
+box.execute("SET sql_reverse_unordered_selects = true;")
+---
+- row_count: 0
+...
+box.execute('SELECT * FROM "_vsession_settings";')
+---
+- metadata:
+  - name: name
+    type: string
+  - name: value
+    type: any
+  rows:
+  - ['sql_where_trace', false]
+  - ['sql_vdbe_trace', false]
+  - ['sql_vdbe_listing', false]
+  - ['sql_vdbe_eqp', false]
+  - ['sql_vdbe_debug', false]
+  - ['sql_vdbe_addoptrace', false]
+  - ['sql_trace', false]
+  - ['sql_select_trace', false]
+  - ['sql_reverse_unordered_selects', true]
+  - ['sql_recursive_triggers', true]
+  - ['sql_parser_trace', false]
+  - ['sql_full_column_names', false]
+  - ['sql_defer_foreign_keys', false]
+  - ['sql_default_engine', 'vinyl']
+  - ['sql_compound_select_limit', 30]
+...
+box.execute("SET sql_default_engine = 'memtx';")
+---
+- row_count: 0
+...
+box.execute("SET sql_reverse_unordered_selects = false;")
+---
+- row_count: 0
+...
+box.execute('SELECT * FROM "_vsession_settings";')
+---
+- metadata:
+  - name: name
+    type: string
+  - name: value
+    type: any
+  rows:
+  - ['sql_compound_select_limit', 30]
+  - ['sql_default_engine', 'memtx']
+  - ['sql_defer_foreign_keys', false]
+  - ['sql_full_column_names', false]
+  - ['sql_parser_trace', false]
+  - ['sql_recursive_triggers', true]
+  - ['sql_reverse_unordered_selects', false]
+  - ['sql_select_trace', false]
+  - ['sql_trace', false]
+  - ['sql_vdbe_addoptrace', false]
+  - ['sql_vdbe_debug', false]
+  - ['sql_vdbe_eqp', false]
+  - ['sql_vdbe_listing', false]
+  - ['sql_vdbe_trace', false]
+  - ['sql_where_trace', false]
+...
+box.execute("SET sql_default_engine = '"..engine.."';")
+---
+- row_count: 0
+...
+box.execute("SET sql_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..83746f0 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 "_vsession_settings";')
+
+engine = box.space._vsession_settings:get{'sql_default_engine'}.value
+order = box.space._vsession_settings:get{'sql_reverse_unordered_selects'}.value
+
+box.execute('SET sql_default_engine = 1;')
+box.execute("SET sql_default_engine = 'some_engine';")
+box.execute("SET engine = 'vinyl';")
+box.execute("SET sql_defer_foreign_keys = 'vinyl';")
+engine == box.space._vsession_settings:get{'sql_default_engine'}.value
+order == box.space._vsession_settings:get{'sql_reverse_unordered_selects'}.value
+
+box.execute("SET sql_default_engine = 'vinyl';")
+box.execute("SET sql_reverse_unordered_selects = true;")
+box.execute('SELECT * FROM "_vsession_settings";')
+
+box.execute("SET sql_default_engine = 'memtx';")
+box.execute("SET sql_reverse_unordered_selects = false;")
+box.execute('SELECT * FROM "_vsession_settings";')
+
+box.execute("SET sql_default_engine = '"..engine.."';")
+box.execute("SET sql_reverse_unordered_selects = "..tostring(order)..";")
-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
                   ` (2 preceding siblings ...)
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 3/5] sql: introduce SET statement imeevma
@ 2019-10-25 15:45 ` imeevma
  2019-10-26 17:35   ` Vladislav Shpilevoy
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 5/5] sql: replace control pragmas imeevma
  2019-10-26 17:34 ` [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET Vladislav Shpilevoy
  5 siblings, 1 reply; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

Since PRAGMA 'sql_default_engine' will be removed in the next
patch, this test will fail until test-run is fixed.

This patch should be removed before patch-set will be pushed.
---
 test/sql/suite.ini | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/sql/suite.ini b/test/sql/suite.ini
index a8664c5..a2573be 100644
--- a/test/sql/suite.ini
+++ b/test/sql/suite.ini
@@ -8,7 +8,7 @@ config = engine.cfg
 is_parallel = True
 lua_libs = lua/sql_tokenizer.lua
 release_disabled = errinj.test.lua view_delayed_wal.test.lua sql-debug.test.lua
-disabled = sql-statN-index-drop.test.lua
+disabled = sql-statN-index-drop.test.lua boolean.test.sql
 pretest_clean = True
 fragile = dll.test.lua           ; gh-4427
           func-recreate.test.lua ; gh-4384
-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Tarantool-patches] [PATCH v2 5/5] sql: replace control pragmas
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
                   ` (3 preceding siblings ...)
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql imeevma
@ 2019-10-25 15:45 ` imeevma
  2019-10-26 17:34 ` [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET Vladislav Shpilevoy
  5 siblings, 0 replies; 13+ messages in thread
From: imeevma @ 2019-10-25 15:45 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

This patch removes pragmas that modify SQL settings. Most of these
pragmas have been replaced by SET. But there are two pragmas that
have been completely removed: 'short_column_names' and
'count_changes'.

Closes #4511
---
 src/box/sql.c                                      |   3 +-
 src/box/sql/delete.c                               |  26 ---
 src/box/sql/insert.c                               |  35 +---
 src/box/sql/parse.y                                |   3 -
 src/box/sql/pragma.c                               | 203 +--------------------
 src/box/sql/pragma.h                               | 150 ---------------
 src/box/sql/select.c                               |  16 +-
 src/box/sql/sqlInt.h                               |   2 -
 src/box/sql/update.c                               |  26 ---
 src/box/sql/vdbe.c                                 |  26 +--
 test/sql-tap/analyze4.test.lua                     |   4 +-
 test/sql-tap/autoinc.test.lua                      |   2 +-
 test/sql-tap/colname.test.lua                      |  37 ++--
 test/sql-tap/fkey2.test.lua                        |   4 +-
 test/sql-tap/gh2548-select-compound-limit.test.lua |   8 +-
 test/sql-tap/lua/sqltester.lua                     |   2 +-
 test/sql-tap/misc1.test.lua                        |   2 +-
 test/sql-tap/pragma.test.lua                       | 135 +-------------
 test/sql-tap/select1.test.lua                      |  35 ++--
 test/sql-tap/tkt3731.test.lua                      |   2 +-
 test/sql-tap/trigger2.test.lua                     |   2 +-
 test/sql-tap/triggerC.test.lua                     |  51 +-----
 test/sql-tap/update.test.lua                       |  17 +-
 test/sql-tap/whereA.test.lua                       |  24 +--
 test/sql/check-clear-ephemeral.result              |   4 +-
 test/sql/check-clear-ephemeral.test.lua            |   4 +-
 test/sql/checks.result                             |   4 +-
 test/sql/checks.test.lua                           |   4 +-
 test/sql/clear.result                              |   4 +-
 test/sql/clear.test.lua                            |   4 +-
 test/sql/collation.result                          |   2 +-
 test/sql/collation.test.lua                        |   2 +-
 test/sql/ddl.result                                |   2 +-
 test/sql/ddl.test.lua                              |   2 +-
 test/sql/delete-multiple-idx.result                |   4 +-
 test/sql/delete-multiple-idx.test.lua              |   4 +-
 test/sql/delete.result                             |   4 +-
 test/sql/delete.test.lua                           |   4 +-
 test/sql/drop-index.result                         |   4 +-
 test/sql/drop-index.test.lua                       |   4 +-
 test/sql/drop-table.result                         |   4 +-
 test/sql/drop-table.test.lua                       |   4 +-
 test/sql/engine.result                             |   6 +-
 test/sql/engine.test.lua                           |   6 +-
 test/sql/errinj.result                             |   2 +-
 test/sql/errinj.test.lua                           |   2 +-
 test/sql/func-recreate.result                      |   2 +-
 test/sql/func-recreate.test.lua                    |   2 +-
 test/sql/gh-2362-select-access-rights.result       |   2 +-
 test/sql/gh-2362-select-access-rights.test.lua     |   2 +-
 test/sql/gh-2929-primary-key.result                |   2 +-
 test/sql/gh-2929-primary-key.test.lua              |   2 +-
 test/sql/gh-2981-check-autoinc.result              |   2 +-
 test/sql/gh-2981-check-autoinc.test.lua            |   2 +-
 test/sql/gh-3199-no-mem-leaks.result               |   2 +-
 test/sql/gh-3199-no-mem-leaks.test.lua             |   2 +-
 test/sql/gh-3613-idx-alter-update-2.result         |   2 +-
 test/sql/gh-3613-idx-alter-update-2.test.lua       |   2 +-
 test/sql/gh-3613-idx-alter-update.result           |   2 +-
 test/sql/gh-3613-idx-alter-update.test.lua         |   2 +-
 test/sql/gh-3888-values-blob-assert.result         |   2 +-
 test/sql/gh-3888-values-blob-assert.test.lua       |   2 +-
 test/sql/gh2141-delete-trigger-drop-table.result   |   2 +-
 test/sql/gh2141-delete-trigger-drop-table.test.lua |   2 +-
 test/sql/gh2251-multiple-update.result             |   2 +-
 test/sql/gh2251-multiple-update.test.lua           |   2 +-
 test/sql/gh2483-remote-persistency-check.result    |   2 +-
 test/sql/gh2483-remote-persistency-check.test.lua  |   2 +-
 .../gh2808-inline-unique-persistency-check.result  |   2 +-
 ...gh2808-inline-unique-persistency-check.test.lua |   2 +-
 test/sql/icu-upper-lower.result                    |   2 +-
 test/sql/icu-upper-lower.test.lua                  |   2 +-
 test/sql/insert-unique.result                      |   4 +-
 test/sql/insert-unique.test.lua                    |   4 +-
 test/sql/integer-overflow.result                   |   2 +-
 test/sql/integer-overflow.test.lua                 |   2 +-
 test/sql/iproto.result                             |  33 +---
 test/sql/iproto.test.lua                           |  10 +-
 test/sql/max-on-index.result                       |   4 +-
 test/sql/max-on-index.test.lua                     |   4 +-
 test/sql/message-func-indexes.result               |   2 +-
 test/sql/message-func-indexes.test.lua             |   2 +-
 test/sql/misc.result                               |   2 +-
 test/sql/misc.test.lua                             |   2 +-
 test/sql/no-pk-space.result                        |   2 +-
 test/sql/no-pk-space.test.lua                      |   2 +-
 test/sql/on-conflict.result                        |   2 +-
 test/sql/on-conflict.test.lua                      |   2 +-
 test/sql/persistency.result                        |   2 +-
 test/sql/persistency.test.lua                      |   2 +-
 test/sql/row-count.result                          |  10 +-
 test/sql/row-count.test.lua                        |   4 +-
 test/sql/savepoints.result                         |   2 +-
 test/sql/savepoints.test.lua                       |   2 +-
 test/sql/select-null.result                        |   4 +-
 test/sql/select-null.test.lua                      |   4 +-
 test/sql/sql-debug.result                          |  50 -----
 test/sql/sql-debug.test.lua                        |  15 --
 test/sql/sql-statN-index-drop.result               |   2 +-
 test/sql/sql-statN-index-drop.test.lua             |   2 +-
 test/sql/tokenizer.result                          |   2 +-
 test/sql/tokenizer.test.lua                        |   2 +-
 test/sql/transition.result                         |   2 +-
 test/sql/transition.test.lua                       |   2 +-
 test/sql/transitive-transactions.result            |   8 +-
 test/sql/transitive-transactions.test.lua          |   8 +-
 test/sql/triggers.result                           |  14 +-
 test/sql/triggers.test.lua                         |  14 +-
 test/sql/update-with-nested-select.result          |   4 +-
 test/sql/update-with-nested-select.test.lua        |   4 +-
 test/sql/upgrade.result                            |   2 +-
 test/sql/upgrade.test.lua                          |   2 +-
 test/sql/view.result                               |   2 +-
 test/sql/view.test.lua                             |   2 +-
 test/sql/view_delayed_wal.result                   |   2 +-
 test/sql/view_delayed_wal.test.lua                 |   2 +-
 test/sql/vinyl-opts.result                         |   2 +-
 test/sql/vinyl-opts.test.lua                       |   2 +-
 118 files changed, 209 insertions(+), 992 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index f1df555..7c1035c 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -59,8 +59,7 @@ static sql *db = NULL;
 
 static const char nil_key[] = { 0x90 }; /* Empty MsgPack array. */
 
-static const uint32_t default_sql_flags = SQL_ShortColNames
-					  | SQL_EnableTrigger
+static const uint32_t default_sql_flags = SQL_EnableTrigger
 					  | SQL_AutoIndex
 					  | SQL_RecTriggers;
 
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 2f73d80..8d9ae4f 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -191,15 +191,6 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 				     tab_cursor);
 	}
 
-	/* Initialize the counter of the number of rows deleted,
-	 * if we are counting rows.
-	 */
-	int reg_count = -1;
-	uint32_t sql_flags = parse->sql_flags;
-	if ((sql_flags & SQL_CountRows) != 0) {
-		reg_count = ++parse->nMem;
-		sqlVdbeAddOp2(v, OP_Integer, 0, reg_count);
-	}
 	/* Special case: A DELETE without a WHERE clause deletes
 	 * everything. It is easier just to erase the whole table.
 	 */
@@ -284,12 +275,6 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 		 */
 		/* assert(is_complex || one_pass != ONEPASS_OFF); */
 
-		/* Keep track of the number of rows to be
-		 * deleted.
-		 */
-		if ((sql_flags & SQL_CountRows) != 0)
-			sqlVdbeAddOp2(v, OP_AddImm, reg_count, 1);
-
 		/* Extract the primary key for the current row */
 		if (!is_view) {
 			struct key_part_def *part = pk_info->parts;
@@ -413,17 +398,6 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 		}
 	}
 
-	/* Return the number of rows that were deleted. */
-	if ((sql_flags & SQL_CountRows) != 0 &&
-	    parse->triggered_space != NULL) {
-		sqlVdbeAddOp2(v, OP_ResultRow, reg_count, 1);
-		sqlVdbeSetNumCols(v, 1);
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, "rows deleted",
-				      SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "INTEGER",
-				  SQL_STATIC);
-	}
-
  delete_from_cleanup:
 	sqlSrcListDelete(db, tab_list);
 	sql_expr_delete(db, where, false);
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 42b8391..43a0de5 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -251,7 +251,6 @@ sqlInsert(Parse * pParse,	/* Parser context */
 
 	/* Register allocations */
 	int regFromSelect = 0;	/* Base register for data coming from SELECT */
-	int regRowCount = 0;	/* Memory cell used for the row counter */
 	int regIns;		/* Block of regs holding data being inserted */
 	int regTupleid;		/* registers holding insert tupleid */
 	int regData;		/* register holding first column to insert */
@@ -334,7 +333,7 @@ sqlInsert(Parse * pParse,	/* Parser context */
 	    xferOptimization(pParse, space, pSelect, on_error)) {
 		assert(trigger == NULL);
 		assert(pList == 0);
-		goto insert_end;
+		goto insert_cleanup;
 	}
 
 	/*
@@ -512,12 +511,6 @@ sqlInsert(Parse * pParse,	/* Parser context */
 		goto insert_cleanup;
 	}
 
-	/* Initialize the count of rows to be inserted
-	 */
-	if ((pParse->sql_flags & SQL_CountRows) != 0) {
-		regRowCount = ++pParse->nMem;
-		sqlVdbeAddOp2(v, OP_Integer, 0, regRowCount);
-	}
 	/* This is the top of the main insertion loop */
 	if (useTempTable) {
 		/* This block codes the top of loop only.  The complete loop is the
@@ -745,12 +738,6 @@ sqlInsert(Parse * pParse,	/* Parser context */
 					       on_error, autoinc_reg);
 	}
 
-	/* Update the count of rows that are inserted
-	 */
-	if ((pParse->sql_flags & SQL_CountRows) != 0) {
-		sqlVdbeAddOp2(v, OP_AddImm, regRowCount, 1);
-	}
-
 	if (trigger != NULL) {
 		/* Code AFTER triggers */
 		vdbe_code_row_trigger(pParse, trigger, TK_INSERT, 0,
@@ -773,23 +760,6 @@ sqlInsert(Parse * pParse,	/* Parser context */
 		sqlVdbeJumpHere(v, addrInsTop);
 	}
 
- insert_end:
-
-	/* Return the number of rows inserted. */
-	if ((pParse->sql_flags & SQL_CountRows) != 0 &&
-	    pParse->triggered_space == NULL) {
-		sqlVdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
-		sqlVdbeSetNumCols(v, 1);
-		const char *column_name;
-		if (on_error == ON_CONFLICT_ACTION_REPLACE)
-			column_name = "rows replaced";
-		else
-			column_name = "rows inserted";
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, column_name, SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "INTEGER",
-				  SQL_STATIC);
-	}
-
  insert_cleanup:
 	sqlSrcListDelete(db, pTabList);
 	sql_expr_list_delete(db, pList);
@@ -1182,9 +1152,6 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	 */
 	if (!rlist_empty(&dest->child_fk_constraint))
 		return 0;
-	if ((pParse->sql_flags & SQL_CountRows) != 0) {
-		return 0;	/* xfer opt does not play well with PRAGMA count_changes */
-	}
 
 	/* If we get this far, it means that the xfer optimization is at
 	 * least a possibility, though it might only work if the destination
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index d0702d7..9f8118e 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -1564,9 +1564,6 @@ cmd ::= PRAGMA nm(X) LP minus_num(Y) RP.     {
 cmd ::= PRAGMA nm(X) LP nm(Z) DOT nm(Y) RP.  {
     sqlPragma(pParse,&X,&Y,&Z,0);
 }
-cmd ::= PRAGMA .                            {
-    sqlPragma(pParse, 0,0,0,0);
-}
 
 nmnum(A) ::= plus_num(A).
 nmnum(A) ::= STRING(A).
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 5bf24ef..0eaa2ca 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -62,56 +62,6 @@
 #include "pragma.h"
 #include "tarantoolInt.h"
 
-/*
- * Interpret the given string as a safety level.  Return 0 for OFF,
- * 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or
- * unrecognized string argument.  The FULL and EXTRA option is disallowed
- * if the omitFull parameter it 1.
- *
- * Note that the values returned are one less that the values that
- * should be passed into sqlBtreeSetSafetyLevel().  The is done
- * to support legacy SQL code.  The safety level used to be boolean
- * and older scripts may have used numbers 0 for OFF and 1 for ON.
- */
-static u8
-getSafetyLevel(const char *z, int omitFull, u8 dflt)
-{
-	/* 123456789 123456789 123 */
-	static const char zText[] = "onoffalseyestruextrafull";
-	static const u8 iOffset[] = { 0, 1, 2, 4, 9, 12, 15, 20 };
-	static const u8 iLength[] = { 2, 2, 3, 5, 3, 4, 5, 4 };
-	static const u8 iValue[] = { 1, 0, 0, 0, 1, 1, 3, 2 };
-	/* on no off false yes true extra full */
-	int i, n;
-	if (sqlIsdigit(*z)) {
-		return (u8) sqlAtoi(z);
-	}
-	n = sqlStrlen30(z);
-	for (i = 0; i < ArraySize(iLength); i++) {
-		if (iLength[i] == n
-		    && sqlStrNICmp(&zText[iOffset[i]], z, n) == 0
-		    && (!omitFull || iValue[i] <= 1)
-		    ) {
-			return iValue[i];
-		}
-	}
-	return dflt;
-}
-
-/*
- * Interpret the given string as a boolean value.
- */
-u8
-sqlGetBoolean(const char *z, u8 dflt)
-{
-	return getSafetyLevel(z, 1, dflt) != 0;
-}
-
-/* The sqlGetBoolean() function is used by other modules but the
- * remainder of this file is specific to PRAGMA processing.  So omit
- * the rest of the file if PRAGMAs are omitted from the build.
- */
-
 /** Set result column names and types for a pragma. */
 static void
 vdbe_set_pragma_result_columns(struct Vdbe *v, const struct PragmaName *pragma)
@@ -128,17 +78,6 @@ vdbe_set_pragma_result_columns(struct Vdbe *v, const struct PragmaName *pragma)
 }
 
 /*
- * Generate code to return a single integer value.
- */
-static void
-returnSingleInt(Vdbe * v, i64 value)
-{
-	sqlVdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8 *)&value,
-			  value < 0 ? P4_INT64 : P4_UINT64);
-	sqlVdbeAddOp2(v, OP_ResultRow, 1, 1);
-}
-
-/*
  * Locate a pragma in the aPragmaName[] array.
  */
 static const PragmaName *
@@ -161,53 +100,6 @@ pragmaLocate(const char *zName)
 	return lwr > upr ? 0 : &aPragmaName[mid];
 }
 
-static void
-vdbe_emit_pragma_status(struct Parse *parse)
-{
-	struct Vdbe *v = sqlGetVdbe(parse);
-	struct session *user_session = current_session();
-
-	sqlVdbeSetNumCols(v, 2);
-	sqlVdbeSetColName(v, 0, COLNAME_NAME, "pragma_name", SQL_STATIC);
-	sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "TEXT", SQL_STATIC);
-	sqlVdbeSetColName(v, 1, COLNAME_NAME, "pragma_value", SQL_STATIC);
-	sqlVdbeSetColName(v, 1, COLNAME_DECLTYPE, "INTEGER", SQL_STATIC);
-
-	parse->nMem = 2;
-	for (int i = 0; i < ArraySize(aPragmaName); ++i) {
-		if (aPragmaName[i].ePragTyp != PragTyp_FLAG)
-			continue;
-		sqlVdbeAddOp4(v, OP_String8, 0, 1, 0, aPragmaName[i].zName, 0);
-		int val = (user_session->sql_flags & aPragmaName[i].iArg) != 0;
-		sqlVdbeAddOp2(v, OP_Integer, val, 2);
-		sqlVdbeAddOp2(v, OP_ResultRow, 1, 2);
-	}
-}
-
-/**
- * Set tarantool backend default engine for SQL interface.
- * @param engine_name to set default.
- * @retval -1 on error.
- * @retval 0 on success.
- */
-static int
-sql_default_engine_set(const char *engine_name)
-{
-	if (engine_name == NULL) {
-		diag_set(ClientError, ER_ILLEGAL_PARAMS,
-			 "'sql_default_engine' was not specified");
-		return -1;
-	}
-	enum sql_storage_engine engine =
-		STR2ENUM(sql_storage_engine, engine_name);
-	if (engine == sql_storage_engine_MAX) {
-		diag_set(ClientError, ER_NO_SUCH_ENGINE, engine_name);
-		return -1;
-	}
-	current_session()->sql_default_engine = engine;
-	return 0;
-}
-
 /**
  * This function handles PRAGMA TABLE_INFO(<table>).
  *
@@ -373,22 +265,6 @@ sql_pragma_index_list(struct Parse *parse, const char *tbl_name)
 }
 
 /*
- * @brief Check whether the specified token is a string or ID.
- * @param token - token to be examined
- * @return true - if the token value is enclosed into quotes (')
- * @return false in other cases
- * The empty value is considered to be a string.
- */
-static bool
-token_is_string(const struct Token* token)
-{
-	if (!token || token->n == 0)
-		return true;
-	return token->n >= 2 && token->z[0] == '\'' &&
-	       token->z[token->n - 1] == '\'';
-}
-
-/*
  * Process a pragma statement.
  *
  * Pragmas are of this form:
@@ -416,17 +292,12 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 	sql *db = pParse->db;	/* The database connection */
 	Vdbe *v = sqlGetVdbe(pParse);	/* Prepared statement */
 	const PragmaName *pPragma;	/* The pragma */
-	struct session *user_session = current_session();
 
 	if (v == 0)
 		return;
 	sqlVdbeRunOnlyOnce(v);
 	pParse->nMem = 2;
 
-	if (pId == NULL) {
-		vdbe_emit_pragma_status(pParse);
-		return;
-	}
 	zLeft = sql_name_from_token(db, pId);
 	if (zLeft == NULL) {
 		pParse->is_aborted = true;
@@ -456,38 +327,10 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 		goto pragma_out;
 	}
 	/* Register the result column names for pragmas that return results */
-	if ((pPragma->mPragFlg & PragFlg_NoColumns) == 0 &&
-	    ((pPragma->mPragFlg & PragFlg_NoColumns1) == 0 || zRight == NULL))
-		vdbe_set_pragma_result_columns(v, pPragma);
+	vdbe_set_pragma_result_columns(v, pPragma);
 	/* Jump to the appropriate pragma handler */
 	switch (pPragma->ePragTyp) {
 
-	case PragTyp_FLAG:{
-		if (zRight == NULL) {
-			vdbe_set_pragma_result_columns(v, pPragma);
-			returnSingleInt(v, (user_session->sql_flags &
-					    pPragma->iArg) != 0);
-		} else {
-			/* Mask of bits to set or clear. */
-			int mask = pPragma->iArg;
-			bool is_pragma_set = sqlGetBoolean(zRight, 0);
-
-			if (is_pragma_set)
-				user_session->sql_flags |= mask;
-			else
-				user_session->sql_flags &= ~mask;
-#if defined(SQL_DEBUG)
-			if (mask == PARSER_TRACE_FLAG) {
-				if (is_pragma_set)
-					sqlParserTrace(stdout, "parser: ");
-				else
-					sqlParserTrace(0, 0);
-			}
-#endif
-		}
-		break;
-	}
-
 	case PragTyp_TABLE_INFO:
 		sql_pragma_table_info(pParse, zRight);
 		break;
@@ -565,54 +408,10 @@ sqlPragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 		break;
 	}
 
-	case PragTyp_DEFAULT_ENGINE: {
-		if (!token_is_string(pValue)) {
-			diag_set(ClientError, ER_ILLEGAL_PARAMS,
-				 "string value is expected");
-			pParse->is_aborted = true;
-			goto pragma_out;
-		}
-		if (zRight == NULL) {
-			const char *engine_name =
-				sql_storage_engine_strs[current_session()->
-							sql_default_engine];
-			sqlVdbeLoadString(v, 1, engine_name);
-			sqlVdbeAddOp2(v, OP_ResultRow, 1, 1);
-		} else {
-			if (sql_default_engine_set(zRight) != 0) {
-				pParse->is_aborted = true;
-				goto pragma_out;
-			}
-			sqlVdbeAddOp0(v, OP_Expire);
-		}
-		break;
-	}
-
-	case PragTyp_COMPOUND_SELECT_LIMIT: {
-		if (zRight != NULL) {
-			sql_limit(db, SQL_LIMIT_COMPOUND_SELECT,
-				      sqlAtoi(zRight));
-		}
-		int retval =
-			sql_limit(db, SQL_LIMIT_COMPOUND_SELECT, -1);
-		returnSingleInt(v, retval);
-		break;
-	}
-
 	default:
 		unreachable();
 	}			/* End of the PRAGMA switch */
 
-	/* The following block is a no-op unless SQL_DEBUG is
-	 * defined. Its only * purpose is to execute assert()
-	 * statements to verify that if the * PragFlg_NoColumns1 flag
-	 * is set and the caller specified an argument * to the PRAGMA,
-	 * the implementation has not added any OP_ResultRow *
-	 * instructions to the VM.
-	 */
-	if ((pPragma->mPragFlg & PragFlg_NoColumns1) && zRight) {
-		sqlVdbeVerifyNoResultRow(v);
-	}
  pragma_out:
 	sqlDbFree(db, zLeft);
 	sqlDbFree(db, zRight);
diff --git a/src/box/sql/pragma.h b/src/box/sql/pragma.h
index 02895b0..dcacbd9 100644
--- a/src/box/sql/pragma.h
+++ b/src/box/sql/pragma.h
@@ -6,19 +6,14 @@
 
 /* The various pragma types */
 #define PragTyp_COLLATION_LIST                 3
-#define PragTyp_FLAG                           5
 #define PragTyp_FOREIGN_KEY_LIST               9
 #define PragTyp_INDEX_INFO                    10
 #define PragTyp_INDEX_LIST                    11
 #define PragTyp_STATS                         15
 #define PragTyp_TABLE_INFO                    17
-#define PragTyp_DEFAULT_ENGINE                25
-#define PragTyp_COMPOUND_SELECT_LIMIT         26
 
 /* Property flags associated with various pragma. */
 #define PragFlg_NeedSchema 0x01	/* Force schema load before running */
-#define PragFlg_NoColumns  0x02	/* OP_ResultRow called with zero columns */
-#define PragFlg_NoColumns1 0x04	/* zero columns if RHS argument is present */
 #define PragFlg_Result0    0x10	/* Acts as query when no argument */
 #define PragFlg_Result1    0x20	/* Acts as query when has one argument */
 #define PragFlg_SchemaOpt  0x40	/* Schema restricts name search if present */
@@ -93,57 +88,6 @@ static const char *const pragCName[] = {
 	/*  55 */ "TEXT",
 	/*  56 */ "match",
 	/*  57 */ "TEXT",
-	/* Used by: count_changes */
-	/*  58 */ "count_changes",
-	/*  59 */ "INTEGER",
-	/* Used by: defer_foreign_keys */
-	/*  60 */ "defer_foreign_keys",
-	/*  61 */ "INTEGER",
-	/* Used by: full_column_names */
-	/*  62 */ "full_column_names",
-	/*  63 */ "INTEGER",
-	/* Used by: parser_trace */
-	/*  64 */ "parser_trace",
-	/*  65 */ "INTEGER",
-	/* Used by: recursive_triggers */
-	/*  66 */ "recursive_triggers",
-	/*  67 */ "INTEGER",
-	/* Used by: reverse_unordered_selects */
-	/*  68 */ "reverse_unordered_selects",
-	/*  69 */ "INTEGER",
-	/* Used by: select_trace */
-	/*  70 */ "select_trace",
-	/*  71 */ "INTEGER",
-	/* Used by: short_column_names */
-	/*  72 */ "short_column_names",
-	/*  73 */ "INTEGER",
-	/* Used by: sql_compound_select_limit */
-	/*  74 */ "sql_compound_select_limit",
-	/*  75 */ "INTEGER",
-	/* Used by: sql_default_engine */
-	/*  76 */ "sql_default_engine",
-	/*  77 */ "TEXT",
-	/* Used by: sql_trace */
-	/*  78 */ "sql_trace",
-	/*  79 */ "INTEGER",
-	/* Used by: vdbe_addoptrace */
-	/*  80 */ "vdbe_addoptrace",
-	/*  81 */ "INTEGER",
-	/* Used by: vdbe_debug */
-	/*  82 */ "vdbe_debug",
-	/*  83 */ "INTEGER",
-	/* Used by: vdbe_eqp */
-	/*  84 */ "vdbe_eqp",
-	/*  85 */ "INTEGER",
-	/* Used by: vdbe_listing */
-	/*  86 */ "vdbe_listing",
-	/*  87 */ "INTEGER",
-	/* Used by: vdbe_trace */
-	/*  88 */ "vdbe_trace",
-	/*  89 */ "INTEGER",
-	/* Used by: where_trace */
-	/*  90 */ "where_trace",
-	/*  91 */ "INTEGER",
 };
 
 /* Definitions of all built-in pragmas */
@@ -165,27 +109,12 @@ static const PragmaName aPragmaName[] = {
 	 /* ePragFlg:  */ PragFlg_Result0,
 	 /* ColNames:  */ 38, 2,
 	 /* iArg:      */ 0},
-	{ /* zName:     */ "count_changes",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 60, 1,
-	 /* iArg:      */ SQL_CountRows},
-	{ /* zName:     */ "defer_foreign_keys",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 62, 1,
-	 /* iArg:      */ SQL_DeferFKs},
 	{ /* zName:     */ "foreign_key_list",
 	 /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
 	 /* ePragFlg:  */
 	 PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt,
 	 /* ColNames:  */ 42, 8,
 	 /* iArg:      */ 0},
-	{ /* zName:     */ "full_column_names",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 64, 1,
-	 /* iArg:      */ SQL_FullColNames},
 	{ /* zName:     */ "index_info",
 	 /* ePragTyp:  */ PragTyp_INDEX_INFO,
 	 /* ePragFlg:  */
@@ -198,52 +127,6 @@ static const PragmaName aPragmaName[] = {
 	 PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt,
 	 /* ColNames:  */ 32, 3,
 	 /* iArg:      */ 0},
-#if defined(SQL_DEBUG)
-	{ /* zName:     */ "parser_trace",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 64, 1,
-	 /* iArg:      */ PARSER_TRACE_FLAG},
-#endif
-	{ /* zName:     */ "recursive_triggers",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 66, 1,
-	 /* iArg:      */ SQL_RecTriggers},
-	{ /* zName:     */ "reverse_unordered_selects",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 68, 1,
-	 /* iArg:      */ SQL_ReverseOrder},
-#if defined(SQL_DEBUG)
-	{ /* zName:     */ "select_trace",
-	/* ePragTyp:  */ PragTyp_FLAG,
-	/* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	/* ColNames:  */ 70, 1,
-	/* iArg:      */ SQL_SelectTrace},
-#endif
-	{ /* zName:     */ "short_column_names",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 72, 1,
-	 /* iArg:      */ SQL_ShortColNames},
-	{ /* zName:     */ "sql_compound_select_limit",
-	/* ePragTyp:  */ PragTyp_COMPOUND_SELECT_LIMIT,
-	/* ePragFlg:  */ PragFlg_Result0,
-	/* ColNames:  */ 74, 1,
-	/* iArg:      */ 0},
-	{ /* zName:     */ "sql_default_engine",
-	 /* ePragTyp:  */ PragTyp_DEFAULT_ENGINE,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 76, 1,
-	 /* iArg:      */ 0},
-#if defined(SQL_DEBUG)
-	{ /* zName:     */ "sql_trace",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 78, 1,
-	 /* iArg:      */ SQL_SqlTrace},
-#endif
 	{ /* zName:     */ "stats",
 	 /* ePragTyp:  */ PragTyp_STATS,
 	 /* ePragFlg:  */
@@ -256,38 +139,5 @@ static const PragmaName aPragmaName[] = {
 	 PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt,
 	 /* ColNames:  */ 0, 6,
 	 /* iArg:      */ 0},
-#if defined(SQL_DEBUG)
-	{ /* zName:     */ "vdbe_addoptrace",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 80, 1,
-	 /* iArg:      */ SQL_VdbeAddopTrace},
-	{ /* zName:     */ "vdbe_debug",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 82, 1,
-	 /* iArg:      */
-	 SQL_SqlTrace | SQL_VdbeListing | SQL_VdbeTrace},
-	{ /* zName:     */ "vdbe_eqp",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 84, 1,
-	 /* iArg:      */ SQL_VdbeEQP},
-	{ /* zName:     */ "vdbe_listing",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 86, 1,
-	 /* iArg:      */ SQL_VdbeListing},
-	{ /* zName:     */ "vdbe_trace",
-	 /* ePragTyp:  */ PragTyp_FLAG,
-	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	 /* ColNames:  */ 88, 1,
-	 /* iArg:      */ SQL_VdbeTrace},
-	{ /* zName:     */ "where_trace",
-	/* ePragTyp:  */ PragTyp_FLAG,
-	/* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
-	/* ColNames:  */ 90, 1,
-	/* iArg:      */ SQL_WhereTrace},
-#endif
 };
 /* Number of pragmas: 36 on by default, 47 total. */
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 8f93edd..b81c7af 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1760,7 +1760,6 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 	Vdbe *v = pParse->pVdbe;
 	int i, j;
 	sql *db = pParse->db;
-	int fullNames, shortNames;
 	/* If this is an EXPLAIN, skip this step */
 	if (pParse->explain) {
 		return;
@@ -1778,8 +1777,6 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 	}
 	assert(pTabList != 0);
 	pParse->colNamesSet = 1;
-	fullNames = (pParse->sql_flags & SQL_FullColNames) != 0;
-	shortNames = (pParse->sql_flags & SQL_ShortColNames) != 0;
 	sqlVdbeSetNumCols(v, pEList->nExpr);
 	uint32_t var_count = 0;
 	for (i = 0; i < pEList->nExpr; i++) {
@@ -1806,12 +1803,7 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 			struct space_def *space_def = pTabList->a[j].space->def;
 			assert(iCol >= 0 && iCol < (int)space_def->field_count);
 			zCol = space_def->fields[iCol].name;
-			if (!shortNames && !fullNames) {
-				sqlVdbeSetColName(v, i, COLNAME_NAME,
-						      sqlDbStrDup(db,
-								      pEList->a[i].zSpan),
-						      SQL_DYNAMIC);
-			} else if (fullNames) {
+			if ((pParse->sql_flags & SQL_FullColNames) != 0) {
 				char *zName = 0;
 				zName = sqlMPrintf(db, "%s.%s",
 						       space_def->name, zCol);
@@ -2022,8 +2014,7 @@ sqlResultSetOfSelect(Parse * pParse, Select * pSelect)
 	sql *db = pParse->db;
 
 	uint32_t saved_flags = pParse->sql_flags;
-	pParse->sql_flags |= ~SQL_FullColNames;
-	pParse->sql_flags &= SQL_ShortColNames;
+	pParse->sql_flags = 0;
 	sqlSelectPrep(pParse, pSelect, 0);
 	if (pParse->is_aborted)
 		return NULL;
@@ -4926,8 +4917,7 @@ selectExpander(Walker * pWalker, Select * p)
 		struct ExprList_item *a = pEList->a;
 		ExprList *pNew = 0;
 		uint32_t flags = pParse->sql_flags;
-		int longNames = (flags & SQL_FullColNames) != 0
-		    && (flags & SQL_ShortColNames) == 0;
+		int longNames = (flags & SQL_FullColNames) != 0;
 
 		for (k = 0; k < pEList->nExpr; k++) {
 			pE = a[k].pExpr;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 0bc8bbd..b11f9b4 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3941,8 +3941,6 @@ int
 sql_rem_int(int64_t lhs, bool is_lhs_neg, int64_t rhs, bool is_rhs_neg,
 	    int64_t *res, bool *is_res_neg);
 
-u8 sqlGetBoolean(const char *z, u8);
-
 const void *sqlValueText(sql_value *);
 int sqlValueBytes(sql_value *);
 void sqlValueSetStr(sql_value *, int, const void *,
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 2d7ebf8..1e2bbe1 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -76,7 +76,6 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 	int aiCurOnePass[2];	/* The write cursors opened by WHERE_ONEPASS */
 
 	/* Register Allocations */
-	int regRowCount = 0;	/* A count of rows changed */
 	int regOldPk = 0;
 	int regNewPk = 0;
 	int regNew = 0;		/* Content of the NEW.* table in triggers */
@@ -269,13 +268,6 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 	sqlWhereEnd(pWInfo);
 
 
-	/* Initialize the count of updated rows
-	 */
-	if ((pParse->sql_flags & SQL_CountRows) != 0 &&
-	    pParse->triggered_space == NULL) {
-		regRowCount = ++pParse->nMem;
-		sqlVdbeAddOp2(v, OP_Integer, 0, regRowCount);
-	}
 	labelBreak = sqlVdbeMakeLabel(v);
 	/* Top of the update loop */
 	if (okOnePass) {
@@ -470,13 +462,6 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 			fk_constraint_emit_actions(pParse, space, regOldPk, aXRef);
 	}
 
-	/* Increment the row counter
-	 */
-	if ((pParse->sql_flags & SQL_CountRows) != 0 &&
-	     pParse->triggered_space == NULL) {
-		sqlVdbeAddOp2(v, OP_AddImm, regRowCount, 1);
-	}
-
 	vdbe_code_row_trigger(pParse, trigger, TK_UPDATE, pChanges,
 			      TRIGGER_AFTER, space, regOldPk, on_error,
 			      labelContinue);
@@ -493,17 +478,6 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 	}
 	sqlVdbeResolveLabel(v, labelBreak);
 
-	/* Return the number of rows that were changed. */
-	if ((pParse->sql_flags & SQL_CountRows) != 0 &&
-	    pParse->triggered_space == NULL) {
-		sqlVdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
-		sqlVdbeSetNumCols(v, 1);
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, "rows updated",
-				      SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "INTEGER",
-				  SQL_STATIC);
-	}
-
  update_cleanup:
 	sqlSrcListDelete(db, pTabList);
 	sql_expr_list_delete(db, pChanges);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index f881a73..7c6742e 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1412,31 +1412,7 @@ case OP_ResultRow: {
 	assert(pOp->p1>0);
 	assert(pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1);
 
-	/* If this statement has violated immediate foreign key constraints, do
-	 * not return the number of rows modified. And do not RELEASE the statement
-	 * transaction. It needs to be rolled back.
-	 */
-	if (sqlVdbeCheckFk(p, 0) != 0) {
-		assert((p->sql_flags & SQL_CountRows) != 0);
-		goto abort_due_to_error;
-	}
-
-	/* If the SQL_CountRows flag is set in sql.flags mask, then
-	 * DML statements invoke this opcode to return the number of rows
-	 * modified to the user. This is the only way that a VM that
-	 * opens a statement transaction may invoke this opcode.
-	 *
-	 * In case this is such a statement, close any statement transaction
-	 * opened by this VM before returning control to the user. This is to
-	 * ensure that statement-transactions are always nested, not overlapping.
-	 * If the open statement-transaction is not closed here, then the user
-	 * may step another VM that opens its own statement transaction. This
-	 * may lead to overlapping statement transactions.
-	 *
-	 * The statement transaction is never a top-level transaction.  Hence
-	 * the RELEASE call below can never fail.
-	 */
-	assert(p->iStatement == 0 || (p->sql_flags & SQL_CountRows) != 0);
+	assert(p->iStatement == 0);
 	rc = sqlVdbeCloseStatement(p, SAVEPOINT_RELEASE);
 	assert(rc==0);
 
diff --git a/test/sql-tap/analyze4.test.lua b/test/sql-tap/analyze4.test.lua
index 7d7498f..cc530ce 100755
--- a/test/sql-tap/analyze4.test.lua
+++ b/test/sql-tap/analyze4.test.lua
@@ -70,9 +70,9 @@ test:do_test(
     function()
         return test:execsql([[
             UPDATE t1 SET b='x' WHERE a%2;
--- pragma vdbe_debug=1;
+-- set vdbe_debug=true;
             ANALYZE;
--- pragma vdbe_debug=0;
+-- set vdbe_debug=false;
             SELECT "idx", "stat" FROM "_sql_stat1" WHERE "tbl"='T1' ORDER BY "idx";
         ]])
     end, {
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
index 39e4796..7b36379 100755
--- a/test/sql-tap/autoinc.test.lua
+++ b/test/sql-tap/autoinc.test.lua
@@ -640,7 +640,7 @@ test:do_test(
         -- </autoinc-10.3>
     })
 
-test:catchsql(" pragma recursive_triggers = off ")
+test:catchsql("SET sql_recursive_triggers = false")
 -- Ticket #3928.  Make sure that triggers to not make extra slots in
 -- the sql_SEQUENCE table.
 --
diff --git a/test/sql-tap/colname.test.lua b/test/sql-tap/colname.test.lua
index 253497c..2ac610c 100755
--- a/test/sql-tap/colname.test.lua
+++ b/test/sql-tap/colname.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(63)
+test:plan(62)
 
 --!./tcltestrunner.lua
 -- 2008 July 15
@@ -47,24 +47,14 @@ local function lreplace(arr, pos, len, val)
 end
 
 test:do_test(
-    "colname-1.1",
-    function()
-        return test:execsql "PRAGMA short_column_names"
-    end, {
-        -- <colname-1.1>
-        1
-        -- </colname-1.1>
-    })
-
-test:do_test(
     "colname-1.2",
     function()
-        return test:execsql "PRAGMA full_column_names"
-    end, {
+        return box.space._vsession_settings:get("sql_full_column_names").value
+    end,
         -- <colname-1.2>
-        0
+        false
         -- </colname-1.2>
-    })
+    )
 
 -- Tests for then short=ON and full=any
 --
@@ -177,8 +167,7 @@ test:do_test(
     "colname-3.1",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='OFF';
+            SET sql_full_column_names = false;
             CREATE VIEW v3 AS SELECT tabC.a, txyZ.x, *
               FROM tabc, txyz ORDER BY 1 LIMIT 1;
             CREATE VIEW v4 AS SELECT tabC.a, txyZ.x, tboTh.a, tbotH.x, * 
@@ -199,7 +188,7 @@ test:do_execsql2_test(
         SELECT Tabc.a, tAbc.b, taBc.c FROM tabc
     ]], {
         -- <colname-3.2>
-        "Tabc.a", 1, "tAbc.b", 2, "taBc.c", 3
+        "A", 1, "B", 2, "C", 3
         -- </colname-3.2>
     })
 
@@ -209,7 +198,7 @@ test:do_execsql2_test(
         SELECT +tabc.a, -tabc.b, tabc.c FROM tabc
     ]], {
         -- <colname-3.3>
-        "+tabc.a", 1, "-tabc.b", -2, "tabc.c", 3
+        "+tabc.a", 1, "-tabc.b", -2, "C", 3
         -- </colname-3.3>
     })
 
@@ -229,7 +218,7 @@ test:do_execsql2_test(
         SELECT Tabc.a, Txyz.x, * FROM tabc, txyz;
     ]], {
         -- <colname-3.5>
-        "Tabc.a", 1, "Txyz.x", 4, "A", 1, "B", 2, "C", 3, "X", 4, "Y", 5, "Z", 6
+        "A", 1, "X", 4, "A", 1, "B", 2, "C", 3, "X", 4, "Y", 5, "Z", 6
         -- </colname-3.5>
     })
 
@@ -259,7 +248,7 @@ test:do_execsql2_test(
         SELECT v1.a, * FROM v1 ORDER BY 2;
     ]], {
         -- <colname-3.8>
-        "v1.a",1,"A",1,"X",4,"A_1",1,"B",2,"C",3,"X_1",4,"Y",5,"Z",6
+        "A",1,"A",1,"X",4,"A_1",1,"B",2,"C",3,"X_1",4,"Y",5,"Z",6
         -- </colname-3.8>
     })
 
@@ -298,8 +287,7 @@ test:do_test(
     "colname-4.1",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='ON';
+            SET sql_full_column_names = true;
             CREATE VIEW v5 AS SELECT tabC.a, txyZ.x, *
               FROM tabc, txyz ORDER BY 1 LIMIT 1;
             CREATE VIEW v6 AS SELECT tabC.a, txyZ.x, tboTh.a, tbotH.x, * 
@@ -456,8 +444,7 @@ test:do_test(
         -- instead of reconnect to database
         -- we are just turning settings to default state
         test:execsql([[
-            PRAGMA short_column_names='ON';
-            PRAGMA full_column_names='OFF';
+            SET sql_full_column_names = false;
             ]])
         test:execsql [=[
             CREATE TABLE t6(a INT primary key, "'a'" INT, """a""" INT, "[a]" INT,  "`a`" INT);
diff --git a/test/sql-tap/fkey2.test.lua b/test/sql-tap/fkey2.test.lua
index 264616d..de89790 100755
--- a/test/sql-tap/fkey2.test.lua
+++ b/test/sql-tap/fkey2.test.lua
@@ -450,7 +450,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "fkey2-4.2",
     [[
-        PRAGMA recursive_triggers = off;
+        SET sql_recursive_triggers = false;
         DELETE FROM t1 WHERE node = 1;
         SELECT node FROM t1;
     ]], {
@@ -473,7 +473,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "fkey2-4.4",
     [[
-        PRAGMA recursive_triggers = on;
+        SET sql_recursive_triggers = true;
         DROP TABLE t2;
         DROP TABLE t1;
         CREATE TABLE t1(
diff --git a/test/sql-tap/gh2548-select-compound-limit.test.lua b/test/sql-tap/gh2548-select-compound-limit.test.lua
index f578870..2b9bce0 100755
--- a/test/sql-tap/gh2548-select-compound-limit.test.lua
+++ b/test/sql-tap/gh2548-select-compound-limit.test.lua
@@ -64,7 +64,7 @@ test:do_catchsql_test(
 
 test:do_execsql_test(
     "gh2548-select-compound-limit-3.1", [[
-        pragma sql_compound_select_limit
+        SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_compound_select_limit'
     ]], {
         -- <gh2548-select-compound-limit-3.1>
         30
@@ -73,7 +73,8 @@ test:do_execsql_test(
 
 test:do_execsql_test(
     "gh2548-select-compound-limit-3.2", [[
-        pragma sql_compound_select_limit=31
+        SET sql_compound_select_limit = 31;
+        SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_compound_select_limit'
     ]], {
         -- <gh2548-select-compound-limit-3.2>
         31
@@ -90,7 +91,8 @@ test:do_execsql_test(
 
 test:do_execsql_test(
     "gh2548-select-compound-limit-3.4", [[
-        pragma sql_compound_select_limit=0
+        SET sql_compound_select_limit = 0;
+        SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_compound_select_limit';
     ]], {
         -- <gh2548-select-compound-limit-3.4>
         0
diff --git a/test/sql-tap/lua/sqltester.lua b/test/sql-tap/lua/sqltester.lua
index 0f34114..c50e3fd 100644
--- a/test/sql-tap/lua/sqltester.lua
+++ b/test/sql-tap/lua/sqltester.lua
@@ -413,7 +413,7 @@ box.cfg{
 }
 
 local engine = test_run and test_run:get_cfg('engine') or 'memtx'
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 function test.engine(self)
     return engine
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index b84093e..339c9d7 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -219,7 +219,7 @@ test:do_test(
         local r = test:execsql([[
             CREATE TABLE t1(a TEXT primary KEY);
             INSERT INTO t1 VALUES('hi');
-            PRAGMA full_column_names=on;
+            SET sql_full_column_names = true;
             --SELECT rowid, * FROM t1;
             SELECT * FROM t1;
         ]])
diff --git a/test/sql-tap/pragma.test.lua b/test/sql-tap/pragma.test.lua
index b3821dc..d6f8b54 100755
--- a/test/sql-tap/pragma.test.lua
+++ b/test/sql-tap/pragma.test.lua
@@ -1,7 +1,7 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
 
-test:plan(23)
+test:plan(10)
 
 test:do_catchsql_test(
 	"pragma-1.3",
@@ -19,66 +19,7 @@ test:do_catchsql_test(
 	[[
 		pragma sql_default_engine='creepy';
 	]], {
-	1, "Space engine 'creepy' does not exist"
-})
-
-test:do_catchsql_test(
-	"pragma-2.2",
-	[[
-		pragma sql_default_engine='vinyl';
-	]], {
-	0
-})
-
-test:do_catchsql_test(
-	"pragma-2.3",
-	[[
-		pragma sql_default_engine='memtx';
-	]], {
-	0
-})
-
-test:do_catchsql_test(
-	"pragma-2.4",
-	[[
-		pragma sql_default_engine 'memtx';
-	]], {
-	1, "Syntax error near ''memtx''"
-})
-
-test:do_catchsql_test(
-	"pragma-2.5",
-	[[
-		pragma sql_default_engine 1;
-	]], {
-	1, "Syntax error near '1'"
-})
-
---
--- gh-3832: Some statements do not return column type
---
--- Check that "PRAGMA sql_default_engine" called without arguments
--- returns currently set sql_default_engine.
-test:do_execsql_test(
-	"pragma-3.1",
-	[[
-		pragma sql_default_engine='vinyl';
-		pragma sql_default_engine;
-	]], {
-	-- <pragma-3.1>
-	'vinyl'
-	-- </pragma-3.1>
-})
-
-test:do_execsql_test(
-	"pragma-3.2",
-	[[
-		pragma sql_default_engine='memtx';
-		pragma sql_default_engine;
-	]], {
-	-- <pragma-3.2>
-	'memtx'
-	-- </pragma-3.2>
+	1, "Pragma 'SQL_DEFAULT_ENGINE' does not exist"
 })
 
 --
@@ -187,76 +128,4 @@ test:do_execsql_test(
 	-- </pragma-8.4>
 })
 
----
---- pragma sql_default_engine accepts string values and rejects IDs
----
-test:do_catchsql_test(
-	"pragma-9.1",
-	[[
-		pragma sql_default_engine(the_engine);
-	]], {
-	-- <pragma-9.1>
-	1, "Illegal parameters, string value is expected"
-	-- </pragma-9.1>
-})
-
-test:do_catchsql_test(
-	"pragma-9.2",
-	[[
-		pragma sql_default_engine(THE_ENGINE);
-	]], {
-	-- <pragma-9.2>
-	1, "Illegal parameters, string value is expected"
-	-- </pragma-9.2>
-})
-
-test:do_catchsql_test(
-	"pragma-9.3",
-	[[
-		pragma sql_default_engine("THE_ENGINE");
-	]], {
-	-- <pragma-9.3>
-	1, "Illegal parameters, string value is expected"
-	-- </pragma-9.3>
-})
-
-test:do_catchsql_test(
-	"pragma-9.4",
-	[[
-		pragma sql_default_engine('THE_ENGINE');
-	]], {
-	-- <pragma-9.4>
-	1, "Space engine 'THE_ENGINE' does not exist"
-	-- </pragma-9.4>
-})
-
-test:do_catchsql_test(
-	"pragma-9.5",
-	[[
-		pragma sql_default_engine(memtx);
-	]], {
-	-- <pragma-9.5>
-	1, "Illegal parameters, string value is expected"
-	-- </pragma-9.5>
-})
-
-test:do_catchsql_test(
-	"pragma-9.6",
-	[[
-		pragma sql_default_engine("memtx");
-	]], {
-	-- <pragma-9.6>
-	1, "Illegal parameters, string value is expected"
-	-- </pragma-9.6>
-})
-
-test:do_execsql_test(
-	"pragma-9.7",
-	[[
-		pragma sql_default_engine('memtx');
-	]], {
-	-- <pragma-9.7>
-	-- </pragma-9.7>
-})
-
 test:finish_test()
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index 4bbfbd6..2caa612 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -916,7 +916,7 @@ test:do_catchsql2_test(
 test:do_test(
     "select1-6.1.1",
     function()
-        test:execsql "PRAGMA full_column_names=on"
+        test:execsql "SET sql_full_column_names = true"
         return test:catchsql2 "SELECT f1 FROM test1 ORDER BY f2"
     end, {
         -- <select1-6.1.1>
@@ -940,7 +940,7 @@ test:do_catchsql2_test(
         SELECT * FROM test1 WHERE f1==11
     ]], {
         -- <select1-6.1.3>
-        0, {"F1", 11, "F2", 22}
+        0, {"TEST1.F1", 11, "TEST1.F2", 22}
         -- </select1-6.1.3>
     })
 
@@ -952,11 +952,11 @@ test:do_test(
             msg = test:execsql2 "SELECT DISTINCT * FROM test1 WHERE f1==11"
             end)
         v = v == true and {0} or {1} 
-        test:execsql "PRAGMA full_column_names=off"
+        test:execsql "SET sql_full_column_names = false"
         return table.insert(v,msg) or v
     end, {
         -- <select1-6.1.4>
-        0, {"F1", 11, "F2", 22}
+        0, {"TEST1.F1", 11, "TEST1.F2", 22}
         -- </select1-6.1.4>
     })
 
@@ -1043,13 +1043,13 @@ test:do_catchsql2_test(
 test:do_test(
     "select1-6.5.1",
     function()
-        test:execsql2 "PRAGMA full_column_names=on"
+        test:execsql2 "SET sql_full_column_names = true"
         local msg
         v = pcall( function ()
                 msg = test:execsql2 "SELECT test1.f1+F2 FROM test1 ORDER BY f2"
             end)
         v = v == true and {0} or {1}
-        test:execsql2 "PRAGMA full_column_names=off"
+        test:execsql2 "SET sql_full_column_names = false"
         return table.insert(v,msg) or v
     end, {
         -- <select1-6.5.1>
@@ -1124,15 +1124,14 @@ test:do_test(
     "select1-6.9.3",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='OFF';
+            SET sql_full_column_names = false;
         ]]
         return test:execsql2 [[
             SELECT test1 . f1, test1 . f2 FROM test1 LIMIT 1
         ]]
     end, {
         -- <select1-6.9.3>
-        "test1 . f1", 11, "test1 . f2", 22
+        "F1", 11, "F2", 22
         -- </select1-6.9.3>
     })
 
@@ -1140,8 +1139,7 @@ test:do_test(
     "select1-6.9.4",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='ON';
+            SET sql_full_column_names = true;
         ]]
         return test:execsql2 [[
             SELECT test1 . f1, test1 . f2 FROM test1 LIMIT 1
@@ -1156,8 +1154,7 @@ test:do_test(
     "select1-6.9.5",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='ON';
+            SET sql_full_column_names = true;
         ]]
         return test:execsql2 [[
             SELECT 123.45;
@@ -1238,8 +1235,7 @@ test:do_test(
     "select1-6.9.11",
     function()
         test:execsql [[
-            PRAGMA short_column_names='ON';
-            PRAGMA full_column_names='ON';
+            SET sql_full_column_names = true;
         ]]
         return test:execsql2 [[
             SELECT a.f1, b.f2 FROM test1 a, test1 b LIMIT 1
@@ -1264,8 +1260,7 @@ test:do_test(
     "select1-6.9.13",
     function()
         test:execsql [[
-            PRAGMA short_column_names='ON';
-            PRAGMA full_column_names='OFF';
+            SET sql_full_column_names = false;
         ]]
         return test:execsql2 [[
             SELECT a.f1, b.f1 FROM test1 a, test1 b LIMIT 1
@@ -1290,8 +1285,7 @@ test:do_test(
     "select1-6.9.15",
     function()
         test:execsql [[
-            PRAGMA short_column_names='OFF';
-            PRAGMA full_column_names='ON';
+            SET sql_full_column_names = true;
         ]]
         return test:execsql2 [[
             SELECT a.f1, b.f1 FROM test1 a, test1 b LIMIT 1
@@ -1313,8 +1307,7 @@ test:do_execsql2_test(
     })
 
 test:execsql [[
-    PRAGMA short_column_names='ON';
-    PRAGMA full_column_names='OFF';
+    SET sql_full_column_names = false;
 ]]
 test:do_catchsql2_test(
         "select1-6.10",
diff --git a/test/sql-tap/tkt3731.test.lua b/test/sql-tap/tkt3731.test.lua
index 454cf67..57e7f3f 100755
--- a/test/sql-tap/tkt3731.test.lua
+++ b/test/sql-tap/tkt3731.test.lua
@@ -22,7 +22,7 @@ test:plan(3)
 -- The tests in this file were written before sql supported recursive
 -- trigger invocation, and some tests depend on that to pass. So disable
 -- recursive triggers for this file.
-test:catchsql " pragma recursive_triggers = off "
+test:catchsql("SET sql_recursive_triggers = false")
 test:do_execsql_test(
     "tkt3731-1.1",
     [[
diff --git a/test/sql-tap/trigger2.test.lua b/test/sql-tap/trigger2.test.lua
index 6e60050..dbe54db 100755
--- a/test/sql-tap/trigger2.test.lua
+++ b/test/sql-tap/trigger2.test.lua
@@ -58,7 +58,7 @@ test:plan(26)
 -- The tests in this file were written before sql supported recursive
 -- trigger invocation, and some tests depend on that to pass. So disable
 -- recursive triggers for this file.
-test:catchsql " pragma recursive_triggers = off "
+test:catchsql("SET sql_recursive_triggers = false")
 -- 1.
 ii = 0
 tbl_definitions = { "CREATE TABLE tbl (id INT PRIMARY KEY AUTOINCREMENT, a INTEGER UNIQUE, b INT );",
diff --git a/test/sql-tap/triggerC.test.lua b/test/sql-tap/triggerC.test.lua
index cf7dd7b..f9b7034 100755
--- a/test/sql-tap/triggerC.test.lua
+++ b/test/sql-tap/triggerC.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(48)
+test:plan(45)
 
 --!./tcltestrunner.lua
 -- 2009 August 24
@@ -36,12 +36,9 @@ testprefix = "triggerC"
 --               REPLACE conflict resolution. And that they are not fired
 --               if recursive triggers are not enabled.
 --
--- triggerC-6.*: Test that the recursive_triggers pragma returns correct
---               results when invoked without an argument.
---
 -- Enable recursive triggers for this file.
 --
-test:execsql " PRAGMA recursive_triggers = on "
+test:execsql("SET sql_recursive_triggers = true;")
 ---------------------------------------------------------------------------
 -- This block of tests, triggerC-1.*, are not aimed at any specific
 -- property of the triggers sub-system. They were created to debug
@@ -504,7 +501,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "triggerC-5.3.0",
     [[
-        PRAGMA recursive_triggers = off
+        SET sql_recursive_triggers = false
     ]], {
         -- <triggerC-5.3.0>
 
@@ -534,49 +531,13 @@ test:do_execsql_test(
 test:do_execsql_test(
     "triggerC-5.3.8",
     [[
-        PRAGMA recursive_triggers = on
+        SET sql_recursive_triggers = true
     ]], {
         -- <triggerC-5.3.8>
 
         -- </triggerC-5.3.8>
     })
 
----------------------------------------------------------------------------
--- This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers"
--- statements return the current value of the recursive triggers flag.
---
-test:do_execsql_test(
-    "triggerC-6.1",
-    [[
-        PRAGMA recursive_triggers
-    ]], {
-        -- <triggerC-6.1>
-        1
-        -- </triggerC-6.1>
-    })
-
-test:do_execsql_test(
-    "triggerC-6.2",
-    [[
-        PRAGMA recursive_triggers = off;
-        PRAGMA recursive_triggers;
-    ]], {
-        -- <triggerC-6.2>
-        0
-        -- </triggerC-6.2>
-    })
-
-test:do_execsql_test(
-    "triggerC-6.3",
-    [[
-        PRAGMA recursive_triggers = on;
-        PRAGMA recursive_triggers;
-    ]], {
-        -- <triggerC-6.3>
-        1
-        -- </triggerC-6.3>
-    })
-
 -- MUST_WORK_TEST
 -- #-------------------------------------------------------------------------
 -- # Test some of the "undefined behaviour" associated with triggers. The
@@ -890,7 +851,7 @@ test:execsql(
 test:do_execsql_test(
     "triggerC-13.1",
     [[
-        PRAGMA recursive_triggers = 'ON';
+        SET sql_recursive_triggers = true;
         CREATE TABLE t12(id INTEGER PRIMARY KEY, a INT, b INT);
         INSERT INTO t12 VALUES(1, 1, 2);
         CREATE TRIGGER tr12 AFTER UPDATE ON t12 FOR EACH ROW BEGIN
@@ -974,7 +935,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "triggerC-15.1.1",
     [[
-        PRAGMA recursive_triggers = 1;
+        SET sql_recursive_triggers = true;
         CREATE TABLE node(
             id int not null primary key,
             pid int not null default 0,
diff --git a/test/sql-tap/update.test.lua b/test/sql-tap/update.test.lua
index 07e4e43..9efc0cf 100755
--- a/test/sql-tap/update.test.lua
+++ b/test/sql-tap/update.test.lua
@@ -124,13 +124,12 @@ test:do_execsql_test("update-3.6", [[
 })
 
 test:do_test("update-3.7", function()
-  test:execsql "PRAGMA count_changes=on"
-  return test:execsql "UPDATE test1 SET f2=f2/3 WHERE f1<=5"
-end, {
+  return box.execute("UPDATE test1 SET f2=f2/3 WHERE f1<=5").row_count
+end,
   -- <update-3.7>
   5
   -- </update-3.7>
-})
+)
 
 test:do_execsql_test("update-3.8", [[
   SELECT f1,f2 FROM test1 ORDER BY f1
@@ -144,7 +143,6 @@ test:do_execsql_test("update-3.9", [[
   UPDATE test1 SET f2=f2/3 WHERE f1>5
 ]], {
   -- <update-3.9>
-  5
   -- </update-3.9>
 })
 
@@ -162,7 +160,6 @@ test:do_execsql_test("update-3.11", [[
   UPDATE test1 SET F2=f1, F1=f2
 ]], {
   -- <update-3.11>
-  10
   -- </update-3.11>
 })
 
@@ -175,7 +172,6 @@ test:do_execsql_test("update-3.12", [[
 })
 
 test:do_test("update-3.13", function()
-  test:execsql "PRAGMA count_changes=off"
   return test:execsql "UPDATE test1 SET F2=f1, F1=f2"
 end, {
   -- <update-3.13>
@@ -255,16 +251,13 @@ end, {
 })
 
 test:do_execsql_test("update-4.6", [[
-  PRAGMA count_changes=on;
   UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128;
 ]], {
   -- <update-4.6>
-  2
   -- </update-4.6>
 })
 
 test:do_execsql_test("update-4.7", [[
-  PRAGMA count_changes=off;
   SELECT f1,f2 FROM test1 ORDER BY f1,f2
 ]], {
   -- <update-4.7>
@@ -392,16 +385,13 @@ test:do_execsql_test("update-5.5.5", [[
 })
 
 test:do_execsql_test("update-5.6", [[
-  PRAGMA count_changes=on;
   UPDATE test1 SET f1=f1-1 WHERE f1<=100 and f2==128;
 ]], {
   -- <update-5.6>
-  2
   -- </update-5.6>
 })
 
 test:do_execsql_test("update-5.6.1", [[
-  PRAGMA count_changes=off;
   SELECT f1,f2 FROM test1 ORDER BY f1,f2
 ]], {
   -- <update-5.6.1>
@@ -443,7 +433,6 @@ test:do_execsql_test("update-5.6.5", [[
 
 -- Repeat the previous sequence of tests with a different index.
 --
---test:execsql "PRAGMA synchronous='FULL'"
 test:do_test("update-6.0", function()
   test:execsql "DROP INDEX idx1 ON test1"
   test:execsql "CREATE INDEX idx1 ON test1(f2)"
diff --git a/test/sql-tap/whereA.test.lua b/test/sql-tap/whereA.test.lua
index b82575f..21675d5 100755
--- a/test/sql-tap/whereA.test.lua
+++ b/test/sql-tap/whereA.test.lua
@@ -14,7 +14,7 @@ test:plan(17)
 --
 -------------------------------------------------------------------------
 -- This file implements regression tests for sql library. The
--- focus of this file is testing the reverse_select_order pragma.
+-- focus of this file is testing the reverse_select_order option.
 --
 -- $Id: whereA.test,v 1.3 2009/06/10 19:33:29 drh Exp $
 -- ["set","testdir",[["file","dirname",["argv0"]]]]
@@ -39,7 +39,7 @@ test:do_test(
     "whereA-1.2",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=1;
+            SET sql_reverse_unordered_selects = true;
             SELECT * FROM t1;
         ]]
     end, {
@@ -55,7 +55,7 @@ test:do_test(
         --db close
         --sql db test.db
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=1;
+            SET sql_reverse_unordered_selects = true;
             SELECT * FROM t1;
         ]]
     end, {
@@ -68,7 +68,7 @@ test:do_test(
 --   db close
 --   sql db test.db
 --   db eval {
---     PRAGMA reverse_unordered_selects=1;
+--     SET sql_reverse_unordered_selects = true;
 --     SELECT * FROM t1 ORDER BY rowid;
 --   }
 -- } {1 2 3 2 hello world 3 4.53 {}}
@@ -76,11 +76,11 @@ test:do_test(
     "whereA-1.6",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects;
+            SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_reverse_unordered_selects';
         ]]
     end, {
         -- <whereA-1.6>
-        1
+        true
         -- </whereA-1.6>
     })
 
@@ -108,7 +108,7 @@ test:do_test(
     "whereA-2.1",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=0;
+            SET sql_reverse_unordered_selects = false;
             SELECT * FROM t1 WHERE a>0;
         ]]
     end, {
@@ -121,7 +121,7 @@ test:do_test(
     "whereA-2.2",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=1;
+            SET sql_reverse_unordered_selects = true;
             SELECT * FROM t1 WHERE a>0;
         ]]
     end, {
@@ -132,7 +132,7 @@ test:do_test(
 
 -- do_test whereA-2.3 {
 --   db eval {
---     PRAGMA reverse_unordered_selects=1;
+--     SET sql_reverse_unordered_selects = true;
 --     SELECT * FROM t1 WHERE a>0 ORDER BY rowid;
 --   }
 -- } {1 2 3 2 hello world 3 4.53 {}}
@@ -140,7 +140,7 @@ test:do_test(
     "whe:reA-3.1",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=0;
+            SET sql_reverse_unordered_selects = false;
             SELECT * FROM t1 WHERE b>0;
         ]]
     end, {
@@ -153,7 +153,7 @@ test:do_test(
     "whereA-3.2",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=1;
+            SET sql_reverse_unordered_selects = true;
             SELECT * FROM t1 WHERE b>0;
         ]]
     end, {
@@ -166,7 +166,7 @@ test:do_test(
     "whereA-3.3",
     function()
         return test:execsql [[
-            PRAGMA reverse_unordered_selects=1;
+            SET sql_reverse_unordered_selects = true;
             SELECT * FROM t1 WHERE b>0 ORDER BY b;
         ]]
     end, {
diff --git a/test/sql/check-clear-ephemeral.result b/test/sql/check-clear-ephemeral.result
index 7d0be5f..3b12457 100644
--- a/test/sql/check-clear-ephemeral.result
+++ b/test/sql/check-clear-ephemeral.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -15,7 +15,7 @@ box.execute("CREATE TABLE t1(a INT,b INT,c INT,PRIMARY KEY(b,c));")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries
 box.execute("WITH RECURSIVE cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000) INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;")
 ---
diff --git a/test/sql/check-clear-ephemeral.test.lua b/test/sql/check-clear-ephemeral.test.lua
index 929a6c9..2ecf11c 100644
--- a/test/sql/check-clear-ephemeral.test.lua
+++ b/test/sql/check-clear-ephemeral.test.lua
@@ -1,13 +1,13 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 -- box.cfg()
 
 -- create space
 box.execute("CREATE TABLE t1(a INT,b INT,c INT,PRIMARY KEY(b,c));")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries
 box.execute("WITH RECURSIVE cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000) INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;")
diff --git a/test/sql/checks.result b/test/sql/checks.result
index a952b2b..f9a6772 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -11,7 +11,7 @@ test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -736,7 +736,7 @@ physics_ck:drop()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index 4d33823..ffcbd26 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -2,7 +2,7 @@ env = require('test_run')
 test_run = env.new()
 test_run:cmd("push filter ".."'\\.lua.*:[0-9]+: ' to '.lua...\"]:<line>: '")
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 --
 -- gh-3272: Move SQL CHECK into server
@@ -240,7 +240,7 @@ physics_ck:drop()
 -- :enable configurator.
 --
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE test(a INT PRIMARY KEY);");
 box.execute('ALTER TABLE test ADD CONSTRAINT CK CHECK(a < 5);')
 box.space.TEST:insert({10})
diff --git a/test/sql/clear.result b/test/sql/clear.result
index afa6520..baeb15e 100644
--- a/test/sql/clear.result
+++ b/test/sql/clear.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -19,7 +19,7 @@ box.execute("CREATE UNIQUE INDEX zoobar2 ON zoobar(c1, c4)")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON;")
+-- box.execute("SET vdbe_debug=ON;")
 -- Seed entry
 for i=1, 100 do box.execute(string.format("INSERT INTO zoobar VALUES (%d, %d, 'c3', 444)", i+i, i)) end
 ---
diff --git a/test/sql/clear.test.lua b/test/sql/clear.test.lua
index 4c58767..8d5e8fb 100644
--- a/test/sql/clear.test.lua
+++ b/test/sql/clear.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -9,7 +9,7 @@ box.execute("CREATE TABLE zoobar (c1 INT, c2 INT PRIMARY KEY, c3 TEXT, c4 INT)")
 box.execute("CREATE UNIQUE INDEX zoobar2 ON zoobar(c1, c4)")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON;")
+-- box.execute("SET vdbe_debug=ON;")
 
 -- Seed entry
 for i=1, 100 do box.execute(string.format("INSERT INTO zoobar VALUES (%d, %d, 'c3', 444)", i+i, i)) end
diff --git a/test/sql/collation.result b/test/sql/collation.result
index 11962ef..dc11d28 100644
--- a/test/sql/collation.result
+++ b/test/sql/collation.result
@@ -7,7 +7,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/collation.test.lua b/test/sql/collation.test.lua
index 1be28b3..5e33562 100644
--- a/test/sql/collation.test.lua
+++ b/test/sql/collation.test.lua
@@ -1,7 +1,7 @@
 remote = require('net.box')
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- gh-3010: COLLATE after LIMIT should throw an error
 
diff --git a/test/sql/ddl.result b/test/sql/ddl.result
index 28acf37..af833d0 100644
--- a/test/sql/ddl.result
+++ b/test/sql/ddl.result
@@ -8,7 +8,7 @@ json = require('json')
 engine = test_run:get_cfg('engine')
  | ---
  | ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
  | ---
  | - row_count: 0
  | ...
diff --git a/test/sql/ddl.test.lua b/test/sql/ddl.test.lua
index 6067b61..b6f0c81 100644
--- a/test/sql/ddl.test.lua
+++ b/test/sql/ddl.test.lua
@@ -1,7 +1,7 @@
 test_run = require('test_run').new()
 json = require('json')
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 --
 -- gh-4086: SQL transactional DDL.
diff --git a/test/sql/delete-multiple-idx.result b/test/sql/delete-multiple-idx.result
index ca58feb..3d58daf 100644
--- a/test/sql/delete-multiple-idx.result
+++ b/test/sql/delete-multiple-idx.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -19,7 +19,7 @@ box.execute("CREATE UNIQUE INDEX t3y ON t3(y);");
 - row_count: 1
 ...
 -- Debug.
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries.
 box.execute("INSERT INTO t3 VALUES (1, 1, NULL);");
 ---
diff --git a/test/sql/delete-multiple-idx.test.lua b/test/sql/delete-multiple-idx.test.lua
index a81cccc..2715d2f 100644
--- a/test/sql/delete-multiple-idx.test.lua
+++ b/test/sql/delete-multiple-idx.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -9,7 +9,7 @@ box.execute("CREATE TABLE t3(id INT primary key,x INT,y INT);");
 box.execute("CREATE UNIQUE INDEX t3y ON t3(y);");
 
 -- Debug.
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries.
 box.execute("INSERT INTO t3 VALUES (1, 1, NULL);");
diff --git a/test/sql/delete.result b/test/sql/delete.result
index e27c79d..9aa074f 100644
--- a/test/sql/delete.result
+++ b/test/sql/delete.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -15,7 +15,7 @@ box.execute("CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a, b));");
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries
 box.execute("INSERT INTO t1 VALUES(1, 2);");
 ---
diff --git a/test/sql/delete.test.lua b/test/sql/delete.test.lua
index 75448d4..ff1e622 100644
--- a/test/sql/delete.test.lua
+++ b/test/sql/delete.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -8,7 +8,7 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a, b));");
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries
 box.execute("INSERT INTO t1 VALUES(1, 2);");
diff --git a/test/sql/drop-index.result b/test/sql/drop-index.result
index e8eb642..551e56f 100644
--- a/test/sql/drop-index.result
+++ b/test/sql/drop-index.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -23,7 +23,7 @@ box.execute("CREATE        INDEX zoobar3 ON zzoobar(c3)")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
 -- Dummy entry
 box.execute("INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
 ---
diff --git a/test/sql/drop-index.test.lua b/test/sql/drop-index.test.lua
index 8cd86ee..fd420b6 100644
--- a/test/sql/drop-index.test.lua
+++ b/test/sql/drop-index.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -11,7 +11,7 @@ box.execute("CREATE UNIQUE INDEX zoobar2 ON zzoobar(c1, c4)")
 box.execute("CREATE        INDEX zoobar3 ON zzoobar(c3)")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
 
 -- Dummy entry
 box.execute("INSERT INTO zzoobar VALUES (111, 222, 'c3', 444)")
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result
index 7bc073d..ef4c5cf 100644
--- a/test/sql/drop-table.result
+++ b/test/sql/drop-table.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -15,7 +15,7 @@ box.execute("CREATE TABLE zzzoobar (c1 INT, c2 INT PRIMARY KEY, c3 TEXT, c4 INT)
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 box.execute("CREATE INDEX zb ON zzzoobar(c1, c3)")
 ---
 - row_count: 1
diff --git a/test/sql/drop-table.test.lua b/test/sql/drop-table.test.lua
index a310db1..f0b1645 100644
--- a/test/sql/drop-table.test.lua
+++ b/test/sql/drop-table.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -8,7 +8,7 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE zzzoobar (c1 INT, c2 INT PRIMARY KEY, c3 TEXT, c4 INT)")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 
 box.execute("CREATE INDEX zb ON zzzoobar(c1, c3)")
 
diff --git a/test/sql/engine.result b/test/sql/engine.result
index 3ee93ad..b392566 100644
--- a/test/sql/engine.result
+++ b/test/sql/engine.result
@@ -4,7 +4,7 @@ env = require('test_run')
 test_run = env.new()
 ---
 ...
-box.execute("pragma sql_default_engine='vinyl'")
+box.execute("set sql_default_engine='vinyl'")
 ---
 - row_count: 0
 ...
@@ -16,7 +16,7 @@ box.execute("CREATE TABLE t2_vinyl(a INT PRIMARY KEY, b INT, c INT);")
 ---
 - row_count: 1
 ...
-box.execute("pragma sql_default_engine='memtx'")
+box.execute("set sql_default_engine='memtx'")
 ---
 - row_count: 0
 ...
@@ -66,7 +66,7 @@ assert(box.space.T1_MEMTX.engine == 'memtx')
 ---
 - true
 ...
-box.execute("pragma sql_default_engine='vinyl'")
+box.execute("set sql_default_engine='vinyl'")
 ---
 - row_count: 0
 ...
diff --git a/test/sql/engine.test.lua b/test/sql/engine.test.lua
index 112d3d3..bc16cc0 100644
--- a/test/sql/engine.test.lua
+++ b/test/sql/engine.test.lua
@@ -1,11 +1,11 @@
 env = require('test_run')
 test_run = env.new()
 
-box.execute("pragma sql_default_engine='vinyl'")
+box.execute("set sql_default_engine='vinyl'")
 box.execute("CREATE TABLE t1_vinyl(a INT PRIMARY KEY, b INT, c INT);")
 box.execute("CREATE TABLE t2_vinyl(a INT PRIMARY KEY, b INT, c INT);")
 
-box.execute("pragma sql_default_engine='memtx'")
+box.execute("set sql_default_engine='memtx'")
 box.execute("CREATE TABLE t3_memtx(a INT PRIMARY KEY, b INT, c INT);")
 
 assert(box.space.T1_VINYL.engine == 'vinyl')
@@ -22,7 +22,7 @@ box.execute("CREATE TABLE t1_vinyl (id INT PRIMARY KEY) WITH ENGINE = 'vinyl'")
 assert(box.space.T1_VINYL.engine == 'vinyl')
 box.execute("CREATE TABLE t1_memtx (id INT PRIMARY KEY) WITH ENGINE = 'memtx'")
 assert(box.space.T1_MEMTX.engine == 'memtx')
-box.execute("pragma sql_default_engine='vinyl'")
+box.execute("set sql_default_engine='vinyl'")
 box.execute("CREATE TABLE t2_vinyl (id INT PRIMARY KEY) WITH ENGINE = 'vinyl'")
 assert(box.space.T2_VINYL.engine == 'vinyl')
 box.execute("CREATE TABLE t2_memtx (id INT PRIMARY KEY) WITH ENGINE = 'memtx'")
diff --git a/test/sql/errinj.result b/test/sql/errinj.result
index 7ab522f..c94afae 100644
--- a/test/sql/errinj.result
+++ b/test/sql/errinj.result
@@ -7,7 +7,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/errinj.test.lua b/test/sql/errinj.test.lua
index b978767..d21629d 100644
--- a/test/sql/errinj.test.lua
+++ b/test/sql/errinj.test.lua
@@ -1,7 +1,7 @@
 remote = require('net.box')
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 errinj = box.error.injection
 fiber = require('fiber')
 
diff --git a/test/sql/func-recreate.result b/test/sql/func-recreate.result
index a0a67a1..6083d19 100644
--- a/test/sql/func-recreate.result
+++ b/test/sql/func-recreate.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/func-recreate.test.lua b/test/sql/func-recreate.test.lua
index 0b32ea9..a819587 100644
--- a/test/sql/func-recreate.test.lua
+++ b/test/sql/func-recreate.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Check errors during function create process
 fiber = require('fiber')
diff --git a/test/sql/gh-2362-select-access-rights.result b/test/sql/gh-2362-select-access-rights.result
index b15b0da..f929914 100644
--- a/test/sql/gh-2362-select-access-rights.result
+++ b/test/sql/gh-2362-select-access-rights.result
@@ -7,7 +7,7 @@ engine = test_run:get_cfg('engine')
 nb = require('net.box')
 ---
 ...
-box.execute("PRAGMA sql_default_engine='"..engine.."'")
+box.execute("SET sql_default_engine='"..engine.."'")
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-2362-select-access-rights.test.lua b/test/sql/gh-2362-select-access-rights.test.lua
index f2b66b6..5666b68 100644
--- a/test/sql/gh-2362-select-access-rights.test.lua
+++ b/test/sql/gh-2362-select-access-rights.test.lua
@@ -2,7 +2,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 nb = require('net.box')
 
-box.execute("PRAGMA sql_default_engine='"..engine.."'")
+box.execute("SET sql_default_engine='"..engine.."'")
 box.execute("CREATE TABLE t1 (s1 INT PRIMARY KEY, s2 INT UNIQUE);")
 box.execute("CREATE TABLE t2 (s1 INT PRIMARY KEY);")
 box.execute("INSERT INTO t1 VALUES (1, 1);")
diff --git a/test/sql/gh-2929-primary-key.result b/test/sql/gh-2929-primary-key.result
index 021d037..35daaf2 100644
--- a/test/sql/gh-2929-primary-key.result
+++ b/test/sql/gh-2929-primary-key.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-2929-primary-key.test.lua b/test/sql/gh-2929-primary-key.test.lua
index 9cc6cd5..f419668 100644
--- a/test/sql/gh-2929-primary-key.test.lua
+++ b/test/sql/gh-2929-primary-key.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- All tables in SQL are now WITHOUT ROW ID, so if user
 -- tries to create table without a primary key, an appropriate error message
diff --git a/test/sql/gh-2981-check-autoinc.result b/test/sql/gh-2981-check-autoinc.result
index d2938cd..11fed1e 100644
--- a/test/sql/gh-2981-check-autoinc.result
+++ b/test/sql/gh-2981-check-autoinc.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-2981-check-autoinc.test.lua b/test/sql/gh-2981-check-autoinc.test.lua
index 0eb8f73..afbefa0 100644
--- a/test/sql/gh-2981-check-autoinc.test.lua
+++ b/test/sql/gh-2981-check-autoinc.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 box.cfg{}
 
diff --git a/test/sql/gh-3199-no-mem-leaks.result b/test/sql/gh-3199-no-mem-leaks.result
index e7ba1d2..00211ce 100644
--- a/test/sql/gh-3199-no-mem-leaks.result
+++ b/test/sql/gh-3199-no-mem-leaks.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-3199-no-mem-leaks.test.lua b/test/sql/gh-3199-no-mem-leaks.test.lua
index 54a6ce5..f63bedf 100644
--- a/test/sql/gh-3199-no-mem-leaks.test.lua
+++ b/test/sql/gh-3199-no-mem-leaks.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 fiber = require('fiber')
 
 -- This test checks that no leaks of region memory happens during
diff --git a/test/sql/gh-3613-idx-alter-update-2.result b/test/sql/gh-3613-idx-alter-update-2.result
index ff63eb2..270f961 100644
--- a/test/sql/gh-3613-idx-alter-update-2.result
+++ b/test/sql/gh-3613-idx-alter-update-2.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-3613-idx-alter-update-2.test.lua b/test/sql/gh-3613-idx-alter-update-2.test.lua
index ff5b651..33730ff 100644
--- a/test/sql/gh-3613-idx-alter-update-2.test.lua
+++ b/test/sql/gh-3613-idx-alter-update-2.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 box.execute('CREATE TABLE t (s1 INT PRIMARY KEY)')
 box.execute('CREATE INDEX i ON t (s1)')
diff --git a/test/sql/gh-3613-idx-alter-update.result b/test/sql/gh-3613-idx-alter-update.result
index ba323a6..34b4a1f 100644
--- a/test/sql/gh-3613-idx-alter-update.result
+++ b/test/sql/gh-3613-idx-alter-update.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-3613-idx-alter-update.test.lua b/test/sql/gh-3613-idx-alter-update.test.lua
index 3027182..389a99d 100644
--- a/test/sql/gh-3613-idx-alter-update.test.lua
+++ b/test/sql/gh-3613-idx-alter-update.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 box.execute('CREATE TABLE t (s1 INT PRIMARY KEY)')
 box.execute('CREATE INDEX i ON t (s1)')
diff --git a/test/sql/gh-3888-values-blob-assert.result b/test/sql/gh-3888-values-blob-assert.result
index 4b8e7ed..5691e70 100644
--- a/test/sql/gh-3888-values-blob-assert.result
+++ b/test/sql/gh-3888-values-blob-assert.result
@@ -10,7 +10,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh-3888-values-blob-assert.test.lua b/test/sql/gh-3888-values-blob-assert.test.lua
index 0b7c385..9680aa5 100644
--- a/test/sql/gh-3888-values-blob-assert.test.lua
+++ b/test/sql/gh-3888-values-blob-assert.test.lua
@@ -6,7 +6,7 @@
 --
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- check 'VALUES' against typedef keywords (should fail)
 box.execute('VALUES(scalar)')
diff --git a/test/sql/gh2141-delete-trigger-drop-table.result b/test/sql/gh2141-delete-trigger-drop-table.result
index 1d373f5..a218328 100644
--- a/test/sql/gh2141-delete-trigger-drop-table.result
+++ b/test/sql/gh2141-delete-trigger-drop-table.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh2141-delete-trigger-drop-table.test.lua b/test/sql/gh2141-delete-trigger-drop-table.test.lua
index 4d21fd7..2d5b987 100644
--- a/test/sql/gh2141-delete-trigger-drop-table.test.lua
+++ b/test/sql/gh2141-delete-trigger-drop-table.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- create space
 box.execute("CREATE TABLE t(id INT PRIMARY KEY)")
diff --git a/test/sql/gh2251-multiple-update.result b/test/sql/gh2251-multiple-update.result
index 42ebf7f..7a21cea 100644
--- a/test/sql/gh2251-multiple-update.result
+++ b/test/sql/gh2251-multiple-update.result
@@ -5,7 +5,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh2251-multiple-update.test.lua b/test/sql/gh2251-multiple-update.test.lua
index 4d55096..eeff047 100644
--- a/test/sql/gh2251-multiple-update.test.lua
+++ b/test/sql/gh2251-multiple-update.test.lua
@@ -1,7 +1,7 @@
 -- Regression test for #2251
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
diff --git a/test/sql/gh2483-remote-persistency-check.result b/test/sql/gh2483-remote-persistency-check.result
index d69fcbd..a7dd7d2 100644
--- a/test/sql/gh2483-remote-persistency-check.result
+++ b/test/sql/gh2483-remote-persistency-check.result
@@ -8,7 +8,7 @@ test_run = env.new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh2483-remote-persistency-check.test.lua b/test/sql/gh2483-remote-persistency-check.test.lua
index 7db1602..bf2fc6b 100644
--- a/test/sql/gh2483-remote-persistency-check.test.lua
+++ b/test/sql/gh2483-remote-persistency-check.test.lua
@@ -2,7 +2,7 @@
 env = require('test_run')
 test_run = env.new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 box.schema.user.grant('guest', 'read,write,execute', 'universe')
 
diff --git a/test/sql/gh2808-inline-unique-persistency-check.result b/test/sql/gh2808-inline-unique-persistency-check.result
index a277b3f..db03feb 100644
--- a/test/sql/gh2808-inline-unique-persistency-check.result
+++ b/test/sql/gh2808-inline-unique-persistency-check.result
@@ -8,7 +8,7 @@ test_run = env.new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/gh2808-inline-unique-persistency-check.test.lua b/test/sql/gh2808-inline-unique-persistency-check.test.lua
index 26b646a..ef38ae3 100644
--- a/test/sql/gh2808-inline-unique-persistency-check.test.lua
+++ b/test/sql/gh2808-inline-unique-persistency-check.test.lua
@@ -2,7 +2,7 @@
 env = require('test_run')
 test_run = env.new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Create a table and insert a datum
 box.execute([[CREATE TABLE t1(a INT PRIMARY KEY, b INT, UNIQUE(b));]])
diff --git a/test/sql/icu-upper-lower.result b/test/sql/icu-upper-lower.result
index 8ff7528..cb687a1 100644
--- a/test/sql/icu-upper-lower.result
+++ b/test/sql/icu-upper-lower.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/icu-upper-lower.test.lua b/test/sql/icu-upper-lower.test.lua
index 00e9699..bbd4f00 100644
--- a/test/sql/icu-upper-lower.test.lua
+++ b/test/sql/icu-upper-lower.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 test_run:cmd("setopt delimiter ';'")
 
diff --git a/test/sql/insert-unique.result b/test/sql/insert-unique.result
index 1cf44c9..ec57681 100644
--- a/test/sql/insert-unique.result
+++ b/test/sql/insert-unique.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -19,7 +19,7 @@ box.execute("CREATE UNIQUE INDEX zoobar2 ON zoobar(c1, c4)")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entry
 box.execute("INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 ---
diff --git a/test/sql/insert-unique.test.lua b/test/sql/insert-unique.test.lua
index 026bc9d..243333e 100644
--- a/test/sql/insert-unique.test.lua
+++ b/test/sql/insert-unique.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -9,7 +9,7 @@ box.execute("CREATE TABLE zoobar (c1 INT, c2 INT PRIMARY KEY, c3 TEXT, c4 INT)")
 box.execute("CREATE UNIQUE INDEX zoobar2 ON zoobar(c1, c4)")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entry
 box.execute("INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
diff --git a/test/sql/integer-overflow.result b/test/sql/integer-overflow.result
index 223ba02..c886f8c 100644
--- a/test/sql/integer-overflow.result
+++ b/test/sql/integer-overflow.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/integer-overflow.test.lua b/test/sql/integer-overflow.test.lua
index 1b3e8ce..57929e2 100644
--- a/test/sql/integer-overflow.test.lua
+++ b/test/sql/integer-overflow.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- gh-3735: make sure that integer overflows errors are
 -- handled during VDBE execution.
diff --git a/test/sql/iproto.result b/test/sql/iproto.result
index 1e5c30a..bac1334 100644
--- a/test/sql/iproto.result
+++ b/test/sql/iproto.result
@@ -7,7 +7,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -732,37 +732,6 @@ res.metadata
   - name: detail
     type: TEXT
 ...
--- When pragma count_changes is on, statements INSERT, REPLACE and
--- UPDATE returns number of changed columns. Make sure that this
--- result has a column type.
-cn:execute("PRAGMA count_changes = 1;")
----
-- row_count: 0
-...
-cn:execute("INSERT INTO t1 VALUES (1), (2), (3);")
----
-- metadata:
-  - name: rows inserted
-    type: INTEGER
-  rows:
-  - [3]
-...
-cn:execute("REPLACE INTO t1 VALUES (2), (3), (4), (5);")
----
-- metadata:
-  - name: rows replaced
-    type: INTEGER
-  rows:
-  - [4]
-...
-cn:execute("UPDATE t1 SET id = id + 100 WHERE id > 10;")
----
-- metadata:
-  - name: rows updated
-    type: INTEGER
-  rows:
-  - [0]
-...
 -- Make sure that built-in functions have a right returning type.
 --
 cn:execute("SELECT zeroblob(1);")
diff --git a/test/sql/iproto.test.lua b/test/sql/iproto.test.lua
index 5dfe95c..d31fb7f 100644
--- a/test/sql/iproto.test.lua
+++ b/test/sql/iproto.test.lua
@@ -1,7 +1,7 @@
 remote = require('net.box')
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 box.execute('create table test (id int primary key, a NUMBER, b text)')
 space = box.space.TEST
@@ -220,14 +220,6 @@ res.metadata
 res = cn:execute("EXPLAIN QUERY PLAN SELECT COUNT(*) FROM t1")
 res.metadata
 
--- When pragma count_changes is on, statements INSERT, REPLACE and
--- UPDATE returns number of changed columns. Make sure that this
--- result has a column type.
-cn:execute("PRAGMA count_changes = 1;")
-cn:execute("INSERT INTO t1 VALUES (1), (2), (3);")
-cn:execute("REPLACE INTO t1 VALUES (2), (3), (4), (5);")
-cn:execute("UPDATE t1 SET id = id + 100 WHERE id > 10;")
-
 -- Make sure that built-in functions have a right returning type.
 --
 cn:execute("SELECT zeroblob(1);")
diff --git a/test/sql/max-on-index.result b/test/sql/max-on-index.result
index 57ce95b..45f29fd 100644
--- a/test/sql/max-on-index.result
+++ b/test/sql/max-on-index.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -25,7 +25,7 @@ box.execute("CREATE TABLE test2 (f1 INT, f2 INT, PRIMARY KEY(f1))")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries
 box.execute("INSERT INTO test1 VALUES(1, 2)");
 ---
diff --git a/test/sql/max-on-index.test.lua b/test/sql/max-on-index.test.lua
index 4cceaa7..73e4199 100644
--- a/test/sql/max-on-index.test.lua
+++ b/test/sql/max-on-index.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -13,7 +13,7 @@ box.execute("CREATE INDEX test1_index ON test1 (f2)")
 box.execute("CREATE TABLE test2 (f1 INT, f2 INT, PRIMARY KEY(f1))")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries
 box.execute("INSERT INTO test1 VALUES(1, 2)");
diff --git a/test/sql/message-func-indexes.result b/test/sql/message-func-indexes.result
index 69e3ee0..d198e14 100644
--- a/test/sql/message-func-indexes.result
+++ b/test/sql/message-func-indexes.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/message-func-indexes.test.lua b/test/sql/message-func-indexes.test.lua
index 9ac5f47..dc67606 100644
--- a/test/sql/message-func-indexes.test.lua
+++ b/test/sql/message-func-indexes.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Creating tables.
 box.execute("CREATE TABLE t1(id INTEGER PRIMARY KEY, a INTEGER)")
diff --git a/test/sql/misc.result b/test/sql/misc.result
index a157ddb..b06ac57 100644
--- a/test/sql/misc.result
+++ b/test/sql/misc.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/misc.test.lua b/test/sql/misc.test.lua
index 541660c..e581b73 100644
--- a/test/sql/misc.test.lua
+++ b/test/sql/misc.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Forbid multistatement queries.
 box.execute('select 1;')
diff --git a/test/sql/no-pk-space.result b/test/sql/no-pk-space.result
index 025f363..d0274ea 100644
--- a/test/sql/no-pk-space.result
+++ b/test/sql/no-pk-space.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/no-pk-space.test.lua b/test/sql/no-pk-space.test.lua
index 318c2ac..f451b57 100644
--- a/test/sql/no-pk-space.test.lua
+++ b/test/sql/no-pk-space.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 format = {}
 format[1] = {'id', 'integer'}
diff --git a/test/sql/on-conflict.result b/test/sql/on-conflict.result
index 6851e21..c0bb802 100644
--- a/test/sql/on-conflict.result
+++ b/test/sql/on-conflict.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/on-conflict.test.lua b/test/sql/on-conflict.test.lua
index 1aa4d1b..958303e 100644
--- a/test/sql/on-conflict.test.lua
+++ b/test/sql/on-conflict.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 --
 -- Check that original sql ON CONFLICT clause is really
 -- disabled.
diff --git a/test/sql/persistency.result b/test/sql/persistency.result
index f8f992c..88778ec 100644
--- a/test/sql/persistency.result
+++ b/test/sql/persistency.result
@@ -7,7 +7,7 @@ test_run = env.new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/persistency.test.lua b/test/sql/persistency.test.lua
index 1964453..72d1992 100644
--- a/test/sql/persistency.test.lua
+++ b/test/sql/persistency.test.lua
@@ -1,7 +1,7 @@
 env = require('test_run')
 test_run = env.new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- create space
 box.execute("CREATE TABLE foobar (foo INT PRIMARY KEY, bar TEXT)")
diff --git a/test/sql/row-count.result b/test/sql/row-count.result
index fb96e21..eb0114b 100644
--- a/test/sql/row-count.result
+++ b/test/sql/row-count.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -314,13 +314,9 @@ box.execute("SELECT ROW_COUNT();")
   rows:
   - [0]
 ...
-box.execute('PRAGMA recursive_triggers')
+box.execute("SET sql_default_engine='"..engine.."';")
 ---
-- metadata:
-  - name: recursive_triggers
-    type: INTEGER
-  rows:
-  - [1]
+- row_count: 0
 ...
 -- Clean-up.
 --
diff --git a/test/sql/row-count.test.lua b/test/sql/row-count.test.lua
index 369e7fa..06686ae 100644
--- a/test/sql/row-count.test.lua
+++ b/test/sql/row-count.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Test cases concerning row count calculations.
 --
@@ -65,7 +65,7 @@ box.execute("SELECT ROW_COUNT();")
 box.execute("SELECT ROW_COUNT();")
 box.execute("EXPLAIN QUERY PLAN INSERT INTO t1 VALUES ('b'), ('c'), ('d');")
 box.execute("SELECT ROW_COUNT();")
-box.execute('PRAGMA recursive_triggers')
+box.execute("SET sql_default_engine='"..engine.."';")
 
 -- Clean-up.
 --
diff --git a/test/sql/savepoints.result b/test/sql/savepoints.result
index e48db30..a111e26 100644
--- a/test/sql/savepoints.result
+++ b/test/sql/savepoints.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/savepoints.test.lua b/test/sql/savepoints.test.lua
index 99622a4..0af67a9 100644
--- a/test/sql/savepoints.test.lua
+++ b/test/sql/savepoints.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- These tests check that SQL savepoints properly work outside
 -- transactions as well as inside transactions started in Lua.
diff --git a/test/sql/select-null.result b/test/sql/select-null.result
index 83d9776..bd25f03 100644
--- a/test/sql/select-null.result
+++ b/test/sql/select-null.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -15,7 +15,7 @@ box.execute("CREATE TABLE t3(id INT, a text, b TEXT, PRIMARY KEY(id))")
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries
 box.execute("INSERT INTO t3 VALUES(1, 'abc',NULL)");
 ---
diff --git a/test/sql/select-null.test.lua b/test/sql/select-null.test.lua
index a49eb43..9f54048 100644
--- a/test/sql/select-null.test.lua
+++ b/test/sql/select-null.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -8,7 +8,7 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE t3(id INT, a text, b TEXT, PRIMARY KEY(id))")
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries
 box.execute("INSERT INTO t3 VALUES(1, 'abc',NULL)");
diff --git a/test/sql/sql-debug.result b/test/sql/sql-debug.result
index bfcc046..10e186d 100644
--- a/test/sql/sql-debug.result
+++ b/test/sql/sql-debug.result
@@ -5,56 +5,6 @@ test_run = require('test_run').new()
 ---
 ...
 --
--- gh-3832: Some statements do not return column type
--- Check that "PRAGMA parser_trace" returns 0 or 1 if called
--- without parameter.
-result = box.execute('PRAGMA parser_trace').rows
----
-...
-box.execute('PRAGMA parser_trace = 1')
----
-- row_count: 0
-...
-box.execute('PRAGMA parser_trace')
----
-- metadata:
-  - name: parser_trace
-    type: INTEGER
-  rows:
-  - [1]
-...
-box.execute('PRAGMA parser_trace = '.. result[1][1])
----
-- row_count: 0
-...
---
--- Make PRAGMA command return the result as a result set.
---
-box.execute('PRAGMA')
----
-- metadata:
-  - name: pragma_name
-    type: TEXT
-  - name: pragma_value
-    type: INTEGER
-  rows:
-  - ['count_changes', 0]
-  - ['defer_foreign_keys', 0]
-  - ['full_column_names', 0]
-  - ['parser_trace', 0]
-  - ['recursive_triggers', 1]
-  - ['reverse_unordered_selects', 0]
-  - ['select_trace', 0]
-  - ['short_column_names', 1]
-  - ['sql_trace', 0]
-  - ['vdbe_addoptrace', 0]
-  - ['vdbe_debug', 0]
-  - ['vdbe_eqp', 0]
-  - ['vdbe_listing', 0]
-  - ['vdbe_trace', 0]
-  - ['where_trace', 0]
-...
---
 -- gh-4511: make sure that SET works.
 --
 box.execute('SELECT "name" FROM "_vsession_settings";')
diff --git a/test/sql/sql-debug.test.lua b/test/sql/sql-debug.test.lua
index 83746f0..b15deee 100644
--- a/test/sql/sql-debug.test.lua
+++ b/test/sql/sql-debug.test.lua
@@ -2,21 +2,6 @@ remote = require('net.box')
 test_run = require('test_run').new()
 
 --
--- gh-3832: Some statements do not return column type
-
--- Check that "PRAGMA parser_trace" returns 0 or 1 if called
--- without parameter.
-result = box.execute('PRAGMA parser_trace').rows
-box.execute('PRAGMA parser_trace = 1')
-box.execute('PRAGMA parser_trace')
-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 "_vsession_settings";')
diff --git a/test/sql/sql-statN-index-drop.result b/test/sql/sql-statN-index-drop.result
index b2a4458..cf0f6f4 100644
--- a/test/sql/sql-statN-index-drop.result
+++ b/test/sql/sql-statN-index-drop.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/sql-statN-index-drop.test.lua b/test/sql/sql-statN-index-drop.test.lua
index 5477a2a..5f9cc68 100644
--- a/test/sql/sql-statN-index-drop.test.lua
+++ b/test/sql/sql-statN-index-drop.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Initializing some things.
 box.execute("CREATE TABLE t1(id INT PRIMARY KEY, a INT);")
diff --git a/test/sql/tokenizer.result b/test/sql/tokenizer.result
index 1ae9ef2..07a7c41 100644
--- a/test/sql/tokenizer.result
+++ b/test/sql/tokenizer.result
@@ -7,7 +7,7 @@ test_run = env.new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/tokenizer.test.lua b/test/sql/tokenizer.test.lua
index 3f5dd12..15cf658 100644
--- a/test/sql/tokenizer.test.lua
+++ b/test/sql/tokenizer.test.lua
@@ -1,7 +1,7 @@
 env = require('test_run')
 test_run = env.new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 sql_tokenizer = require('sql_tokenizer')
 
diff --git a/test/sql/transition.result b/test/sql/transition.result
index 9738092..35e7af6 100644
--- a/test/sql/transition.result
+++ b/test/sql/transition.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/transition.test.lua b/test/sql/transition.test.lua
index a05c26a..9b8b868 100644
--- a/test/sql/transition.test.lua
+++ b/test/sql/transition.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- create space
 box.execute("CREATE TABLE foobar (foo INT PRIMARY KEY, bar TEXT)")
diff --git a/test/sql/transitive-transactions.result b/test/sql/transitive-transactions.result
index 29c7316..17311ee 100644
--- a/test/sql/transitive-transactions.result
+++ b/test/sql/transitive-transactions.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute("pragma sql_default_engine=\'"..engine.."\'")
+box.execute("set sql_default_engine=\'"..engine.."\'")
 ---
 - row_count: 0
 ...
@@ -88,7 +88,7 @@ box.space.PARENT:select();
 ---
 - - [1, 1]
 ...
--- Make sure that 'PRAGMA defer_foreign_keys' works.
+-- Make sure that SQL option 'sql_defer_foreign_keys' works.
 --
 box.execute('DROP TABLE child;')
 box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))')
@@ -116,7 +116,7 @@ box.space.PARENT:select();
 ---
 - - [1, 1]
 ...
-box.execute('PRAGMA defer_foreign_keys = 1;')
+box.execute('SET sql_defer_foreign_keys = true;')
 box.rollback()
 fk_defer();
 ---
@@ -131,7 +131,7 @@ box.space.PARENT:select();
   - [2, 2]
 ...
 -- Cleanup
-box.execute('PRAGMA defer_foreign_keys = 0;')
+box.execute('SET sql_defer_foreign_keys = false;')
 
 box.execute('DROP TABLE child;');
 ---
diff --git a/test/sql/transitive-transactions.test.lua b/test/sql/transitive-transactions.test.lua
index 4633f07..3c5fecb 100644
--- a/test/sql/transitive-transactions.test.lua
+++ b/test/sql/transitive-transactions.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute("pragma sql_default_engine=\'"..engine.."\'")
+box.execute("set sql_default_engine=\'"..engine.."\'")
 test_run:cmd("setopt delimiter ';'")
 
 -- These tests are aimed at checking transitive transactions
@@ -45,7 +45,7 @@ fk_violation_3();
 box.space.CHILD:select();
 box.space.PARENT:select();
 
--- Make sure that 'PRAGMA defer_foreign_keys' works.
+-- Make sure that SQL option 'sql_defer_foreign_keys' works.
 --
 box.execute('DROP TABLE child;')
 box.execute('CREATE TABLE child(id INT PRIMARY KEY, x INT REFERENCES parent(y))')
@@ -62,13 +62,13 @@ end;
 fk_defer();
 box.space.CHILD:select();
 box.space.PARENT:select();
-box.execute('PRAGMA defer_foreign_keys = 1;')
+box.execute('SET sql_defer_foreign_keys = true;')
 box.rollback()
 fk_defer();
 box.space.CHILD:select();
 box.space.PARENT:select();
 
-box.execute('PRAGMA defer_foreign_keys = 0;')
+box.execute('SET sql_defer_foreign_keys = false;')
 
 -- Cleanup
 box.execute('DROP TABLE child;');
diff --git a/test/sql/triggers.result b/test/sql/triggers.result
index 9dfe981..de1f074 100644
--- a/test/sql/triggers.result
+++ b/test/sql/triggers.result
@@ -7,7 +7,7 @@ test_run = env.new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -292,7 +292,7 @@ box.execute("DROP TABLE T1;")
 -- gh-3531: Assertion with trigger and two storage engines
 --
 -- Case 1: Src 'vinyl' table; Dst 'memtx' table
-box.execute("PRAGMA sql_default_engine ('vinyl');")
+box.execute("SET sql_default_engine  = 'vinyl';")
 ---
 - row_count: 0
 ...
@@ -304,7 +304,7 @@ box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SE
 ---
 - row_count: 1
 ...
-box.execute("PRAGMA sql_default_engine('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 ---
 - row_count: 0
 ...
@@ -336,7 +336,7 @@ box.execute("DROP TABLE n;")
 - row_count: 1
 ...
 -- Case 2: Src 'memtx' table; Dst 'vinyl' table
-box.execute("PRAGMA sql_default_engine ('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 ---
 - row_count: 0
 ...
@@ -348,7 +348,7 @@ box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SE
 ---
 - row_count: 1
 ...
-box.execute("PRAGMA sql_default_engine('vinyl');")
+box.execute("SET sql_default_engine = 'vinyl';")
 ---
 - row_count: 0
 ...
@@ -380,7 +380,7 @@ box.execute("DROP TABLE n;")
 - row_count: 1
 ...
 -- Test SQL Transaction with LUA
-box.execute("PRAGMA sql_default_engine ('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 ---
 - row_count: 0
 ...
@@ -388,7 +388,7 @@ box.execute("CREATE TABLE test (id INT PRIMARY KEY)")
 ---
 - row_count: 1
 ...
-box.execute("PRAGMA sql_default_engine='vinyl'")
+box.execute("SET sql_default_engine='vinyl'")
 ---
 - row_count: 0
 ...
diff --git a/test/sql/triggers.test.lua b/test/sql/triggers.test.lua
index f0397dc..138d1c0 100644
--- a/test/sql/triggers.test.lua
+++ b/test/sql/triggers.test.lua
@@ -1,7 +1,7 @@
 env = require('test_run')
 test_run = env.new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Get invariant part of the tuple; name and opts don't change.
  function immutable_part(data) local r = {} for i, l in pairs(data) do table.insert(r, {l.name, l.opts}) end return r end
@@ -100,10 +100,10 @@ box.execute("DROP TABLE T1;")
 -- gh-3531: Assertion with trigger and two storage engines
 --
 -- Case 1: Src 'vinyl' table; Dst 'memtx' table
-box.execute("PRAGMA sql_default_engine ('vinyl');")
+box.execute("SET sql_default_engine  = 'vinyl';")
 box.execute("CREATE TABLE m (s0 INT PRIMARY KEY, s1 TEXT UNIQUE);")
 box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = 'now'; END;")
-box.execute("PRAGMA sql_default_engine('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 box.execute("CREATE TABLE n (s0 INT PRIMARY KEY, s1 TEXT UNIQUE, s2 NUMBER);")
 box.execute("INSERT INTO m VALUES (0, '0');")
 box.execute("INSERT INTO n VALUES (0, '',null);")
@@ -116,10 +116,10 @@ box.execute("DROP TABLE n;")
 
 
 -- Case 2: Src 'memtx' table; Dst 'vinyl' table
-box.execute("PRAGMA sql_default_engine ('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 box.execute("CREATE TABLE m (s0 INT PRIMARY KEY, s1 TEXT UNIQUE);")
 box.execute("CREATE TRIGGER m1 BEFORE UPDATE ON m FOR EACH ROW BEGIN UPDATE n SET s2 = 'now'; END;")
-box.execute("PRAGMA sql_default_engine('vinyl');")
+box.execute("SET sql_default_engine = 'vinyl';")
 box.execute("CREATE TABLE n (s0 INT PRIMARY KEY, s1 TEXT UNIQUE, s2 NUMBER);")
 box.execute("INSERT INTO m VALUES (0, '0');")
 box.execute("INSERT INTO n VALUES (0, '',null);")
@@ -131,9 +131,9 @@ box.execute("DROP TABLE m;")
 box.execute("DROP TABLE n;")
 
 -- Test SQL Transaction with LUA
-box.execute("PRAGMA sql_default_engine ('memtx');")
+box.execute("SET sql_default_engine = 'memtx';")
 box.execute("CREATE TABLE test (id INT PRIMARY KEY)")
-box.execute("PRAGMA sql_default_engine='vinyl'")
+box.execute("SET sql_default_engine='vinyl'")
 box.execute("CREATE TABLE test2 (id INT PRIMARY KEY)")
 box.execute("INSERT INTO test2 VALUES (2)")
 box.execute("START TRANSACTION")
diff --git a/test/sql/update-with-nested-select.result b/test/sql/update-with-nested-select.result
index 3172430..b6ccda2 100644
--- a/test/sql/update-with-nested-select.result
+++ b/test/sql/update-with-nested-select.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
@@ -15,7 +15,7 @@ box.execute("CREATE TABLE t1(a integer primary key, b INT UNIQUE, e INT);");
 - row_count: 1
 ...
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 -- Seed entries
 box.execute("INSERT INTO t1 VALUES(1,4,6);");
 ---
diff --git a/test/sql/update-with-nested-select.test.lua b/test/sql/update-with-nested-select.test.lua
index 88424fc..07587ff 100644
--- a/test/sql/update-with-nested-select.test.lua
+++ b/test/sql/update-with-nested-select.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- box.cfg()
 
@@ -8,7 +8,7 @@ box.execute('pragma sql_default_engine=\''..engine..'\'')
 box.execute("CREATE TABLE t1(a integer primary key, b INT UNIQUE, e INT);");
 
 -- Debug
--- box.execute("PRAGMA vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
+-- box.execute("SET vdbe_debug=ON ; INSERT INTO zoobar VALUES (111, 222, 'c3', 444)")
 
 -- Seed entries
 box.execute("INSERT INTO t1 VALUES(1,4,6);");
diff --git a/test/sql/upgrade.result b/test/sql/upgrade.result
index f0997e1..6627777 100644
--- a/test/sql/upgrade.result
+++ b/test/sql/upgrade.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/upgrade.test.lua b/test/sql/upgrade.test.lua
index 37425ae..0c882ba 100644
--- a/test/sql/upgrade.test.lua
+++ b/test/sql/upgrade.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 work_dir = 'sql/upgrade/1.10/'
 test_run:cmd('create server upgrade with script="sql/upgrade/upgrade.lua", workdir="' .. work_dir .. '"')
diff --git a/test/sql/view.result b/test/sql/view.result
index d845df8..3df08fc 100644
--- a/test/sql/view.result
+++ b/test/sql/view.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/view.test.lua b/test/sql/view.test.lua
index 0008056..6a1fae2 100644
--- a/test/sql/view.test.lua
+++ b/test/sql/view.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 
 -- Verify that constraints on 'view' option are working.
 
diff --git a/test/sql/view_delayed_wal.result b/test/sql/view_delayed_wal.result
index d518e7d..a5f64f2 100644
--- a/test/sql/view_delayed_wal.result
+++ b/test/sql/view_delayed_wal.result
@@ -4,7 +4,7 @@ test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
 ---
 ...
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/view_delayed_wal.test.lua b/test/sql/view_delayed_wal.test.lua
index 7e6fce6..ec93e72 100644
--- a/test/sql/view_delayed_wal.test.lua
+++ b/test/sql/view_delayed_wal.test.lua
@@ -1,6 +1,6 @@
 test_run = require('test_run').new()
 engine = test_run:get_cfg('engine')
-box.execute('pragma sql_default_engine=\''..engine..'\'')
+box.execute('set sql_default_engine=\''..engine..'\'')
 fiber = require('fiber')
 
 -- View reference counters are incremented before firing
diff --git a/test/sql/vinyl-opts.result b/test/sql/vinyl-opts.result
index 10a649a..b9e07c1 100644
--- a/test/sql/vinyl-opts.result
+++ b/test/sql/vinyl-opts.result
@@ -13,7 +13,7 @@ test_run:cmd("switch test")
 ---
 - true
 ...
-box.execute('pragma sql_default_engine= \'vinyl\'')
+box.execute('set sql_default_engine= \'vinyl\'')
 ---
 - row_count: 0
 ...
diff --git a/test/sql/vinyl-opts.test.lua b/test/sql/vinyl-opts.test.lua
index 4460724..05864d0 100644
--- a/test/sql/vinyl-opts.test.lua
+++ b/test/sql/vinyl-opts.test.lua
@@ -3,7 +3,7 @@ test_run:cmd("create server test with script='sql/vinyl-opts-cfg.lua'")
 test_run:cmd("start server test")
 test_run:cmd("switch test")
 
-box.execute('pragma sql_default_engine= \'vinyl\'')
+box.execute('set sql_default_engine= \'vinyl\'')
 box.execute('CREATE TABLE v1 (id INT PRIMARY KEY, b INT);')
 box.space.V1.index[0].options
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET
  2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
                   ` (4 preceding siblings ...)
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 5/5] sql: replace control pragmas imeevma
@ 2019-10-26 17:34 ` Vladislav Shpilevoy
  2019-10-27 10:29   ` [Tarantool-patches] [tarantool-patches] " Mergen Imeev
  5 siblings, 1 reply; 13+ messages in thread
From: Vladislav Shpilevoy @ 2019-10-26 17:34 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches, tarantool-patches

I've just realized - we wanted a universal language independent way
to set session settings? Or only to get their values?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview imeevma
@ 2019-10-26 17:35   ` Vladislav Shpilevoy
  2019-10-31 11:26     ` [Tarantool-patches] [tarantool-patches] " Mergen Imeev
  0 siblings, 1 reply; 13+ messages in thread
From: Vladislav Shpilevoy @ 2019-10-26 17:35 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches, tarantool-patches

Hi! Thanks for the fixes!

On 25/10/2019 17:45, imeevma@tarantool.org wrote:
> 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?

Nah, I still think one request for the whole _vsession_settings
feature is enough. You describe what is _vsession_settings,
which options it has already, how to set them, and it should be
sufficient.

> 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

Recently I've seen a ticket https://github.com/tarantool/tarantool/issues/4205
about read-only sessions. That looks like a first candidate on a
non-SQL session local setting.

That means we probably need to design how to make session
settings iterator more generic. Currently all the settings
iteration code consists of explicit SQL things.

On the other hand I don't really know whether we should
consider read-only option a session setting.
And do we need to create a more generic session settings
iterator in scope of this patchset?

Here is my personal opinion how it should be done:

    - We push this patchset with current SQL-centric design of
      the settings iteration to stabilize the public API as
      soon as possible;

    - Later in scope of 4205 we add session-local option
      read-only and reimplement session settings iterator so
      as it would not depend on SQL so much.


See 6 comments below.

> @@ -360,3 +363,116 @@ generic_session_sync(struct session *session)
> +
> +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;

1. Strangely GE does not return anything here:

tarantool> box.space._vsession_settings:select({'sql_'}, {iterator = 'GE'})
---
- []
...

LE also behaves strange:

tarantool> box.space._vsession_settings:select({'sql_d'}, {iterator = 'LE'})
---
- - ['sql_where_trace', false]
  - ['sql_vdbe_trace', false]
  - ['sql_vdbe_listing', false]
  - ['sql_vdbe_eqp', false]
  - ['sql_vdbe_debug', false]
  - ['sql_vdbe_addoptrace', false]
  - ['sql_trace', false]
  - ['sql_select_trace', false]
  - ['sql_reverse_unordered_selects', false]
  - ['sql_recursive_triggers', true]
  - ['sql_parser_trace', false]
  - ['sql_full_column_names', false]
  - ['sql_defer_foreign_keys', false]
  - ['sql_default_engine', 'memtx']
  - ['sql_compound_select_limit', 30]
...

'sql_where_trace' definitely is not <= 'sql_d'.

This is why I was thinking that probably our _vsession_settings
iterator API should be very limited. After all, it is a fixed
size space with settings. A user don't need to be able to dance
with it using different iterators. I would allow only EQ, and either
empty key, or a subsystem name like 'sql', or a full key for a
concrete setting.

Up to you. And probably to Kirill since it is a public API.

> +	} else {
> +		sql_option_id = iterator_type_is_reverse(type) ?
> +				sql_option_id_max() - 1 : 0;
> +	}
> 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
> @@ -3242,3 +3243,160 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name,
> +/**
> + * 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.
> + */

2. Please, add a test that selects all the options and checks
that they are sorted. It would prevent accidental reorders.

> +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;

3. What is the option mask?

> +};
> +
> +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];

4. So the SQL_LIMIT_COMPOUND_SELECT is not session local? Then
why is it in the session settings?

> +		size += mp_sizeof_uint(limit);
> +	}
> +
> +	size_t svp = region_used(region);
> +	char *pos_ret = region_alloc(region, size);

5. Up to you, but probably static_alloc() would work well here.
Size of option tuples is limited, and static_alloc() returns up
to 12KB that should be more than enough here. We could assert,
that static_alloc() returns not NULL for the given 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/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
> +...

6. Are you sure? We have no options, whose name is <= 'a'.
At least because all of them start with 'sql_' which > 'a'.

If you want to keep these iterator types, then probably
the most correct test would fill a normal space with
session settings, and check for each of these keys above,
that the virtual space and the real one return the same.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql
  2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql imeevma
@ 2019-10-26 17:35   ` Vladislav Shpilevoy
  2019-10-27 10:45     ` Mergen Imeev
  0 siblings, 1 reply; 13+ messages in thread
From: Vladislav Shpilevoy @ 2019-10-26 17:35 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches, tarantool-patches

Thanks for the patch!

On 25/10/2019 17:45, imeevma@tarantool.org wrote:
> Since PRAGMA 'sql_default_engine' will be removed in the next
> patch, this test will fail until test-run is fixed.
> 
> This patch should be removed before patch-set will be pushed.

Not sure if I understand. Does the next patch break this
test? If so, why does not it fix the test?

> ---
>  test/sql/suite.ini | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/test/sql/suite.ini b/test/sql/suite.ini
> index a8664c5..a2573be 100644
> --- a/test/sql/suite.ini
> +++ b/test/sql/suite.ini
> @@ -8,7 +8,7 @@ config = engine.cfg
>  is_parallel = True
>  lua_libs = lua/sql_tokenizer.lua
>  release_disabled = errinj.test.lua view_delayed_wal.test.lua sql-debug.test.lua
> -disabled = sql-statN-index-drop.test.lua
> +disabled = sql-statN-index-drop.test.lua boolean.test.sql
>  pretest_clean = True
>  fragile = dll.test.lua           ; gh-4427
>            func-recreate.test.lua ; gh-4384
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [tarantool-patches] Re: [PATCH v2 0/5] Replace control pragmas by SET
  2019-10-26 17:34 ` [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET Vladislav Shpilevoy
@ 2019-10-27 10:29   ` Mergen Imeev
  0 siblings, 0 replies; 13+ messages in thread
From: Mergen Imeev @ 2019-10-27 10:29 UTC (permalink / raw)
  To: v.shpilevoy, tarantool-patches; +Cc: tarantool-patches

On Sat, Oct 26, 2019 at 07:34:01PM +0200, Vladislav Shpilevoy wrote:
> I've just realized - we wanted a universal language independent way
> to set session settings? Or only to get their values?
> 
As far as I know, only to get their values.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql
  2019-10-26 17:35   ` Vladislav Shpilevoy
@ 2019-10-27 10:45     ` Mergen Imeev
  0 siblings, 0 replies; 13+ messages in thread
From: Mergen Imeev @ 2019-10-27 10:45 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches, tarantool-patches

On Sat, Oct 26, 2019 at 07:35:37PM +0200, Vladislav Shpilevoy wrote:
> Thanks for the patch!
> 
> On 25/10/2019 17:45, imeevma@tarantool.org wrote:
> > Since PRAGMA 'sql_default_engine' will be removed in the next
> > patch, this test will fail until test-run is fixed.
> > 
> > This patch should be removed before patch-set will be pushed.
> 
> Not sure if I understand. Does the next patch break this
> test? If so, why does not it fix the test?
> 

The problem is not really in this test, but in all tests of type
'*.test.sql.'' But since there is only one such test, I decided to
temporarily disable it.

This problem can be solved by changing the default SQL engine
setting method in test-run. But since test-run is in a different
repository, it will be incorrect to update it now until SET is
implemented, I think.

I plan to push patch to test-run after we implement SET but
before we remove control pragmas.

> > ---
> >  test/sql/suite.ini | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/test/sql/suite.ini b/test/sql/suite.ini
> > index a8664c5..a2573be 100644
> > --- a/test/sql/suite.ini
> > +++ b/test/sql/suite.ini
> > @@ -8,7 +8,7 @@ config = engine.cfg
> >  is_parallel = True
> >  lua_libs = lua/sql_tokenizer.lua
> >  release_disabled = errinj.test.lua view_delayed_wal.test.lua sql-debug.test.lua
> > -disabled = sql-statN-index-drop.test.lua
> > +disabled = sql-statN-index-drop.test.lua boolean.test.sql
> >  pretest_clean = True
> >  fragile = dll.test.lua           ; gh-4427
> >            func-recreate.test.lua ; gh-4384
> > 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [tarantool-patches] Re: [PATCH v2 2/5] box: introdice _vsession_settings sysview
  2019-10-26 17:35   ` Vladislav Shpilevoy
@ 2019-10-31 11:26     ` Mergen Imeev
  2019-11-02 16:17       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 13+ messages in thread
From: Mergen Imeev @ 2019-10-31 11:26 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches, tarantool-patches

Thank you for review! My answers and new patch below.

On Sat, Oct 26, 2019 at 07:35:27PM +0200, Vladislav Shpilevoy wrote:
> Hi! Thanks for the fixes!
> 
> On 25/10/2019 17:45, imeevma@tarantool.org wrote:
> > 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?
> 
> Nah, I still think one request for the whole _vsession_settings
> feature is enough. You describe what is _vsession_settings,
> which options it has already, how to set them, and it should be
> sufficient.
> 
> > 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
> 
> Recently I've seen a ticket https://github.com/tarantool/tarantool/issues/4205
> about read-only sessions. That looks like a first candidate on a
> non-SQL session local setting.
> 
> That means we probably need to design how to make session
> settings iterator more generic. Currently all the settings
> iteration code consists of explicit SQL things.
> 
> On the other hand I don't really know whether we should
> consider read-only option a session setting.
> And do we need to create a more generic session settings
> iterator in scope of this patchset?
> 
> Here is my personal opinion how it should be done:
> 
>     - We push this patchset with current SQL-centric design of
>       the settings iteration to stabilize the public API as
>       soon as possible;
> 
>     - Later in scope of 4205 we add session-local option
>       read-only and reimplement session settings iterator so
>       as it would not depend on SQL so much.
> 
> 
> See 6 comments below.
> 
> > @@ -360,3 +363,116 @@ generic_session_sync(struct session *session)
> > +
> > +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;
> 
> 1. Strangely GE does not return anything here:
> 
> tarantool> box.space._vsession_settings:select({'sql_'}, {iterator = 'GE'})
> ---
> - []
> ...
> 
> LE also behaves strange:
> 
> tarantool> box.space._vsession_settings:select({'sql_d'}, {iterator = 'LE'})
> ---
> - - ['sql_where_trace', false]
>   - ['sql_vdbe_trace', false]
>   - ['sql_vdbe_listing', false]
>   - ['sql_vdbe_eqp', false]
>   - ['sql_vdbe_debug', false]
>   - ['sql_vdbe_addoptrace', false]
>   - ['sql_trace', false]
>   - ['sql_select_trace', false]
>   - ['sql_reverse_unordered_selects', false]
>   - ['sql_recursive_triggers', true]
>   - ['sql_parser_trace', false]
>   - ['sql_full_column_names', false]
>   - ['sql_defer_foreign_keys', false]
>   - ['sql_default_engine', 'memtx']
>   - ['sql_compound_select_limit', 30]
> ...
> 
> 'sql_where_trace' definitely is not <= 'sql_d'.
> 
> This is why I was thinking that probably our _vsession_settings
> iterator API should be very limited. After all, it is a fixed
> size space with settings. A user don't need to be able to dance
> with it using different iterators. I would allow only EQ, and either
> empty key, or a subsystem name like 'sql', or a full key for a
> concrete setting.
> 
> Up to you. And probably to Kirill since it is a public API.
> 
I fixed behaviour of iterators.

> > +	} else {
> > +		sql_option_id = iterator_type_is_reverse(type) ?
> > +				sql_option_id_max() - 1 : 0;
> > +	}
> > 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
> > @@ -3242,3 +3243,160 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name,
> > +/**
> > + * 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.
> > + */
> 
> 2. Please, add a test that selects all the options and checks
> that they are sorted. It would prevent accidental reorders.
> 
Not sure that we can do this since some of the options
appears only in debug build. But I reworked some tests
using additional space to check sorting and iterator.

> > +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;
> 
> 3. What is the option mask?
> 
Previously it was "flag", but since one of the options
(sql_debug) have three three of flags to set/unset I
changed its name to "mask".

> > +};
> > +
> > +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];
> 
> 4. So the SQL_LIMIT_COMPOUND_SELECT is not session local? Then
> why is it in the session settings?
> 
True, I forgot about this when changed sysview. Still, I do
not know where should we move this option.

> > +		size += mp_sizeof_uint(limit);
> > +	}
> > +
> > +	size_t svp = region_used(region);
> > +	char *pos_ret = region_alloc(region, size);
> 
> 5. Up to you, but probably static_alloc() would work well here.
> Size of option tuples is limited, and static_alloc() returns up
> to 12KB that should be more than enough here. We could assert,
> that static_alloc() returns not NULL for the given size.
> 
Thanks, fixed.

> > +	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/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
> > +...
> 
> 6. Are you sure? We have no options, whose name is <= 'a'.
> At least because all of them start with 'sql_' which > 'a'.
> 
> If you want to keep these iterator types, then probably
> the most correct test would fill a normal space with
> session settings, and check for each of these keys above,
> that the virtual space and the real one return the same.
> 
Thank you for suggestion! I reworked tests using additional
space.


New patch:

From 61f75f2b4a800bab37ba5195b71c488fe0d145ee Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
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 f6e96f0..9b5df28 100644
--- a/src/box/lua/space.cc
+++ b/src/box/lua/space.cc
@@ -653,6 +653,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 d69b657..6d301bf 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",
@@ -361,3 +364,135 @@ 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 id_max = sql_option_id_max();
+	for (uint32_t id = 0; id < id_max; ++id) {
+		if (sql_option_compare(name, id) == 0)
+			return sql_option_tuple(space->format, id, result);
+	}
+	*result = NULL;
+	return 0;
+}
+
+/**
+ * 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;
+	/** Counter, count number of options already shown. */
+	uint32_t counter;
+	/** Decoded key. */
+	char *key;
+	/** Type of iterator. */
+	enum iterator_type iterator_type;
+};
+
+static int
+session_options_iterator_next(struct iterator *itr, struct tuple **ret)
+{
+	struct session_options_iterator *it =
+		(struct session_options_iterator *)itr;
+	uint32_t id_max = sql_option_id_max();
+	if (it->key == NULL)
+		return sql_option_tuple(it->format, it->counter++, ret);
+	for (; it->counter < id_max; ++it->counter) {
+		int compare = sql_option_compare(it->key, it->counter);
+		if (compare == 0 && (it->iterator_type == ITER_EQ ||
+				     it->iterator_type == ITER_GE ||
+				     it->iterator_type == ITER_ALL))
+			break;
+		if (compare > 0 && (it->iterator_type == ITER_GT ||
+				    it->iterator_type == ITER_GE ||
+				    it->iterator_type == ITER_ALL))
+			break;
+	}
+	if (it->counter < id_max)
+		return sql_option_tuple(it->format, it->counter++, ret);
+	*ret = NULL;
+	return 0;
+}
+
+static int
+session_options_iterator_prev(struct iterator *itr, struct tuple **ret)
+{
+	struct session_options_iterator *it =
+		(struct session_options_iterator *)itr;
+	uint32_t id_max = sql_option_id_max();
+	if (it->key == NULL)
+		return sql_option_tuple(it->format, id_max - 1 - it->counter++,
+					ret);
+	for (; it->counter < id_max; ++it->counter) {
+		uint32_t id = id_max - it->counter - 1;
+		int compare = sql_option_compare(it->key, id);
+		if (compare == 0 && (it->iterator_type == ITER_REQ ||
+				     it->iterator_type == ITER_LE))
+			break;
+		if (compare < 0 && (it->iterator_type == ITER_LT ||
+				    it->iterator_type == ITER_LE))
+			break;
+	}
+	if (it->counter < id_max)
+		return sql_option_tuple(it->format, id_max - 1 - it->counter++,
+					ret);
+	*ret = NULL;
+	return 0;
+}
+
+static void
+session_options_iterator_free(struct iterator *itr)
+{
+	struct session_options_iterator *it =
+		(struct session_options_iterator *)itr;
+	free(it->key);
+	free(it);
+}
+
+struct iterator *
+session_options_create_iterator(struct index *index, enum iterator_type type,
+				const char *key, uint32_t part_count)
+{
+	char *decoded_key = NULL;
+	if (part_count > 0) {
+		assert(part_count == 1);
+		assert(mp_typeof(*key) == MP_STR);
+		uint32_t len;
+		const char *name = mp_decode_str(&key, &len);
+		name = tt_cstr(name, len);
+		decoded_key = (char *)malloc(len + 1);
+		memcpy(decoded_key, name, len + 1);
+	}
+	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->key = decoded_key;
+	it->iterator_type = type;
+	it->format = space->format;
+	it->counter = 0;
+	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..ad85f1e 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,40 @@ void
 vdbe_field_ref_prepare_tuple(struct vdbe_field_ref *field_ref,
 			     struct tuple *tuple);
 
+/**
+ * Return the next number after the ID of the last SQL option.
+ *
+ * @retval Next number after the last SQL option.
+ */
+uint32_t
+sql_option_id_max();
+
+/**
+ * Return an integer less than, equal to, or greater than zero if
+ * name of option with given ID is found, respectively, to be less
+ * than, to match, or be greater than key.
+ *
+ * @param key Key to compare with option name.
+ * @param id ID of the option.
+ * @retval result of comparison.
+ */
+int
+sql_option_compare(const char *key, uint32_t id);
+
+/**
+ * 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..dceb092 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,151 @@ 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_compare(const char *key, uint32_t id)
+{
+	assert(id < SQL_OPTION_max);
+	return strcmp(sql_options[id].name, key);
+}
+
+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 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);
+	}
+
+	char *pos_ret = static_alloc(size);
+	assert(pos_ret != NULL);
+	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);
+	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..1edd59e 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -1330,3 +1330,174 @@ 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
+...
+s = box.schema.space.create('settings', {format = v:format()})
+---
+...
+_ = s:create_index('primary')
+---
+...
+for _,value in v:pairs() do s:insert(value) end
+---
+...
+(#v:select({'abcde'}, {iterator = 'ALL'})) == (#s:select({'abcde'}, {iterator = 'ALL'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'REQ'})) == (#s:select({'abcde'}, {iterator = 'REQ'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'EQ'})) == (#s:select({'abcde'}, {iterator = 'EQ'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'GE'})) == (#s:select({'abcde'}, {iterator = 'GE'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'GT'})) == (#s:select({'abcde'}, {iterator = 'GT'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'LE'})) == (#s:select({'abcde'}, {iterator = 'LE'}))
+---
+- true
+...
+(#v:select({'abcde'}, {iterator = 'LT'})) == (#s:select({'abcde'}, {iterator = 'LT'}))
+---
+- 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']
+...
+-- Check get() method.
+v:get({'sql_defer_foreign_keys'})
+---
+- ['sql_defer_foreign_keys', false]
+...
+v:get({'sql_recursive_triggers'})
+---
+- ['sql_recursive_triggers', true]
+...
+v:get({'sql_reverse_unordered_selects'})
+---
+- ['sql_reverse_unordered_selects', false]
+...
+v:get({'sql_compound_select_limit'})
+---
+- ['sql_compound_select_limit', 30]
+...
+v:get({'sql_default_engine'})
+---
+- ['sql_default_engine', 'memtx']
+...
+-- Make sure that space is read-only.
+new_record = v:frommap({name='abs', value=123})
+---
+...
+v:insert(new_record)
+---
+- error: View '_vsession_settings' is read-only
+...
+-- Check pairs() method.
+t = {}
+---
+...
+for key, value in box.space._vsession_settings:pairs() do table.insert(t, {key, value}) end
+---
+...
+#t == option_count
+---
+- true
+...
+-- Check sorting.
+in_sysview = v:select()
+---
+...
+in_space = s:select()
+---
+...
+is_right = true
+---
+...
+for key, value in pairs(in_sysview) do is_right = is_right and (in_space[key].name == value.name) end
+---
+...
+is_right
+---
+- true
+...
+-- Make sure that SQL SELECT works.
+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..037c866 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -383,3 +383,66 @@ 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
+
+s = box.schema.space.create('settings', {format = v:format()})
+_ = s:create_index('primary')
+for _,value in v:pairs() do s:insert(value) end
+
+(#v:select({'abcde'}, {iterator = 'ALL'})) == (#s:select({'abcde'}, {iterator = 'ALL'}))
+(#v:select({'abcde'}, {iterator = 'REQ'})) == (#s:select({'abcde'}, {iterator = 'REQ'}))
+(#v:select({'abcde'}, {iterator = 'EQ'})) == (#s:select({'abcde'}, {iterator = 'EQ'}))
+(#v:select({'abcde'}, {iterator = 'GE'})) == (#s:select({'abcde'}, {iterator = 'GE'}))
+(#v:select({'abcde'}, {iterator = 'GT'})) == (#s:select({'abcde'}, {iterator = 'GT'}))
+(#v:select({'abcde'}, {iterator = 'LE'})) == (#s:select({'abcde'}, {iterator = 'LE'}))
+(#v:select({'abcde'}, {iterator = 'LT'})) == (#s:select({'abcde'}, {iterator = 'LT'}))
+
+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'})
+
+-- Check get() method.
+v:get({'sql_defer_foreign_keys'})
+v:get({'sql_recursive_triggers'})
+v:get({'sql_reverse_unordered_selects'})
+v:get({'sql_compound_select_limit'})
+v:get({'sql_default_engine'})
+
+-- Make sure that space is read-only.
+new_record = v:frommap({name='abs', value=123})
+v:insert(new_record)
+
+-- Check pairs() method.
+t = {}
+for key, value in box.space._vsession_settings:pairs() do table.insert(t, {key, value}) end
+#t == option_count
+
+-- Check sorting.
+in_sysview = v:select()
+in_space = s:select()
+is_right = true
+for key, value in pairs(in_sysview) do is_right = is_right and (in_space[key].name == value.name) end
+is_right
+
+-- Make sure that SQL SELECT works.
+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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Tarantool-patches] [tarantool-patches] Re: [PATCH v2 2/5] box: introdice _vsession_settings sysview
  2019-10-31 11:26     ` [Tarantool-patches] [tarantool-patches] " Mergen Imeev
@ 2019-11-02 16:17       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 13+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-02 16:17 UTC (permalink / raw)
  To: tarantool-patches, Mergen Imeev; +Cc: tarantool-patches

Hi! Thanks for the fixes!

See 7 comments below.

> diff --git a/src/box/session.cc b/src/box/session.cc
> index d69b657..6d301bf 100644
> --- a/src/box/session.cc
> +++ b/src/box/session.cc
> @@ -361,3 +364,135 @@ 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 id_max = sql_option_id_max();
> +	for (uint32_t id = 0; id < id_max; ++id) {
> +		if (sql_option_compare(name, id) == 0)
> +			return sql_option_tuple(space->format, id, result);
> +	}
> +	*result = NULL;
> +	return 0;
> +}
> +
> +/**
> + * 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;
> +	/** Counter, count number of options already shown. */
> +	uint32_t counter;
> +	/** Decoded key. */
> +	char *key;
> +	/** Type of iterator. */
> +	enum iterator_type iterator_type;
> +};
> +
> +static int
> +session_options_iterator_next(struct iterator *itr, struct tuple **ret)
> +{
> +	struct session_options_iterator *it =
> +		(struct session_options_iterator *)itr;
> +	uint32_t id_max = sql_option_id_max();
> +	if (it->key == NULL)
> +		return sql_option_tuple(it->format, it->counter++, ret);
> +	for (; it->counter < id_max; ++it->counter) {
> +		int compare = sql_option_compare(it->key, it->counter);
> +		if (compare == 0 && (it->iterator_type == ITER_EQ ||
> +				     it->iterator_type == ITER_GE ||
> +				     it->iterator_type == ITER_ALL))
> +			break;
> +		if (compare > 0 && (it->iterator_type == ITER_GT ||
> +				    it->iterator_type == ITER_GE ||
> +				    it->iterator_type == ITER_ALL))
> +			break;
> +	}
> +	if (it->counter < id_max)
> +		return sql_option_tuple(it->format, it->counter++, ret);
> +	*ret = NULL;
> +	return 0;
> +}
> +
> +static int
> +session_options_iterator_prev(struct iterator *itr, struct tuple **ret)
> +{
> +	struct session_options_iterator *it =
> +		(struct session_options_iterator *)itr;
> +	uint32_t id_max = sql_option_id_max();
> +	if (it->key == NULL)
> +		return sql_option_tuple(it->format, id_max - 1 - it->counter++,
> +					ret);
> +	for (; it->counter < id_max; ++it->counter) {
> +		uint32_t id = id_max - it->counter - 1;

1. These 'id_max - 1 - counter' look really complex. Could you
simplify it? For example, rename it to 'current_id', and in
iterator_prev() decrement it instead of increment.

> +		int compare = sql_option_compare(it->key, id);
> +		if (compare == 0 && (it->iterator_type == ITER_REQ ||
> +				     it->iterator_type == ITER_LE))
> +			break;
> +		if (compare < 0 && (it->iterator_type == ITER_LT ||
> +				    it->iterator_type == ITER_LE))
> +			break;
> +	}
> +	if (it->counter < id_max)
> +		return sql_option_tuple(it->format, id_max - 1 - it->counter++,
> +					ret);
> +	*ret = NULL;
> +	return 0;
> +}
> +
> +static void
> +session_options_iterator_free(struct iterator *itr)
> +{
> +	struct session_options_iterator *it =
> +		(struct session_options_iterator *)itr;
> +	free(it->key);
> +	free(it);
> +}
> +
> +struct iterator *
> +session_options_create_iterator(struct index *index, enum iterator_type type,
> +				const char *key, uint32_t part_count)
> +{
> +	char *decoded_key = NULL;
> +	if (part_count > 0) {
> +		assert(part_count == 1);
> +		assert(mp_typeof(*key) == MP_STR);
> +		uint32_t len;
> +		const char *name = mp_decode_str(&key, &len);
> +		name = tt_cstr(name, len);
> +		decoded_key = (char *)malloc(len + 1);

2. I guess, you don't need tt_cstr() here, if you anyway
copy the key onto the heap memory.

3. You don't check malloc() result.

> +		memcpy(decoded_key, name, len + 1);
> +	}
> +	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->key = decoded_key;
> +	it->iterator_type = type;
> +	it->format = space->format;
> +	it->counter = 0;
> +	return (struct iterator *)it;
> +}
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index 51cd7ce..dceb092 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -3242,3 +3243,151 @@ 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_compare(const char *key, uint32_t id)
> +{
> +	assert(id < SQL_OPTION_max);
> +	return strcmp(sql_options[id].name, key);
> +}
> +
> +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 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);

4. I propose you to remove compound select setting from there. Since
it is not session local.

Another question is where to show its value then? Certainly not
here.

> +	}
> +
> +	char *pos_ret = static_alloc(size);
> +	assert(pos_ret != NULL);
> +	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);
> +	if (tuple == NULL)
> +		return -1;
> +	*result = tuple;
> +	return 0;
> +}
> diff --git a/test/box/misc.result b/test/box/misc.result
> index b293051..1edd59e 100644
> --- a/test/box/misc.result
> +++ b/test/box/misc.result
> @@ -1330,3 +1330,174 @@ test_run:grep_log('default', 'test log')
>  ---
>  - test log
>  ...
> +--
> +-- gh-4511: make sure that _vsession_settings sysview works as
> +-- intended.

5. I just realized that probably Kirill would want it to be in a
separate file. But if he doesn't, then probably access_sysview.test.lua
fits better than misc.

> +--
> +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

6. Why do you need braces around #v:select?

> +---
> +- true
> +...
> +s = box.schema.space.create('settings', {format = v:format()})
> +---
> +...
> +_ = s:create_index('primary')
> +---
> +...
> +for _,value in v:pairs() do s:insert(value) end
> +---
> +...
> +(#v:select({'abcde'}, {iterator = 'ALL'})) == (#s:select({'abcde'}, {iterator = 'ALL'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'REQ'})) == (#s:select({'abcde'}, {iterator = 'REQ'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'EQ'})) == (#s:select({'abcde'}, {iterator = 'EQ'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'GE'})) == (#s:select({'abcde'}, {iterator = 'GE'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'GT'})) == (#s:select({'abcde'}, {iterator = 'GT'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'LE'})) == (#s:select({'abcde'}, {iterator = 'LE'}))
> +---
> +- true
> +...
> +(#v:select({'abcde'}, {iterator = 'LT'})) == (#s:select({'abcde'}, {iterator = 'LT'}))
> +---
> +- true

7. Sorry, but counts are rather useless here, they don't check order nor content.
Please, check them properly. Also there is still no a single test about partial
keys. You check for empty, full, not found, but not for partial matches like 'sql_v'
+ GE/LE/GT/LT. Which already appeared to be buggy two times.

I propose you to implement a function, which takes a key, and checks
it with different iterator types on both 's' and 'v', and compares their result
sets. Then you call it with different keys and without tests code duplication.

Additionally, you could find useful gcov build to check code coverage locally.
Use make distclean && cmake . -DENABLE_GCOV=1 && make -j. Then run a needed
test. Then call

    gcov <path_to_session.cc> -o <path_to_session.gcno>

Then a file session.gcov is generated where you can check whether you have
covered your code with tests properly. File session.gcno should appear somewhere
after you run a test.

> +...
> +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']
> +...
> +-- Check get() method.
> +v:get({'sql_defer_foreign_keys'})
> +---
> +- ['sql_defer_foreign_keys', false]
> +...
> +v:get({'sql_recursive_triggers'})
> +---
> +- ['sql_recursive_triggers', true]
> +...
> +v:get({'sql_reverse_unordered_selects'})
> +---
> +- ['sql_reverse_unordered_selects', false]
> +...
> +v:get({'sql_compound_select_limit'})
> +---
> +- ['sql_compound_select_limit', 30]
> +...
> +v:get({'sql_default_engine'})
> +---
> +- ['sql_default_engine', 'memtx']
> +...
> +-- Make sure that space is read-only.
> +new_record = v:frommap({name='abs', value=123})
> +---
> +...
> +v:insert(new_record)
> +---
> +- error: View '_vsession_settings' is read-only
> +...
> +-- Check pairs() method.
> +t = {}
> +---
> +...
> +for key, value in box.space._vsession_settings:pairs() do table.insert(t, {key, value}) end
> +---
> +...
> +#t == option_count
> +---
> +- true
> +...
> +-- Check sorting.
> +in_sysview = v:select()
> +---
> +...
> +in_space = s:select()
> +---
> +...
> +is_right = true
> +---
> +...
> +for key, value in pairs(in_sysview) do is_right = is_right and (in_space[key].name == value.name) end
> +---
> +...
> +is_right
> +---
> +- true
> +...
> +-- Make sure that SQL SELECT works.
> +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']
> +...

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-11-02 16:11 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-25 15:45 [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET imeevma
2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 1/5] sysview: make get() and create_iterator() methods virtual imeevma
2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 2/5] box: introdice _vsession_settings sysview imeevma
2019-10-26 17:35   ` Vladislav Shpilevoy
2019-10-31 11:26     ` [Tarantool-patches] [tarantool-patches] " Mergen Imeev
2019-11-02 16:17       ` Vladislav Shpilevoy
2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 3/5] sql: introduce SET statement imeevma
2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 4/5] temporary: disable boolean.test.sql imeevma
2019-10-26 17:35   ` Vladislav Shpilevoy
2019-10-27 10:45     ` Mergen Imeev
2019-10-25 15:45 ` [Tarantool-patches] [PATCH v2 5/5] sql: replace control pragmas imeevma
2019-10-26 17:34 ` [Tarantool-patches] [PATCH v2 0/5] Replace control pragmas by SET Vladislav Shpilevoy
2019-10-27 10:29   ` [Tarantool-patches] [tarantool-patches] " Mergen Imeev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox