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

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 session-local
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.

Changes in v3:
1) SQL settings divided into session and global.
2) Patch 2, 3 and 5 were refactored due to removal of
sql_compound_select_limit from the session options.

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                                 | 131 +++++++++++
 src/box/session.h                                  |  13 ++
 src/box/sql.c                                      |   3 +-
 src/box/sql.h                                      |  36 +++
 src/box/sql/build.c                                | 245 +++++++++++++++++++++
 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                     | 124 ++++++++++-
 test/box/access_sysview.test.lua                   |  54 +++++
 test/box/alter.result                              |   5 +-
 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 |  16 +-
 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                          | 144 +++++++++---
 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 +-
 134 files changed, 1044 insertions(+), 992 deletions(-)

-- 
2.7.4

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

* [Tarantool-patches] [PATCH v3 1/5] sysview: make get() and create_iterator() methods virtual
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
@ 2019-11-07 10:36 ` imeevma
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 2/5] box: introdice _vsession_settings sysview imeevma
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 30+ messages in thread
From: imeevma @ 2019-11-07 10:36 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: 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] 30+ messages in thread

* [Tarantool-patches] [PATCH v3 2/5] box: introdice _vsession_settings sysview
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 1/5] sysview: make get() and create_iterator() methods virtual imeevma
@ 2019-11-07 10:36 ` imeevma
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement imeevma
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 30+ messages in thread
From: imeevma @ 2019-11-07 10:36 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches

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

On 11/2/19 7:17 PM, Vladislav Shpilevoy wrote:
> 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.
>
Fixed.

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

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

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

> 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.
>
Fixed, moved to access_sysview.test.lua.

>> +--
>> +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?
>
I thought that this looked easier to understand, but guess it is
not so.

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

Done, gcov after access_sysview.test.lua:
        -:  367:
        -:  368:int
        5:  369:session_options_get(struct index *index, const char *key, uint32_t part_count,
        -:  370:		    struct tuple **result)
        -:  371:{
        5:  372:	assert(part_count == 1);
        -:  373:	(void)part_count;
        5:  374:	struct space *space = space_cache_find(index->def->space_id);
        -:  375:	uint32_t len;
        5:  376:	const char *name = mp_decode_str(&key, &len);
        5:  377:	name = tt_cstr(name, len);
        -:  378:	/*
        -:  379:	 * Currently, the only session local options are SQL
        -:  380:	 * options.
        -:  381:	 */
        5:  382:	uint32_t id_max = sql_session_opt_id_max();
       29:  383:	for (uint32_t id = 0; id < id_max; ++id) {
       28:  384:		if (sql_session_opt_compare(name, id) == 0)
        4:  385:			return sql_session_opt_tuple(space->format, id, result);
        -:  386:	}
        1:  387:	*result = NULL;
        1:  388:	return 0;
        -:  389:}
        -:  390:
        -:  391:/**
        -:  392: * An iterator that iterates over current session options.
        -:  393: */
        -:  394:struct session_options_iterator {
        -:  395:	/** Base iterator. Must be the first member. */
        -:  396:	struct iterator base;
        -:  397:	/** Format of the tuples this iterator returns. */
        -:  398:	struct tuple_format *format;
        -:  399:	/** ID of the option in global list of the options. */
        -:  400:	int current_id;
        -:  401:	/** Decoded key. */
        -:  402:	char *key;
        -:  403:	/** Type of iterator. */
        -:  404:	enum iterator_type iterator_type;
        -:  405:};
        -:  406:
        -:  407:static int
      264:  408:session_options_iterator_next(struct iterator *itr, struct tuple **ret)
        -:  409:{
        -:  410:	struct session_options_iterator *it =
      264:  411:		(struct session_options_iterator *)itr;
      264:  412:	if (it->key == NULL)
      105:  413:		return sql_session_opt_tuple(it->format, it->current_id++, ret);
      159:  414:	int id_max = sql_session_opt_id_max();
      351:  415:	for (; it->current_id < id_max; ++it->current_id) {
      238:  416:		int compare = sql_session_opt_compare(it->key, it->current_id);
      241:  417:		if (compare == 0 && (it->iterator_type == ITER_EQ ||
        5:  418:				     it->iterator_type == ITER_GE ||
        2:  419:				     it->iterator_type == ITER_ALL))
        -:  420:			break;
      385:  421:		if (compare > 0 && (it->iterator_type == ITER_GT ||
      256:  422:				    it->iterator_type == ITER_GE ||
      105:  423:				    it->iterator_type == ITER_ALL))
        -:  424:			break;
        -:  425:	}
      159:  426:	return sql_session_opt_tuple(it->format, it->current_id++, ret);
        -:  427:}
        -:  428:
        -:  429:static int
       77:  430:session_options_iterator_prev(struct iterator *itr, struct tuple **ret)
        -:  431:{
        -:  432:	struct session_options_iterator *it =
       77:  433:		(struct session_options_iterator *)itr;
       77:  434:	if (it->key == NULL)
       45:  435:		return sql_session_opt_tuple(it->format, it->current_id--, ret);
      328:  436:	for (; it->current_id >= 0; --it->current_id) {
      168:  437:		int compare = sql_session_opt_compare(it->key, it->current_id);
      170:  438:		if (compare == 0 && (it->iterator_type == ITER_REQ ||
        2:  439:				     it->iterator_type == ITER_LE))
        -:  440:			break;
      184:  441:		if (compare < 0 && (it->iterator_type == ITER_LT ||
       18:  442:				    it->iterator_type == ITER_LE))
        -:  443:			break;
        -:  444:	}
       32:  445:	return sql_session_opt_tuple(it->format, it->current_id--, ret);
        -:  446:}
        -:  447:
        -:  448:static void
       37:  449:session_options_iterator_free(struct iterator *itr)
        -:  450:{
        -:  451:	struct session_options_iterator *it =
       37:  452:		(struct session_options_iterator *)itr;
       37:  453:	free(it->key);
       37:  454:	free(it);
       37:  455:}
        -:  456:
        -:  457:struct iterator *
       39:  458:session_options_create_iterator(struct index *index, enum iterator_type type,
        -:  459:				const char *key, uint32_t part_count)
        -:  460:{
       39:  461:	char *decoded_key = NULL;
       39:  462:	if (part_count > 0) {
       29:  463:		assert(part_count == 1);
       58:  464:		assert(mp_typeof(*key) == MP_STR);
        -:  465:		uint32_t len;
       29:  466:		const char *name = mp_decode_str(&key, &len);
       29:  467:		decoded_key = (char *)malloc(len + 1);
       29:  468:		if (decoded_key == NULL) {
    #####:  469:			diag_set(OutOfMemory, len + 1, "malloc", "decoded_key");
    #####:  470:			return NULL;
        -:  471:		}
       29:  472:		memcpy(decoded_key, name, len);
       29:  473:		decoded_key[len] = '\0';
        -:  474:	}
       39:  475:	struct space *space = space_cache_find(index->def->space_id);
        -:  476:	struct session_options_iterator *it =
       39:  477:		(session_options_iterator *)malloc(sizeof(*it));
       39:  478:	if (it == NULL) {
    #####:  479:		diag_set(OutOfMemory, sizeof(*it), "malloc", "it");
    #####:  480:		return NULL;
        -:  481:	}
       39:  482:	int current_id = iterator_type_is_reverse(type) ?
       39:  483:			 sql_session_opt_id_max() - 1 : 0;
       39:  484:	iterator_create(&it->base, index);
       39:  485:	it->base.next = iterator_type_is_reverse(type) ?
        -:  486:			session_options_iterator_prev :
       39:  487:			session_options_iterator_next;
       39:  488:	it->base.free = session_options_iterator_free;
       39:  489:	it->key = decoded_key;
       39:  490:	it->iterator_type = type;
       39:  491:	it->format = space->format;
       39:  492:	it->current_id = current_id;
       39:  493:	return (struct iterator *)it;
       12:  494:}


New patch:

From 3d55476778a0b8be41703ccdc4d25d558b861dfd 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 b171e23..d9e3b2d 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,131 @@ 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_session_opt_id_max();
+	for (uint32_t id = 0; id < id_max; ++id) {
+		if (sql_session_opt_compare(name, id) == 0)
+			return sql_session_opt_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;
+	/** ID of the option in global list of the options. */
+	int current_id;
+	/** 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;
+	if (it->key == NULL)
+		return sql_session_opt_tuple(it->format, it->current_id++, ret);
+	int id_max = sql_session_opt_id_max();
+	for (; it->current_id < id_max; ++it->current_id) {
+		int compare = sql_session_opt_compare(it->key, it->current_id);
+		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;
+	}
+	return sql_session_opt_tuple(it->format, it->current_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->key == NULL)
+		return sql_session_opt_tuple(it->format, it->current_id--, ret);
+	for (; it->current_id >= 0; --it->current_id) {
+		int compare = sql_session_opt_compare(it->key, it->current_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;
+	}
+	return sql_session_opt_tuple(it->format, it->current_id--, ret);
+}
+
+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);
+		decoded_key = (char *)malloc(len + 1);
+		if (decoded_key == NULL) {
+			diag_set(OutOfMemory, len + 1, "malloc", "decoded_key");
+			return NULL;
+		}
+		memcpy(decoded_key, name, len);
+		decoded_key[len] = '\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;
+	}
+	int current_id = iterator_type_is_reverse(type) ?
+			 sql_session_opt_id_max() - 1 : 0;
+	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->current_id = current_id;
+	return (struct iterator *)it;
+}
diff --git a/src/box/session.h b/src/box/session.h
index eff3d7a..f5e3cf2 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
@@ -347,6 +350,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..604c3d2 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,41 @@ 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 session
+ * option.
+ *
+ * @retval Next number after the last SQL option.
+ */
+uint32_t
+sql_session_opt_id_max();
+
+/**
+ * Return an integer less than, equal to, or greater than zero if
+ * name of session 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_session_opt_compare(const char *key, uint32_t id);
+
+/**
+ * Create a tuple that contains the name and value of the SQL
+ * session 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_session_opt_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..ce87b88 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,142 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name,
 	*fieldno = i;
 	return 0;
 }
+
+/**
+ * Identifiers of all SQL session options that can be viewed. The
+ * identifier of the option is equal to its place in the sorted
+ * list of session options, which starts at 0.
+ *
+ * It is IMPORTANT that these 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_SESSION_OPTION_DEFAULT_ENGINE = 0,
+	SQL_SESSION_OPTION_DEFER_FOREIGN_KEYS,
+	SQL_SESSION_OPTION_FULL_COLUMN_NAMES,
+#ifndef NDEBUG
+	SQL_SESSION_OPTION_PARSER_TRACE,
+#endif
+	SQL_SESSION_OPTION_RECURSIVE_TRIGGERS,
+	SQL_SESSION_OPTION_REVERSE_UNORDERED_SELECTS,
+#ifndef NDEBUG
+	SQL_SESSION_OPTION_SELECT_TRACE,
+	SQL_SESSION_OPTION_TRACE,
+	SQL_SESSION_OPTION_VDBE_ADDOPTRACE,
+	SQL_SESSION_OPTION_VDBE_DEBUG,
+	SQL_SESSION_OPTION_VDBE_EQP,
+	SQL_SESSION_OPTION_VDBE_LISTING,
+	SQL_SESSION_OPTION_VDBE_TRACE,
+	SQL_SESSION_OPTION_WHERE_TRACE,
+#endif
+	SQL_SESSION_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 session 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_session_opts[] = {
+	/** SQL_SESSION_OPTION_DEFAULT_ENGINE */
+	{"sql_default_engine", FIELD_TYPE_STRING, 0},
+	/** SQL_SESSION_OPTION_DEFER_FOREIGN_KEYS */
+	{"sql_defer_foreign_keys", FIELD_TYPE_BOOLEAN, SQL_DeferFKs},
+	/** SQL_SESSION_OPTION_FULL_COLUMN_NAMES */
+	{"sql_full_column_names", FIELD_TYPE_BOOLEAN, SQL_FullColNames},
+#ifndef NDEBUG
+	/** SQL_SESSION_OPTION_PARSER_TRACE */
+	{"sql_parser_trace", FIELD_TYPE_BOOLEAN, PARSER_TRACE_FLAG},
+#endif
+	/** SQL_SESSION_OPTION_RECURSIVE_TRIGGERS */
+	{"sql_recursive_triggers", FIELD_TYPE_BOOLEAN, SQL_RecTriggers},
+	/** SQL_SESSION_OPTION_REVERSE_UNORDERED_SELECTS */
+	{"sql_reverse_unordered_selects", FIELD_TYPE_BOOLEAN, SQL_ReverseOrder},
+#ifndef NDEBUG
+	/** SQL_SESSION_OPTION_SELECT_TRACE */
+	{"sql_select_trace", FIELD_TYPE_BOOLEAN, SQL_SelectTrace},
+	/** SQL_SESSION_OPTION_TRACE */
+	{"sql_trace", FIELD_TYPE_BOOLEAN, SQL_SqlTrace},
+	/** SQL_SESSION_OPTION_VDBE_ADDOPTRACE */
+	{"sql_vdbe_addoptrace", FIELD_TYPE_BOOLEAN, SQL_VdbeAddopTrace},
+	/** SQL_SESSION_OPTION_VDBE_DEBUG */
+	{"sql_vdbe_debug", FIELD_TYPE_BOOLEAN,
+	 SQL_SqlTrace | SQL_VdbeListing | SQL_VdbeTrace},
+	/** SQL_SESSION_OPTION_VDBE_EQP */
+	{"sql_vdbe_eqp", FIELD_TYPE_BOOLEAN, SQL_VdbeEQP},
+	/** SQL_SESSION_OPTION_VDBE_LISTING */
+	{"sql_vdbe_listing", FIELD_TYPE_BOOLEAN, SQL_VdbeListing},
+	/** SQL_SESSION_OPTION_VDBE_TRACE */
+	{"sql_vdbe_trace", FIELD_TYPE_BOOLEAN, SQL_VdbeTrace},
+	/** SQL_SESSION_OPTION_WHERE_TRACE */
+	{"sql_where_trace", FIELD_TYPE_BOOLEAN, SQL_WhereTrace},
+#endif
+};
+
+uint32_t
+sql_session_opt_id_max()
+{
+	return SQL_SESSION_OPTION_max;
+}
+
+int
+sql_session_opt_compare(const char *key, uint32_t id)
+{
+	assert(id < SQL_SESSION_OPTION_max);
+	return strcmp(sql_session_opts[id].name, key);
+}
+
+int
+sql_session_opt_tuple(struct tuple_format *format, int option_id,
+		 struct tuple **result)
+{
+	if (option_id < 0 || option_id >= SQL_SESSION_OPTION_max) {
+		*result = NULL;
+		return 0;
+	}
+	struct session *session = current_session();
+	uint32_t flags = session->sql_flags;
+	uint32_t mask = sql_session_opts[option_id].mask;
+	const char *engine = NULL;
+	/* 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_session_opts[option_id].name));
+	if (sql_session_opts[option_id].field_type == FIELD_TYPE_BOOLEAN) {
+		size += mp_sizeof_bool(true);
+	} else {
+		assert(option_id == SQL_SESSION_OPTION_DEFAULT_ENGINE);
+		engine = sql_storage_engine_strs[session->sql_default_engine];
+		size += mp_sizeof_str(strlen(engine));
+	}
+
+	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_session_opts[option_id].name,
+			    strlen(sql_session_opts[option_id].name));
+	if (sql_session_opts[option_id].field_type == FIELD_TYPE_BOOLEAN)
+		pos = mp_encode_bool(pos, (flags & mask) == mask);
+	else
+		pos = mp_encode_str(pos, engine, strlen(engine));
+	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 1f33dec..c032248 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{}
 ---
@@ -743,3 +743,121 @@ s = box.space._space:create_index('owner', {parts = { 2, 'unsigned' }, id = 1, u
 session = nil
 ---
 ...
+--
+-- gh-4511: make sure that _vsession_settings sysview works as
+-- intended.
+--
+v = box.space._vsession_settings
+---
+...
+v:format()
+---
+- [{'name': 'name', 'type': 'string'}, {'name': 'value', 'type': 'any'}]
+...
+s = box.schema.space.create('settings', {format = v:format()})
+---
+...
+_ = s:create_index('primary')
+---
+...
+for _,value in v:pairs() do s:insert(value) end
+---
+...
+env = require('test_run')
+---
+...
+test_run = env.new()
+---
+...
+test_run:cmd('setopt delimiter ";"')
+---
+- true
+...
+function check_sorting(vs, ts, key)
+    local is_right = true
+    local iterators_list = {'ALL', 'REQ', 'EQ', 'GE', 'GT', 'LE', 'LT'}
+    for _, it in pairs(iterators_list) do
+        local view_space = vs:select({key}, {iterator = it})
+        local test_space = ts:select({key}, {iterator = it})
+        for key, value in pairs(view_space) do
+            is_right = is_right and (test_space[key].name == value.name)
+        end
+    end
+    return is_right
+end;
+---
+...
+test_run:cmd('setopt delimiter ""');
+---
+- true
+...
+check_sorting(v, s)
+---
+- true
+...
+check_sorting(v, s, 'abcde')
+---
+- true
+...
+check_sorting(v, s, 'sql_d')
+---
+- true
+...
+check_sorting(v, s, 'sql_v')
+---
+- true
+...
+check_sorting(v, s, 'sql_defer_foreign_keys')
+---
+- true
+...
+-- 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_default_engine'})
+---
+- ['sql_default_engine', 'memtx']
+...
+v:get({'abcd'})
+---
+...
+-- 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 v:pairs() do table.insert(t, {key, value}) end
+---
+...
+#t == v:count()
+---
+- 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/access_sysview.test.lua b/test/box/access_sysview.test.lua
index 17420ae..a35a79c 100644
--- a/test/box/access_sysview.test.lua
+++ b/test/box/access_sysview.test.lua
@@ -308,3 +308,57 @@ s = box.space._space:create_index('owner', {parts = { 2, 'unsigned' }, id = 1, u
 #box.space._vspace.index[1]:select(1) > 0
 
 session = nil
+
+--
+-- gh-4511: make sure that _vsession_settings sysview works as
+-- intended.
+--
+
+v = box.space._vsession_settings
+v:format()
+
+s = box.schema.space.create('settings', {format = v:format()})
+_ = s:create_index('primary')
+for _,value in v:pairs() do s:insert(value) end
+
+env = require('test_run')
+test_run = env.new()
+test_run:cmd('setopt delimiter ";"')
+function check_sorting(vs, ts, key)
+    local is_right = true
+    local iterators_list = {'ALL', 'REQ', 'EQ', 'GE', 'GT', 'LE', 'LT'}
+    for _, it in pairs(iterators_list) do
+        local view_space = vs:select({key}, {iterator = it})
+        local test_space = ts:select({key}, {iterator = it})
+        for key, value in pairs(view_space) do
+            is_right = is_right and (test_space[key].name == value.name)
+        end
+    end
+    return is_right
+end;
+test_run:cmd('setopt delimiter ""');
+
+check_sorting(v, s)
+check_sorting(v, s, 'abcde')
+check_sorting(v, s, 'sql_d')
+check_sorting(v, s, 'sql_v')
+check_sorting(v, s, 'sql_defer_foreign_keys')
+
+-- Check get() method.
+v:get({'sql_defer_foreign_keys'})
+v:get({'sql_recursive_triggers'})
+v:get({'sql_reverse_unordered_selects'})
+v:get({'sql_default_engine'})
+v:get({'abcd'})
+
+-- 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 v:pairs() do table.insert(t, {key, value}) end
+#t == v:count()
+
+-- Make sure that SQL SELECT works.
+box.execute([[SELECT * from "_vsession_settings" WHERE "name" = 'sql_default_engine']])
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/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] 30+ messages in thread

* [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 1/5] sysview: make get() and create_iterator() methods virtual imeevma
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 2/5] box: introdice _vsession_settings sysview imeevma
@ 2019-11-07 10:36 ` imeevma
  2019-11-07 12:40   ` Vladislav Shpilevoy
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 4/5] temporary: disable boolean.test.sql imeevma
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 30+ messages in thread
From: imeevma @ 2019-11-07 10:36 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches

Due to the removal of sql_compound_select_limit from the session
options, this patch has been modified.

New patch:

From 12ed4be2e7e433fdca58a43fc3b937eb9a54f52f 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 ce87b88..77f8dd4 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -3275,6 +3275,21 @@ enum {
 	SQL_SESSION_OPTION_max,
 };
 
+
+/**
+ * Identifiers of all SQL global options that can be viewed. The
+ * identifier of the option is equal to its place in the sorted
+ * list of global options, which starts at 0.
+ *
+ * It is IMPORTANT that these 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_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT = 0,
+	SQL_GLOBAL_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
@@ -3329,6 +3344,17 @@ static struct sql_option_metadata sql_session_opts[] = {
 #endif
 };
 
+/**
+ * Variable that contains names of the SQL global 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_global_opts[] = {
+	/** SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT */
+	{"sql_compound_select_limit", FIELD_TYPE_INTEGER, 0},
+};
+
 uint32_t
 sql_session_opt_id_max()
 {
@@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
 	*result = tuple;
 	return 0;
 }
+
+static void
+sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
+{
+	struct session *session = current_session();
+	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
+			if (is_set)
+				sqlParserTrace(stdout, "parser: ");
+			else
+				sqlParserTrace(NULL, NULL);
+		}
+#endif
+	} else {
+		assert(id == SQL_SESSION_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;
+	}
+}
+
+static void
+sql_set_global_option(struct Parse *parse_context, int id, struct Expr *value)
+{
+	(void)id;
+	assert(id == SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT);
+	int limit = value->u.iValue;
+	if (sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, limit) < 0)
+		parse_context->is_aborted = true;
+}
+
+void
+sql_set_settings(struct Parse *parse_context, struct Token *name,
+		 struct Expr *value)
+{
+	int option_id;
+	char *name_str = sql_name_from_token(sql_get(), name);
+	if (name_str == NULL) {
+		parse_context->is_aborted = true;
+		return;
+	}
+	/* Try to find the option among the session options. */
+	for (option_id = 0; option_id < SQL_SESSION_OPTION_max; ++option_id) {
+		if (strcasecmp(sql_session_opts[option_id].name, name_str) == 0)
+			break;
+	}
+	if (option_id < SQL_SESSION_OPTION_max)
+		return sql_set_session_option(parse_context, option_id, value);
+	/* Try to find the option among the global options. */
+	for (option_id = 0; option_id < SQL_GLOBAL_OPTION_max; ++option_id) {
+		if (strcasecmp(sql_global_opts[option_id].name, name_str) == 0)
+			break;
+	}
+	if (option_id < SQL_GLOBAL_OPTION_max)
+		return sql_set_global_option(parse_context, option_id, value);
+	diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Setting is not found");
+	parse_context->is_aborted = true;
+	return;
+}
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 2594b73..8a2e370 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4467,4 +4467,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..632293a 100644
--- a/test/sql/sql-debug.result
+++ b/test/sql/sql-debug.result
@@ -54,3 +54,131 @@ 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_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']
+...
+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_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] 30+ messages in thread

* [Tarantool-patches] [PATCH v3 4/5] temporary: disable boolean.test.sql
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
                   ` (2 preceding siblings ...)
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement imeevma
@ 2019-11-07 10:36 ` imeevma
  2019-11-07 10:37 ` [Tarantool-patches] [PATCH v3 5/5] sql: replace control pragmas imeevma
  2019-12-06 11:37 ` [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET Kirill Yukhin
  5 siblings, 0 replies; 30+ messages in thread
From: imeevma @ 2019-11-07 10:36 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: 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] 30+ messages in thread

* [Tarantool-patches] [PATCH v3 5/5] sql: replace control pragmas
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
                   ` (3 preceding siblings ...)
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 4/5] temporary: disable boolean.test.sql imeevma
@ 2019-11-07 10:37 ` imeevma
  2019-12-06 11:37 ` [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET Kirill Yukhin
  5 siblings, 0 replies; 30+ messages in thread
From: imeevma @ 2019-11-07 10:37 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: 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
---
Due to the removal of sql_compound_select_limit from the session
options, the sql-tap/gh2548-select-component-limit.test.lua test
has been slightly modified.

 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 |  16 +-
 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, 213 insertions(+), 996 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 8a2e370..40fa7cb 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3950,8 +3950,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 03c63d8..cd60e28 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..cd1a79e 100755
--- a/test/sql-tap/gh2548-select-compound-limit.test.lua
+++ b/test/sql-tap/gh2548-select-compound-limit.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(14)
+test:plan(13)
 
 -- box.cfg{wal_mode='none'}
 
@@ -53,7 +53,6 @@ for _, term in ipairs({'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT'}) do
 --    end
 end
 
-
 test:do_catchsql_test(
     "gh2548-select-compound-limit-2",
     select_string_last, {
@@ -62,21 +61,24 @@ test:do_catchsql_test(
         -- </gh2548-select-compound-limit-2>
     })
 
+-- Currently there is no way to get this option value.
+if (0 > 0) then
 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
         -- </gh2548-select-compound-limit-3.1>
     })
+end
 
 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
         -- </gh2548-select-compound-limit-3.2>
 })
 
@@ -90,10 +92,10 @@ 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
         -- </gh2548-select-compound-limit-3.4>
     })
 
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 632293a..e2d60a9 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] 30+ messages in thread

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement imeevma
@ 2019-11-07 12:40   ` Vladislav Shpilevoy
  2019-11-07 14:12     ` Mergen Imeev
  0 siblings, 1 reply; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-07 12:40 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

Hi! Thanks for the fixes!

See 5 comments below.

On 07/11/2019 13:36, imeevma@tarantool.org wrote:
> Due to the removal of sql_compound_select_limit from the session
> options, this patch has been modified.
> 
> New patch:
> 
> From 12ed4be2e7e433fdca58a43fc3b937eb9a54f52f 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;

1. I tried this:

tarantool> box.execute('SET full_column_names = true;')
---
- null
- Setting is not found
...

???

> SET sql_compound_select_limit = 10;
> SET sql_default_engine = 'memtx';

2. It would be cool to sum up here what is a purpose of
PRAGMA and SET. How are they different. From the code I
see, that looks like PRAGMA never changes anything. It
only returns something. While SET only sets and never
returns, right?

In the next patch I see diff like this:

> -        return test:execsql "PRAGMA full_column_names"
> -    end, {
> +        return box.space._vsession_settings:get("sql_full_column_names").value
> +    end,

Is there any plan how to make it simpler? Seems like it is
impossible for a user to get session settings other than via
direct select from a system space. It was simpler with PRAGMA.

> 
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index ce87b88..77f8dd4 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -3275,6 +3275,21 @@ enum {
>  	SQL_SESSION_OPTION_max,
>  };
>  
> +

3. Nit: unnecessary empty line.

> +/**
> + * Identifiers of all SQL global options that can be viewed. The
> + * identifier of the option is equal to its place in the sorted
> + * list of global options, which starts at 0.
> + *
> + * It is IMPORTANT that these 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.

4. First question - why should they be sorted? Second question -
aren't they removed from _vsession_settings space?

> + */
> +enum {
> +	SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT = 0,
> +	SQL_GLOBAL_OPTION_max,
> +};
> @@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
>  	*result = tuple;
>  	return 0;
>  }
> +
> +static void
> +sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
> +{
> +	struct session *session = current_session();
> +	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
> +			if (is_set)
> +				sqlParserTrace(stdout, "parser: ");
> +			else
> +				sqlParserTrace(NULL, NULL);
> +		}
> +#endif
> +	} else {
> +		assert(id == SQL_SESSION_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;
> +	}
> +}

5. Wait. So the settings are set during parsing? Isn't it wrong?
'Parser only parses' and everything? PRAGMA works in runtime.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-07 12:40   ` Vladislav Shpilevoy
@ 2019-11-07 14:12     ` Mergen Imeev
  2019-11-11 21:56       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 30+ messages in thread
From: Mergen Imeev @ 2019-11-07 14:12 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

Thank you for review! My answers, new commit-message and
diff below.

On Thu, Nov 07, 2019 at 03:40:39PM +0300, Vladislav Shpilevoy wrote:
> Hi! Thanks for the fixes!
> 
> See 5 comments below.
> 
> On 07/11/2019 13:36, imeevma@tarantool.org wrote:
> > Due to the removal of sql_compound_select_limit from the session
> > options, this patch has been modified.
> > 
> > New patch:
> > 
> > From 12ed4be2e7e433fdca58a43fc3b937eb9a54f52f 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;
> 
> 1. I tried this:
> 
> tarantool> box.execute('SET full_column_names = true;')
> ---
> - null
> - Setting is not found
> ...
> 
> ???
> 
Fixed commit-message. Now this option called
'sql_full_column_names'.

> > SET sql_compound_select_limit = 10;
> > SET sql_default_engine = 'memtx';
> 
> 2. It would be cool to sum up here what is a purpose of
> PRAGMA and SET. How are they different. From the code I
> see, that looks like PRAGMA never changes anything. It
> only returns something. While SET only sets and never
> returns, right?
> 
How pragma works:
PRAGMA vdbe_trace = true; -- Sets vdbe_trace, returns nothing.
PRAGMA vdbe_trace; -- Returns current value of vdbe_trace flag.

How SET works:
SET sql_vdbe_trace = true; -- Sets vdbe_trace, returns nothing.

> In the next patch I see diff like this:
> 
> > -        return test:execsql "PRAGMA full_column_names"
> > -    end, {
> > +        return box.space._vsession_settings:get("sql_full_column_names").value
> > +    end,
> 
> Is there any plan how to make it simpler? Seems like it is
> impossible for a user to get session settings other than via
> direct select from a system space. It was simpler with PRAGMA.
> 
As far as I know, there is no such plans. It definitely was
simpler with PRAGMA, but it was decided to remove PRAGMA.
I do not know exact reaso why.

> > 
> > diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> > index ce87b88..77f8dd4 100644
> > --- a/src/box/sql/build.c
> > +++ b/src/box/sql/build.c
> > @@ -3275,6 +3275,21 @@ enum {
> >  	SQL_SESSION_OPTION_max,
> >  };
> >  
> > +
> 
> 3. Nit: unnecessary empty line.
> 
Fixed. Diff below.

> > +/**
> > + * Identifiers of all SQL global options that can be viewed. The
> > + * identifier of the option is equal to its place in the sorted
> > + * list of global options, which starts at 0.
> > + *
> > + * It is IMPORTANT that these 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.
> 
> 4. First question - why should they be sorted? Second question -
> aren't they removed from _vsession_settings space?
> 
Fixed:
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -3275,16 +3275,7 @@ enum {
 	SQL_SESSION_OPTION_max,
 };
 
-
-/**
- * Identifiers of all SQL global options that can be viewed. The
- * identifier of the option is equal to its place in the sorted
- * list of global options, which starts at 0.
- *
- * It is IMPORTANT that these 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.
- */
+/**  Identifiers of all SQL global options that can be set. */
 enum {
 	SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT = 0,
 	SQL_GLOBAL_OPTION_max,
@@ -3347,8 +3338,6 @@ static struct sql_option_metadata sql_session_opts[] = {
 /**
  * Variable that contains names of the SQL global 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_global_opts[] = {
 	/** SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT */


> > + */
> > +enum {
> > +	SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT = 0,
> > +	SQL_GLOBAL_OPTION_max,
> > +};
> > @@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
> >  	*result = tuple;
> >  	return 0;
> >  }
> > +
> > +static void
> > +sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
> > +{
> > +	struct session *session = current_session();
> > +	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
> > +			if (is_set)
> > +				sqlParserTrace(stdout, "parser: ");
> > +			else
> > +				sqlParserTrace(NULL, NULL);
> > +		}
> > +#endif
> > +	} else {
> > +		assert(id == SQL_SESSION_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;
> > +	}
> > +}
> 
> 5. Wait. So the settings are set during parsing? Isn't it wrong?
> 'Parser only parses' and everything? PRAGMA works in runtime.
No, PRAGMA also set during parsing. I once suggested to
change it, so parser would only parse, but my suggestion
was declined.

Examples of pragma:

tarantool> box.execute('pragma vdbe_trace = 1')
---
- row_count: 0
...

tarantool> box.execute('pragma full_column_names = 1')
SQL: [pragma full_column_names = 1]
VDBE Trace:
 102>    0 Init             0    1    0               00 Start at 1
 102>    1 Halt             0    0    0               00 
---
- row_count: 0
...

tarantool> box.execute('pragma vdbe_trace = 1')
SQL: [pragma vdbe_trace = 1]
VDBE Trace:
 102>    0 Init             0    1    0               00 Start at 1
 102>    1 Halt             0    0    0               00 
---
- row_count: 0
...

New description:

    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'
    
    All of these setting with exception of 'sql_compound_select_limit'
    are session-local settings. Their value can be viewed in
    _vsession_settings sysview.
    
    Example of usage:
    SET sql_full_column_names = true;
    SET sql_compound_select_limit = 10;
    SET sql_default_engine = 'memtx';

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-07 14:12     ` Mergen Imeev
@ 2019-11-11 21:56       ` Vladislav Shpilevoy
  2019-11-15 14:06         ` Mergen Imeev
  0 siblings, 1 reply; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-11 21:56 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

Hi! Thanks for the fixes!

See 3 comments below.

>>> SET sql_compound_select_limit = 10;
>>> SET sql_default_engine = 'memtx';
>>
>> 2. It would be cool to sum up here what is a purpose of
>> PRAGMA and SET. How are they different. From the code I
>> see, that looks like PRAGMA never changes anything. It
>> only returns something. While SET only sets and never
>> returns, right?
>>
> How pragma works:
> PRAGMA vdbe_trace = true; -- Sets vdbe_trace, returns nothing.
> PRAGMA vdbe_trace; -- Returns current value of vdbe_trace flag.

1. These PRAGMAs don't exist anymore. I wanted to understand
how rest of the pragmas (not removed) coexist with SET. When a
user should try to look at PRAGMA list, and when at SET list?

> 
> How SET works:
> SET sql_vdbe_trace = true; -- Sets vdbe_trace, returns nothing.
> 
>> In the next patch I see diff like this:
>>
>>> -        return test:execsql "PRAGMA full_column_names"
>>> -    end, {
>>> +        return box.space._vsession_settings:get("sql_full_column_names").value
>>> +    end,
>>
>> Is there any plan how to make it simpler? Seems like it is
>> impossible for a user to get session settings other than via
>> direct select from a system space. It was simpler with PRAGMA.
>>
> As far as I know, there is no such plans. It definitely was
> simpler with PRAGMA, but it was decided to remove PRAGMA.
> I do not know exact reaso why.
> 

2. Ok, but now it looks really unusable when a user want's to
learn an option value. I will create a ticket, if this patchset
will be pushed and nobody will care about usability beforehand.

>>> @@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
>>>  	*result = tuple;
>>>  	return 0;
>>>  }
>>> +
>>> +static void
>>> +sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
>>> +{
>>> +	struct session *session = current_session();
>>> +	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
>>> +			if (is_set)
>>> +				sqlParserTrace(stdout, "parser: ");
>>> +			else
>>> +				sqlParserTrace(NULL, NULL);
>>> +		}
>>> +#endif
>>> +	} else {
>>> +		assert(id == SQL_SESSION_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;
>>> +	}
>>> +}
>>
>> 5. Wait. So the settings are set during parsing? Isn't it wrong?
>> 'Parser only parses' and everything? PRAGMA works in runtime.
> No, PRAGMA also set during parsing. I once suggested to
> change it, so parser would only parse, but my suggestion
> was declined.

3. This is bad and should be fixed.
https://github.com/tarantool/tarantool/issues/4621

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-11 21:56       ` Vladislav Shpilevoy
@ 2019-11-15 14:06         ` Mergen Imeev
  2019-11-17 17:26           ` Vladislav Shpilevoy
  0 siblings, 1 reply; 30+ messages in thread
From: Mergen Imeev @ 2019-11-15 14:06 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

Hi! Thank you for review. My answers, diff and new version
below.

On Mon, Nov 11, 2019 at 10:56:46PM +0100, Vladislav Shpilevoy wrote:
> Hi! Thanks for the fixes!
> 
> See 3 comments below.
> 
> >>> SET sql_compound_select_limit = 10;
> >>> SET sql_default_engine = 'memtx';
> >>
> >> 2. It would be cool to sum up here what is a purpose of
> >> PRAGMA and SET. How are they different. From the code I
> >> see, that looks like PRAGMA never changes anything. It
> >> only returns something. While SET only sets and never
> >> returns, right?
> >>
> > How pragma works:
> > PRAGMA vdbe_trace = true; -- Sets vdbe_trace, returns nothing.
> > PRAGMA vdbe_trace; -- Returns current value of vdbe_trace flag.
> 
> 1. These PRAGMAs don't exist anymore. I wanted to understand
> how rest of the pragmas (not removed) coexist with SET. When a
> user should try to look at PRAGMA list, and when at SET list?
> 
All pragmas that remain after pushing this patch-set are
informational. Since they do not change any sql settings, I think
there will be no problems. I mean these pragmas: table_info,
stats, index_info, index_list, collation_list, foreign_key_list.

> > 
> > How SET works:
> > SET sql_vdbe_trace = true; -- Sets vdbe_trace, returns nothing.
> > 
> >> In the next patch I see diff like this:
> >>
> >>> -        return test:execsql "PRAGMA full_column_names"
> >>> -    end, {
> >>> +        return box.space._vsession_settings:get("sql_full_column_names").value
> >>> +    end,
> >>
> >> Is there any plan how to make it simpler? Seems like it is
> >> impossible for a user to get session settings other than via
> >> direct select from a system space. It was simpler with PRAGMA.
> >>
> > As far as I know, there is no such plans. It definitely was
> > simpler with PRAGMA, but it was decided to remove PRAGMA.
> > I do not know exact reaso why.
> > 
> 
> 2. Ok, but now it looks really unusable when a user want's to
> learn an option value. I will create a ticket, if this patchset
> will be pushed and nobody will care about usability beforehand.
> 
I think this is fair, but I suggest creating an issue and moving
it to later releases.

> >>> @@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
> >>>  	*result = tuple;
> >>>  	return 0;
> >>>  }
> >>> +
> >>> +static void
> >>> +sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
> >>> +{
> >>> +	struct session *session = current_session();
> >>> +	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
> >>> +			if (is_set)
> >>> +				sqlParserTrace(stdout, "parser: ");
> >>> +			else
> >>> +				sqlParserTrace(NULL, NULL);
> >>> +		}
> >>> +#endif
> >>> +	} else {
> >>> +		assert(id == SQL_SESSION_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;
> >>> +	}
> >>> +}
> >>
> >> 5. Wait. So the settings are set during parsing? Isn't it wrong?
> >> 'Parser only parses' and everything? PRAGMA works in runtime.
> > No, PRAGMA also set during parsing. I once suggested to
> > change it, so parser would only parse, but my suggestion
> > was declined.
> 
> 3. This is bad and should be fixed.
> https://github.com/tarantool/tarantool/issues/4621
Fixed. Since control pragmas will be deleted, SET is now
using VDBE I closed the issue in this commit. Still, it
may be better to close it in the last commit of the
patch-set. Should I move it to the last commit?


Diff:

From dc43af324da16f031b712b28805575e770ac4e7e Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Thu, 14 Nov 2019 20:03:45 +0300
Subject: [PATCH] Review fix


diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 322ba41..8e3ba6a 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -3398,17 +3398,17 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
 	return 0;
 }
 
-static void
-sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
+int
+sql_set_session_option(int id, void *opt_value)
 {
+	struct Expr *value = (struct Expr *)opt_value;
 	struct session *session = current_session();
 	struct sql_option_metadata *option = &sql_session_opts[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;
+		return -1;
 	}
 	if (value->type == FIELD_TYPE_BOOLEAN) {
 		bool is_set = value->op == TK_TRUE;
@@ -3429,49 +3429,53 @@ sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
 		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;
+			return -1;
 		}
 		current_session()->sql_default_engine = engine;
 	}
+	return 0;
 }
 
-static void
-sql_set_global_option(struct Parse *parse_context, int id, struct Expr *value)
+int
+sql_set_global_option(int id, void *opt_value)
 {
+	struct Expr *value = (struct Expr *)opt_value;
 	(void)id;
 	assert(id == SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT);
 	int limit = value->u.iValue;
-	if (sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, limit) < 0)
-		parse_context->is_aborted = true;
+	int rc = sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, limit);
+	assert(rc >= 0);
+	return rc < 0 ? -1 : 0;
 }
 
 void
 sql_set_settings(struct Parse *parse_context, struct Token *name,
 		 struct Expr *value)
 {
-	int option_id;
+	int opt_id;
+	const char *val = (const char*) value;
+	struct Vdbe *vdbe = sqlGetVdbe(parse_context);
 	char *name_str = sql_name_from_token(sql_get(), name);
 	if (name_str == NULL) {
 		parse_context->is_aborted = true;
 		return;
 	}
 	/* Try to find the option among the session options. */
-	for (option_id = 0; option_id < SQL_SESSION_OPTION_max; ++option_id) {
-		if (strcasecmp(sql_session_opts[option_id].name, name_str) == 0)
-			break;
+	for (opt_id = 0; opt_id < SQL_SESSION_OPTION_max; ++opt_id) {
+		if (strcasecmp(sql_session_opts[opt_id].name, name_str) == 0) {
+			sqlVdbeAddOp4(vdbe, OP_Set, 0, opt_id, 0, val, P4_PTR);
+			return;
+		}
 	}
-	if (option_id < SQL_SESSION_OPTION_max)
-		return sql_set_session_option(parse_context, option_id, value);
 	/* Try to find the option among the global options. */
-	for (option_id = 0; option_id < SQL_GLOBAL_OPTION_max; ++option_id) {
-		if (strcasecmp(sql_global_opts[option_id].name, name_str) == 0)
-			break;
+	for (opt_id = 0; opt_id < SQL_GLOBAL_OPTION_max; ++opt_id) {
+		if (strcasecmp(sql_global_opts[opt_id].name, name_str) == 0) {
+			sqlVdbeAddOp4(vdbe, OP_Set, 1, opt_id, 0, val, P4_PTR);
+			return;
+		}
 	}
-	if (option_id < SQL_GLOBAL_OPTION_max)
-		return sql_set_global_option(parse_context, option_id, value);
 	diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Setting is not found");
 	parse_context->is_aborted = true;
 	return;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 8a2e370..75977ce 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4468,17 +4468,38 @@ sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name,
 		    uint32_t *fieldno);
 
 /**
- * Set new value for SQL setting.
+ * Create VDBE instructions to set new value of 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.
+ * @param name Name of the SQL setting.
+ * @param value New value of the SQL setting.
  */
 void
 sql_set_settings(struct Parse *parse_context, struct Token *name,
 		 struct Expr *value);
 
+/**
+ * Set new value to session-local SQL setting.
+ *
+ * @param if ID of the SQL setting.
+ * @param value New value of the SQL setting.
+ *
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+int
+sql_set_session_option(int id, void *opt_value);
+
+/**
+ * Set new value to global SQL setting.
+ *
+ * @param if ID of the SQL setting.
+ * @param value New value of the SQL setting.
+ *
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+int
+sql_set_global_option(int id, void *opt_value);
+
 #endif				/* sqlINT_H */
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index ab86be9..f45e4ff 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -5281,6 +5281,26 @@ case OP_IncMaxid: {
 	break;
 }
 
+/* Opcode: Set P1 P2 * P4 *
+ *
+ * Set new value to SQL setting. P1 is either 0 or 1. If P1 == 0,
+ * than this is session setting. If P1 == 1, than this is global
+ * setting. P2 is ID of the setting. P4 is actually of type
+ * "struct Expr *" and contains value of the setting.
+ */
+case OP_Set: {
+	assert(pOp->p1 == 0 || pOp->p1 == 1);
+	assert(pOp->p4type == P4_PTR);
+	if (pOp->p1 == 0) {
+		if (sql_set_session_option(pOp->p2, pOp->p4.p) != 0)
+			goto abort_due_to_error;
+	} else {
+		if (sql_set_global_option(pOp->p2, pOp->p4.p) != 0)
+			goto abort_due_to_error;
+	}
+	break;
+}
+
 /* Opcode: Noop * * * * *
  *
  * Do nothing.  This instruction is often useful as a jump



New patch:

From 36cede6e91074df11fb0eefdab9141cdfac0a4d5 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
Closes #4621

@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'

All of these setting with exception of 'sql_compound_select_limit'
are session-local settings. Their value can be viewed in
_vsession_settings sysview.

Example of usage:
SET sql_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 ce87b88..8e3ba6a 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -3275,6 +3275,12 @@ enum {
 	SQL_SESSION_OPTION_max,
 };
 
+/**  Identifiers of all SQL global options that can be set. */
+enum {
+	SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT = 0,
+	SQL_GLOBAL_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
@@ -3329,6 +3335,15 @@ static struct sql_option_metadata sql_session_opts[] = {
 #endif
 };
 
+/**
+ * Variable that contains names of the SQL global options, their
+ * field types and mask if they have one or 0 if don't have.
+ */
+static struct sql_option_metadata sql_global_opts[] = {
+	/** SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT */
+	{"sql_compound_select_limit", FIELD_TYPE_INTEGER, 0},
+};
+
 uint32_t
 sql_session_opt_id_max()
 {
@@ -3382,3 +3397,86 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
 	*result = tuple;
 	return 0;
 }
+
+int
+sql_set_session_option(int id, void *opt_value)
+{
+	struct Expr *value = (struct Expr *)opt_value;
+	struct session *session = current_session();
+	struct sql_option_metadata *option = &sql_session_opts[id];
+	if (value->type != option->field_type) {
+		diag_set(ClientError, ER_INCONSISTENT_TYPES,
+			 field_type_strs[option->field_type],
+			 field_type_strs[value->type]);
+		return -1;
+	}
+	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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
+			if (is_set)
+				sqlParserTrace(stdout, "parser: ");
+			else
+				sqlParserTrace(NULL, NULL);
+		}
+#endif
+	} else {
+		assert(id == SQL_SESSION_OPTION_DEFAULT_ENGINE);
+		enum sql_storage_engine engine =
+			STR2ENUM(sql_storage_engine, value->u.zToken);
+		if (engine == sql_storage_engine_MAX) {
+			diag_set(ClientError, ER_NO_SUCH_ENGINE,
+				 value->u.zToken);
+			return -1;
+		}
+		current_session()->sql_default_engine = engine;
+	}
+	return 0;
+}
+
+int
+sql_set_global_option(int id, void *opt_value)
+{
+	struct Expr *value = (struct Expr *)opt_value;
+	(void)id;
+	assert(id == SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT);
+	int limit = value->u.iValue;
+	int rc = sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, limit);
+	assert(rc >= 0);
+	return rc < 0 ? -1 : 0;
+}
+
+void
+sql_set_settings(struct Parse *parse_context, struct Token *name,
+		 struct Expr *value)
+{
+	int opt_id;
+	const char *val = (const char*) value;
+	struct Vdbe *vdbe = sqlGetVdbe(parse_context);
+	char *name_str = sql_name_from_token(sql_get(), name);
+	if (name_str == NULL) {
+		parse_context->is_aborted = true;
+		return;
+	}
+	/* Try to find the option among the session options. */
+	for (opt_id = 0; opt_id < SQL_SESSION_OPTION_max; ++opt_id) {
+		if (strcasecmp(sql_session_opts[opt_id].name, name_str) == 0) {
+			sqlVdbeAddOp4(vdbe, OP_Set, 0, opt_id, 0, val, P4_PTR);
+			return;
+		}
+	}
+	/* Try to find the option among the global options. */
+	for (opt_id = 0; opt_id < SQL_GLOBAL_OPTION_max; ++opt_id) {
+		if (strcasecmp(sql_global_opts[opt_id].name, name_str) == 0) {
+			sqlVdbeAddOp4(vdbe, OP_Set, 1, opt_id, 0, val, P4_PTR);
+			return;
+		}
+	}
+	diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Setting is not found");
+	parse_context->is_aborted = true;
+	return;
+}
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 2594b73..75977ce 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4467,4 +4467,39 @@ int
 sql_fieldno_by_name(struct Parse *parse_context, struct Expr *field_name,
 		    uint32_t *fieldno);
 
+/**
+ * Create VDBE instructions to set new value of SQL setting.
+ *
+ * @param parse_context Parsing context.
+ * @param name Name of the SQL setting.
+ * @param value New value of the SQL setting.
+ */
+void
+sql_set_settings(struct Parse *parse_context, struct Token *name,
+		 struct Expr *value);
+
+/**
+ * Set new value to session-local SQL setting.
+ *
+ * @param if ID of the SQL setting.
+ * @param value New value of the SQL setting.
+ *
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+int
+sql_set_session_option(int id, void *opt_value);
+
+/**
+ * Set new value to global SQL setting.
+ *
+ * @param if ID of the SQL setting.
+ * @param value New value of the SQL setting.
+ *
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+int
+sql_set_global_option(int id, void *opt_value);
+
 #endif				/* sqlINT_H */
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index ab86be9..f45e4ff 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -5281,6 +5281,26 @@ case OP_IncMaxid: {
 	break;
 }
 
+/* Opcode: Set P1 P2 * P4 *
+ *
+ * Set new value to SQL setting. P1 is either 0 or 1. If P1 == 0,
+ * than this is session setting. If P1 == 1, than this is global
+ * setting. P2 is ID of the setting. P4 is actually of type
+ * "struct Expr *" and contains value of the setting.
+ */
+case OP_Set: {
+	assert(pOp->p1 == 0 || pOp->p1 == 1);
+	assert(pOp->p4type == P4_PTR);
+	if (pOp->p1 == 0) {
+		if (sql_set_session_option(pOp->p2, pOp->p4.p) != 0)
+			goto abort_due_to_error;
+	} else {
+		if (sql_set_global_option(pOp->p2, pOp->p4.p) != 0)
+			goto abort_due_to_error;
+	}
+	break;
+}
+
 /* Opcode: Noop * * * * *
  *
  * Do nothing.  This instruction is often useful as a jump
diff --git a/test/sql/sql-debug.result b/test/sql/sql-debug.result
index b190753..6276bcc 100644
--- a/test/sql/sql-debug.result
+++ b/test/sql/sql-debug.result
@@ -54,3 +54,131 @@ 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_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']
+...
+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_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)..";")

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-15 14:06         ` Mergen Imeev
@ 2019-11-17 17:26           ` Vladislav Shpilevoy
  2019-11-17 20:32             ` Vladislav Shpilevoy
  0 siblings, 1 reply; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-17 17:26 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

Hi! Thanks for the fixes!

See 4 comments below.

>>>>> @@ -3382,3 +3408,82 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
>>>>>  	*result = tuple;
>>>>>  	return 0;
>>>>>  }
>>>>> +
>>>>> +static void
>>>>> +sql_set_session_option(struct Parse *parse_context, int id, struct Expr *value)
>>>>> +{
>>>>> +	struct session *session = current_session();
>>>>> +	struct sql_option_metadata *option = &sql_session_opts[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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
>>>>> +			if (is_set)
>>>>> +				sqlParserTrace(stdout, "parser: ");
>>>>> +			else
>>>>> +				sqlParserTrace(NULL, NULL);
>>>>> +		}
>>>>> +#endif
>>>>> +	} else {
>>>>> +		assert(id == SQL_SESSION_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;
>>>>> +	}
>>>>> +}
>>>>
>>>> 5. Wait. So the settings are set during parsing? Isn't it wrong?
>>>> 'Parser only parses' and everything? PRAGMA works in runtime.
>>> No, PRAGMA also set during parsing. I once suggested to
>>> change it, so parser would only parse, but my suggestion
>>> was declined.
>>
>> 3. This is bad and should be fixed.
>> https://github.com/tarantool/tarantool/issues/4621
> Fixed. Since control pragmas will be deleted, SET is now
> using VDBE I closed the issue in this commit. Still, it
> may be better to close it in the last commit of the
> patch-set. Should I move it to the last commit?

1. You can try to fix it now, it is ok.

Talking of control pragmas, PRAGMA still exists after your
patch. And still works during parsing. I don't know what to
do with it, because I don't know what are we going to do
with PRAGMA. And seems like nobody knows.

> 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
> Closes #4621

2. This commit message is getting worse and worse.
I think it needs to be totally rewritten. Still existing
problems with the current message:

- I don't understand, which pragmas are totally deleted,
  which moved to SET, which of the moved have a new name;

- From the message it still is not clear when a user needs
  to use PRAGMA and when SET. Yes, you said PRAGMA is purely
  informative, but I don't see it in the message. And the
  technical writer, who will see this message out of all
  the discussion, will be very confused with what has
  happened, and will ask for more details, I can guarantee
  that;

- Parts of the message before '@Tarantoolbot document' and
  after are in some ideas different, in some they are totally
  the same. I propose you to remove the part before doc
  request, and write the doc request more accurate. And check
  again that all deleted PRAGMAs really don't work (in the last
  patch), all new SETs really work, with exactly the same names
  as in the commit message;

- I think you need to explain what is a result of SET - metadata
  like DQL? Sql_info like DML/DDL?

> 
> @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'
> 
> All of these setting with exception of 'sql_compound_select_limit'
> are session-local settings. Their value can be viewed in
> _vsession_settings sysview.
> 
> Example of usage:
> SET sql_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 ce87b88..8e3ba6a 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -3382,3 +3397,86 @@ sql_session_opt_tuple(struct tuple_format *format, int option_id,
>  	*result = tuple;
>  	return 0;
>  }
> +
> +int
> +sql_set_session_option(int id, void *opt_value)
> +{
> +	struct Expr *value = (struct Expr *)opt_value;
> +	struct session *session = current_session();
> +	struct sql_option_metadata *option = &sql_session_opts[id];
> +	if (value->type != option->field_type) {
> +		diag_set(ClientError, ER_INCONSISTENT_TYPES,
> +			 field_type_strs[option->field_type],
> +			 field_type_strs[value->type]);
> +		return -1;
> +	}
> +	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 (id == SQL_SESSION_OPTION_PARSER_TRACE) {
> +			if (is_set)
> +				sqlParserTrace(stdout, "parser: ");
> +			else
> +				sqlParserTrace(NULL, NULL);
> +		}
> +#endif
> +	} else {
> +		assert(id == SQL_SESSION_OPTION_DEFAULT_ENGINE);
> +		enum sql_storage_engine engine =
> +			STR2ENUM(sql_storage_engine, value->u.zToken);
> +		if (engine == sql_storage_engine_MAX) {
> +			diag_set(ClientError, ER_NO_SUCH_ENGINE,
> +				 value->u.zToken);
> +			return -1;
> +		}
> +		current_session()->sql_default_engine = engine;
> +	}
> +	return 0;
> +}
> +
> +int
> +sql_set_global_option(int id, void *opt_value)
> +{
> +	struct Expr *value = (struct Expr *)opt_value;
> +	(void)id;
> +	assert(id == SQL_GLOBAL_OPTION_COMPOUND_SELECT_LIMIT);
> +	int limit = value->u.iValue;
> +	int rc = sql_limit(sql_get(), SQL_LIMIT_COMPOUND_SELECT, limit);
> +	assert(rc >= 0);
> +	return rc < 0 ? -1 : 0;
> +}
> +
> +void
> +sql_set_settings(struct Parse *parse_context, struct Token *name,
> +		 struct Expr *value)
> +{
> +	int opt_id;
> +	const char *val = (const char*) value;
> +	struct Vdbe *vdbe = sqlGetVdbe(parse_context);
> +	char *name_str = sql_name_from_token(sql_get(), name);
> +	if (name_str == NULL) {
> +		parse_context->is_aborted = true;
> +		return;
> +	}
> +	/* Try to find the option among the session options. */
> +	for (opt_id = 0; opt_id < SQL_SESSION_OPTION_max; ++opt_id) {
> +		if (strcasecmp(sql_session_opts[opt_id].name, name_str) == 0) {
> +			sqlVdbeAddOp4(vdbe, OP_Set, 0, opt_id, 0, val, P4_PTR);
> +			return;

3. Expr is a parser time structure. You can't use it at runtime.

4. There is a leak. 'val' is not freed.

> +		}
> +	}
> +	/* Try to find the option among the global options. */
> +	for (opt_id = 0; opt_id < SQL_GLOBAL_OPTION_max; ++opt_id) {
> +		if (strcasecmp(sql_global_opts[opt_id].name, name_str) == 0) {
> +			sqlVdbeAddOp4(vdbe, OP_Set, 1, opt_id, 0, val, P4_PTR);
> +			return;
> +		}
> +	}
> +	diag_set(ClientError, ER_SQL_PARSER_GENERIC, "Setting is not found");
> +	parse_context->is_aborted = true;
> +	return;
> +}

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-17 17:26           ` Vladislav Shpilevoy
@ 2019-11-17 20:32             ` Vladislav Shpilevoy
  2019-11-27 10:33               ` Mergen Imeev
  0 siblings, 1 reply; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-17 20:32 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

I was thinking about it, and realized, that SET is
really castrated. For example:

    box.cfg{}
    box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, a BOOLEAN)')
    box.execute('INSERT INTO test VALUES (1, TRUE)')
    tarantool> box.execute('UPDATE test SET a = FALSE AND TRUE')
    ---
    - row_count: 1
    ...

This UPDATE SET works. Settings SET does not work:

    tarantool> box.execute('SET sql_full_column_names = FALSE AND TRUE;')
    ---
    - null
    - Keyword 'AND' is reserved. Please use double quotes if 'AND' is an identifier.
    ...

I think we need to make them working the same. We can't expect that a user
will always pass a trivial constant boolean value.

Binding also does not work:

    tarantool> box.execute('SET sql_full_column_names = ?;', {true})
    ---
    - null
    - Syntax error near '?'
    ...

And as well, we can't force a user to always concatenate its
settings into a query string. At least this is not safe.

But I think this might be moved to 4621 issue. Because PRAGMA
also does not understand complex expressions, nor bound
parameters.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-17 20:32             ` Vladislav Shpilevoy
@ 2019-11-27 10:33               ` Mergen Imeev
  2019-11-27 23:03                 ` Vladislav Shpilevoy
  0 siblings, 1 reply; 30+ messages in thread
From: Mergen Imeev @ 2019-11-27 10:33 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

Hi! Thanks for the suggestion! I think your points are correct,
but I think we should create a new issue after pushing SET.
Issue #4621 about using VDBE in SET/control pragmas. All other
pragmas already use VDBE. Since SET will use VDBE, I think we
should close #4621 with #4511.

I will create this issue when SET is pushed if you have no
objections.


On Sun, Nov 17, 2019 at 09:32:17PM +0100, Vladislav Shpilevoy wrote:
> I was thinking about it, and realized, that SET is
> really castrated. For example:
> 
>     box.cfg{}
>     box.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, a BOOLEAN)')
>     box.execute('INSERT INTO test VALUES (1, TRUE)')
>     tarantool> box.execute('UPDATE test SET a = FALSE AND TRUE')
>     ---
>     - row_count: 1
>     ...
> 
> This UPDATE SET works. Settings SET does not work:
> 
>     tarantool> box.execute('SET sql_full_column_names = FALSE AND TRUE;')
>     ---
>     - null
>     - Keyword 'AND' is reserved. Please use double quotes if 'AND' is an identifier.
>     ...
> 
> I think we need to make them working the same. We can't expect that a user
> will always pass a trivial constant boolean value.
> 
> Binding also does not work:
> 
>     tarantool> box.execute('SET sql_full_column_names = ?;', {true})
>     ---
>     - null
>     - Syntax error near '?'
>     ...
> 
> And as well, we can't force a user to always concatenate its
> settings into a query string. At least this is not safe.
> 
> But I think this might be moved to 4621 issue. Because PRAGMA
> also does not understand complex expressions, nor bound
> parameters.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-27 10:33               ` Mergen Imeev
@ 2019-11-27 23:03                 ` Vladislav Shpilevoy
  2019-11-27 23:07                   ` Vladislav Shpilevoy
  2019-11-28  8:56                   ` Mergen Imeev
  0 siblings, 2 replies; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-27 23:03 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

On 27/11/2019 11:33, Mergen Imeev wrote:
> Hi! Thanks for the suggestion! I think your points are correct,
> but I think we should create a new issue after pushing SET.
> Issue #4621 about using VDBE in SET/control pragmas. All other
> pragmas already use VDBE. Since SET will use VDBE, I think we
> should close #4621 with #4511.

I see that we have different understanding of what it means - use
VDBE. I mean, that option value should be get/set at runtime.
Currently the only thing runtime does is return of metadata. All
the actual work happens at compile time.

To make binding works the only solution is to make
PRAGMA/SET/whatever work at runtime totally. When you will
properly move PRAGMA/SET to VDBE, you will get bindings for
free.

The patchset LGTM. Perhaps. I don't really know what is
our plan on session and SQL settings, so I can only approve the
technical part.

Seems like in our team design decisions about everything work
like 'lets see what PostgreSQL/MySQL/Ya.DB do, and we will do
literally the same'.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-27 23:03                 ` Vladislav Shpilevoy
@ 2019-11-27 23:07                   ` Vladislav Shpilevoy
  2019-11-27 23:09                     ` Vladislav Shpilevoy
  2019-11-28  8:59                     ` Mergen Imeev
  2019-11-28  8:56                   ` Mergen Imeev
  1 sibling, 2 replies; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-27 23:07 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

No, stop. It is not LGTM.

1) Why on the branch I see a commit 

    "sql: refactor PRAGMA-related code"

But don't see it in this thread?

2) In a previous email I wrote this:

	- Parts of the message before '@Tarantoolbot document' and
	  after are in some ideas different, in some they are totally
	  the same. I propose you to remove the part before doc
	  request, and write the doc request more accurate. And check
	  again that all deleted PRAGMAs really don't work (in the last
	  patch), all new SETs really work, with exactly the same names
	  as in the commit message;

This is still actual. You wrote lots of text before docrequest,
and just a few lines after. The doc team will see the small part.
Once again, I propose you to drop the part before doc request,
and write everything after @Tarantoolbot document.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-27 23:07                   ` Vladislav Shpilevoy
@ 2019-11-27 23:09                     ` Vladislav Shpilevoy
  2019-11-28  8:59                     ` Mergen Imeev
  1 sibling, 0 replies; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-11-27 23:09 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches



On 28/11/2019 00:07, Vladislav Shpilevoy wrote:
> No, stop. It is not LGTM.
> 
> 1) Why on the branch I see a commit 
> 
>     "sql: refactor PRAGMA-related code"

Ok, I see it in v5 thread. I am fucked. I have
50 emails on review. Sorry.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-27 23:03                 ` Vladislav Shpilevoy
  2019-11-27 23:07                   ` Vladislav Shpilevoy
@ 2019-11-28  8:56                   ` Mergen Imeev
  1 sibling, 0 replies; 30+ messages in thread
From: Mergen Imeev @ 2019-11-28  8:56 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

On Thu, Nov 28, 2019 at 12:03:52AM +0100, Vladislav Shpilevoy wrote:
> On 27/11/2019 11:33, Mergen Imeev wrote:
> > Hi! Thanks for the suggestion! I think your points are correct,
> > but I think we should create a new issue after pushing SET.
> > Issue #4621 about using VDBE in SET/control pragmas. All other
> > pragmas already use VDBE. Since SET will use VDBE, I think we
> > should close #4621 with #4511.
> 
> I see that we have different understanding of what it means - use
> VDBE. I mean, that option value should be get/set at runtime.
> Currently the only thing runtime does is return of metadata. All
> the actual work happens at compile time.
> 
> To make binding works the only solution is to make
> PRAGMA/SET/whatever work at runtime totally. When you will
> properly move PRAGMA/SET to VDBE, you will get bindings for
> free.
> 
I see. Now I understand what you meant earlier. I added a
comment to #4621 and replaced “Closes #4621” with
“Part of #4621” in the commit message.

Link to comment:
https://github.com/tarantool/tarantool/issues/4621#issuecomment-559399461

> The patchset LGTM. Perhaps. I don't really know what is
> our plan on session and SQL settings, so I can only approve the
> technical part.
> 
> Seems like in our team design decisions about everything work
> like 'lets see what PostgreSQL/MySQL/Ya.DB do, and we will do
> literally the same'.

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

* Re: [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement
  2019-11-27 23:07                   ` Vladislav Shpilevoy
  2019-11-27 23:09                     ` Vladislav Shpilevoy
@ 2019-11-28  8:59                     ` Mergen Imeev
  1 sibling, 0 replies; 30+ messages in thread
From: Mergen Imeev @ 2019-11-28  8:59 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

On Thu, Nov 28, 2019 at 12:07:34AM +0100, Vladislav Shpilevoy wrote:
> No, stop. It is not LGTM.
> 
> 1) Why on the branch I see a commit 
> 
>     "sql: refactor PRAGMA-related code"
> 
> But don't see it in this thread?
> 
> 2) In a previous email I wrote this:
> 
> 	- Parts of the message before '@Tarantoolbot document' and
> 	  after are in some ideas different, in some they are totally
> 	  the same. I propose you to remove the part before doc
> 	  request, and write the doc request more accurate. And check
> 	  again that all deleted PRAGMAs really don't work (in the last
> 	  patch), all new SETs really work, with exactly the same names
> 	  as in the commit message;
> 
> This is still actual. You wrote lots of text before docrequest,
> and just a few lines after. The doc team will see the small part.
> Once again, I propose you to drop the part before doc request,
> and write everything after @Tarantoolbot document.

Thank you for review! I fixed mentioned problems. New
commit-message and diff below.


New commit-message:

sql: replace control pragmas by SET

This patch replaces the control pragmas with SET. After this patch
there will be no control pragmas.

Closes #4511
Part of #4621

@TarantoolBot document
Title: SQL SET statement

The SQL SET statement is used to change SQL settings. It should be
used as a substitute for PRAGMA. Pragmas replaced by SET are
deleted.

To change the value of an SQL setting, use the following syntax:
SET <setting name> = <setting value>;

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

List of replaced control pragmas and their SET analogues:
	Control pragmas			SET parameters
defer_foreign_keys		sql_defer_foreign_keys
full_column_names		sql_full_column_names
recursive_triggers		sql_recursive_triggers
reverse_unordered_selects	sql_reverse_unordered_selects
sql_compound_select_limit	sql_compound_select_limit
sql_default_engine		sql_default_engine

Also, in debug build, these control pragmas are replaced by SET
analogues:
	Control pragmas			SET parameters
parser_trace			sql_parser_trace
select_trace			sql_select_trace
sql_trace			sql_trace
vdbe_addoptrace			sql_vdbe_addoptrace
vdbe_debug			sql_vdbe_debug
vdbe_eqp			sql_vdbe_eqp
vdbe_listing			sql_vdbe_listing
vdbe_trace			sql_vdbe_trace
where_trace			sql_where_trace

Difference between SET and control pragma:
1) SET have more definite syntax:
SET <setting name> = <setting value>;
In PRAGMA, we could set the settings using these methods:
PRAGMA <setting name> = <setting value>;
PRAGMA <setting name>(<setting value>);

2) SET allows only a specific type of value for each setting. In
PRAGMA, we could use almost everything to set up any setting.
Although the rules by which the settings were set in PRAGMA were
pretty easy to understand.

3) SET cannot display setting values. PRAGMA showed the setting
values using the syntax "PRAGMA <setting name>;". With SET, we
must use other means to get the current setting values. For
session settings, we could use the sysview "_vsession_settings"
to get these values. It is worth noting that all current SQL
settings are session settings, with the exception of
'sql_reverse_unordered_selects'.

Example of usage:
SET sql_default_engine = 'memtx';
SET sql_reverse_unordered_selects = false;



Diff:

diff --git a/test/sql/sql-debug.result b/test/sql/sql-debug.result
index e2d60a9..2f21cc1 100644
--- a/test/sql/sql-debug.result
+++ b/test/sql/sql-debug.result
@@ -132,3 +132,79 @@ box.execute("SET sql_reverse_unordered_selects = "..tostring(order)..";")
 ---
 - row_count: 0
 ...
+-- Make sure that pragmas doesn't work anymore
+box.execute("PRAGMA defer_foreign_keys = 'true';")
+---
+- null
+- Pragma 'DEFER_FOREIGN_KEYS' does not exist
+...
+box.execute("PRAGMA full_column_names = 1;")
+---
+- null
+- Pragma 'FULL_COLUMN_NAMES' does not exist
+...
+box.execute("PRAGMA recursive_triggers;")
+---
+- null
+- Pragma 'RECURSIVE_TRIGGERS' does not exist
+...
+box.execute("PRAGMA reverse_unordered_selects = 0;")
+---
+- null
+- Pragma 'REVERSE_UNORDERED_SELECTS' does not exist
+...
+box.execute("PRAGMA sql_compound_select_limit = 15;")
+---
+- null
+- Pragma 'SQL_COMPOUND_SELECT_LIMIT' does not exist
+...
+box.execute("PRAGMA sql_default_engine = 'some_engine';")
+---
+- null
+- Pragma 'SQL_DEFAULT_ENGINE' does not exist
+...
+box.execute("PRAGMA parser_trace = true;")
+---
+- null
+- Pragma 'PARSER_TRACE' does not exist
+...
+box.execute("PRAGMA select_trace = 0;")
+---
+- null
+- Pragma 'SELECT_TRACE' does not exist
+...
+box.execute("PRAGMA sql_trace = 1;")
+---
+- null
+- Pragma 'SQL_TRACE' does not exist
+...
+box.execute("PRAGMA vdbe_addoptrace = 'OFF'")
+---
+- null
+- Pragma 'VDBE_ADDOPTRACE' does not exist
+...
+box.execute("PRAGMA vdbe_debug = 'ON'")
+---
+- null
+- Pragma 'VDBE_DEBUG' does not exist
+...
+box.execute("PRAGMA vdbe_eqp;")
+---
+- null
+- Pragma 'VDBE_EQP' does not exist
+...
+box.execute("PRAGMA vdbe_listing = 'false'")
+---
+- null
+- Pragma 'VDBE_LISTING' does not exist
+...
+box.execute("PRAGMA vdbe_trace;")
+---
+- null
+- Pragma 'VDBE_TRACE' does not exist
+...
+box.execute("PRAGMA where_trace = false")
+---
+- null
+- Pragma 'WHERE_TRACE' does not exist
+...
diff --git a/test/sql/sql-debug.test.lua b/test/sql/sql-debug.test.lua
index b15deee..033acd1 100644
--- a/test/sql/sql-debug.test.lua
+++ b/test/sql/sql-debug.test.lua
@@ -26,3 +26,21 @@ box.execute('SELECT * FROM "_vsession_settings";')
 
 box.execute("SET sql_default_engine = '"..engine.."';")
 box.execute("SET sql_reverse_unordered_selects = "..tostring(order)..";")
+
+-- Make sure that pragmas doesn't work anymore
+box.execute("PRAGMA defer_foreign_keys = 'true';")
+box.execute("PRAGMA full_column_names = 1;")
+box.execute("PRAGMA recursive_triggers;")
+box.execute("PRAGMA reverse_unordered_selects = 0;")
+box.execute("PRAGMA sql_compound_select_limit = 15;")
+box.execute("PRAGMA sql_default_engine = 'some_engine';")
+
+box.execute("PRAGMA parser_trace = true;")
+box.execute("PRAGMA select_trace = 0;")
+box.execute("PRAGMA sql_trace = 1;")
+box.execute("PRAGMA vdbe_addoptrace = 'OFF'")
+box.execute("PRAGMA vdbe_debug = 'ON'")
+box.execute("PRAGMA vdbe_eqp;")
+box.execute("PRAGMA vdbe_listing = 'false'")
+box.execute("PRAGMA vdbe_trace;")
+box.execute("PRAGMA where_trace = false")

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
                   ` (4 preceding siblings ...)
  2019-11-07 10:37 ` [Tarantool-patches] [PATCH v3 5/5] sql: replace control pragmas imeevma
@ 2019-12-06 11:37 ` Kirill Yukhin
  2019-12-06 13:50   ` Mergen Imeev
  5 siblings, 1 reply; 30+ messages in thread
From: Kirill Yukhin @ 2019-12-06 11:37 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches, v.shpilevoy

Hello Mergen!

On 07 ноя 13:36, imeevma@tarantool.org wrote:
> 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 session-local
> settings in unified way.
> 
> https://github.com/tarantool/tarantool/issues/4511
> https://github.com/tarantool/tarantool/tree/imeevma/gh-4511-pragma-replaced-by-set

We have at least two mail threads with discussions of how
this will be working (PRAGMA and SET keywords).

We have couple of verbal discussions, could you please
post approach we developed?

This is what I can remember: we're introducing new view (say
_vsettings), which is specific for each sessions.
This view should contain all settings which user allowed to
read and write. Inserts are prohibited to that view. Updates
are alowed only if user has enough privilages to the given
setting. E.g. user cannot changes a way FK are checked or
max nesting depth of a SELECT statement.

I guess, we should create this view lazily in order not to harm
performance. Please, make sure when you'll be working on the
patchset.

Having such a view will alow us to:
  1. get rid of nasty pragma/set statements at all;
  2. will simplify connectors programming;
  3. improve security by allowing to *bind* values we
     wish to update, instead of concatenating big string
     like other broken DBMSes.

AFAIR, we decided to set {'string', 'any'} format for that
new view.

Could you please summarize overall design and post it here
(or in discussions, whatever).

--
Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-06 11:37 ` [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET Kirill Yukhin
@ 2019-12-06 13:50   ` Mergen Imeev
  2019-12-06 14:06     ` Sergey Ostanevich
  2019-12-17 22:11     ` Alexander Turenko
  0 siblings, 2 replies; 30+ messages in thread
From: Mergen Imeev @ 2019-12-06 13:50 UTC (permalink / raw)
  To: Kirill Yukhin; +Cc: tarantool-patches, v.shpilevoy, tarantool-discussions


Hello Kirill!

Below you can see my idea of solving the problem. Also,
after that I will answer your questions.

In the last discussion, we decided to solve the problem more
globally: we are going to create a way to change session settings
that can be used from any interface. So, here are the requirements
for this method:
1) All settings must be in the system space or system view.
2) We should be able to SELECT from this space.
3) We should be able to UPDATE data in this space. INSERT, DELETE
and REPLACE cannot be used on this space.
4) This space should not affect performance.
5) This space should not be involved in transactions.
6) We should be able to change the settings on master and on
replica.
7) Space does not have to be persistent.

To fulfill these requirements, I decided to create and use a new
engine. This engine will only be used for this space. The format
of the space will be {{name = 'name', type = 'string'},
{name = 'value', type = 'any'}}. The space will be temporary.

When the user selects a tuple from space, the space will create a
new tuple on the fly. The space itself will be empty, so do not
worry about performance degradation. On UPDATE, the space will
change the session settings.

After we create the space, we can simply remove the control
pragmas. To change a setting from SQL we just need to
update value in the space using UPDATE statement.


On Fri, Dec 06, 2019 at 02:37:11PM +0300, Kirill Yukhin wrote:
> Hello Mergen!
> 
> On 07 ноя 13:36, imeevma@tarantool.org wrote:
> > 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 session-local
> > settings in unified way.
> > 
> > https://github.com/tarantool/tarantool/issues/4511
> > https://github.com/tarantool/tarantool/tree/imeevma/gh-4511-pragma-replaced-by-set
> 
> We have at least two mail threads with discussions of how
> this will be working (PRAGMA and SET keywords).
> 
> We have couple of verbal discussions, could you please
> post approach we developed?
> 
> This is what I can remember: we're introducing new view (say
> _vsettings), which is specific for each sessions.
In the current idea, this is not entirely true. The space
is the same for all sessions. Simply, the tuples it creates
contain the settings for the current session.

> This view should contain all settings which user allowed to
> read and write. Inserts are prohibited to that view. Updates
> are alowed only if user has enough privilages to the given
> setting. E.g. user cannot changes a way FK are checked or
> max nesting depth of a SELECT statement.
Since the user will change the setting of current session,
there won't be any interactions between users/sessions.
> 
> I guess, we should create this view lazily in order not to harm
> performance. Please, make sure when you'll be working on the
> patchset.
In a sense, space will work lazily - it will create a tuple
only when asked about it. The only thing we have to do when
starting Tarantool (not a session!) Is to initialize an
array of settings. Also, we must release it upon exiting
Tarantool.

> 
> Having such a view will alow us to:
>   1. get rid of nasty pragma/set statements at all;
>   2. will simplify connectors programming;
>   3. improve security by allowing to *bind* values we
>      wish to update, instead of concatenating big string
>      like other broken DBMSes.
> 
> AFAIR, we decided to set {'string', 'any'} format for that
> new view.
Yes.

> 
> Could you please summarize overall design and post it here
> (or in discussions, whatever).
> 
> --
> Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-06 13:50   ` Mergen Imeev
@ 2019-12-06 14:06     ` Sergey Ostanevich
  2019-12-17 22:11     ` Alexander Turenko
  1 sibling, 0 replies; 30+ messages in thread
From: Sergey Ostanevich @ 2019-12-06 14:06 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: v.shpilevoy, tarantool-patches, tarantool-discussions

Hi!

I believe it can be a missing point: the system space described actually
contains no data at no time. On SELECT from this space a tuple is filled
from the session settings and on UPDATE corresponding setting will be
set in session structure and no data will be present in the space 
thereafter.

Given that - the space will be the same for all sessions, but since it 
contains no data there will be no cross-session interaction.

Regards,
Sergos

On 06 Dec 16:50, Mergen Imeev wrote:
> 
> Hello Kirill!
> 
> Below you can see my idea of solving the problem. Also,
> after that I will answer your questions.
> 
> In the last discussion, we decided to solve the problem more
> globally: we are going to create a way to change session settings
> that can be used from any interface. So, here are the requirements
> for this method:
> 1) All settings must be in the system space or system view.
> 2) We should be able to SELECT from this space.
> 3) We should be able to UPDATE data in this space. INSERT, DELETE
> and REPLACE cannot be used on this space.
> 4) This space should not affect performance.
> 5) This space should not be involved in transactions.
> 6) We should be able to change the settings on master and on
> replica.
> 7) Space does not have to be persistent.
> 
> To fulfill these requirements, I decided to create and use a new
> engine. This engine will only be used for this space. The format
> of the space will be {{name = 'name', type = 'string'},
> {name = 'value', type = 'any'}}. The space will be temporary.
> 
> When the user selects a tuple from space, the space will create a
> new tuple on the fly. The space itself will be empty, so do not
> worry about performance degradation. On UPDATE, the space will
> change the session settings.
> 
> After we create the space, we can simply remove the control
> pragmas. To change a setting from SQL we just need to
> update value in the space using UPDATE statement.
> 
> 
> On Fri, Dec 06, 2019 at 02:37:11PM +0300, Kirill Yukhin wrote:
> > Hello Mergen!
> > 
> > On 07 ноя 13:36, imeevma@tarantool.org wrote:
> > > 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 session-local
> > > settings in unified way.
> > > 
> > > https://github.com/tarantool/tarantool/issues/4511
> > > https://github.com/tarantool/tarantool/tree/imeevma/gh-4511-pragma-replaced-by-set
> > 
> > We have at least two mail threads with discussions of how
> > this will be working (PRAGMA and SET keywords).
> > 
> > We have couple of verbal discussions, could you please
> > post approach we developed?
> > 
> > This is what I can remember: we're introducing new view (say
> > _vsettings), which is specific for each sessions.
> In the current idea, this is not entirely true. The space
> is the same for all sessions. Simply, the tuples it creates
> contain the settings for the current session.
> 
> > This view should contain all settings which user allowed to
> > read and write. Inserts are prohibited to that view. Updates
> > are alowed only if user has enough privilages to the given
> > setting. E.g. user cannot changes a way FK are checked or
> > max nesting depth of a SELECT statement.
> Since the user will change the setting of current session,
> there won't be any interactions between users/sessions.
> > 
> > I guess, we should create this view lazily in order not to harm
> > performance. Please, make sure when you'll be working on the
> > patchset.
> In a sense, space will work lazily - it will create a tuple
> only when asked about it. The only thing we have to do when
> starting Tarantool (not a session!) Is to initialize an
> array of settings. Also, we must release it upon exiting
> Tarantool.
> 
> > 
> > Having such a view will alow us to:
> >   1. get rid of nasty pragma/set statements at all;
> >   2. will simplify connectors programming;
> >   3. improve security by allowing to *bind* values we
> >      wish to update, instead of concatenating big string
> >      like other broken DBMSes.
> > 
> > AFAIR, we decided to set {'string', 'any'} format for that
> > new view.
> Yes.
> 
> > 
> > Could you please summarize overall design and post it here
> > (or in discussions, whatever).
> > 
> > --
> > Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-06 13:50   ` Mergen Imeev
  2019-12-06 14:06     ` Sergey Ostanevich
@ 2019-12-17 22:11     ` Alexander Turenko
  2019-12-18  2:39       ` Peter Gulutzan
  2019-12-18 10:20       ` Kirill Yukhin
  1 sibling, 2 replies; 30+ messages in thread
From: Alexander Turenko @ 2019-12-17 22:11 UTC (permalink / raw)
  To: Mergen Imeev
  Cc: v.shpilevoy, Peter Gulutzan, tarantool-discussions, tarantool-patches

Mergen,

I don't have enough context here, but have questions about this
proposal. Sorry if they were already discussed and I missed it.

Most important question is that I don't understand why we don't want to
provide language specific APIs for sessions settings. It looks both more
convenient and more performant.

See this and other questions and notes below.

(CCed Peter, because he may have some opinion how SQL API should look.)

WBR, Alexader Turenko.

----

AFAIR discussions around a space / view for session settings arose from
Kostya O. proposal to move toward support of standard information schema
views (please, correct me, if I remember it wrongly). Then it becomes
out of scope somehow. But okay, let it being out.

(BTW, I looked over SQL/Schemata 2011 and don't found anything like
MySQL's GLOBAL_VARIABLES and SESSION_VARIABLES tables. It seems there is
no standard table for session variables. I don't sure however.)

----

We have two basic variants:

* Implement an API for session settings for each supported language
  (C, Lua, SQL) and a protocol for connectors.
* Provide a system view / space (this is proposed by Mergen).

First, a space / view is not most convenient way to operate on session
settings from a language. Let's compare.

Lua:

 | box.space._vsession_settings:get({'sql_default_engine'}).value
 | box.space._vsession_settings:update({'sql_default_engine'},
 |                                     {{'=', 'value', 'vinyl'}})
 |
 | box.session.settings:get('sql_default_engine')
 | box.session.settings:set('sql_default_engine', 'vinyl')

SQL:

 | SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_default_engine'
 | UPDATE "_vsession_settings" SET "value" = 'vinyl' \
 |                             WHERE "name" = 'sql_default_engine'
 |
 | SESSION GET 'sql_default_engine'
 | SESSION SET 'sql_default_engine' = 'vinyl'

C (sketchy):

 | /* Read from a _vsession_settings. */
 |
 | enum {
 |         BOX_VSESSION_SETTINGS_VALUE_ID = 2
 | };
 |
 | char key[32];
 | char *key_end = key;
 | key_end = mp_encode_array(key_end, 1);
 | key_end = mp_encode_str(key_end, "sql_default_engine",
 |                         sizeof("sql_default_engine") - 1);
 |
 | box_tuple_t *tuple;
 | box_iterator_t *it = box_index_iterator(BOX_VSESSION_SETTINGS_ID, 0, ITER_EQ,
 |                                         key, key_end);
 | box_iterator_next(it, &tuple);
 | const char *buf = box_tuple_field(tuple, BOX_VSESSION_SETTINGS_VALUE_ID);
 |
 | uint32_t engine_len;
 | const char *engine = mp_decode_str(&buf, &engine_len);
 |
 | box_iterator_free(it);
 |
 | /* Update a value in _vsession_settings. */
 |
 | <I'll skip it.>
 |
 | /* Get and set with a language aware API. */
 |
 | uint32_t engine_len;
 | const char *engine = box_session_get_str(SESSION_SQL_DEFAULT_ENGINE,
 |                                          &engine_len);
 |
 | box_session_set_str(SESSION_SQL_DEFAULT_ENGINE, "vinyl",
 |                     sizeof("vinyl") - 1);

Languare-aware APIs above are just examples. I propose to implement such
APIs, but not how they should look exactly.

To sum the examples up: it seems for me that language aware APIs are a
way more simple for a user.

Second, all tuples are msgpack encoded (at least now). So any get/set
operation on _vspace_settings will require to encode and decode msgpack
(yep, both encode and decode at once). It will be surely less performant
then a hashmap lookup (session id -> struct session_settings) plus a
field access.

So, language aware API can be implemented in more performant way then
general space-like one.

It seems that we anyway need an API for connectors. So we can provide
the proposed view, but don't use it internally to implement language
specific APIs (for performance).

----

Re SET / SHOW, GET / SELECT -- I don't think it really matters so much.
Maybe we should look for SQL/PSM and catch some syntax to make things
look consistent in a future. Maybe we should add a keyword SESSION (as
in my SQL API examples) to avoid possible future incompatibilities (say,
with SQL/PSM).

----

Console session settings (like statements delimiter, input language,
output format) are out of scope here?

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-17 22:11     ` Alexander Turenko
@ 2019-12-18  2:39       ` Peter Gulutzan
  2019-12-18 17:39         ` Peter Gulutzan
  2019-12-18 10:20       ` Kirill Yukhin
  1 sibling, 1 reply; 30+ messages in thread
From: Peter Gulutzan @ 2019-12-18  2:39 UTC (permalink / raw)
  To: Alexander Turenko, Mergen Imeev
  Cc: v.shpilevoy, tarantool-discussions, tarantool-patches

Hi,

On 2019-12-17 3:11 p.m., Alexander Turenko wrote:
 > Mergen,
 >
 > I don't have enough context here, but have questions about this
 > proposal. Sorry if they were already discussed and I missed it.
 >
 > Most important question is that I don't understand why we don't want to
 > provide language specific APIs for sessions settings. It looks both more
 > convenient and more performant.
 >
 > See this and other questions and notes below.
 >
 > (CCed Peter, because he may have some opinion how SQL API should look.)
 >
 > WBR, Alexader Turenko.
 >
 > ----
 >
 > AFAIR discussions around a space / view for session settings arose from
 > Kostya O. proposal to move toward support of standard information schema
 > views (please, correct me, if I remember it wrongly). Then it becomes
 > out of scope somehow. But okay, let it being out.
 >

I don't know whether you are wrong, but I have looked at the dev thread
that Imeev Mergen started on September 12,
"[dev] Replacing control pragmas by SET".
It seemed to me that Imeev Mergen + Nikita Pettik + Konstantin Osipov
all collaborated about having a system space.


 > (BTW, I looked over SQL/Schemata 2011 and don't found anything like
 > MySQL's GLOBAL_VARIABLES and SESSION_VARIABLES tables. It seems there is
 > no standard table for session variables. I don't sure however.)
 >

You are right, there is no standard table.

 > ----
 >
 > We have two basic variants:
 >
 > * Implement an API for session settings for each supported language
 >   (C, Lua, SQL) and a protocol for connectors.
 > * Provide a system view / space (this is proposed by Mergen).
 >
 > First, a space / view is not most convenient way to operate on session
 > settings from a language. Let's compare.
 >
 > Lua:
 >
 >  | box.space._vsession_settings:get({'sql_default_engine'}).value
 >  | box.space._vsession_settings:update({'sql_default_engine'},
 >  |                                     {{'=', 'value', 'vinyl'}})
 >  |
 >  | box.session.settings:get('sql_default_engine')
 >  | box.session.settings:set('sql_default_engine', 'vinyl')
 >
 > SQL:
 >
 >  | SELECT "value" FROM "_vsession_settings" WHERE "name" = 
'sql_default_engine'
 >  | UPDATE "_vsession_settings" SET "value" = 'vinyl' \
 >  |                             WHERE "name" = 'sql_default_engine'
 >  |
 >  | SESSION GET 'sql_default_engine'
 >  | SESSION SET 'sql_default_engine' = 'vinyl'

 >

 From Issue#4511 "sql: replace PRAGMA by SET for some pragmas"
I gather that Imeev Mergen is already working on something very close to
your UPDATE "_vsession_settings" example.
But Imeev Mergen says I can't SELECT from this space, I don't know why not.
Anyway, if a space exists, SESSION GET or SESSION SET would be redundant.

 > C (sketchy):
 >
 >  | /* Read from a _vsession_settings. */
 >  |
 >  | enum {
 >  |         BOX_VSESSION_SETTINGS_VALUE_ID = 2
 >  | };
 >  |
 >  | char key[32];
 >  | char *key_end = key;
 >  | key_end = mp_encode_array(key_end, 1);
 >  | key_end = mp_encode_str(key_end, "sql_default_engine",
 >  |                         sizeof("sql_default_engine") - 1);
 >  |
 >  | box_tuple_t *tuple;
 >  | box_iterator_t *it = box_index_iterator(BOX_VSESSION_SETTINGS_ID, 
0, ITER_EQ,
 >  |                                         key, key_end);
 >  | box_iterator_next(it, &tuple);
 >  | const char *buf = box_tuple_field(tuple, 
BOX_VSESSION_SETTINGS_VALUE_ID);
 >  |
 >  | uint32_t engine_len;
 >  | const char *engine = mp_decode_str(&buf, &engine_len);
 >  |
 >  | box_iterator_free(it);
 >  |
 >  | /* Update a value in _vsession_settings. */
 >  |
 >  | <I'll skip it.>
 >  |
 >  | /* Get and set with a language aware API. */
 >  |
 >  | uint32_t engine_len;
 >  | const char *engine = box_session_get_str(SESSION_SQL_DEFAULT_ENGINE,
 >  |                                          &engine_len);
 >  |
 >  | box_session_set_str(SESSION_SQL_DEFAULT_ENGINE, "vinyl",
 >  |                     sizeof("vinyl") - 1);
 >
 > Languare-aware APIs above are just examples. I propose to implement such
 > APIs, but not how they should look exactly.
 >
 > To sum the examples up: it seems for me that language aware APIs are a
 > way more simple for a user.

To me, the SQL looks way more simple. But I admit I am prejudiced.

 >
 > Second, all tuples are msgpack encoded (at least now). So any get/set
 > operation on _vspace_settings will require to encode and decode msgpack
 > (yep, both encode and decode at once). It will be surely less performant
 > then a hashmap lookup (session id -> struct session_settings) plus a
 > field access.
 >
 > So, language aware API can be implemented in more performant way then
 > general space-like one.
 >
 > It seems that we anyway need an API for connectors. So we can provide
 > the proposed view, but don't use it internally to implement language
 > specific APIs (for performance).
 > ----
 >
 > Re SET / SHOW, GET / SELECT -- I don't think it really matters so much.
 > Maybe we should look for SQL/PSM and catch some syntax to make things
 > look consistent in a future. Maybe we should add a keyword SESSION (as
 > in my SQL API examples) to avoid possible future incompatibilities (say,
 > with SQL/PSM).
 >
 > ----

Oracle has a variety. For example changing the encryption wallet is done
with special statements (ALTER SYSTEM etc.) and reading is done
with special tables (V$WALLET etc.).
https://www.morganslibrary.org/reference/wallet.html
Here I believe we're getting into an area where trying for compatibility
would be difficult and not rewarding. But I also believe that by
using a system table we'd be slightly more compatible than we are now.

 >
 > Console session settings (like statements delimiter, input language,
 > output format) are out of scope here?

I have documented PRAGMA in the version-2.3 manual.
If you believe it should be removed before this becomes the master manual,
please discuss with Roman Khabibov.

Peter Gulutzan

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-17 22:11     ` Alexander Turenko
  2019-12-18  2:39       ` Peter Gulutzan
@ 2019-12-18 10:20       ` Kirill Yukhin
  2019-12-18 10:53         ` Alexander Turenko
  1 sibling, 1 reply; 30+ messages in thread
From: Kirill Yukhin @ 2019-12-18 10:20 UTC (permalink / raw)
  To: Alexander Turenko
  Cc: tarantool-patches, v.shpilevoy, tarantool-discussions, Peter Gulutzan

Hello,

On 18 дек 01:11, Alexander Turenko wrote:
> Mergen,
> 
> I don't have enough context here, but have questions about this
> proposal. Sorry if they were already discussed and I missed it.
> 
> Most important question is that I don't understand why we don't want to
> provide language specific APIs for sessions settings. It looks both more
> convenient and more performant.
> 
> See this and other questions and notes below.
> 
> (CCed Peter, because he may have some opinion how SQL API should look.)
> 
> WBR, Alexader Turenko.
> 
> ----
> 
> AFAIR discussions around a space / view for session settings arose from
> Kostya O. proposal to move toward support of standard information schema
> views (please, correct me, if I remember it wrongly). Then it becomes
> out of scope somehow. But okay, let it being out.
> 
> (BTW, I looked over SQL/Schemata 2011 and don't found anything like
> MySQL's GLOBAL_VARIABLES and SESSION_VARIABLES tables. It seems there is
> no standard table for session variables. I don't sure however.)
> 
> ----
> 
> We have two basic variants:
> 
> * Implement an API for session settings for each supported language
>   (C, Lua, SQL) and a protocol for connectors.
> * Provide a system view / space (this is proposed by Mergen).
> 
> First, a space / view is not most convenient way to operate on session
> settings from a language. Let's compare.
> 
> Lua:
> 
>  | box.space._vsession_settings:get({'sql_default_engine'}).value
>  | box.space._vsession_settings:update({'sql_default_engine'},
>  |                                     {{'=', 'value', 'vinyl'}})
>  |
>  | box.session.settings:get('sql_default_engine')
>  | box.session.settings:set('sql_default_engine', 'vinyl')

Frankly, to me this is not of big difference. Especially when we are
talking about settings, references to which are rare.

After all, one might want to implement setter to avoid such
updates.

> SQL:
> 
>  | SELECT "value" FROM "_vsession_settings" WHERE "name" = 'sql_default_engine'
>  | UPDATE "_vsession_settings" SET "value" = 'vinyl' \
>  |                             WHERE "name" = 'sql_default_engine'
>  |
>  | SESSION GET 'sql_default_engine'
>  | SESSION SET 'sql_default_engine' = 'vinyl'
> 
> C (sketchy):
> 
>  | /* Read from a _vsession_settings. */
>  |
>  | enum {
>  |         BOX_VSESSION_SETTINGS_VALUE_ID = 2
>  | };
>  |
>  | char key[32];
>  | char *key_end = key;
>  | key_end = mp_encode_array(key_end, 1);
>  | key_end = mp_encode_str(key_end, "sql_default_engine",
>  |                         sizeof("sql_default_engine") - 1);
>  |
>  | box_tuple_t *tuple;
>  | box_iterator_t *it = box_index_iterator(BOX_VSESSION_SETTINGS_ID, 0, ITER_EQ,
>  |                                         key, key_end);
>  | box_iterator_next(it, &tuple);
>  | const char *buf = box_tuple_field(tuple, BOX_VSESSION_SETTINGS_VALUE_ID);
>  |
>  | uint32_t engine_len;
>  | const char *engine = mp_decode_str(&buf, &engine_len);
>  |
>  | box_iterator_free(it);
>  |
>  | /* Update a value in _vsession_settings. */
>  |
>  | <I'll skip it.>
>  |
>  | /* Get and set with a language aware API. */
>  |
>  | uint32_t engine_len;
>  | const char *engine = box_session_get_str(SESSION_SQL_DEFAULT_ENGINE,
>  |                                          &engine_len);
>  |
>  | box_session_set_str(SESSION_SQL_DEFAULT_ENGINE, "vinyl",
>  |                     sizeof("vinyl") - 1);
> 
> Languare-aware APIs above are just examples. I propose to implement such
> APIs, but not how they should look exactly.

This might have sense, but I'd treat it as a follow up activity.

> To sum the examples up: it seems for me that language aware APIs are a
> way more simple for a user.
> 
> Second, all tuples are msgpack encoded (at least now). So any get/set
> operation on _vspace_settings will require to encode and decode msgpack
> (yep, both encode and decode at once). It will be surely less performant
> then a hashmap lookup (session id -> struct session_settings) plus a
> field access.
> 
> So, language aware API can be implemented in more performant way then
> general space-like one.

I think performance out of scope here at all.
 
> It seems that we anyway need an API for connectors. So we can provide
> the proposed view, but don't use it internally to implement language
> specific APIs (for performance).
> 
> Console session settings (like statements delimiter, input language,
> output format) are out of scope here?

Yes.

To sum up. We spent too much time here. I think we can improve approaches
in future. But I see no serious reasons for that:
  1. To make it easier to use we might whant to implement some stored
     routines or something/
  2. Performance of encode/decode is out of intereset here.

I propose you to file a feature request as follow up of the patchset.

--
Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-18 10:20       ` Kirill Yukhin
@ 2019-12-18 10:53         ` Alexander Turenko
  0 siblings, 0 replies; 30+ messages in thread
From: Alexander Turenko @ 2019-12-18 10:53 UTC (permalink / raw)
  To: Kirill Yukhin
  Cc: tarantool-patches, v.shpilevoy, tarantool-discussions, Peter Gulutzan

> To sum up. We spent too much time here. I think we can improve approaches
> in future. But I see no serious reasons for that:
>   1. To make it easier to use we might whant to implement some stored
>      routines or something/
>   2. Performance of encode/decode is out of intereset here.
> 
> I propose you to file a feature request as follow up of the patchset.

I read this as 'any design / API is okay'. So there is no sense to
discuss it further.

For me access a field of a structure with msgpack encode and then decode
is a kind of `toString(bool_value).length() != 5` check.

It is a bit toxic, I know. Sorry for this.

WBR, Alexander Turenko.

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-18  2:39       ` Peter Gulutzan
@ 2019-12-18 17:39         ` Peter Gulutzan
  2019-12-19  9:59           ` Mergen Imeev
  2019-12-19 21:09           ` Vladislav Shpilevoy
  0 siblings, 2 replies; 30+ messages in thread
From: Peter Gulutzan @ 2019-12-18 17:39 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches, v.shpilevoy, tarantool-discussions

Hi,

I think that there still might be a few small SQL-specific issues.
I pulled today from branch imeevma/gh-4511-pragma-replaced-by-set.

1.

The type of "value" is 'any', which is shown in metadata as 'string':
"
tarantool> box.execute([[SELECT typeof("value") FROM 
"_vsession_settings" LIMIT 1;]])
---
- metadata:
   - name: typeof("value")
     type: string
   rows:
   - ['any']
...
"

But that means that searches of "value" will usually fail, thus:
"
tarantool> box.execute([[SELECT "name", "value" FROM 
"_vsession_settings" where "value" = 'vinyl';]])
---
- null
- 'Type mismatch: can not convert text to boolean'
...
"

Why not scalar?

2.

You wrote this comment on issue#4511:
"
@pgulutzan @kostja It seems that we are going to solve the problem in a 
different way: we will create a special space that will contain the 
settings. This space will only allow updates. So, to change the setting 
value, you should do something like this:
box.execute([[UPDATE "_session_settings" SET "value" = 'vinyl' WHERE 
"name" = 'sql_default_engine']])
or
box.space._session_settings:update('sql_default_engine', {{'=', 'value', 
'vinyl'}})
This will allow us to use the same method to change any settings in any 
front-end. Also after that we can simply remove the control p
"
But at this moment _session_settings does not exist.
The only thing that works is
box.execute([[SET sql_default_engine = 'vinyl';]])
which is what I and Konstantin Osipov were raising questions about.
In fact I can do it without 'write' privileges on anything.

This is just temporary, right?

3.

VALUE happens to be a reserved word in DB2 and Oracle.
Although we have no plans to reserve it, well, it's a micro-issue for 
compatibility.
You might of course dismiss this because our column name is "value" not 
value.
But suppose that some user agrees totally with Konstantin Osipov (alas),
and decides to use a method that allows access to the data without quote 
marks:
"
tarantool> box.execute([[CREATE VIEW vsession_settings AS SELECT "value" 
AS value, "name" AS name FROM "_vsession_settings";]])
---
- row_count: 1
...

tarantool> box.execute([[SELECT * FROM vsession_settings WHERE name = 
'sql_default_engine';]])
---
- metadata:
   - name: VALUE
     type: any
   - name: NAME
     type: string
   rows:
   - ['vinyl', 'sql_default_engine']
...
"
I think this means that some users will have columns named VALUE,
so we will cause trouble if someday we reserve it.

4.

This suggestion was accepted according to Issue#4511:
_session_settings has columns 'name' and 'value', so:
UPDATE "session_settings" SET "value" = 'vinyl' WHERE "name" = 
'sql_default_engine';
This suggestion (made by N. Pettik in the thread) was rejected:
_session_settings has many columns including 'sql_default_engine' and 
'value', so
UPDATE "session_settings" SET "sql_default_engine" = 'vinyl';

Okay, but ...

If we someday support GRANT, and sql_default_engine was a column, we 
could say:
GRANT UPDATE ON "_session_settings" ("sql_default_engine");
that is, we could be very specific about what you can update.
But there is no equivalent GRANT statement, with #4511,
unless one adds a non-standard extension like
GRANT UPDATE on "_session_settings" ("value") WHERE "name" = 
'sql_default_engine';

I think that a few other things are simpler if sql_default_engine is a 
column:
CHECK ("sql_default_engine" IN ('memtx','vinyl')) versus
CHECK ("name" <> 'sql_default_engine' OR "value" IN ('memtx','vinyl'))
and
SELECT "sql_default_engine", "parser_trace" FROM "_vsession_settings"; 
versus
SELECT "value" AS sql_default_engine FROM "_vsession_settings" WHERE 
"name" = 'sql_default_engine'
UNION
SELECT "value" AS parser_trace FROM "_vsession_settings" WHERE "name" = 
'parser_trace';
(I say "I think" and admit that there may be better solutions I didn't 
think about.)

5.

The name _session_settings hints that, if I change the setting, I only 
affect my own session.
However, as you know, if I change sql_compound_select_limit, I affect 
all sessions.
So perhaps it should be in a new different space, _vglobal_settings?

Peter Gulutzan

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-18 17:39         ` Peter Gulutzan
@ 2019-12-19  9:59           ` Mergen Imeev
  2019-12-19 17:35             ` Peter Gulutzan
  2019-12-19 21:09           ` Vladislav Shpilevoy
  1 sibling, 1 reply; 30+ messages in thread
From: Mergen Imeev @ 2019-12-19  9:59 UTC (permalink / raw)
  To: Peter Gulutzan; +Cc: tarantool-patches, v.shpilevoy, tarantool-discussions

Hi,

Thank you for your suggestions! I will try to answer your
questions.

On Wed, Dec 18, 2019 at 10:39:58AM -0700, Peter Gulutzan wrote:
> Hi,
> 
> I think that there still might be a few small SQL-specific issues.
> I pulled today from branch imeevma/gh-4511-pragma-replaced-by-set.
>
This branch is out of date. I have not deleted it since
the problem is still not resolved.

New branch: imeevma/gh-4511-new-engine

> 1.
> 
> The type of "value" is 'any', which is shown in metadata as 'string':
> "
> tarantool> box.execute([[SELECT typeof("value") FROM "_vsession_settings"
> LIMIT 1;]])
> ---
> - metadata:
>   - name: typeof("value")
>     type: string
>   rows:
>   - ['any']
> ...
> "
> 
> But that means that searches of "value" will usually fail, thus:
> "
> tarantool> box.execute([[SELECT "name", "value" FROM "_vsession_settings"
> where "value" = 'vinyl';]])
> ---
> - null
> - 'Type mismatch: can not convert text to boolean'
> ...
> "
> 
> Why not scalar?
> 
True, I did not think about this problem before. I think
that I will change the type of the field to SCALAR if
there are no objections.

> 2.
> 
> You wrote this comment on issue#4511:
> "
> @pgulutzan @kostja It seems that we are going to solve the problem in a
> different way: we will create a special space that will contain the
> settings. This space will only allow updates. So, to change the setting
> value, you should do something like this:
> box.execute([[UPDATE "_session_settings" SET "value" = 'vinyl' WHERE "name"
> = 'sql_default_engine']])
> or
> box.space._session_settings:update('sql_default_engine', {{'=', 'value',
> 'vinyl'}})
> This will allow us to use the same method to change any settings in any
> front-end. Also after that we can simply remove the control p
> "
> But at this moment _session_settings does not exist.
> The only thing that works is
> box.execute([[SET sql_default_engine = 'vinyl';]])
> which is what I and Konstantin Osipov were raising questions about.
> In fact I can do it without 'write' privileges on anything.
> 
> This is just temporary, right?
> 
Not exactly, the system space with allowed UPDATE can be
seen on new branch.

> 3.
> 
> VALUE happens to be a reserved word in DB2 and Oracle.
> Although we have no plans to reserve it, well, it's a micro-issue for
> compatibility.
> You might of course dismiss this because our column name is "value" not
> value.
> But suppose that some user agrees totally with Konstantin Osipov (alas),
> and decides to use a method that allows access to the data without quote
> marks:
> "
> tarantool> box.execute([[CREATE VIEW vsession_settings AS SELECT "value" AS
> value, "name" AS name FROM "_vsession_settings";]])
> ---
> - row_count: 1
> ...
> 
> tarantool> box.execute([[SELECT * FROM vsession_settings WHERE name =
> 'sql_default_engine';]])
> ---
> - metadata:
>   - name: VALUE
>     type: any
>   - name: NAME
>     type: string
>   rows:
>   - ['vinyl', 'sql_default_engine']
> ...
> "
> I think this means that some users will have columns named VALUE,
> so we will cause trouble if someday we reserve it.
> 
We can change the name of the field before the patch is
pushed. Do you have any suggestions on how we should name
the field?

> 4.
> 
> This suggestion was accepted according to Issue#4511:
> _session_settings has columns 'name' and 'value', so:
> UPDATE "session_settings" SET "value" = 'vinyl' WHERE "name" =
> 'sql_default_engine';
> This suggestion (made by N. Pettik in the thread) was rejected:
> _session_settings has many columns including 'sql_default_engine' and
> 'value', so
> UPDATE "session_settings" SET "sql_default_engine" = 'vinyl';
> 
> Okay, but ...
> 
> If we someday support GRANT, and sql_default_engine was a column, we could
> say:
> GRANT UPDATE ON "_session_settings" ("sql_default_engine");
> that is, we could be very specific about what you can update.
> But there is no equivalent GRANT statement, with #4511,
> unless one adds a non-standard extension like
> GRANT UPDATE on "_session_settings" ("value") WHERE "name" =
> 'sql_default_engine';
> 
> I think that a few other things are simpler if sql_default_engine is a
> column:
> CHECK ("sql_default_engine" IN ('memtx','vinyl')) versus
> CHECK ("name" <> 'sql_default_engine' OR "value" IN ('memtx','vinyl'))
> and
> SELECT "sql_default_engine", "parser_trace" FROM "_vsession_settings";
> versus
> SELECT "value" AS sql_default_engine FROM "_vsession_settings" WHERE "name"
> = 'sql_default_engine'
> UNION
> SELECT "value" AS parser_trace FROM "_vsession_settings" WHERE "name" =
> 'parser_trace';
> (I say "I think" and admit that there may be better solutions I didn't think
> about.)
> 
That is a bit problematic, since if we want to
add/change/remove a setting, we have to rebuild bootstrap.

At the same time, I think we can add privilege checking.
This should not be a big problem for this space, since
it has custom methods.

> 5.
> 
> The name _session_settings hints that, if I change the setting, I only
> affect my own session.
> However, as you know, if I change sql_compound_select_limit, I affect all
> sessions.
You are a bit wrong: both _vsession_settings and
_session_settings do not contain sql_compound_select_limit
setting.

> So perhaps it should be in a new different space, _vglobal_settings?
> 
There is definitely should be a different system space for
global settings. But, we have to decide, should it be
persistent or not. If the space should be persistent, than
we can create usual system space with memtx engine, that
should contain the settings. In the other case we can use
the same approach as for _session_settings system space.

> Peter Gulutzan
> 

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-19  9:59           ` Mergen Imeev
@ 2019-12-19 17:35             ` Peter Gulutzan
  2019-12-19 17:51               ` Mergen Imeev
  0 siblings, 1 reply; 30+ messages in thread
From: Peter Gulutzan @ 2019-12-19 17:35 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches, v.shpilevoy, tarantool-discussions

Hi,

On 2019-12-19 2:59 a.m., Mergen Imeev wrote:
 > Hi,
 >
 > Thank you for your suggestions! I will try to answer your
 > questions.
 >
 > On Wed, Dec 18, 2019 at 10:39:58AM -0700, Peter Gulutzan wrote:
 >> Hi,
 >>
 >> I think that there still might be a few small SQL-specific issues.
 >> I pulled today from branch imeevma/gh-4511-pragma-replaced-by-set.
 >>
 > This branch is out of date. I have not deleted it since
 > the problem is still not resolved.
 >
 > New branch: imeevma/gh-4511-new-engine
 >
 >> 1.
 >>
 >> The type of "value" is 'any', which is shown in metadata as 'string':
 >> "
 >> tarantool> box.execute([[SELECT typeof("value") FROM 
"_vsession_settings"
 >> LIMIT 1;]])
 >> ---
 >> - metadata:
 >>   - name: typeof("value")
 >>     type: string
 >>   rows:
 >>   - ['any']
 >> ...
 >> "
 >>
 >> But that means that searches of "value" will usually fail, thus:
 >> "
 >> tarantool> box.execute([[SELECT "name", "value" FROM 
"_vsession_settings"
 >> where "value" = 'vinyl';]])
 >> ---
 >> - null
 >> - 'Type mismatch: can not convert text to boolean'
 >> ...
 >> "
 >>
 >> Why not scalar?
 >>
 > True, I did not think about this problem before. I think
 > that I will change the type of the field to SCALAR if
 > there are no objections.
 >

Thanks, although I see now that my suggestion had a flaw.
Even if you change to SCALAR, the problem will still exist.
I vaguely remember that this has been discussed before,
but I cannot find an email that mentions it.
Anyway: it is bad and I think it should be regarded as a bug.
However, I certainly don't object to changing the data type
to a data type that is known to SQL.

 >> 2.
 >>
 >> You wrote this comment on issue#4511:
 >> "
 >> @pgulutzan @kostja It seems that we are going to solve the problem in a
 >> different way: we will create a special space that will contain the
 >> settings. This space will only allow updates. So, to change the setting
 >> value, you should do something like this:
 >> box.execute([[UPDATE "_session_settings" SET "value" = 'vinyl' WHERE 
"name"
 >> = 'sql_default_engine']])
 >> or
 >> box.space._session_settings:update('sql_default_engine', {{'=', 'value',
 >> 'vinyl'}})
 >> This will allow us to use the same method to change any settings in any
 >> front-end. Also after that we can simply remove the control p
 >> "
 >> But at this moment _session_settings does not exist.
 >> The only thing that works is
 >> box.execute([[SET sql_default_engine = 'vinyl';]])
 >> which is what I and Konstantin Osipov were raising questions about.
 >> In fact I can do it without 'write' privileges on anything.
 >>
 >> This is just temporary, right?
 >>
 > Not exactly, the system space with allowed UPDATE can be
 > seen on new branch.
 >

Yes, I see _session_settings now, although I didn't UPDATE successfully.
And box.execute([[SET sql_default_engine = 'vinyl';]]) fails -- hurray.

 >> 3.
 >>
 >> VALUE happens to be a reserved word in DB2 and Oracle.
 >> Although we have no plans to reserve it, well, it's a micro-issue for
 >> compatibility.
 >> You might of course dismiss this because our column name is "value" not
 >> value.
 >> But suppose that some user agrees totally with Konstantin Osipov (alas),
 >> and decides to use a method that allows access to the data without quote
 >> marks:
 >> "
 >> tarantool> box.execute([[CREATE VIEW vsession_settings AS SELECT 
"value" AS
 >> value, "name" AS name FROM "_vsession_settings";]])
 >> ---
 >> - row_count: 1
 >> ...
 >>
 >> tarantool> box.execute([[SELECT * FROM vsession_settings WHERE name =
 >> 'sql_default_engine';]])
 >> ---
 >> - metadata:
 >>   - name: VALUE
 >>     type: any
 >>   - name: NAME
 >>     type: string
 >>   rows:
 >>   - ['vinyl', 'sql_default_engine']
 >> ...
 >> "
 >> I think this means that some users will have columns named VALUE,
 >> so we will cause trouble if someday we reserve it.
 >>
 > We can change the name of the field before the patch is
 > pushed. Do you have any suggestions on how we should name
 > the field?
 >

Thanks for considering a change.
Unfortunately I have tried and failed to think of a better word.
Therefore, if nobody else has an idea, let us forget this complaint.

 >> 4.
 >>
 >> This suggestion was accepted according to Issue#4511:
 >> _session_settings has columns 'name' and 'value', so:
 >> UPDATE "session_settings" SET "value" = 'vinyl' WHERE "name" =
 >> 'sql_default_engine';
 >> This suggestion (made by N. Pettik in the thread) was rejected:
 >> _session_settings has many columns including 'sql_default_engine' and
 >> 'value', so
 >> UPDATE "session_settings" SET "sql_default_engine" = 'vinyl';
 >>
 >> Okay, but ...
 >>
 >> If we someday support GRANT, and sql_default_engine was a column, we 
could
 >> say:
 >> GRANT UPDATE ON "_session_settings" ("sql_default_engine");
 >> that is, we could be very specific about what you can update.
 >> But there is no equivalent GRANT statement, with #4511,
 >> unless one adds a non-standard extension like
 >> GRANT UPDATE on "_session_settings" ("value") WHERE "name" =
 >> 'sql_default_engine';
 >>
 >> I think that a few other things are simpler if sql_default_engine is a
 >> column:
 >> CHECK ("sql_default_engine" IN ('memtx','vinyl')) versus
 >> CHECK ("name" <> 'sql_default_engine' OR "value" IN ('memtx','vinyl'))
 >> and
 >> SELECT "sql_default_engine", "parser_trace" FROM "_vsession_settings";
 >> versus
 >> SELECT "value" AS sql_default_engine FROM "_vsession_settings" WHERE 
"name"
 >> = 'sql_default_engine'
 >> UNION
 >> SELECT "value" AS parser_trace FROM "_vsession_settings" WHERE "name" =
 >> 'parser_trace';
 >> (I say "I think" and admit that there may be better solutions I 
didn't think
 >> about.)
 >>
 > That is a bit problematic, since if we want to
 > add/change/remove a setting, we have to rebuild bootstrap.
 >

Okay. I regret that, but realize that the world is real.

 > At the same time, I think we can add privilege checking.
 > This should not be a big problem for this space, since
 > it has custom methods.
 >

I guess you mean that you can add a non-standard extension for GRANT.

 >> 5.
 >>
 >> The name _session_settings hints that, if I change the setting, I only
 >> affect my own session.
 >> However, as you know, if I change sql_compound_select_limit, I 
affect all
 >> sessions.
 > You are a bit wrong: both _vsession_settings and
 > _session_settings do not contain sql_compound_select_limit
 > setting.
 >

You are a bit right. I didn't say they contained it, but my remark was 
off topic.

 >> So perhaps it should be in a new different space, _vglobal_settings?
 >>
 > There is definitely should be a different system space for
 > global settings. But, we have to decide, should it be
 > persistent or not. If the space should be persistent, than
 > we can create usual system space with memtx engine, that
 > should contain the settings. In the other case we can use
 > the same approach as for _session_settings system space.

I do not know anything about that.
If the differences affect behaviour that users might expect
(for example rollback and logging), maybe the manual will
mention it but maybe we'll decide they're not important.

Peter Gulutzan

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-19 17:35             ` Peter Gulutzan
@ 2019-12-19 17:51               ` Mergen Imeev
  0 siblings, 0 replies; 30+ messages in thread
From: Mergen Imeev @ 2019-12-19 17:51 UTC (permalink / raw)
  To: Peter Gulutzan; +Cc: tarantool-patches, v.shpilevoy, tarantool-discussions

Hi,

On Thu, Dec 19, 2019 at 10:35:54AM -0700, Peter Gulutzan wrote:
> Hi,
> 
> On 2019-12-19 2:59 a.m., Mergen Imeev wrote:
> > Hi,
> >
> > Thank you for your suggestions! I will try to answer your
> > questions.
> >
> > On Wed, Dec 18, 2019 at 10:39:58AM -0700, Peter Gulutzan wrote:
> >> Hi,
> >>
> >> I think that there still might be a few small SQL-specific issues.
> >> I pulled today from branch imeevma/gh-4511-pragma-replaced-by-set.
> >>
> > This branch is out of date. I have not deleted it since
> > the problem is still not resolved.
> >
> > New branch: imeevma/gh-4511-new-engine
> >
> >> 1.
> >>
> >> The type of "value" is 'any', which is shown in metadata as 'string':
> >> "
> >> tarantool> box.execute([[SELECT typeof("value") FROM "_vsession_settings"
> >> LIMIT 1;]])
> >> ---
> >> - metadata:
> >>   - name: typeof("value")
> >>     type: string
> >>   rows:
> >>   - ['any']
> >> ...
> >> "
> >>
> >> But that means that searches of "value" will usually fail, thus:
> >> "
> >> tarantool> box.execute([[SELECT "name", "value" FROM "_vsession_settings"
> >> where "value" = 'vinyl';]])
> >> ---
> >> - null
> >> - 'Type mismatch: can not convert text to boolean'
> >> ...
> >> "
> >>
> >> Why not scalar?
> >>
> > True, I did not think about this problem before. I think
> > that I will change the type of the field to SCALAR if
> > there are no objections.
> >
> 
> Thanks, although I see now that my suggestion had a flaw.
> Even if you change to SCALAR, the problem will still exist.
> I vaguely remember that this has been discussed before,
> but I cannot find an email that mentions it.
> Anyway: it is bad and I think it should be regarded as a bug.
> However, I certainly don't object to changing the data type
> to a data type that is known to SQL.
> 
> >> 2.
> >>
> >> You wrote this comment on issue#4511:
> >> "
> >> @pgulutzan @kostja It seems that we are going to solve the problem in a
> >> different way: we will create a special space that will contain the
> >> settings. This space will only allow updates. So, to change the setting
> >> value, you should do something like this:
> >> box.execute([[UPDATE "_session_settings" SET "value" = 'vinyl' WHERE
> "name"
> >> = 'sql_default_engine']])
> >> or
> >> box.space._session_settings:update('sql_default_engine', {{'=', 'value',
> >> 'vinyl'}})
> >> This will allow us to use the same method to change any settings in any
> >> front-end. Also after that we can simply remove the control p
> >> "
> >> But at this moment _session_settings does not exist.
> >> The only thing that works is
> >> box.execute([[SET sql_default_engine = 'vinyl';]])
> >> which is what I and Konstantin Osipov were raising questions about.
> >> In fact I can do it without 'write' privileges on anything.
> >>
> >> This is just temporary, right?
> >>
> > Not exactly, the system space with allowed UPDATE can be
> > seen on new branch.
> >
> 
> Yes, I see _session_settings now, although I didn't UPDATE successfully.
> And box.execute([[SET sql_default_engine = 'vinyl';]]) fails -- hurray.
> 
Well, for SQL it is just a usual space. To update it you
have to use something like:

UPDATE "_session_settings" SET "value" = 'vinyl' WHERE "name" = 'sql_default_engine';

or
box.space._session_settings:update('sql_default_engine', {{'=', 2, 'vinyl'}})

Well, not exactly usual. It can be seen if you try to
change type of value of any setting.

> >> 3.
> >>
> >> VALUE happens to be a reserved word in DB2 and Oracle.
> >> Although we have no plans to reserve it, well, it's a micro-issue for
> >> compatibility.
> >> You might of course dismiss this because our column name is "value" not
> >> value.
> >> But suppose that some user agrees totally with Konstantin Osipov (alas),
> >> and decides to use a method that allows access to the data without quote
> >> marks:
> >> "
> >> tarantool> box.execute([[CREATE VIEW vsession_settings AS SELECT "value"
> AS
> >> value, "name" AS name FROM "_vsession_settings";]])
> >> ---
> >> - row_count: 1
> >> ...
> >>
> >> tarantool> box.execute([[SELECT * FROM vsession_settings WHERE name =
> >> 'sql_default_engine';]])
> >> ---
> >> - metadata:
> >>   - name: VALUE
> >>     type: any
> >>   - name: NAME
> >>     type: string
> >>   rows:
> >>   - ['vinyl', 'sql_default_engine']
> >> ...
> >> "
> >> I think this means that some users will have columns named VALUE,
> >> so we will cause trouble if someday we reserve it.
> >>
> > We can change the name of the field before the patch is
> > pushed. Do you have any suggestions on how we should name
> > the field?
> >
> 
> Thanks for considering a change.
> Unfortunately I have tried and failed to think of a better word.
> Therefore, if nobody else has an idea, let us forget this complaint.
> 
> >> 4.
> >>
> >> This suggestion was accepted according to Issue#4511:
> >> _session_settings has columns 'name' and 'value', so:
> >> UPDATE "session_settings" SET "value" = 'vinyl' WHERE "name" =
> >> 'sql_default_engine';
> >> This suggestion (made by N. Pettik in the thread) was rejected:
> >> _session_settings has many columns including 'sql_default_engine' and
> >> 'value', so
> >> UPDATE "session_settings" SET "sql_default_engine" = 'vinyl';
> >>
> >> Okay, but ...
> >>
> >> If we someday support GRANT, and sql_default_engine was a column, we
> could
> >> say:
> >> GRANT UPDATE ON "_session_settings" ("sql_default_engine");
> >> that is, we could be very specific about what you can update.
> >> But there is no equivalent GRANT statement, with #4511,
> >> unless one adds a non-standard extension like
> >> GRANT UPDATE on "_session_settings" ("value") WHERE "name" =
> >> 'sql_default_engine';
> >>
> >> I think that a few other things are simpler if sql_default_engine is a
> >> column:
> >> CHECK ("sql_default_engine" IN ('memtx','vinyl')) versus
> >> CHECK ("name" <> 'sql_default_engine' OR "value" IN ('memtx','vinyl'))
> >> and
> >> SELECT "sql_default_engine", "parser_trace" FROM "_vsession_settings";
> >> versus
> >> SELECT "value" AS sql_default_engine FROM "_vsession_settings" WHERE
> "name"
> >> = 'sql_default_engine'
> >> UNION
> >> SELECT "value" AS parser_trace FROM "_vsession_settings" WHERE "name" =
> >> 'parser_trace';
> >> (I say "I think" and admit that there may be better solutions I didn't
> think
> >> about.)
> >>
> > That is a bit problematic, since if we want to
> > add/change/remove a setting, we have to rebuild bootstrap.
> >
> 
> Okay. I regret that, but realize that the world is real.
> 
> > At the same time, I think we can add privilege checking.
> > This should not be a big problem for this space, since
> > it has custom methods.
> >
> 
> I guess you mean that you can add a non-standard extension for GRANT.
> 
Not sure for now, but I will look at this later.

> >> 5.
> >>
> >> The name _session_settings hints that, if I change the setting, I only
> >> affect my own session.
> >> However, as you know, if I change sql_compound_select_limit, I affect all
> >> sessions.
> > You are a bit wrong: both _vsession_settings and
> > _session_settings do not contain sql_compound_select_limit
> > setting.
> >
> 
> You are a bit right. I didn't say they contained it, but my remark was off
> topic.
> 
> >> So perhaps it should be in a new different space, _vglobal_settings?
> >>
> > There is definitely should be a different system space for
> > global settings. But, we have to decide, should it be
> > persistent or not. If the space should be persistent, than
> > we can create usual system space with memtx engine, that
> > should contain the settings. In the other case we can use
> > the same approach as for _session_settings system space.
> 
> I do not know anything about that.
> If the differences affect behaviour that users might expect
> (for example rollback and logging), maybe the manual will
> mention it but maybe we'll decide they're not important.
> 
> Peter Gulutzan
> 

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

* Re: [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET
  2019-12-18 17:39         ` Peter Gulutzan
  2019-12-19  9:59           ` Mergen Imeev
@ 2019-12-19 21:09           ` Vladislav Shpilevoy
  1 sibling, 0 replies; 30+ messages in thread
From: Vladislav Shpilevoy @ 2019-12-19 21:09 UTC (permalink / raw)
  To: Peter Gulutzan, Mergen Imeev; +Cc: tarantool-discussions, tarantool-patches

Hi!

Just one small note below.

On 18/12/2019 18:39, Peter Gulutzan wrote:
> Hi,
> 
> I think that there still might be a few small SQL-specific issues.
> I pulled today from branch imeevma/gh-4511-pragma-replaced-by-set.
> 
> 1.
> 
> The type of "value" is 'any', which is shown in metadata as 'string':
> "
> tarantool> box.execute([[SELECT typeof("value") FROM "_vsession_settings" LIMIT 1;]])
> ---
> - metadata:
>   - name: typeof("value")
>     type: string
>   rows:
>   - ['any']
> ...
> "

Well, 'string' is not a type of "value". It is a type of
typeof() function result. So here everything is alright.

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

end of thread, other threads:[~2019-12-19 21:09 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-07 10:36 [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET imeevma
2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 1/5] sysview: make get() and create_iterator() methods virtual imeevma
2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 2/5] box: introdice _vsession_settings sysview imeevma
2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 3/5] sql: introduce SET statement imeevma
2019-11-07 12:40   ` Vladislav Shpilevoy
2019-11-07 14:12     ` Mergen Imeev
2019-11-11 21:56       ` Vladislav Shpilevoy
2019-11-15 14:06         ` Mergen Imeev
2019-11-17 17:26           ` Vladislav Shpilevoy
2019-11-17 20:32             ` Vladislav Shpilevoy
2019-11-27 10:33               ` Mergen Imeev
2019-11-27 23:03                 ` Vladislav Shpilevoy
2019-11-27 23:07                   ` Vladislav Shpilevoy
2019-11-27 23:09                     ` Vladislav Shpilevoy
2019-11-28  8:59                     ` Mergen Imeev
2019-11-28  8:56                   ` Mergen Imeev
2019-11-07 10:36 ` [Tarantool-patches] [PATCH v3 4/5] temporary: disable boolean.test.sql imeevma
2019-11-07 10:37 ` [Tarantool-patches] [PATCH v3 5/5] sql: replace control pragmas imeevma
2019-12-06 11:37 ` [Tarantool-patches] [PATCH v3 0/5] Replace control pragmas by SET Kirill Yukhin
2019-12-06 13:50   ` Mergen Imeev
2019-12-06 14:06     ` Sergey Ostanevich
2019-12-17 22:11     ` Alexander Turenko
2019-12-18  2:39       ` Peter Gulutzan
2019-12-18 17:39         ` Peter Gulutzan
2019-12-19  9:59           ` Mergen Imeev
2019-12-19 17:35             ` Peter Gulutzan
2019-12-19 17:51               ` Mergen Imeev
2019-12-19 21:09           ` Vladislav Shpilevoy
2019-12-18 10:20       ` Kirill Yukhin
2019-12-18 10:53         ` Alexander Turenko

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