[tarantool-patches] [PATCH v2 3/3] sql: use name instead of function pointer for UDF

Kirill Shcherbatov kshcherbatov at tarantool.org
Thu Sep 12 11:06:43 MSK 2019


This patch changes OP_Function parameters convention: now a
function's name is passed instead of pointer to the function
object. This allows to normally handle the situation, when UDF
had been deleted to the moment of the VDBE code execution.
In particular case this may happen with CK constraints that
refer to a persistent function.
---
 src/box/sql/expr.c       | 17 ++++++++++++-----
 src/box/sql/vdbe.c       | 17 +++++++++++------
 src/box/sql/vdbe.h       |  1 +
 test/sql/checks.result   | 10 +++++++---
 test/sql/checks.test.lua |  3 ++-
 5 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 6d5ad2a27..04c9393be 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4136,11 +4136,18 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 				sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
 						  (char *)coll, P4_COLLSEQ);
 			}
-			int op = func->def->language ==
-				 FUNC_LANGUAGE_SQL_BUILTIN ?
-				 OP_BuiltinFunction0 : OP_Function;
-			sqlVdbeAddOp4(v, op, constMask, r1, target,
-				      (char *)func, P4_FUNC);
+			if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
+				sqlVdbeAddOp4(v, OP_BuiltinFunction0, constMask,
+					      r1, target, (char *)func,
+					      P4_FUNC);
+			} else {
+				sqlVdbeAddOp4(v, OP_Function,
+					      func->def->name_len, r1, target,
+					      sqlDbStrNDup(sql_get(),
+							   func->def->name,
+							   func->def->name_len),
+					      P4_DYNAMIC);
+			}
 			sqlVdbeChangeP5(v, (u8) nFarg);
 			if (nFarg && constMask == 0) {
 				sqlReleaseTempRange(pParse, r1, nFarg);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 02e16da19..4c6245348 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1795,16 +1795,21 @@ case OP_BuiltinFunction: {
 	break;
 }
 
-/* Opcode: Function * P2 P3 P4 P5
+/* Opcode: Function P1 P2 P3 P4 P5
  * Synopsis: r[P3]=func(r[P2 at P5])
  *
- * Invoke a user function (P4 is a pointer to a function object
- * that defines the function) with P5 arguments taken from
- * register P2 and successors. The result of the function is
- * stored in register P3.
+ * Invoke a user function (P4 is a name of the function while P1
+ * is a function name length) with P5 arguments taken from register P2 and
+ * successors. The result of the function is stored in
+ * register P3.
  */
 case OP_Function: {
-	struct func *func = pOp->p4.func;
+	assert(pOp->p4type == P4_DYNAMIC);
+	struct func *func = func_by_name(pOp->p4.z, pOp->p1);
+	if (unlikely(func == NULL)) {
+		diag_set(ClientError, ER_NO_SUCH_FUNCTION, pOp->p4.z);
+		goto abort_due_to_error;
+	}
 	int argc = pOp->p5;
 	struct Mem *argv = &aMem[pOp->p2];
 	struct port args, ret;
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 29ff99867..e57d7f979 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -128,6 +128,7 @@ struct SubProgram {
 #define P4_COLLSEQ  (-3)	/* P4 is a pointer to a CollSeq structure */
 /** P4 is a pointer to a func structure. */
 #define P4_FUNC     (-4)
+/** P4 is a function identifier. */
 #define P4_MEM      (-7)	/* P4 is a pointer to a Mem*    structure */
 #define P4_TRANSIENT  0		/* P4 is a pointer to a transient string */
 #define P4_REAL     (-9)	/* P4 is a 64-bit floating point value */
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 7939d46df..02951b3cf 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -867,12 +867,16 @@ box.space.T6:insert({11})
 ---
 - error: 'Check constraint failed ''ck_unnamed_T6_1'': myfunc(a)'
 ...
+box.func.MYFUNC:drop()
+---
+...
+box.space.T6:insert({11})
+---
+- error: Function 'MYFUNC' does not exist
+...
 box.space.T6:drop()
 ---
 ...
-box.func.MYFUNC:drop()
----
-...
 test_run:cmd("clear filter")
 ---
 - true
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index 051c9ae38..d64f3305a 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -291,7 +291,8 @@ box.space.T6:insert({11})
 test_run:cmd("restart server default")
 box.space.T6:insert({11})
 
+box.func.MYFUNC:drop()
+box.space.T6:insert({11})
 box.space.T6:drop()
-box.func.MYFUNC:drop()
 
 test_run:cmd("clear filter")
-- 
2.23.0





More information about the Tarantool-patches mailing list