<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<p>Thank you for review! Diff between two last patches and new patch<br>
below.<br>
</p>
<br>
<div class="moz-cite-prefix">On 10/11/2018 06:09 PM, n.pettik wrote:<br>
</div>
<blockquote type="cite"
cite="mid:A38890C9-9974-4677-AFED-E6D0C3FBDD8F@tarantool.org">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<div><br class="">
<blockquote type="cite" class="">
<div class="">
<blockquote type="cite"
cite="mid:1AF44E5C-F76B-4783-8578-FC4AFA437E66@tarantool.org"
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; orphans:
auto; text-align: start; text-indent: 0px; text-transform:
none; white-space: normal; widows: auto; word-spacing:
0px; -webkit-text-size-adjust: auto;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<blockquote type="cite" class="">
<pre class="" wrap="">+--
+-- Check that _space, _index and _sequence have the same number of
+-- records.
+--
+space_count == #box.space._space:select()
+index_count == #box.space._index:select()
+sequence_count == #box.space._sequence:select()
+
+box.schema.user.drop('tmp’)
</pre>
</blockquote>
<pre class="" wrap="">I see no tests involving FK constraints. Add them as well.
</pre>
</blockquote>
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">Added.</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
</div>
</blockquote>
<div><br class="">
</div>
<br class="">
<blockquote type="cite" class="">
<div class=""><span style="font-family: Helvetica; font-size:
12px; font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">diff --git a/test/sql/drop-table.test.lua
b/test/sql/drop-table.test.lua</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">index 1bc8894..f86e3d8 100644</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">--- a/test/sql/drop-table.test.lua</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+++ b/test/sql/drop-table.test.lua</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<br style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+-- Give user right to write in _sequence. Still
have not enough</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+-- rights to write in _fk_constraint.</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+--</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+box.schema.user.grant('tmp', 'write', 'space',
'_sequence')</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+box.session.su('tmp')</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+box.sql.execute('CREATE TABLE t3(a INTEGER
PRIMARY KEY);')</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+--</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+-- Error: user do not have rights to write in
_fk_constraint.</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+--</span><br style="font-family: Helvetica;
font-size: 12px; font-style: normal; font-variant-caps:
normal; font-weight: normal; letter-spacing: normal;
text-align: start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+box.sql.execute('CREATE TABLE t4(x INTEGER
PRIMARY KEY REFERENCES t3);')</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
<span style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255); float: none; display: inline !important;"
class="">+box.sql.execute('DROP TABLE t3;’)</span><br
style="font-family: Helvetica; font-size: 12px;
font-style: normal; font-variant-caps: normal;
font-weight: normal; letter-spacing: normal; text-align:
start; text-indent: 0px; text-transform: none;
white-space: normal; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255,
255, 255);" class="">
</div>
</blockquote>
<div><br class="">
</div>
<div>You misunderstood me a bit. I mean following test:</div>
<div><span style="background-color: rgb(255, 255, 255);"
class=""><br class="">
</span></div>
<div>fk_count = <span style="background-color: rgb(255, 255,
255);" class="">#box.space._fk_constraints:select()</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class=""><br class="">
</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class="">box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY
KEY REFERENCES t3, a INT UNIQUE, c INT REFERENCES t3);’)</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class=""><br class="">
</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class="">Here creation of last FK fails - for instance due
to type mismatch.</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class="">Then, number of created FK constraints (and
indexes) should be unchanged:</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class=""><br class="">
</span></div>
<div>fk_count == <span style="background-color: rgb(255, 255,
255);" class="">#box.space._fk_constraints:select()</span></div>
<div><span style="background-color: rgb(255, 255, 255);"
class="">index_count == </span><span
style="background-color: rgb(255, 255, 255);" class="">#box.space._fk_constraints:select()</span></div>
<div><br class="">
</div>
<div>Note that FK constraints are created after indexes.</div>
<div><br class="">
</div>
</div>
</blockquote>
Fixed - changed last test.<br>
<br>
<b>Diff between last two patches:</b><br>
<br>
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result<br>
index 43da275..297799e 100644<br>
--- a/test/sql/drop-table.result<br>
+++ b/test/sql/drop-table.result<br>
@@ -132,11 +132,13 @@ sequence_count ==
#box.space._sequence:select()<br>
---<br>
- true<br>
...<br>
+fk_constraint_count = #box.space._fk_constraint:select()<br>
+---<br>
+...<br>
--<br>
--- Give user right to write in _sequence. Still have not enough<br>
--- rights to write in _fk_constraint.<br>
+-- Check that clean-up works fine after another error.<br>
--<br>
-box.schema.user.grant('tmp', 'write', 'space', '_sequence')<br>
+box.schema.user.grant('tmp', 'write', 'space')<br>
---<br>
...<br>
box.session.su('tmp')<br>
@@ -146,18 +148,16 @@ box.sql.execute('CREATE TABLE t3(a INTEGER
PRIMARY KEY);')<br>
---<br>
...<br>
--<br>
--- Error: user do not have rights to write in _fk_constraint.<br>
+-- Error: Failed to create foreign key constraint.<br>
--<br>
-box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3);')<br>
+box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3, a INT UNIQUE, c INT REFERENCES t3);')<br>
---<br>
-- error: Write access to space '_fk_constraint' is denied for user
'tmp'<br>
+- error: 'Failed to create foreign key constraint
''FK_CONSTRAINT_2_T4'': field type<br>
+ mismatch'<br>
...<br>
box.sql.execute('DROP TABLE t3;')<br>
---<br>
...<br>
-box.session.su('admin')<br>
----<br>
-...<br>
--<br>
-- Check that _space, _index and _sequence have the same number of<br>
-- records.<br>
@@ -174,6 +174,13 @@ sequence_count == #box.space._sequence:select()<br>
---<br>
- true<br>
...<br>
+fk_constraint_count == #box.space._fk_constraint:select()<br>
+---<br>
+- true<br>
+...<br>
+box.session.su('admin')<br>
+---<br>
+...<br>
box.schema.user.drop('tmp')<br>
---<br>
...<br>
diff --git a/test/sql/drop-table.test.lua
b/test/sql/drop-table.test.lua<br>
index f86e3d8..b1c5253 100644<br>
--- a/test/sql/drop-table.test.lua<br>
+++ b/test/sql/drop-table.test.lua<br>
@@ -83,22 +83,21 @@ space_count == #box.space._space:select()<br>
index_count == #box.space._index:select()<br>
sequence_count == #box.space._sequence:select()<br>
<br>
+fk_constraint_count = #box.space._fk_constraint:select()<br>
+<br>
--<br>
--- Give user right to write in _sequence. Still have not enough<br>
--- rights to write in _fk_constraint.<br>
+-- Check that clean-up works fine after another error.<br>
--<br>
-box.schema.user.grant('tmp', 'write', 'space', '_sequence')<br>
+box.schema.user.grant('tmp', 'write', 'space')<br>
box.session.su('tmp')<br>
<br>
box.sql.execute('CREATE TABLE t3(a INTEGER PRIMARY KEY);')<br>
--<br>
--- Error: user do not have rights to write in _fk_constraint.<br>
+-- Error: Failed to create foreign key constraint.<br>
--<br>
-box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3);')<br>
+box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3, a INT UNIQUE, c INT REFERENCES t3);')<br>
box.sql.execute('DROP TABLE t3;')<br>
<br>
-box.session.su('admin')<br>
-<br>
--<br>
-- Check that _space, _index and _sequence have the same number of<br>
-- records.<br>
@@ -106,5 +105,8 @@ box.session.su('admin')<br>
space_count == #box.space._space:select()<br>
index_count == #box.space._index:select()<br>
sequence_count == #box.space._sequence:select()<br>
+fk_constraint_count == #box.space._fk_constraint:select()<br>
+<br>
+box.session.su('admin')<br>
<br>
box.schema.user.drop('tmp')<br>
<br>
<b>New patch:</b><br>
<br>
commit f9092f3fd17676bfe220bf9d31aa4ed9a648590c<br>
Author: Mergen Imeev <a class="moz-txt-link-rfc2396E"
href="mailto:imeevma@gmail.com"><imeevma@gmail.com></a><br>
Date: Fri Aug 31 15:50:17 2018 +0300<br>
<br>
sql: clean-up on failed CREATE TABLE<br>
<br>
In case statement "CREATE TABLE ..." fails it can left some<br>
records in system spaces that shouldn't be there. These records<br>
won't be left behind after this patch.<br>
<br>
@TarantoolBot document<br>
Title: Clean up after failure of CREATE TABLE<br>
Usually CREATE TABLE creates no less than two objects which are<br>
space and index. If creation of index (or any object after
space)<br>
failed, created space (and other created objects) won't be
deleted<br>
though operation failed. Now these objects will be deleted<br>
properly.<br>
<br>
Closes #3592<br>
<br>
diff --git a/src/box/sql/build.c b/src/box/sql/build.c<br>
index a806fb4..28b488c 100644<br>
--- a/src/box/sql/build.c<br>
+++ b/src/box/sql/build.c<br>
@@ -55,6 +55,53 @@<br>
#include "box/tuple_format.h"<br>
#include "box/coll_id_cache.h"<br>
<br>
+/**<br>
+ * Structure that contains information about record that was<br>
+ * inserted into system space.<br>
+ */<br>
+struct saved_record<br>
+{<br>
+ /** A link in a record list. */<br>
+ struct rlist link;<br>
+ /** Id of space in which the record was inserted. */<br>
+ uint32_t space_id;<br>
+ /** First register of the key of the record. */<br>
+ int reg_key;<br>
+ /** Number of registers the key consists of. */<br>
+ int reg_key_count;<br>
+ /** The number of the OP_SInsert operation. */<br>
+ int insertion_opcode;<br>
+};<br>
+<br>
+/**<br>
+ * Save inserted in system space record in list.<br>
+ *<br>
+ * @param parser SQL Parser object.<br>
+ * @param space_id Id of table in which record is inserted.<br>
+ * @param reg_key Register that contains first field of the key.<br>
+ * @param reg_key_count Exact number of fields of the key.<br>
+ * @param insertion_opcode Number of OP_SInsert opcode.<br>
+ */<br>
+static inline void<br>
+save_record(struct Parse *parser, uint32_t space_id, int reg_key,<br>
+ int reg_key_count, int insertion_opcode)<br>
+{<br>
+ struct saved_record *record =<br>
+ region_alloc(&parser->region, sizeof(*record));<br>
+ if (record == NULL) {<br>
+ diag_set(OutOfMemory, sizeof(*record), "region_alloc",<br>
+ "record");<br>
+ parser->rc = SQL_TARANTOOL_ERROR;<br>
+ parser->nErr++;<br>
+ return;<br>
+ }<br>
+ record->space_id = space_id;<br>
+ record->reg_key = reg_key;<br>
+ record->reg_key_count = reg_key_count;<br>
+ record->insertion_opcode = insertion_opcode;<br>
+ rlist_add_entry(&parser->record_list, record, link);<br>
+}<br>
+<br>
void<br>
sql_finish_coding(struct Parse *parse_context)<br>
{<br>
@@ -62,6 +109,42 @@ sql_finish_coding(struct Parse *parse_context)<br>
struct sqlite3 *db = parse_context->db;<br>
struct Vdbe *v = sqlite3GetVdbe(parse_context);<br>
sqlite3VdbeAddOp0(v, OP_Halt);<br>
+ /*<br>
+ * In case statement "CREATE TABLE ..." fails it can<br>
+ * left some records in system spaces that shouldn't be<br>
+ * there. To clean-up properly this code is added. Last<br>
+ * record isn't deleted because if statement fails than<br>
+ * it won't be created. This code works the same way for<br>
+ * other "CREATE ..." statements but it won't delete<br>
+ * anything as these statements create no more than one<br>
+ * record.<br>
+ */<br>
+ if (!rlist_empty(&parse_context->record_list)) {<br>
+ struct saved_record *record =<br>
+ rlist_shift_entry(&parse_context->record_list,<br>
+ struct saved_record, link);<br>
+ /* Set P2 of SInsert. */<br>
+ sqlite3VdbeChangeP2(v, record->insertion_opcode,
v->nOp);<br>
+ MAYBE_UNUSED const char *comment =<br>
+ "Delete entry from %s if CREATE TABLE fails";<br>
+ rlist_foreach_entry(record,
&parse_context->record_list, link) {<br>
+ int record_reg = ++parse_context->nMem;<br>
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, record->reg_key,<br>
+ record->reg_key_count, record_reg);<br>
+ sqlite3VdbeAddOp2(v, OP_SDelete, record->space_id,<br>
+ record_reg);<br>
+ MAYBE_UNUSED struct space *space =<br>
+ space_by_id(record->space_id);<br>
+ VdbeComment((v, comment, space_name(space)));<br>
+ /* Set P2 of SInsert. */<br>
+ sqlite3VdbeChangeP2(v, record->insertion_opcode,<br>
+ v->nOp);<br>
+ }<br>
+ sqlite3VdbeAddOp1(v, OP_Halt, SQL_TARANTOOL_ERROR);<br>
+ VdbeComment((v,<br>
+ "Exit with an error if CREATE statement fails"));<br>
+ }<br>
+<br>
if (db->mallocFailed || parse_context->nErr != 0) {<br>
if (parse_context->rc == SQLITE_OK)<br>
parse_context->rc = SQLITE_ERROR;<br>
@@ -1101,13 +1184,14 @@ vdbe_emit_create_index(struct Parse *parse,
struct space_def *def,<br>
sqlite3VdbeAddOp4(v, OP_Blob, index_parts_sz, entry_reg + 5,<br>
SQL_SUBTYPE_MSGPACK, index_parts, P4_STATIC);<br>
sqlite3VdbeAddOp3(v, OP_MakeRecord, entry_reg, 6, tuple_reg);<br>
- sqlite3VdbeAddOp2(v, OP_SInsert, BOX_INDEX_ID, tuple_reg);<br>
+ sqlite3VdbeAddOp3(v, OP_SInsert, BOX_INDEX_ID, 0, tuple_reg);<br>
/*<br>
* Non-NULL value means that index has been created via<br>
* separate CREATE INDEX statement.<br>
*/<br>
if (idx_def->opts.sql != NULL)<br>
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);<br>
+ save_record(parse, BOX_INDEX_ID, entry_reg, 2, v->nOp - 1);<br>
return;<br>
error:<br>
parse->rc = SQL_TARANTOOL_ERROR;<br>
@@ -1165,8 +1249,9 @@ createSpace(Parse * pParse, int iSpaceId, char
*zStmt)<br>
sqlite3VdbeAddOp4(v, OP_Blob, table_stmt_sz, iFirstCol + 6,<br>
SQL_SUBTYPE_MSGPACK, table_stmt, P4_STATIC);<br>
sqlite3VdbeAddOp3(v, OP_MakeRecord, iFirstCol, 7, iRecord);<br>
- sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SPACE_ID, iRecord);<br>
+ sqlite3VdbeAddOp3(v, OP_SInsert, BOX_SPACE_ID, 0, iRecord);<br>
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);<br>
+ save_record(pParse, BOX_SPACE_ID, iFirstCol, 1, v->nOp - 1);<br>
return;<br>
error:<br>
pParse->nErr++;<br>
@@ -1340,9 +1425,11 @@ vdbe_emit_fkey_create(struct Parse
*parse_context, const struct fkey_def *fk)<br>
parent_links, P4_DYNAMIC);<br>
sqlite3VdbeAddOp3(vdbe, OP_MakeRecord, constr_tuple_reg, 9,<br>
constr_tuple_reg + 9);<br>
- sqlite3VdbeAddOp2(vdbe, OP_SInsert, BOX_FK_CONSTRAINT_ID,<br>
+ sqlite3VdbeAddOp3(vdbe, OP_SInsert, BOX_FK_CONSTRAINT_ID, 0,<br>
constr_tuple_reg + 9);<br>
sqlite3VdbeChangeP5(vdbe, OPFLAG_NCHANGE);<br>
+ save_record(parse_context, BOX_FK_CONSTRAINT_ID,
constr_tuple_reg, 2,<br>
+ vdbe->nOp - 1);<br>
sqlite3ReleaseTempRange(parse_context, constr_tuple_reg, 10);<br>
return;<br>
error:<br>
@@ -1487,14 +1574,18 @@ sqlite3EndTable(Parse * pParse, /* Parse
context */<br>
int reg_seq_record =<br>
emitNewSysSequenceRecord(pParse, reg_seq_id,<br>
p->def->name);<br>
- sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SEQUENCE_ID,<br>
+ sqlite3VdbeAddOp3(v, OP_SInsert, BOX_SEQUENCE_ID, 0,<br>
reg_seq_record);<br>
+ save_record(pParse, BOX_SEQUENCE_ID, reg_seq_record + 1, 1,<br>
+ v->nOp - 1);<br>
/* Do an insertion into _space_sequence. */<br>
int reg_space_seq_record =<br>
emitNewSysSpaceSequenceRecord(pParse, reg_space_id,<br>
reg_seq_id);<br>
- sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SPACE_SEQUENCE_ID,<br>
+ sqlite3VdbeAddOp3(v, OP_SInsert, BOX_SPACE_SEQUENCE_ID, 0,<br>
reg_space_seq_record);<br>
+ save_record(pParse, BOX_SPACE_SEQUENCE_ID,<br>
+ reg_space_seq_record + 1, 1, v->nOp - 1);<br>
}<br>
/* Code creation of FK constraints, if any. */<br>
struct fkey_parse *fk_parse;<br>
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c<br>
index e98e845..a4b65eb 100644<br>
--- a/src/box/sql/prepare.c<br>
+++ b/src/box/sql/prepare.c<br>
@@ -274,6 +274,7 @@ sql_parser_create(struct Parse *parser, sqlite3
*db)<br>
memset(parser, 0, sizeof(struct Parse));<br>
parser->db = db;<br>
rlist_create(&parser->new_fkey);<br>
+ rlist_create(&parser->record_list);<br>
region_create(&parser->region, &cord()->slabc);<br>
}<br>
<br>
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h<br>
index 744b660..d8eb516 100644<br>
--- a/src/box/sql/sqliteInt.h<br>
+++ b/src/box/sql/sqliteInt.h<br>
@@ -2765,6 +2765,11 @@ struct Parse {<br>
* Foreign key constraint appeared in CREATE TABLE stmt.<br>
*/<br>
struct rlist new_fkey;<br>
+ /**<br>
+ * List of all records that were inserted in system spaces<br>
+ * in current statement.<br>
+ */<br>
+ struct rlist record_list;<br>
bool initiateTTrans; /* Initiate Tarantool transaction */<br>
/** True, if table to be created has AUTOINCREMENT PK. */<br>
bool is_new_table_autoinc;<br>
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c<br>
index 7c1015c..1bec2fa 100644<br>
--- a/src/box/sql/vdbe.c<br>
+++ b/src/box/sql/vdbe.c<br>
@@ -1010,8 +1010,12 @@ case OP_Halt: {<br>
p->pc = pcx;<br>
if (p->rc) {<br>
if (p->rc == SQL_TARANTOOL_ERROR) {<br>
- assert(pOp->p4.z != NULL);<br>
- box_error_set(__FILE__, __LINE__, pOp->p5,
pOp->p4.z);<br>
+ if (pOp->p4.z == NULL) {<br>
+ assert(! diag_is_empty(diag_get()));<br>
+ } else {<br>
+ box_error_set(__FILE__, __LINE__, pOp->p5,<br>
+ pOp->p4.z);<br>
+ }<br>
} else if (pOp->p5 != 0) {<br>
static const char * const azType[] = { "NOT NULL",
"UNIQUE", "CHECK",<br>
"FOREIGN KEY" };<br>
@@ -4308,8 +4312,8 @@ case OP_IdxInsert: {<br>
break;<br>
}<br>
<br>
-/* Opcode: SInsert P1 P2 * * P5<br>
- * Synopsis: space id = P1, key = r[P2]<br>
+/* Opcode: SInsert P1 P2 P3 * P5<br>
+ * Synopsis: space id = P1, key = r[P3], on error goto P2<br>
*<br>
* This opcode is used only during DDL routine.<br>
* In contrast to ordinary insertion, insertion to system spaces<br>
@@ -4322,15 +4326,15 @@ case OP_IdxInsert: {<br>
*/<br>
case OP_SInsert: {<br>
assert(pOp->p1 > 0);<br>
- assert(pOp->p2 >= 0);<br>
+ assert(pOp->p2 > 0);<br>
+ assert(pOp->p3 >= 0);<br>
<br>
- pIn2 = &aMem[pOp->p2];<br>
+ pIn3 = &aMem[pOp->p3];<br>
struct space *space = space_by_id(pOp->p1);<br>
assert(space != NULL);<br>
assert(space_is_system(space));<br>
- rc = tarantoolSqlite3Insert(space, pIn2->z, pIn2->z +
pIn2->n);<br>
- if (rc)<br>
- goto abort_due_to_error;<br>
+ if (tarantoolSqlite3Insert(space, pIn3->z, pIn3->z +
pIn3->n) != 0)<br>
+ goto jump_to_p2;<br>
if (pOp->p5 & OPFLAG_NCHANGE)<br>
p->nChange++;<br>
break;<br>
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result<br>
index 08f2496..297799e 100644<br>
--- a/test/sql/drop-table.result<br>
+++ b/test/sql/drop-table.result<br>
@@ -33,3 +33,154 @@ box.sql.execute("INSERT INTO zzzoobar VALUES
(111, 222, 'c3', 444)")<br>
-- DROP TABLE should do the job<br>
-- Debug<br>
-- require("console").start()<br>
+--<br>
+-- gh-3592: clean-up garbage on failed CREATE TABLE statement.<br>
+--<br>
+-- Let user have enough rights to create space, but not enough to<br>
+-- create index.<br>
+--<br>
+box.schema.user.create('tmp')<br>
+---<br>
+...<br>
+box.schema.user.grant('tmp', 'create, read', 'universe')<br>
+---<br>
+...<br>
+box.schema.user.grant('tmp', 'write', 'space', '_space')<br>
+---<br>
+...<br>
+box.schema.user.grant('tmp', 'write', 'space', '_schema')<br>
+---<br>
+...<br>
+-- Number of records in _space, _index, _sequence:<br>
+space_count = #box.space._space:select()<br>
+---<br>
+...<br>
+index_count = #box.space._index:select()<br>
+---<br>
+...<br>
+sequence_count = #box.space._sequence:select()<br>
+---<br>
+...<br>
+box.session.su('tmp')<br>
+---<br>
+...<br>
+--<br>
+-- Error: user do not have rights to write in box.space._index.<br>
+-- Space that was already created should be automatically dropped.<br>
+--<br>
+box.sql.execute('CREATE TABLE t1 (id INT PRIMARY KEY, a INT)')<br>
+---<br>
+- error: Write access to space '_index' is denied for user 'tmp'<br>
+...<br>
+-- Error: no such table.<br>
+box.sql.execute('DROP TABLE t1')<br>
+---<br>
+- error: 'no such table: T1'<br>
+...<br>
+box.session.su('admin')<br>
+---<br>
+...<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+---<br>
+- true<br>
+...<br>
+index_count == #box.space._index:select()<br>
+---<br>
+- true<br>
+...<br>
+sequence_count == #box.space._sequence:select()<br>
+---<br>
+- true<br>
+...<br>
+--<br>
+-- Give user right to write in _index. Still have not enough<br>
+-- rights to write in _sequence.<br>
+--<br>
+box.schema.user.grant('tmp', 'write', 'space', '_index')<br>
+---<br>
+...<br>
+box.session.su('tmp')<br>
+---<br>
+...<br>
+--<br>
+-- Error: user do not have rights to write in _sequence.<br>
+--<br>
+box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY AUTOINCREMENT,
a UNIQUE, b UNIQUE, c UNIQUE, d UNIQUE)')<br>
+---<br>
+- error: Write access to space '_sequence' is denied for user 'tmp'<br>
+...<br>
+box.session.su('admin')<br>
+---<br>
+...<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+---<br>
+- true<br>
+...<br>
+index_count == #box.space._index:select()<br>
+---<br>
+- true<br>
+...<br>
+sequence_count == #box.space._sequence:select()<br>
+---<br>
+- true<br>
+...<br>
+fk_constraint_count = #box.space._fk_constraint:select()<br>
+---<br>
+...<br>
+--<br>
+-- Check that clean-up works fine after another error.<br>
+--<br>
+box.schema.user.grant('tmp', 'write', 'space')<br>
+---<br>
+...<br>
+box.session.su('tmp')<br>
+---<br>
+...<br>
+box.sql.execute('CREATE TABLE t3(a INTEGER PRIMARY KEY);')<br>
+---<br>
+...<br>
+--<br>
+-- Error: Failed to create foreign key constraint.<br>
+--<br>
+box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3, a INT UNIQUE, c INT REFERENCES t3);')<br>
+---<br>
+- error: 'Failed to create foreign key constraint
''FK_CONSTRAINT_2_T4'': field type<br>
+ mismatch'<br>
+...<br>
+box.sql.execute('DROP TABLE t3;')<br>
+---<br>
+...<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+---<br>
+- true<br>
+...<br>
+index_count == #box.space._index:select()<br>
+---<br>
+- true<br>
+...<br>
+sequence_count == #box.space._sequence:select()<br>
+---<br>
+- true<br>
+...<br>
+fk_constraint_count == #box.space._fk_constraint:select()<br>
+---<br>
+- true<br>
+...<br>
+box.session.su('admin')<br>
+---<br>
+...<br>
+box.schema.user.drop('tmp')<br>
+---<br>
+...<br>
diff --git a/test/sql/drop-table.test.lua
b/test/sql/drop-table.test.lua<br>
index 9663074..b1c5253 100644<br>
--- a/test/sql/drop-table.test.lua<br>
+++ b/test/sql/drop-table.test.lua<br>
@@ -25,3 +25,88 @@ box.sql.execute("INSERT INTO zzzoobar VALUES
(111, 222, 'c3', 444)")<br>
<br>
-- Debug<br>
-- require("console").start()<br>
+<br>
+--<br>
+-- gh-3592: clean-up garbage on failed CREATE TABLE statement.<br>
+--<br>
+-- Let user have enough rights to create space, but not enough to<br>
+-- create index.<br>
+--<br>
+box.schema.user.create('tmp')<br>
+box.schema.user.grant('tmp', 'create, read', 'universe')<br>
+box.schema.user.grant('tmp', 'write', 'space', '_space')<br>
+box.schema.user.grant('tmp', 'write', 'space', '_schema')<br>
+<br>
+-- Number of records in _space, _index, _sequence:<br>
+space_count = #box.space._space:select()<br>
+index_count = #box.space._index:select()<br>
+sequence_count = #box.space._sequence:select()<br>
+<br>
+box.session.su('tmp')<br>
+--<br>
+-- Error: user do not have rights to write in box.space._index.<br>
+-- Space that was already created should be automatically dropped.<br>
+--<br>
+box.sql.execute('CREATE TABLE t1 (id INT PRIMARY KEY, a INT)')<br>
+-- Error: no such table.<br>
+box.sql.execute('DROP TABLE t1')<br>
+<br>
+box.session.su('admin')<br>
+<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+index_count == #box.space._index:select()<br>
+sequence_count == #box.space._sequence:select()<br>
+<br>
+--<br>
+-- Give user right to write in _index. Still have not enough<br>
+-- rights to write in _sequence.<br>
+--<br>
+box.schema.user.grant('tmp', 'write', 'space', '_index')<br>
+box.session.su('tmp')<br>
+<br>
+--<br>
+-- Error: user do not have rights to write in _sequence.<br>
+--<br>
+box.sql.execute('CREATE TABLE t2 (id INT PRIMARY KEY AUTOINCREMENT,
a UNIQUE, b UNIQUE, c UNIQUE, d UNIQUE)')<br>
+<br>
+box.session.su('admin')<br>
+<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+index_count == #box.space._index:select()<br>
+sequence_count == #box.space._sequence:select()<br>
+<br>
+fk_constraint_count = #box.space._fk_constraint:select()<br>
+<br>
+--<br>
+-- Check that clean-up works fine after another error.<br>
+--<br>
+box.schema.user.grant('tmp', 'write', 'space')<br>
+box.session.su('tmp')<br>
+<br>
+box.sql.execute('CREATE TABLE t3(a INTEGER PRIMARY KEY);')<br>
+--<br>
+-- Error: Failed to create foreign key constraint.<br>
+--<br>
+box.sql.execute('CREATE TABLE t4(x INTEGER PRIMARY KEY REFERENCES
t3, a INT UNIQUE, c INT REFERENCES t3);')<br>
+box.sql.execute('DROP TABLE t3;')<br>
+<br>
+--<br>
+-- Check that _space, _index and _sequence have the same number of<br>
+-- records.<br>
+--<br>
+space_count == #box.space._space:select()<br>
+index_count == #box.space._index:select()<br>
+sequence_count == #box.space._sequence:select()<br>
+fk_constraint_count == #box.space._fk_constraint:select()<br>
+<br>
+box.session.su('admin')<br>
+<br>
+box.schema.user.drop('tmp')<br>
<br>
</body>
</html>