[tarantool-patches] [PATCH v1 1/1] sql: cleanup on failed table creation

imeevma at tarantool.org imeevma at tarantool.org
Thu Aug 9 16:48:34 MSK 2018


In some cases operation "create table" left some
created objects not deleted after operation fails.
After this patch all created objects will be deleted.

Closes #3592.
---
Branch: imeevma/gh-3592-cleanup-on-failed-create-table
Issue: https://github.com/tarantool/tarantool/issues/3592

 src/box/sql/vdbe.c           | 54 ++++++++++++++++++++++++++++++++++++++++++++
 test/sql/drop-table.result   | 37 ++++++++++++++++++++++++++++++
 test/sql/drop-table.test.lua | 15 ++++++++++++
 3 files changed, 106 insertions(+)

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index ca89908..0583587 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -568,6 +568,23 @@ out2Prerelease(Vdbe *p, VdbeOp *pOp)
 }
 
 /*
+ * Inserted in current query record.
+ */
+struct inserted_record
+{
+	/* Reference to previous record */
+	struct inserted_record *prev;
+	/* Space in which record was inserted */
+	struct space *space;
+	/* Length of packed primary key of record */
+	uint32_t len;
+	/* Flag to decrease nChanges if needed */
+	bool is_changes_increased;
+	/* Packed primary key of record */
+	char key[0];
+};
+
+/*
  * Execute as much of a VDBE program as we can.
  * This is the core of sqlite3_step().
  */
@@ -599,6 +616,7 @@ int sqlite3VdbeExec(Vdbe *p)
 	u64 start;                 /* CPU clock count at start of opcode */
 #endif
 	struct session *user_session = current_session();
+	struct inserted_record *inserted_record = NULL;
 	/*** INSERT STACK UNION HERE ***/
 
 	assert(p->magic==VDBE_MAGIC_RUN);  /* sqlite3_step() verifies this */
@@ -4352,6 +4370,28 @@ case OP_SInsert: {
 		goto abort_due_to_error;
 	if (pOp->p5 & OPFLAG_NCHANGE)
 		p->nChange++;
+
+	uint32_t key_size;
+	char *key = tuple_extract_key_raw(pIn2->z, pIn2->z + pIn2->n,
+					  space->index[0]->def->key_def,
+					  &key_size);
+	if (key == NULL) {
+		rc = SQLITE_NOMEM_BKPT;
+		goto abort_due_to_error;
+	}
+	struct inserted_record *tmp =
+		(struct inserted_record *)malloc(sizeof(*tmp) + key_size);
+	if (tmp == NULL) {
+		rc = SQLITE_NOMEM_BKPT;
+		goto abort_due_to_error;
+	}
+	tmp->prev = inserted_record;
+	tmp->space = space;
+	tmp->len = key_size;
+	tmp->is_changes_increased = pOp->p5 & OPFLAG_NCHANGE;
+	memcpy(tmp->key, key, key_size);
+
+	inserted_record = tmp;
 	break;
 }
 
@@ -5344,6 +5384,15 @@ default: {          /* This is really OP_Noop and OP_Explain */
 	 * an error of some kind.
 	 */
 abort_due_to_error:
+	while (inserted_record != NULL) {
+		sql_delete_by_key(inserted_record->space, inserted_record->key,
+				  inserted_record->len);
+		if (inserted_record->is_changes_increased)
+			p->nChange--;
+		struct inserted_record *tmp = inserted_record->prev;
+		free(inserted_record);
+		inserted_record = tmp;
+	}
 	if (db->mallocFailed) rc = SQLITE_NOMEM_BKPT;
 	assert(rc);
 	if (p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM) {
@@ -5372,6 +5421,11 @@ abort_due_to_error:
 
 	/* This is the only way out of this procedure. */
 vdbe_return:
+	while (inserted_record != NULL) {
+		struct inserted_record *tmp = inserted_record->prev;
+		free(inserted_record);
+		inserted_record = tmp;
+	}
 	testcase( nVmStep>0);
 	p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
 	assert(rc!=SQLITE_OK || nExtraDelete==0
diff --git a/test/sql/drop-table.result b/test/sql/drop-table.result
index 08f2496..f1fdc17 100644
--- a/test/sql/drop-table.result
+++ b/test/sql/drop-table.result
@@ -33,3 +33,40 @@ box.sql.execute("INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 -- DROP TABLE should do the job
 -- Debug
 -- require("console").start()
+-- gh-3592: net.box segmentation fault after "create table" with
+-- autoincrement
+test_run = require('test_run').new()
+---
+...
+box.schema.user.create('tmp')
+---
+...
+box.schema.user.grant('tmp', 'create', 'space')
+---
+...
+box.schema.user.grant('tmp', 'write', 'space', '_space')
+---
+...
+box.schema.user.grant('tmp', 'write', 'space', '_schema')
+---
+...
+box.session.su('tmp')
+---
+...
+-- Error - nothing should be created
+box.sql.execute('create table t (id integer primary key, a integer)')
+---
+- error: Write access to space '_index' is denied for user 'tmp'
+...
+box.space.T
+---
+- null
+...
+box.sql.execute('drop table t')
+---
+- error: 'no such table: T'
+...
+test_run:cmd('restart server default');
+box.schema.user.drop('tmp')
+---
+...
diff --git a/test/sql/drop-table.test.lua b/test/sql/drop-table.test.lua
index 9663074..f059619 100644
--- a/test/sql/drop-table.test.lua
+++ b/test/sql/drop-table.test.lua
@@ -25,3 +25,18 @@ box.sql.execute("INSERT INTO zzzoobar VALUES (111, 222, 'c3', 444)")
 
 -- Debug
 -- require("console").start()
+
+-- gh-3592: net.box segmentation fault after "create table" with
+-- autoincrement
+test_run = require('test_run').new()
+box.schema.user.create('tmp')
+box.schema.user.grant('tmp', 'create', 'space')
+box.schema.user.grant('tmp', 'write', 'space', '_space')
+box.schema.user.grant('tmp', 'write', 'space', '_schema')
+box.session.su('tmp')
+-- Error - nothing should be created
+box.sql.execute('create table t (id integer primary key, a integer)')
+box.space.T
+box.sql.execute('drop table t')
+test_run:cmd('restart server default');
+box.schema.user.drop('tmp')
-- 
2.7.4





More information about the Tarantool-patches mailing list