[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