[Tarantool-patches] [PATCH v2 2/3] sql: don't select from _index during parsing

Roman Khabibov roman.habibov at tarantool.org
Tue Mar 3 13:12:03 MSK 2020


Remove function box_index_by_name() from parser to avoid selects
during parsing. Add the ability to choose index during VDBE code
compilation which will be used to find the tuple to drop from a
system space.

Needed for #4120
---
 src/box/space.h      | 15 +++++++++++
 src/box/sql/build.c  | 59 +++++++++++++++++++++++++++-----------------
 src/box/sql/pragma.c |  8 ++----
 src/box/sql/vdbe.c   | 10 +++++---
 4 files changed, 59 insertions(+), 33 deletions(-)

diff --git a/src/box/space.h b/src/box/space.h
index 9aea4e5be..28885d037 100644
--- a/src/box/space.h
+++ b/src/box/space.h
@@ -287,6 +287,21 @@ space_index(struct space *space, uint32_t id)
 	return NULL;
 }
 
+/**
+ * Get index by index name.
+ * @return NULL if the index is not found.
+ */
+static inline struct index *
+space_index_by_name(struct space *space, const char *index_name)
+{
+	for(uint32_t i = 0; i < space->index_count; i++) {
+		struct index *index = space->index[i];
+		if (strcmp(index_name, index->def->name) == 0)
+			return index;
+	}
+	return NULL;
+}
+
 /**
  * Return true if the unique constraint must be checked for
  * the index with the given id before inserting a tuple into
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index d9bf8de91..e0f690fc2 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -47,7 +47,6 @@
 #include "sqlInt.h"
 #include "vdbeInt.h"
 #include "tarantoolInt.h"
-#include "box/box.h"
 #include "box/ck_constraint.h"
 #include "box/fk_constraint.h"
 #include "box/sequence.h"
@@ -1469,6 +1468,40 @@ vdbe_emit_stat_space_clear(struct Parse *parse, const char *stat_table_name,
 	sql_table_delete_from(parse, src_list, where);
 }
 
+/**
+ * Generate VDBE program to remove entry from _index space.
+ *
+ * @param parse_context Parsing context.
+ * @param name Index name.
+ * @param space_def Def of table which index belongs to.
+ * @param errcode Type of printing error: "no such index" or
+ *                "no such constraint".
+ * @param if_exist True if there was <IF EXISTS> in the query.
+ */
+static void
+vdbe_emit_index_drop(struct Parse *parse_context, const char *name,
+		     struct space_def *space_def, int errcode, bool if_exist)
+{
+	assert(errcode == ER_NO_SUCH_INDEX_NAME ||
+	       errcode == ER_NO_SUCH_CONSTRAINT);
+	struct Vdbe *vdbe = sqlGetVdbe(parse_context);
+	assert(vdbe != NULL);
+	assert(parse_context->db != NULL);
+	int key_reg = sqlGetTempRange(parse_context, 3);
+	sqlVdbeAddOp2(vdbe, OP_Integer, space_def->id, key_reg);
+	sqlVdbeAddOp4(vdbe, OP_String8, 0, key_reg + 1, 0,
+		      sqlDbStrDup(parse_context->db, name), P4_DYNAMIC);
+	const char *error_msg =
+		tt_sprintf(tnt_errcode_desc(errcode), name, space_def->name);
+	if (vdbe_emit_halt_with_presence_test(parse_context, BOX_INDEX_ID, 2,
+					      key_reg, 2, errcode, error_msg,
+					      if_exist, OP_Found) != 0)
+		return;
+	sqlVdbeAddOp3(vdbe, OP_MakeRecord, key_reg, 2, key_reg + 2);
+	sqlVdbeAddOp3(vdbe, OP_SDelete, BOX_INDEX_ID, key_reg + 2, 2);
+	sqlReleaseTempRange(parse_context, key_reg, 3);
+}
+
 /**
  * Generate VDBE program to remove entry from _fk_constraint space.
  *
@@ -2695,29 +2728,9 @@ sql_drop_index(struct Parse *parse_context)
 		parse_context->is_aborted = true;
 		goto exit_drop_index;
 	}
-	uint32_t index_id = box_index_id_by_name(space->def->id, index_name,
-						 strlen(index_name));
-	if (index_id == BOX_ID_NIL) {
-		if (!if_exists) {
-			diag_set(ClientError, ER_NO_SUCH_INDEX_NAME,
-				 index_name, table_name);
-			parse_context->is_aborted = true;
-		}
-		goto exit_drop_index;
-	}
 
-	/*
-	 * Generate code to remove entry from _index space
-	 * But firstly, delete statistics since schema
-	 * changes after DDL.
-	 */
-	int record_reg = ++parse_context->nMem;
-	int space_id_reg = ++parse_context->nMem;
-	int index_id_reg = ++parse_context->nMem;
-	sqlVdbeAddOp2(v, OP_Integer, space->def->id, space_id_reg);
-	sqlVdbeAddOp2(v, OP_Integer, index_id, index_id_reg);
-	sqlVdbeAddOp3(v, OP_MakeRecord, space_id_reg, 2, record_reg);
-	sqlVdbeAddOp2(v, OP_SDelete, BOX_INDEX_ID, record_reg);
+	vdbe_emit_index_drop(parse_context, index_name, space->def,
+			     ER_NO_SUCH_INDEX_NAME, if_exists);
 	sqlVdbeChangeP5(v, OPFLAG_NCHANGE);
  exit_drop_index:
 	sqlSrcListDelete(db, table_list);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index a77bf4b16..c15f2e0d1 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -33,7 +33,6 @@
  * This file contains code used to implement the PRAGMA command.
  */
 #include "box/index.h"
-#include "box/box.h"
 #include "box/tuple.h"
 #include "box/fk_constraint.h"
 #include "box/schema.h"
@@ -192,12 +191,9 @@ sql_pragma_index_info(struct Parse *parse,
 	struct space *space = space_by_name(tbl_name);
 	if (space == NULL)
 		return;
-	uint32_t iid = box_index_id_by_name(space->def->id, idx_name,
-					    strlen(idx_name));
-	if (iid == BOX_ID_NIL)
+	struct index *idx = space_index_by_name(space, idx_name);
+	if (idx == NULL)
 		return;
-	struct index *idx = space_index(space, iid);
-	assert(idx != NULL);
 	parse->nMem = 6;
 	struct Vdbe *v = sqlGetVdbe(parse);
 	assert(v != NULL);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 620d74e66..912a10153 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4460,11 +4460,12 @@ case OP_SInsert: {
 	break;
 }
 
-/* Opcode: SDelete P1 P2 * * P5
- * Synopsis: space id = P1, key = r[P2]
+/* Opcode: SDelete P1 P2 P3 * P5
+ * Synopsis: space id = P1, key = r[P2], searching index id = P3
  *
  * This opcode is used only during DDL routine.
- * Delete entry with given key from system space.
+ * Delete entry with given key from system space. P3 is the index
+ * number by which to search for the key.
  *
  * If P5 is set to OPFLAG_NCHANGE, account overall changes
  * made to database.
@@ -4472,13 +4473,14 @@ case OP_SInsert: {
 case OP_SDelete: {
 	assert(pOp->p1 > 0);
 	assert(pOp->p2 >= 0);
+	assert(pOp->p3 >= 0);
 
 	pIn2 = &aMem[pOp->p2];
 	struct space *space = space_by_id(pOp->p1);
 	assert(space != NULL);
 	assert(space_is_system(space));
 	assert(p->errorAction == ON_CONFLICT_ACTION_ABORT);
-	if (sql_delete_by_key(space, 0, pIn2->z, pIn2->n) != 0)
+	if (sql_delete_by_key(space, pOp->p3, pIn2->z, pIn2->n) != 0)
 		goto abort_due_to_error;
 	if (pOp->p5 & OPFLAG_NCHANGE)
 		p->nChange++;
-- 
2.21.0 (Apple Git-122)



More information about the Tarantool-patches mailing list