[patches] [autoinc 1/2] sql: fix autoincrement for constraints
Bulat Niatshin
niatshin at tarantool.org
Tue Feb 13 17:03:13 MSK 2018
- Compute next autoincrement value before running constraints checks and
put it to mentioned registers instead of NULL, like it was before.
- Implement new opcode OP_NextValue, which calls sequence_next from
Tarantool and puts new value to necessary register.
- Implement necessary tests
Closes #2981
Signed-off-by: Bulat Niatshin <niatshin at tarantool.org>
---
src/box/sql/insert.c | 6 ++++-
src/box/sql/vdbe.c | 34 ++++++++++++++++++++++++++++
test/sql/gh-2981-check-autoinc.result | 40 +++++++++++++++++++++++++++++++++
test/sql/gh-2981-check-autoinc.test.lua | 16 +++++++++++++
4 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 test/sql/gh-2981-check-autoinc.result
create mode 100644 test/sql/gh-2981-check-autoinc.test.lua
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index bc1906fb6..35f428fbf 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -34,6 +34,7 @@
* to handle INSERT statements in SQLite.
*/
#include "sqliteInt.h"
+#include "tarantoolInt.h"
#include "box/session.h"
/*
@@ -323,6 +324,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */
int iDataCur = 0; /* VDBE cursor that is the main data repository */
int iIdxCur = 0; /* First index cursor */
int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
+ int space_id = -1; /* space id of table */
int endOfLoop; /* Label for the end of the insertion loop */
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
int addrInsTop = 0; /* Jump to label "D" */
@@ -379,6 +381,8 @@ sqlite3Insert(Parse * pParse, /* Parser context */
goto insert_cleanup;
}
+ space_id = (int) SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
+
/* Figure out if we have any triggers and if the table being
* inserted into is a view
*/
@@ -758,7 +762,7 @@ sqlite3Insert(Parse * pParse, /* Parser context */
if (j < 0 || nColumn == 0
|| (pColumn && j >= pColumn->nId)) {
if (i == pTab->iAutoIncPKey) {
- sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore);
+ sqlite3VdbeAddOp2(v, OP_NextValue, space_id, iRegStore);
continue;
}
sqlite3ExprCodeFactorable(pParse,
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index c3d726672..eaa9b7932 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -45,6 +45,7 @@
#include "vdbeInt.h"
#include "tarantoolInt.h"
#include "box/sql.h"
+#include "box/sequence.h"
#include "msgpuck/msgpuck.h"
@@ -1139,6 +1140,39 @@ case OP_String: { /* out2 */
break;
}
+/* Opcode: NextValue P1 P2 * * *
+ * Synopsis: r[P2] = next val from seq r[P1]
+ *
+ * Get next value for space from register P1 and write it into
+ * register P2. Opcode semantics assumes that space P1 has attached
+ * sequence, otherwise assertion fault will be caused.
+ *
+ * P1 - contains space_id of necessary space with sequence
+ * P2 - register number for output
+ */
+case OP_NextValue: {
+ int64_t value;
+ int space_id = pOp->p1;
+
+ struct space * autoinc_space = space_by_id(space_id);
+ assert(autoinc_space);
+
+ struct sequence * space_seq = autoinc_space->sequence;
+ assert(space_seq);
+
+ if (sequence_next(space_seq, &value) != 0) {
+ rc = SQLITE_TARANTOOL_ERROR;
+ goto abort_due_to_error;
+ }
+
+ pOut = out2Prerelease(p, pOp);
+
+ pOut->flags = MEM_Int;
+ pOut->n = 0;
+ pOut->u.i = value;
+
+ break;
+}
/* Opcode: Null P1 P2 P3 * *
* Synopsis: r[P2..P3]=NULL
*
diff --git a/test/sql/gh-2981-check-autoinc.result b/test/sql/gh-2981-check-autoinc.result
new file mode 100644
index 000000000..b34e35d49
--- /dev/null
+++ b/test/sql/gh-2981-check-autoinc.result
@@ -0,0 +1,40 @@
+box.cfg{}
+---
+...
+box.sql.execute("CREATE TABLE t1 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19));");
+---
+...
+box.sql.execute("CREATE TABLE t2 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19 AND s1 <> 25));");
+---
+...
+box.sql.execute("CREATE TABLE t3 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 < 10));");
+---
+...
+box.sql.execute("insert into t1 values (18, null);")
+---
+...
+box.sql.execute("insert into t1(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T1'
+...
+box.sql.execute("insert into t2 values (18, null);")
+---
+...
+box.sql.execute("insert into t2(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T2'
+...
+box.sql.execute("insert into t2 values (24, null);")
+---
+...
+box.sql.execute("insert into t2(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T2'
+...
+box.sql.execute("insert into t3 values (9, null)")
+---
+...
+box.sql.execute("insert into t3(s2) values (null)")
+---
+- error: 'CHECK constraint failed: T3'
+...
diff --git a/test/sql/gh-2981-check-autoinc.test.lua b/test/sql/gh-2981-check-autoinc.test.lua
new file mode 100644
index 000000000..3b4066bf8
--- /dev/null
+++ b/test/sql/gh-2981-check-autoinc.test.lua
@@ -0,0 +1,16 @@
+box.cfg{}
+
+box.sql.execute("CREATE TABLE t1 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19));");
+box.sql.execute("CREATE TABLE t2 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19 AND s1 <> 25));");
+box.sql.execute("CREATE TABLE t3 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 < 10));");
+
+box.sql.execute("insert into t1 values (18, null);")
+box.sql.execute("insert into t1(s2) values (null);")
+
+box.sql.execute("insert into t2 values (18, null);")
+box.sql.execute("insert into t2(s2) values (null);")
+box.sql.execute("insert into t2 values (24, null);")
+box.sql.execute("insert into t2(s2) values (null);")
+
+box.sql.execute("insert into t3 values (9, null)")
+box.sql.execute("insert into t3(s2) values (null)")
--
2.14.1
More information about the Tarantool-patches
mailing list