From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp16.mail.ru (smtp16.mail.ru [94.100.176.153]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 5886A442BB9 for ; Mon, 23 Mar 2020 14:42:14 +0300 (MSK) Received: by smtp16.mail.ru with esmtpa (envelope-from ) id 1jGLTB-0001rr-Rz for tarantool-patches@dev.tarantool.org; Mon, 23 Mar 2020 14:42:14 +0300 References: <23e20a4665756721778df4e46d8efb3d273fde02.1579247383.git.imeevma@gmail.com> <20200120175725.GE82780@tarantool.org> <20200225101729.GA28823@tarantool.org> <20200311152759.GA29797@tarantool.org> <20200323114052.GA24332@tarantool.org> From: Imeev Mergen Message-ID: <5a06f7c5-9c95-279b-276b-0282dbcf54ca@tarantool.org> Date: Mon, 23 Mar 2020 14:42:13 +0300 MIME-Version: 1.0 In-Reply-To: <20200323114052.GA24332@tarantool.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US Subject: Re: [Tarantool-patches] [PATCH v1 1/1] sql: use rowid as PK of ephemeral space on INSERT List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org On 3/23/20 2:40 PM, Mergen Imeev wrote: > Hi! Thank you for the patch. My answers, diff and new > version below. Sorry, I mean "the review". > > On Wed, Mar 11, 2020 at 03:27:59PM +0000, Nikita Pettik wrote: >> On 25 Feb 13:17, Mergen Imeev wrote: >>> Hi! Thank you for review. My answers and new patch beliw. >>> Date: Mon, 24 Feb 2020 16:44:07 +0300 >>> Subject: [PATCH] sql: do not change order of inserted values on INSERT >>> >>> Prior to this patch, if ephemeral space was used during INSERT, >> Does fix affect only insert, but not replace? Or both? > It affects both, but the problem appears only during INSERT > since we cannot use REPLACE to insert NULL in field with > AUTOINCREMENT. Changed the commit-message. > >>> the inserted values were sorted by the first column. >> Are inserted values are always sorted during insertion op? > No. It says "if ephemeral space was used", is this not > enough? > >>> This can lead >>> to an error when using the autoincrement feature. >> Why? Could you please provide details? Not personally for me, >> but in commit message. > Extended the commit message. > >>> To avoid this, >>> the patch makes it possible to make the rowid of the value >>> inserted into the ephemeral space be the first part of >>> ephemeral space index. >> So, before patch rowid could be only last column of table? > Now it is also the last column of the table. > >> And you achieve it extending sql_key_info with additional field? > Yes. > >> All these tip-questions should help you to make commit message >> more informative. > Thanks. > >>> Closes #4256 >> Please attach a changelog to the patch. > Done. > >>> diff --git a/src/box/sql.c b/src/box/sql.c >>> index 1256df8..47cf235 100644 >>> --- a/src/box/sql.c >>> +++ b/src/box/sql.c >>> @@ -338,7 +338,10 @@ sql_ephemeral_space_create(uint32_t field_count, struct sql_key_info *key_info) >>> return NULL; >>> } >>> for (uint32_t i = 0; i < field_count; ++i) { >>> - struct key_part_def *part = &ephemer_key_parts[i]; >>> + uint32_t j = i; >>> + if (key_info != NULL && key_info->is_rowid_first) >>> + j = (j + 1) % field_count; >> What is going on here?? > Cyclic shift. > >>> + struct key_part_def *part = &ephemer_key_parts[j]; >>> part->fieldno = i; >>> part->nullable_action = ON_CONFLICT_ACTION_NONE; >>> part->is_nullable = true; >>> diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c >>> index 43a0de5..6ee728a 100644 >>> --- a/src/box/sql/insert.c >>> +++ b/src/box/sql/insert.c >>> @@ -455,8 +455,17 @@ sqlInsert(Parse * pParse, /* Parser context */ >>> reg_eph = ++pParse->nMem; >>> regRec = sqlGetTempReg(pParse); >>> regCopy = sqlGetTempRange(pParse, nColumn + 1); >>> - sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_eph, >>> - nColumn + 1); >>> + /* >>> + * This key_info is used to show that >>> + * rowid should be the first part of PK. >>> + */ >> Please, explain here why rowid should come as first column. >> See reference example in sql_table_delete_from(): >> >> 233 if (is_view) { >> 234 /* >> 235 * At this stage SELECT is already materialized >> 236 * into ephemeral table, which has one additional >> 237 * tail field (except for ones specified in view >> 238 * format) which contains sequential ids. These ids >> 239 * are required since selected values may turn out to >> 240 * be non-unique. For instance: >> 241 * CREATE TABLE t (id INT PRIMARY KEY, a INT); >> 242 * INSERT INTO t VALUES (1, 1), (2, 1), (3, 1); >> 243 * CREATE VIEW v AS SELECT a FROM t; >> >> ... >> > Done. > >>> + struct sql_key_info *key_info = >>> + sql_key_info_new(pParse->db, nColumn + 1); >>> + key_info->parts[nColumn].type = FIELD_TYPE_UNSIGNED; >>> + key_info->is_rowid_first = true; >>> + sqlVdbeAddOp4(v, OP_OpenTEphemeral, reg_eph, >>> + nColumn + 1, 0, (char *)key_info, >>> + P4_KEYINFO); >>> addrL = sqlVdbeAddOp1(v, OP_Yield, dest.iSDParm); >>> VdbeCoverage(v); >>> sqlVdbeAddOp2(v, OP_NextIdEphemeral, reg_eph, >>> diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h >>> index d1fcf47..d9da921 100644 >>> --- a/src/box/sql/sqlInt.h >>> +++ b/src/box/sql/sqlInt.h >>> @@ -4111,6 +4111,8 @@ struct sql_key_info { >>> struct key_def *key_def; >>> /** Reference counter. */ >>> uint32_t refs; >>> + /** Rowid should be the first part of PK if true. */ >>> + bool is_rowid_first; >> Otherwise it is last or not presented at all? > Yes. I changed the comment, but I am not sure if this is > right. The only porpose of this flag is to show that if > the rowid the first column. If this flag is false we may > say that rowid may be not the first column. > >>> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c >>> index 620d74e..db782a7 100644 >>> --- a/src/box/sql/vdbe.c >>> +++ b/src/box/sql/vdbe.c >>> @@ -2702,8 +2702,25 @@ case OP_Column: { >>> * key parts. >>> */ >>> if (pC->uc.pCursor->curFlags & BTCF_TEphemCursor) { >>> - field_type = pC->uc.pCursor->index->def-> >>> - key_def->parts[p2].type; >>> + struct key_def *key_def = >>> + pC->uc.pCursor->index->def->key_def; >>> + /* >>> + * There are three options: >>> + * |Rowid|First field|...|Last field| >>> + * Or: >>> + * |First field|...|Last field| >>> + * Or: >>> + * |First field|...|Last field|Rowid| >>> + * >>> + * If ephemeral space has a rowid column, >> But it contradicts schema above. > How? > >>> + * it is always the last column. Due to >>> + * this, the field number of the rowid >>> + * column cannot be 0. >>> + */ >>> + int partno = p2; >>> + if (key_def->parts[0].fieldno != 0) >>> + partno = (partno + 1) % key_def->part_count; >> See this for the second time, still don't understand what it is >> supposed to mean. > Simplified a bit and extended the comment. > >>> + field_type = key_def->parts[partno].type; >>> } else if (pC->uc.pCursor->curFlags & BTCF_TaCursor) { >>> field_type = pC->uc.pCursor->space->def-> >>> fields[p2].type; >>> diff --git a/test/sql/autoincrement.test.lua b/test/sql/autoincrement.test.lua >>> index 63a902a..99f4813 100644 >>> --- a/test/sql/autoincrement.test.lua >>> +++ b/test/sql/autoincrement.test.lua >>> @@ -31,3 +31,13 @@ seqs = box.space._sequence:select{} >>> #seqs == 0 or seqs >>> >>> box.schema.user.drop('user1') >>> + >>> +-- >>> +-- gh-4256: make sure that when inserting, values are inserted in >>> +-- the given order when ephemeral space is used. >>> +-- >>> +box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') >>> +box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') >>> +box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') >> Leave explanation why no-op trigger is required. Otherwise it >> looks redundant. > Done. > >> Also, Kirill forces new convention saying that >> each bug fix should be placed at separate file named gh-xxxx-description. > Done. > >>> +box.execute('SELECT * FROM t;') >>> +box.execute('DROP TABLE t;') > > Diff: > > > diff --git a/src/box/sql.c b/src/box/sql.c > index 47cf235..8c25095 100644 > --- a/src/box/sql.c > +++ b/src/box/sql.c > @@ -339,6 +339,12 @@ sql_ephemeral_space_create(uint32_t field_count, struct sql_key_info *key_info) > } > for (uint32_t i = 0; i < field_count; ++i) { > uint32_t j = i; > + /* > + * In case we know that the last column is rowid, > + * and we want to make it the first part of the > + * index, we will do a cyclic shift. Thus, we will > + * not disrupt the order of other columns. > + */ > if (key_info != NULL && key_info->is_rowid_first) > j = (j + 1) % field_count; > struct key_part_def *part = &ephemer_key_parts[j]; > diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c > index 6ee728a..28e3096 100644 > --- a/src/box/sql/insert.c > +++ b/src/box/sql/insert.c > @@ -458,6 +458,12 @@ sqlInsert(Parse * pParse, /* Parser context */ > /* > * This key_info is used to show that > * rowid should be the first part of PK. > + * This way we will save initial order of > + * the inserted values. The order is > + * important if we use the AUTOINCREMENT > + * feature, since changing the order can > + * change the number inserted instead of > + * NULL. > */ > struct sql_key_info *key_info = > sql_key_info_new(pParse->db, nColumn + 1); > diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h > index 9c00a7b..a5f0249 100644 > --- a/src/box/sql/sqlInt.h > +++ b/src/box/sql/sqlInt.h > @@ -4114,7 +4114,11 @@ struct sql_key_info { > struct key_def *key_def; > /** Reference counter. */ > uint32_t refs; > - /** Rowid should be the first part of PK if true. */ > + /** > + * Rowid should be the first part of PK, if true. If this > + * flag is false, rowid may be any part of the index or > + * may be absent. > + */ > bool is_rowid_first; > /** Number of parts in the key. */ > uint32_t part_count; > diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c > index a200063..e5cfa5e 100644 > --- a/src/box/sql/vdbe.c > +++ b/src/box/sql/vdbe.c > @@ -2715,11 +2715,21 @@ case OP_Column: { > * If ephemeral space has a rowid column, > * it is always the last column. Due to > * this, the field number of the rowid > - * column cannot be 0. > + * column cannot be 0. So, if the first > + * part of the index have something other > + * than 0 as a fieldno, we know that this > + * is fieldno of rowid, since in all other > + * cases fieldno of the first part is 0. > + * > + * If rowid is the first part of the > + * index, we know that all the other parts > + * are columns sorted in the required > + * order. So, we should increment partno > + * by 1. > */ > - int partno = p2; > + uint32_t partno = p2; > if (key_def->parts[0].fieldno != 0) > - partno = (partno + 1) % key_def->part_count; > + ++partno; > field_type = key_def->parts[partno].type; > } else if (pC->uc.pCursor->curFlags & BTCF_TaCursor) { > field_type = pC->uc.pCursor->space->def-> > diff --git a/test/sql/autoincrement.result b/test/sql/autoincrement.result > index 7d3e902..ca3d6f3 100644 > --- a/test/sql/autoincrement.result > +++ b/test/sql/autoincrement.result > @@ -78,43 +78,3 @@ seqs = box.space._sequence:select{} > box.schema.user.drop('user1') > | --- > | ... > - > --- > --- gh-4256: make sure that when inserting, values are inserted in > --- the given order when ephemeral space is used. > --- > -box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > - | --- > - | - row_count: 1 > - | ... > -box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > - | --- > - | - row_count: 1 > - | ... > -box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > - | --- > - | - autoincrement_ids: > - | - 2 > - | - 11 > - | - 12 > - | - 13 > - | row_count: 7 > - | ... > -box.execute('SELECT * FROM t;') > - | --- > - | - metadata: > - | - name: I > - | type: integer > - | rows: > - | - [1] > - | - [2] > - | - [3] > - | - [10] > - | - [11] > - | - [12] > - | - [13] > - | ... > -box.execute('DROP TABLE t;') > - | --- > - | - row_count: 1 > - | ... > diff --git a/test/sql/autoincrement.test.lua b/test/sql/autoincrement.test.lua > index 99f4813..63a902a 100644 > --- a/test/sql/autoincrement.test.lua > +++ b/test/sql/autoincrement.test.lua > @@ -31,13 +31,3 @@ seqs = box.space._sequence:select{} > #seqs == 0 or seqs > > box.schema.user.drop('user1') > - > --- > --- gh-4256: make sure that when inserting, values are inserted in > --- the given order when ephemeral space is used. > --- > -box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > -box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > -box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > -box.execute('SELECT * FROM t;') > -box.execute('DROP TABLE t;') > diff --git a/test/sql/gh-4256-do-not-change-order-during-insertion.result b/test/sql/gh-4256-do-not-change-order-during-insertion.result > new file mode 100644 > index 0000000..56e28b5 > --- /dev/null > +++ b/test/sql/gh-4256-do-not-change-order-during-insertion.result > @@ -0,0 +1,50 @@ > +-- test-run result file version 2 > +test_run = require('test_run').new() > + | --- > + | ... > +engine = test_run:get_cfg('engine') > + | --- > + | ... > +-- > +-- Make sure that when inserting, values are inserted in the given > +-- order when ephemeral space is used. > +-- > +box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > + | --- > + | - row_count: 1 > + | ... > +-- > +-- In order for this INSERT to use the ephemeral space, we created > +-- this trigger. > +-- > +box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > + | --- > + | - row_count: 1 > + | ... > +box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > + | --- > + | - autoincrement_ids: > + | - 2 > + | - 11 > + | - 12 > + | - 13 > + | row_count: 7 > + | ... > +box.execute('SELECT * FROM t;') > + | --- > + | - metadata: > + | - name: I > + | type: integer > + | rows: > + | - [1] > + | - [2] > + | - [3] > + | - [10] > + | - [11] > + | - [12] > + | - [13] > + | ... > +box.execute('DROP TABLE t;') > + | --- > + | - row_count: 1 > + | ... > diff --git a/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua b/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua > new file mode 100644 > index 0000000..4d8367c > --- /dev/null > +++ b/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua > @@ -0,0 +1,15 @@ > +test_run = require('test_run').new() > +engine = test_run:get_cfg('engine') > +-- > +-- Make sure that when inserting, values are inserted in the given > +-- order when ephemeral space is used. > +-- > +box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > +-- > +-- In order for this INSERT to use the ephemeral space, we created > +-- this trigger. > +-- > +box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > +box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > +box.execute('SELECT * FROM t;') > +box.execute('DROP TABLE t;') > > > New version: > > > From 4244c170e0b22fa1084d8d9e1fac9c252b9b73cd Mon Sep 17 00:00:00 2001 > Message-Id: <4244c170e0b22fa1084d8d9e1fac9c252b9b73cd.1584962777.git.imeevma@gmail.com> > From: Mergen Imeev > Date: Mon, 24 Feb 2020 16:44:07 +0300 > Subject: [PATCH v2 1/1] sql: do not change order of inserted values > > Before this patch, if an ephemeral space was used during INSERT or > REPLACE, the inserted values were sorted by the first column, > since this was the first part of the index. This can lead to an > error when using the AUTOINCREMENT feature, since changing the > order of the inserted value can change the value inserted instead > of NULL. To avoid this, the patch makes the rowid of the inserted > row in the ephemeral space the first part of the ephemeral space > index. Currently, if the ephemeral space has a rowid, it is always > the last column of the ephemeral space. So, to make rowid the > first part of the index, a cyclic shift is used. Thus, we will not > change the order of all other columns. > > Closes #4256 > --- > https://github.com/tarantool/tarantool/issues/4256 > https://github.com/tarantool/tarantool/tree/imeevma/gh-4256-fix-order-during-insertion > > @ChangeLog > - During INSERT and REPLACE the order of inserted rows will not > be changed (gh-4256). > > src/box/sql.c | 11 ++++- > src/box/sql/insert.c | 19 +++++++- > src/box/sql/select.c | 2 + > src/box/sql/sqlInt.h | 6 +++ > src/box/sql/vdbe.c | 31 +++++++++++++- > ...256-do-not-change-order-during-insertion.result | 50 ++++++++++++++++++++++ > ...6-do-not-change-order-during-insertion.test.lua | 15 +++++++ > 7 files changed, 129 insertions(+), 5 deletions(-) > create mode 100644 test/sql/gh-4256-do-not-change-order-during-insertion.result > create mode 100644 test/sql/gh-4256-do-not-change-order-during-insertion.test.lua > > diff --git a/src/box/sql.c b/src/box/sql.c > index 1256df8..8c25095 100644 > --- a/src/box/sql.c > +++ b/src/box/sql.c > @@ -338,7 +338,16 @@ sql_ephemeral_space_create(uint32_t field_count, struct sql_key_info *key_info) > return NULL; > } > for (uint32_t i = 0; i < field_count; ++i) { > - struct key_part_def *part = &ephemer_key_parts[i]; > + uint32_t j = i; > + /* > + * In case we know that the last column is rowid, > + * and we want to make it the first part of the > + * index, we will do a cyclic shift. Thus, we will > + * not disrupt the order of other columns. > + */ > + if (key_info != NULL && key_info->is_rowid_first) > + j = (j + 1) % field_count; > + struct key_part_def *part = &ephemer_key_parts[j]; > part->fieldno = i; > part->nullable_action = ON_CONFLICT_ACTION_NONE; > part->is_nullable = true; > diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c > index 43a0de5..28e3096 100644 > --- a/src/box/sql/insert.c > +++ b/src/box/sql/insert.c > @@ -455,8 +455,23 @@ sqlInsert(Parse * pParse, /* Parser context */ > reg_eph = ++pParse->nMem; > regRec = sqlGetTempReg(pParse); > regCopy = sqlGetTempRange(pParse, nColumn + 1); > - sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_eph, > - nColumn + 1); > + /* > + * This key_info is used to show that > + * rowid should be the first part of PK. > + * This way we will save initial order of > + * the inserted values. The order is > + * important if we use the AUTOINCREMENT > + * feature, since changing the order can > + * change the number inserted instead of > + * NULL. > + */ > + struct sql_key_info *key_info = > + sql_key_info_new(pParse->db, nColumn + 1); > + key_info->parts[nColumn].type = FIELD_TYPE_UNSIGNED; > + key_info->is_rowid_first = true; > + sqlVdbeAddOp4(v, OP_OpenTEphemeral, reg_eph, > + nColumn + 1, 0, (char *)key_info, > + P4_KEYINFO); > addrL = sqlVdbeAddOp1(v, OP_Yield, dest.iSDParm); > VdbeCoverage(v); > sqlVdbeAddOp2(v, OP_NextIdEphemeral, reg_eph, > diff --git a/src/box/sql/select.c b/src/box/sql/select.c > index 65e41f2..105a4a3 100644 > --- a/src/box/sql/select.c > +++ b/src/box/sql/select.c > @@ -1422,6 +1422,7 @@ sql_key_info_new(sql *db, uint32_t part_count) > key_info->key_def = NULL; > key_info->refs = 1; > key_info->part_count = part_count; > + key_info->is_rowid_first = false; > for (uint32_t i = 0; i < part_count; i++) { > struct key_part_def *part = &key_info->parts[i]; > part->fieldno = i; > @@ -1448,6 +1449,7 @@ sql_key_info_new_from_key_def(sql *db, const struct key_def *key_def) > key_info->key_def = NULL; > key_info->refs = 1; > key_info->part_count = key_def->part_count; > + key_info->is_rowid_first = false; > key_def_dump_parts(key_def, key_info->parts, NULL); > return key_info; > } > diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h > index 1579cc9..a5f0249 100644 > --- a/src/box/sql/sqlInt.h > +++ b/src/box/sql/sqlInt.h > @@ -4114,6 +4114,12 @@ struct sql_key_info { > struct key_def *key_def; > /** Reference counter. */ > uint32_t refs; > + /** > + * Rowid should be the first part of PK, if true. If this > + * flag is false, rowid may be any part of the index or > + * may be absent. > + */ > + bool is_rowid_first; > /** Number of parts in the key. */ > uint32_t part_count; > /** Definition of the key parts. */ > diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c > index e8a029a..e5cfa5e 100644 > --- a/src/box/sql/vdbe.c > +++ b/src/box/sql/vdbe.c > @@ -2702,8 +2702,35 @@ case OP_Column: { > * key parts. > */ > if (pC->uc.pCursor->curFlags & BTCF_TEphemCursor) { > - field_type = pC->uc.pCursor->index->def-> > - key_def->parts[p2].type; > + struct key_def *key_def = > + pC->uc.pCursor->index->def->key_def; > + /* > + * There are three options: > + * |Rowid|First field|...|Last field| > + * Or: > + * |First field|...|Last field| > + * Or: > + * |First field|...|Last field|Rowid| > + * > + * If ephemeral space has a rowid column, > + * it is always the last column. Due to > + * this, the field number of the rowid > + * column cannot be 0. So, if the first > + * part of the index have something other > + * than 0 as a fieldno, we know that this > + * is fieldno of rowid, since in all other > + * cases fieldno of the first part is 0. > + * > + * If rowid is the first part of the > + * index, we know that all the other parts > + * are columns sorted in the required > + * order. So, we should increment partno > + * by 1. > + */ > + uint32_t partno = p2; > + if (key_def->parts[0].fieldno != 0) > + ++partno; > + field_type = key_def->parts[partno].type; > } else if (pC->uc.pCursor->curFlags & BTCF_TaCursor) { > field_type = pC->uc.pCursor->space->def-> > fields[p2].type; > diff --git a/test/sql/gh-4256-do-not-change-order-during-insertion.result b/test/sql/gh-4256-do-not-change-order-during-insertion.result > new file mode 100644 > index 0000000..56e28b5 > --- /dev/null > +++ b/test/sql/gh-4256-do-not-change-order-during-insertion.result > @@ -0,0 +1,50 @@ > +-- test-run result file version 2 > +test_run = require('test_run').new() > + | --- > + | ... > +engine = test_run:get_cfg('engine') > + | --- > + | ... > +-- > +-- Make sure that when inserting, values are inserted in the given > +-- order when ephemeral space is used. > +-- > +box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > + | --- > + | - row_count: 1 > + | ... > +-- > +-- In order for this INSERT to use the ephemeral space, we created > +-- this trigger. > +-- > +box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > + | --- > + | - row_count: 1 > + | ... > +box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > + | --- > + | - autoincrement_ids: > + | - 2 > + | - 11 > + | - 12 > + | - 13 > + | row_count: 7 > + | ... > +box.execute('SELECT * FROM t;') > + | --- > + | - metadata: > + | - name: I > + | type: integer > + | rows: > + | - [1] > + | - [2] > + | - [3] > + | - [10] > + | - [11] > + | - [12] > + | - [13] > + | ... > +box.execute('DROP TABLE t;') > + | --- > + | - row_count: 1 > + | ... > diff --git a/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua b/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua > new file mode 100644 > index 0000000..4d8367c > --- /dev/null > +++ b/test/sql/gh-4256-do-not-change-order-during-insertion.test.lua > @@ -0,0 +1,15 @@ > +test_run = require('test_run').new() > +engine = test_run:get_cfg('engine') > +-- > +-- Make sure that when inserting, values are inserted in the given > +-- order when ephemeral space is used. > +-- > +box.execute('CREATE TABLE t (i INT PRIMARY KEY AUTOINCREMENT);') > +-- > +-- In order for this INSERT to use the ephemeral space, we created > +-- this trigger. > +-- > +box.execute('CREATE TRIGGER r AFTER INSERT ON t FOR EACH ROW BEGIN SELECT 1; END') > +box.execute('INSERT INTO t VALUES (1), (NULL), (10), (NULL), (NULL), (3), (NULL);') > +box.execute('SELECT * FROM t;') > +box.execute('DROP TABLE t;')