[Tarantool-patches] [PATCH] sql: remove expmask from prepared statement

Nikita Pettik korablev at tarantool.org
Fri Oct 18 16:47:10 MSK 2019


expmask indicated necessity to recompile statement after parameter was
bound: it might turn out that parameter can affect query plan. However,
part of this mechanism has been removed long ago as a SQLite's legacy.
In its current state expmask is likely to be useless and assertions
involving it are obviously unsuitable. This patch completely removes
expmask and related routines.

Closes #4566
---
Branch: https://github.com/tarantool/tarantool/tree/np/gh-4566-remove-exp-mask
Issue: https://github.com/tarantool/tarantool/issues/4566

 src/box/sql/vdbe.h      |  1 -
 src/box/sql/vdbeInt.h   |  1 -
 src/box/sql/vdbeapi.c   | 19 -------------------
 src/box/sql/vdbeaux.c   | 16 ----------------
 src/box/sql/vdbemem.c   |  1 -
 src/box/sql/whereexpr.c |  2 --
 test/sql/bind.result    | 32 ++++++++++++++++++++++++++++++++
 test/sql/bind.test.lua  |  9 +++++++++
 8 files changed, 41 insertions(+), 40 deletions(-)

diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 29ff99867..582d48a1f 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -255,7 +255,6 @@ void sqlVdbeSetSql(Vdbe *, const char *z, int n, int);
 void sqlVdbeSwap(Vdbe *, Vdbe *);
 VdbeOp *sqlVdbeTakeOpArray(Vdbe *, int *, int *);
 sql_value *sqlVdbeGetBoundValue(Vdbe *, int, u8);
-void sqlVdbeSetVarmask(Vdbe *, int);
 char *sqlVdbeExpandSql(Vdbe *, const char *);
 int sqlMemCompare(const Mem *, const Mem *, const struct coll *);
 
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 104a05613..0f32b4cd6 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -428,7 +428,6 @@ struct Vdbe {
 	VdbeFrame *pFrame;	/* Parent frame */
 	VdbeFrame *pDelFrame;	/* List of frame objects to free on VM reset */
 	int nFrame;		/* Number of frames in pFrame list */
-	u32 expmask;		/* Binding to these vars invalidates VM */
 	SubProgram *pProgram;	/* Linked list of all sub-programs used by VM */
 	/** Parser flags with which this object was built. */
 	uint32_t sql_flags;
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index bf40b44fa..b91d16a9d 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -112,9 +112,6 @@ sql_clear_bindings(sql_stmt * pStmt)
 		sqlVdbeMemRelease(&p->aVar[i]);
 		p->aVar[i].flags = MEM_Null;
 	}
-	if (p->isPrepareV2 && p->expmask) {
-		p->expired = 1;
-	}
 	return rc;
 }
 
@@ -826,22 +823,6 @@ vdbeUnbind(Vdbe * p, int i)
 	sqlVdbeMemRelease(pVar);
 	pVar->flags = MEM_Null;
 	pVar->field_type = field_type_MAX;
-
-	/* If the bit corresponding to this variable in Vdbe.expmask is set, then
-	 * binding a new value to this variable invalidates the current query plan.
-	 *
-	 * IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
-	 * parameter in the WHERE clause might influence the choice of query plan
-	 * for a statement, then the statement will be automatically recompiled,
-	 * as if there had been a schema change, on the first sql_step() call
-	 * following any change to the bindings of that parameter.
-	 */
-	if (p->isPrepareV2 &&
-	    ((i < 32 && p->expmask & ((u32) 1 << i))
-	     || p->expmask == 0xffffffff)
-	    ) {
-		p->expired = 1;
-	}
 	return 0;
 }
 
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 40918e7e7..a1d658648 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -2988,22 +2988,6 @@ sqlVdbeGetBoundValue(Vdbe * v, int iVar, u8 aff)
 	return 0;
 }
 
-/*
- * Configure SQL variable iVar so that binding a new value to it signals
- * to sql_reoptimize() that re-preparing the statement may result
- * in a better query plan.
- */
-void
-sqlVdbeSetVarmask(Vdbe * v, int iVar)
-{
-	assert(iVar > 0);
-	if (iVar > 32) {
-		v->expmask = 0xffffffff;
-	} else {
-		v->expmask |= ((u32) 1 << (iVar - 1));
-	}
-}
-
 int
 sqlVdbeCompareMsgpack(const char **key1,
 			  struct UnpackedRecord *unpacked, int key2_idx)
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 15276c224..dcfc59820 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -1596,7 +1596,6 @@ stat4ValueFromExpr(Parse * pParse,	/* Parse context */
 	    ) {
 		Vdbe *v;
 		int iBindVar = pExpr->iColumn;
-		sqlVdbeSetVarmask(pParse->pVdbe, iBindVar);
 		if ((v = pParse->pReprepare) != 0) {
 			pVal = valueNew(db, pAlloc);
 			if (pVal) {
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index 98615b118..d9b5c78f5 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -314,7 +314,6 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 		if (pVal && sql_value_type(pVal) == MP_STR) {
 			z = (char *)sql_value_text(pVal);
 		}
-		sqlVdbeSetVarmask(pParse->pVdbe, iCol);
 		assert(pRight->op == TK_VARIABLE || pRight->op == TK_REGISTER);
 	} else if (op == TK_STRING) {
 		z = pRight->u.zToken;
@@ -336,7 +335,6 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 			*ppPrefix = pPrefix;
 			if (op == TK_VARIABLE) {
 				Vdbe *v = pParse->pVdbe;
-				sqlVdbeSetVarmask(v, pRight->iColumn);
 				if (*pisComplete && pRight->u.zToken[1]) {
 					/* If the rhs of the LIKE expression is a variable, and the current
 					 * value of the variable means there is no need to invoke the LIKE
diff --git a/test/sql/bind.result b/test/sql/bind.result
index 86126e86f..82a058c90 100644
--- a/test/sql/bind.result
+++ b/test/sql/bind.result
@@ -337,3 +337,35 @@ box.execute('SELECT $2', {1, 2, 3})
 - null
 - 'Failed to execute SQL statement: The number of parameters is too large'
 ...
+-- gh-4566: bind variable to LIKE argument resulted to crash.
+--
+box.execute("CREATE TABLE t (id INT PRIMARY KEY, a TEXT);")
+---
+- row_count: 1
+...
+box.execute("SELECT * FROM t WHERE a LIKE ?;", {'a%'});
+---
+- metadata:
+  - name: ID
+    type: integer
+  - name: A
+    type: string
+  rows: []
+...
+box.execute("INSERT INTO t VALUES (1, 'aA'), (2, 'Ba'), (3, 'A');")
+---
+- row_count: 3
+...
+box.execute("SELECT * FROM t WHERE a LIKE ?;", {'a%'});
+---
+- metadata:
+  - name: ID
+    type: integer
+  - name: A
+    type: string
+  rows:
+  - [1, 'aA']
+...
+box.space.T:drop()
+---
+...
diff --git a/test/sql/bind.test.lua b/test/sql/bind.test.lua
index 29d71edcd..2ced7775a 100644
--- a/test/sql/bind.test.lua
+++ b/test/sql/bind.test.lua
@@ -124,3 +124,12 @@ box.execute('DROP TABLE test')
 
 box.execute('SELECT ?', {1, 2})
 box.execute('SELECT $2', {1, 2, 3})
+
+-- gh-4566: bind variable to LIKE argument resulted to crash.
+--
+box.execute("CREATE TABLE t (id INT PRIMARY KEY, a TEXT);")
+box.execute("SELECT * FROM t WHERE a LIKE ?;", {'a%'});
+box.execute("INSERT INTO t VALUES (1, 'aA'), (2, 'Ba'), (3, 'A');")
+box.execute("SELECT * FROM t WHERE a LIKE ?;", {'a%'});
+
+box.space.T:drop()
-- 
2.15.1



More information about the Tarantool-patches mailing list