Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions
@ 2021-08-19  5:31 Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 1/5] sql: remove OP_BuiltinFunction0 and OP_AggStep0 Mergen Imeev via Tarantool-patches
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

This patch-set changes structure of SQL built-in functions.

https://github.com/tarantool/tarantool/issues/6105
https://github.com/tarantool/tarantool/tree/imeevma/gh-6105-properly-check-funcs-args-types

Mergen Imeev (5):
  sql: remove OP_BuiltinFunction0 and OP_AggStep0
  sql: remove unnecessary MEM finalization
  sql: remove struct func from struct sql_context
  sql: do not use struct func for finalization
  sql: remove unused code

 src/box/box.cc        |   1 -
 src/box/sql.c         |   1 -
 src/box/sql.h         |   9 -
 src/box/sql/analyze.c |   6 +-
 src/box/sql/expr.c    |   2 +-
 src/box/sql/func.c    | 999 +++++++-----------------------------------
 src/box/sql/mem.c     |  34 +-
 src/box/sql/mem.h     |  19 +-
 src/box/sql/select.c  |   2 +-
 src/box/sql/sqlInt.h  |  42 --
 src/box/sql/vdbe.c    | 109 +----
 src/box/sql/vdbe.h    |   9 +-
 src/box/sql/vdbeInt.h |  10 +-
 src/box/sql/vdbeapi.c |  10 +-
 src/box/sql/vdbeaux.c |  11 +-
 15 files changed, 184 insertions(+), 1080 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Tarantool-patches] [PATCH v2 1/5] sql: remove OP_BuiltinFunction0 and OP_AggStep0
  2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
@ 2021-08-19  5:31 ` Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 2/5] sql: remove unnecessary MEM finalization Mergen Imeev via Tarantool-patches
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

This patch moves the initialization of sql_context out of the VDBE. This
allows us to remove the opcodes OP_BuiltinFunction0 and OP_AggStep0,
which work in a rather strange way. Moreover, due to the changes these
opcodes make to the VDBEs, it is possible that the estimated size of the
VDBE could become non-constant, which could lead to various problems.

Part of #6105
---
 src/box/sql/analyze.c |  6 +--
 src/box/sql/expr.c    |  2 +-
 src/box/sql/func.c    | 13 ++++++-
 src/box/sql/select.c  |  2 +-
 src/box/sql/vdbe.c    | 87 ++-----------------------------------------
 src/box/sql/vdbeInt.h |  2 +-
 src/box/sql/vdbeaux.c |  2 +-
 7 files changed, 22 insertions(+), 92 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index fb4ad2a81..b9b6f5da8 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -725,7 +725,7 @@ callStatGet(Vdbe * v, int regStat4, int iParam, int regOut)
 	 */
 	struct func *func = sql_func_by_signature("_sql_stat_get", 2);
 	assert(func != NULL);
-	sqlVdbeAddOp4(v, OP_BuiltinFunction0, 0, regStat4, regOut,
+	sqlVdbeAddOp4(v, OP_BuiltinFunction, 0, regStat4, regOut,
 		      (char *)func, P4_FUNC);
 	sqlVdbeChangeP5(v, 2);
 }
@@ -869,7 +869,7 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		struct func *init_func =
 			sql_func_by_signature("_sql_stat_init", 3);
 		assert(init_func != NULL);
-		sqlVdbeAddOp4(v, OP_BuiltinFunction0, 0, stat4_reg + 1,
+		sqlVdbeAddOp4(v, OP_BuiltinFunction, 0, stat4_reg + 1,
 			      stat4_reg, (char *)init_func, P4_FUNC);
 		sqlVdbeChangeP5(v, 3);
 		/*
@@ -974,7 +974,7 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		struct func *push_func =
 			sql_func_by_signature("_sql_stat_push", 3);
 		assert(push_func != NULL);
-		sqlVdbeAddOp4(v, OP_BuiltinFunction0, 1, stat4_reg, tmp_reg,
+		sqlVdbeAddOp4(v, OP_BuiltinFunction, 1, stat4_reg, tmp_reg,
 			      (char *)push_func, P4_FUNC);
 		sqlVdbeChangeP5(v, 3);
 		sqlVdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 50dc98a94..d0bdee4fd 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4168,7 +4168,7 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 				sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
 						  (char *)coll, P4_COLLSEQ);
 			}
-			if (sql_emit_func_call(v, pExpr, OP_BuiltinFunction0,
+			if (sql_emit_func_call(v, pExpr, OP_BuiltinFunction,
 					       constMask, r1, target,
 					       nFarg) != 0) {
 				pParse->is_aborted = true;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ea3b44472..4a0d2d097 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2889,7 +2889,18 @@ sql_emit_func_call(struct Vdbe *vdbe, struct Expr *expr, int op, int mask,
 	struct func *func = sql_func_find(expr);
 	if (func == NULL)
 		return -1;
-	sqlVdbeAddOp4(vdbe, op, mask, r1, r2, (char *)func, P4_FUNC);
+	uint32_t size = sizeof(struct sql_context);
+	if (argc > 1)
+		size += (argc - 1) * sizeof(struct Mem);
+	struct sql_context *ctx = sqlDbMallocRawNN(sql_get(), size);
+	if (ctx == NULL)
+		return -1;
+	ctx->pOut = NULL;
+	ctx->func = func;
+	ctx->iOp = 0;
+	ctx->pVdbe = vdbe;
+	ctx->argc = argc;
+	sqlVdbeAddOp4(vdbe, op, mask, r1, r2, (char *)ctx, P4_FUNCCTX);
 	sqlVdbeChangeP5(vdbe, argc);
 	return 0;
 }
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 87f2012f1..cb92f2ed0 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -5632,7 +5632,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
 			sqlVdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
 					  (char *)coll, P4_COLLSEQ);
 		}
-		sql_emit_func_call(v, pF->pExpr, OP_AggStep0, 0, regAgg,
+		sql_emit_func_call(v, pF->pExpr, OP_AggStep, 0, regAgg,
 				   pF->iMem, nArg);
 		sql_expr_type_cache_change(pParse, regAgg, nArg);
 		sqlReleaseTempRange(pParse, regAgg, nArg);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 7f86fa7b3..98ea37c67 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1181,20 +1181,6 @@ case OP_CollSeq: {
 	break;
 }
 
-/* Opcode: BuiltinFunction0 P1 P2 P3 P4 P5
- * Synopsis: r[P3]=func(r[P2@P5])
- *
- * Invoke a user function (P4 is a pointer to a FuncDef object that
- * defines the function) with P5 arguments taken from register P2 and
- * successors.  The result of the function is stored in register P3.
- * Register P3 must not be one of the function inputs.
- *
- * P1 is a 32-bit bitmask indicating whether or not each argument to the
- * function was determined to be constant at compile time. If the first
- * argument was constant then bit 0 of P1 is set.
- *
- * See also: BuiltinFunction, AggStep, AggFinal
- */
 /* Opcode: BuiltinFunction P1 P2 P3 P4 P5
  * Synopsis: r[P3]=func(r[P2@P5])
  *
@@ -1207,44 +1193,15 @@ case OP_CollSeq: {
  * function was determined to be constant at compile time. If the first
  * argument was constant then bit 0 of P1 is set.
  *
- * SQL functions are initially coded as OP_BuiltinFunction0 with
- * P4 pointing to a FuncDef object.  But on first evaluation,
- * the P4 operand is automatically converted into an sql_context
- * object and the operation changed to this OP_BuiltinFunction
- * opcode.  In this way, the initialization of the sql_context
- * object occurs only once, rather than once for each evaluation
- * of the function.
- *
- * See also: BuiltinFunction0, AggStep, AggFinal
+ * See also: AggStep, AggFinal
  */
-case OP_BuiltinFunction0: {
-	int n;
-	sql_context *pCtx;
-
-	assert(pOp->p4type == P4_FUNC);
-	n = pOp->p5;
-	assert(pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor));
-	assert(n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1));
-	assert(pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n);
-	pCtx = sqlDbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sql_value*));
-	if (pCtx==0) goto no_mem;
-	pCtx->pOut = 0;
-	pCtx->func = pOp->p4.func;
-	pCtx->iOp = (int)(pOp - aOp);
-	pCtx->pVdbe = p;
-	pCtx->argc = n;
-	pOp->p4type = P4_FUNCCTX;
-	pOp->p4.pCtx = pCtx;
-	pOp->opcode = OP_BuiltinFunction;
-	/* Fall through into OP_BuiltinFunction */
-	FALLTHROUGH;
-}
 case OP_BuiltinFunction: {
 	int i;
 	sql_context *pCtx;
 
 	assert(pOp->p4type==P4_FUNCCTX);
 	pCtx = pOp->p4.pCtx;
+	pCtx->iOp = (int)(pOp - aOp);
 
 	/* If this function is inside of a trigger, the register array in aMem[]
 	 * might change from one evaluation to the next.  The next block of code
@@ -4184,17 +4141,6 @@ case OP_DecrJumpZero: {      /* jump, in1 */
 }
 
 
-/* Opcode: AggStep0 * P2 P3 P4 P5
- * Synopsis: accum=r[P3] step(r[P2@P5])
- *
- * Execute the step function for an aggregate.  The
- * function has P5 arguments.   P4 is a pointer to the FuncDef
- * structure that specifies the function.  Register P3 is the
- * accumulator.
- *
- * The P5 arguments are taken from register P2 and its
- * successors.
- */
 /* Opcode: AggStep * P2 P3 P4 P5
  * Synopsis: accum=r[P3] step(r[P2@P5])
  *
@@ -4205,35 +4151,7 @@ case OP_DecrJumpZero: {      /* jump, in1 */
  *
  * The P5 arguments are taken from register P2 and its
  * successors.
- *
- * This opcode is initially coded as OP_AggStep0.  On first evaluation,
- * the FuncDef stored in P4 is converted into an sql_context and
- * the opcode is changed.  In this way, the initialization of the
- * sql_context only happens once, instead of on each call to the
- * step function.
  */
-case OP_AggStep0: {
-	int n;
-	sql_context *pCtx;
-
-	assert(pOp->p4type == P4_FUNC);
-	n = pOp->p5;
-	assert(pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor));
-	assert(n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1));
-	assert(pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n);
-	pCtx = sqlDbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sql_value*));
-	if (pCtx==0) goto no_mem;
-	pCtx->pMem = 0;
-	pCtx->func = pOp->p4.func;
-	pCtx->iOp = (int)(pOp - aOp);
-	pCtx->pVdbe = p;
-	pCtx->argc = n;
-	pOp->p4type = P4_FUNCCTX;
-	pOp->p4.pCtx = pCtx;
-	pOp->opcode = OP_AggStep;
-	/* Fall through into OP_AggStep */
-	FALLTHROUGH;
-}
 case OP_AggStep: {
 	int i;
 	sql_context *pCtx;
@@ -4242,6 +4160,7 @@ case OP_AggStep: {
 
 	assert(pOp->p4type==P4_FUNCCTX);
 	pCtx = pOp->p4.pCtx;
+	pCtx->iOp = (int)(pOp - aOp);
 	pMem = &aMem[pOp->p3];
 
 	/* If this function is inside of a trigger, the register array in aMem[]
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index cfe743b94..073ac0b97 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -174,7 +174,7 @@ struct sql_context {
 	struct func *func;
 	Mem *pMem;		/* Memory cell used to store aggregate context */
 	Vdbe *pVdbe;		/* The VM that owns this context */
-	/** Instruction number of OP_BuiltinFunction0. */
+	/** Instruction number of OP_BuiltinFunction or OP_AggStep. */
 	int iOp;
 	/*
 	 * True, if an error occurred during the execution of the
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 2d7800b17..662fbbf81 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1070,7 +1070,7 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
 		}
 #if defined(SQL_DEBUG) || defined(VDBE_PROFILE)
 	case P4_FUNCCTX:{
-			struct func *func = pOp->p4.func;
+			struct func *func = pOp->p4.pCtx->func;
 			sqlXPrintf(&x, "%s(%d)", func->def->name,
 				   func->def->param_count);
 			break;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Tarantool-patches] [PATCH v2 2/5] sql: remove unnecessary MEM finalization
  2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 1/5] sql: remove OP_BuiltinFunction0 and OP_AggStep0 Mergen Imeev via Tarantool-patches
@ 2021-08-19  5:31 ` Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 3/5] sql: remove struct func from struct sql_context Mergen Imeev via Tarantool-patches
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

After removing the setting of the error in the patch "sql: modify
arithmetic aggregate functions", we no longer need to finalize the MEM
that has not been finalized. The logic is this: if the MEM has not been
finalized, then something has happened, and we no longer need to
finalize it. The MEM will be freed like a normal MEM with allocated
memory.

Part of #6105
---
 src/box/sql/mem.c     | 34 ++--------------------------------
 src/box/sql/mem.h     | 19 +------------------
 src/box/sql/vdbe.c    | 14 +++++++++++++-
 src/box/sql/vdbeapi.c | 10 ++--------
 4 files changed, 18 insertions(+), 59 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 74febd182..01d73968c 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -217,11 +217,7 @@ mem_create(struct Mem *mem)
 static inline void
 mem_clear(struct Mem *mem)
 {
-	if ((mem->type & (MEM_TYPE_AGG | MEM_TYPE_FRAME)) != 0 ||
-	    (mem->flags & MEM_Dyn) != 0) {
-		if (mem->type == MEM_TYPE_AGG)
-			sql_vdbemem_finalize(mem, mem->u.func);
-		assert(mem->type != MEM_TYPE_AGG);
+	if (mem->type == MEM_TYPE_FRAME || (mem->flags & MEM_Dyn) != 0) {
 		if ((mem->flags & MEM_Dyn) != 0) {
 			assert(mem->xDel != SQL_DYNAMIC && mem->xDel != NULL);
 			mem->xDel((void *)mem->z);
@@ -610,7 +606,7 @@ mem_set_frame(struct Mem *mem, struct VdbeFrame *frame)
 }
 
 int
-mem_set_agg(struct Mem *mem, struct func *func, int size)
+mem_set_agg(struct Mem *mem, int size)
 {
 	mem_clear(mem);
 	if (size <= 0)
@@ -621,7 +617,6 @@ mem_set_agg(struct Mem *mem, struct func *func, int size)
 	mem->n = size;
 	mem->type = MEM_TYPE_AGG;
 	assert(mem->flags == 0);
-	mem->u.func = func;
 	return 0;
 }
 
@@ -3045,31 +3040,6 @@ sqlVdbeMemTooBig(Mem * p)
 	return 0;
 }
 
-int
-sql_vdbemem_finalize(struct Mem *mem, struct func *func)
-{
-	assert(func != NULL);
-	assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	assert(func->def->aggregate == FUNC_AGGREGATE_GROUP);
-	assert(mem->type == MEM_TYPE_NULL || func == mem->u.func);
-	sql_context ctx;
-	memset(&ctx, 0, sizeof(ctx));
-	Mem t;
-	memset(&t, 0, sizeof(t));
-	t.type = MEM_TYPE_NULL;
-	assert(t.flags == 0);
-	t.db = mem->db;
-	ctx.pOut = &t;
-	ctx.pMem = mem;
-	ctx.func = func;
-	((struct func_sql_builtin *)func)->finalize(&ctx);
-	assert((mem->flags & MEM_Dyn) == 0);
-	if (mem->szMalloc > 0)
-		sqlDbFree(mem->db, mem->zMalloc);
-	memcpy(mem, &t, sizeof(t));
-	return ctx.is_aborted ? -1 : 0;
-}
-
 int
 sqlVdbeRecordCompareMsgpack(const void *key1,
 				struct UnpackedRecord *key2)
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 543944b80..bddac1a67 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -70,11 +70,6 @@ struct Mem {
 		bool b;         /* Boolean value used when MEM_Bool is set in flags */
 		int nZero;	/* Used when bit MEM_Zero is set in flags */
 		void *p;	/* Generic pointer */
-		/**
-		 * A pointer to function implementation.
-		 * Used only when flags==MEM_Agg.
-		 */
-		struct func *func;
 		struct VdbeFrame *pFrame;	/* Used when flags==MEM_Frame */
 		struct tt_uuid uuid;
 		decimal_t d;
@@ -569,7 +564,7 @@ mem_set_frame(struct Mem *mem, struct VdbeFrame *frame);
  * hold the accumulation structure for the aggregate function.
  */
 int
-mem_set_agg(struct Mem *mem, struct func *func, int size);
+mem_set_agg(struct Mem *mem, int size);
 
 /** Clear MEM and set it to special, "cleared", NULL. */
 void
@@ -961,18 +956,6 @@ int sqlVdbeMemTooBig(Mem *);
 #define VdbeMemDynamic(X) (((X)->flags & MEM_Dyn) != 0 ||\
 			   ((X)->type & (MEM_TYPE_AGG | MEM_TYPE_FRAME)) != 0)
 
-/** MEM manipulate functions. */
-
-/**
- * Memory cell mem contains the context of an aggregate function.
- * This routine calls the finalize method for that function. The
- * result of the aggregate is stored back into mem.
- *
- * Returns -1 if the finalizer reports an error. 0 otherwise.
- */
-int
-sql_vdbemem_finalize(struct Mem *mem, struct func *func);
-
 /**
  * Perform comparison of two tuples: unpacked (key1) and packed (key2)
  *
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 98ea37c67..9fb103e82 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4219,8 +4219,20 @@ case OP_AggFinal: {
 	assert(pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor));
 	pMem = &aMem[pOp->p1];
 	assert(mem_is_null(pMem) || mem_is_agg(pMem));
-	if (sql_vdbemem_finalize(pMem, pOp->p4.func) != 0)
+	struct sql_context ctx;
+	memset(&ctx, 0, sizeof(ctx));
+	struct Mem t;
+	mem_create(&t);
+	ctx.pOut = &t;
+	ctx.pMem = pMem;
+	((struct func_sql_builtin *)pOp->p4.func)->finalize(&ctx);
+	if (ctx.is_aborted)
 		goto abort_due_to_error;
+	assert((pMem->flags & MEM_Dyn) == 0);
+	if (pMem->szMalloc > 0)
+		sqlDbFree(pMem->db, pMem->zMalloc);
+	memcpy(pMem, &t, sizeof(t));
+
 	UPDATE_MAX_BLOBSIZE(pMem);
 	if (sqlVdbeMemTooBig(pMem)) {
 		goto too_big;
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 8031ee0dc..52d008c5f 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -383,10 +383,7 @@ sqlStmtCurrentTime(sql_context * p)
 void *
 sql_aggregate_context(sql_context * p, int nByte)
 {
-	assert(p != NULL && p->func != NULL);
-	assert(p->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	assert(p->func->def->aggregate == FUNC_AGGREGATE_GROUP);
-	if (!mem_is_agg(p->pMem) && mem_set_agg(p->pMem, p->func, nByte) != 0)
+	if (!mem_is_agg(p->pMem) && mem_set_agg(p->pMem, nByte) != 0)
 		return NULL;
 	void *accum;
 	if (mem_get_agg(p->pMem, &accum) != 0)
@@ -397,12 +394,9 @@ sql_aggregate_context(sql_context * p, int nByte)
 struct Mem *
 sql_context_agg_mem(struct sql_context *ctx)
 {
-	assert(ctx != NULL && ctx->func != NULL);
-	assert(ctx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	assert(ctx->func->def->aggregate == FUNC_AGGREGATE_GROUP);
 	struct Mem *mem;
 	if (!mem_is_agg(ctx->pMem)) {
-		if (mem_set_agg(ctx->pMem, ctx->func, sizeof(*mem)) != 0)
+		if (mem_set_agg(ctx->pMem, sizeof(*mem)) != 0)
 			return NULL;
 		if (mem_get_agg(ctx->pMem, (void **)&mem) != 0)
 			return NULL;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Tarantool-patches] [PATCH v2 3/5] sql: remove struct func from struct sql_context
  2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 1/5] sql: remove OP_BuiltinFunction0 and OP_AggStep0 Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 2/5] sql: remove unnecessary MEM finalization Mergen Imeev via Tarantool-patches
@ 2021-08-19  5:31 ` Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 4/5] sql: do not use struct func for finalization Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 5/5] sql: remove unused code Mergen Imeev via Tarantool-patches
  4 siblings, 0 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

This patch removes struct func from struct sql_context since we don't
need the functionality of struct func here. Without this structure, we
can make it easier to work with SQL built-in functions.

Part of #6105
---
 src/box/sql/func.c    | 123 +++++++++++++++++++++++++++++++++++++-----
 src/box/sql/vdbe.c    |   8 +--
 src/box/sql/vdbeInt.h |   6 ++-
 src/box/sql/vdbeaux.c |   5 +-
 4 files changed, 119 insertions(+), 23 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 4a0d2d097..adbc6d5a4 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -132,8 +132,7 @@ minmaxFunc(sql_context * context, int argc, sql_value ** argv)
 	int i;
 	int iBest;
 	struct coll *pColl;
-	struct func *func = context->func;
-	int mask = sql_func_flag_is_set(func, SQL_FUNC_MAX) ? -1 : 0;
+	int mask = (context->flags & SQL_FUNC_MAX) != 0 ? -1 : 0;
 	if (argc < 2) {
 		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT,
 		mask ? "GREATEST" : "LEAST", "at least two", argc);
@@ -1799,8 +1798,6 @@ minmaxStep(sql_context * context, int NotUsed, sql_value ** argv)
 	Mem *pBest;
 	UNUSED_PARAMETER(NotUsed);
 
-	struct func_sql_builtin *func =
-		(struct func_sql_builtin *)context->func;
 	pBest = sql_context_agg_mem(context);
 	if (!pBest)
 		return;
@@ -1816,7 +1813,7 @@ minmaxStep(sql_context * context, int NotUsed, sql_value ** argv)
 		 * between the two being that the sense of the
 		 * comparison is inverted.
 		 */
-		bool is_max = (func->flags & SQL_FUNC_MAX) != 0;
+		bool is_max = (context->flags & SQL_FUNC_MAX) != 0;
 		int cmp = mem_cmp_scalar(pBest, pArg, pColl);
 		if ((is_max && cmp < 0) || (!is_max && cmp > 0)) {
 			mem_copy(pBest, pArg);
@@ -1930,9 +1927,7 @@ static void
 sql_builtin_stub(sql_context *ctx, int argc, sql_value **argv)
 {
 	(void) argc; (void) argv;
-	diag_set(ClientError, ER_SQL_EXECUTE,
-		 tt_sprintf("function '%s' is not implemented",
-			    ctx->func->def->name));
+	diag_set(ClientError, ER_SQL_EXECUTE, "function is not implemented");
 	ctx->is_aborted = true;
 }
 
@@ -2886,20 +2881,124 @@ int
 sql_emit_func_call(struct Vdbe *vdbe, struct Expr *expr, int op, int mask,
 		   int r1, int r2, uint8_t argc)
 {
-	struct func *func = sql_func_find(expr);
-	if (func == NULL)
-		return -1;
 	uint32_t size = sizeof(struct sql_context);
 	if (argc > 1)
 		size += (argc - 1) * sizeof(struct Mem);
 	struct sql_context *ctx = sqlDbMallocRawNN(sql_get(), size);
 	if (ctx == NULL)
 		return -1;
+	switch(expr->func_id) {
+	case TK_ABS:
+		ctx->call = absFunc;
+		break;
+	case TK_AVG:
+	case TK_SUM:
+		ctx->call = sum_step;
+		break;
+	case TK_CHAR:
+		ctx->call = charFunc;
+		break;
+	case TK_CHAR_LEN:
+	case TK_LENGTH:
+		ctx->call = lengthFunc;
+		break;
+	case TK_COALESCE:
+	case TK_IFNULL:
+	case TK_LIKELIHOOD:
+	case TK_LIKELY:
+	case TK_UNLIKELY:
+		ctx->call = sql_builtin_stub;
+		break;
+	case TK_COUNT:
+		ctx->call = countStep;
+		break;
+	case TK_GREATEST:
+	case TK_LEAST:
+		ctx->call = minmaxFunc;
+		break;
+	case TK_GROUP_CONCAT:
+		ctx->call = groupConcatStep;
+		break;
+	case TK_HEX:
+		ctx->call = hexFunc;
+		break;
+	case TK_LIKE_KW:
+		ctx->call = likeFunc;
+		break;
+	case TK_LOWER:
+		ctx->call = LowerICUFunc;
+		break;
+	case TK_MAX:
+	case TK_MIN:
+		ctx->call = minmaxStep;
+		break;
+	case TK_NULLIF:
+		ctx->call = nullifFunc;
+		break;
+	case TK_POSITION:
+		ctx->call = position_func;
+		break;
+	case TK_PRINTF:
+		ctx->call = printfFunc;
+		break;
+	case TK_QUOTE:
+		ctx->call = quoteFunc;
+		break;
+	case TK_RANDOM:
+		ctx->call = randomFunc;
+		break;
+	case TK_RANDOMBLOB:
+		ctx->call = randomBlob;
+		break;
+	case TK_REPLACE:
+		ctx->call = replaceFunc;
+		break;
+	case TK_ROUND:
+		ctx->call = roundFunc;
+		break;
+	case TK_ROW_COUNT:
+		ctx->call = sql_row_count;
+		break;
+	case TK_SOUNDEX:
+		ctx->call = soundexFunc;
+		break;
+	case TK_SUBSTR:
+		ctx->call = substrFunc;
+		break;
+	case TK_TOTAL:
+		ctx->call = total_step;
+		break;
+	case TK_TRIM:
+		ctx->call = trim_func;
+		break;
+	case TK_TYPEOF:
+		ctx->call = typeofFunc;
+		break;
+	case TK_UNICODE:
+		ctx->call = unicodeFunc;
+		break;
+	case TK_UPPER:
+		ctx->call = UpperICUFunc;
+		break;
+	case TK_UUID:
+		ctx->call = sql_func_uuid;
+		break;
+	case TK_VERSION:
+		ctx->call = sql_func_version;
+		break;
+	case TK_ZEROBLOB:
+		ctx->call = zeroblobFunc;
+		break;
+	default:
+		unreachable();
+	}
+	assert(strlen(expr->u.zToken) < 24);
+	strcpy(ctx->name, expr->u.zToken);
 	ctx->pOut = NULL;
-	ctx->func = func;
 	ctx->iOp = 0;
 	ctx->pVdbe = vdbe;
 	ctx->argc = argc;
+	ctx->flags = sql_func_flags(expr->func_id);
 	sqlVdbeAddOp4(vdbe, op, mask, r1, r2, (char *)ctx, P4_FUNCCTX);
 	sqlVdbeChangeP5(vdbe, argc);
 	return 0;
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 9fb103e82..c63dbaa5a 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1221,9 +1221,7 @@ case OP_BuiltinFunction: {
 	}
 #endif
 	pCtx->is_aborted = false;
-	assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	struct func_sql_builtin *func = (struct func_sql_builtin *)pCtx->func;
-	func->call(pCtx, pCtx->argc, pCtx->argv);
+	pCtx->call(pCtx, pCtx->argc, pCtx->argv);
 
 	/* If the function returned an error, throw an exception */
 	if (pCtx->is_aborted)
@@ -4185,9 +4183,7 @@ case OP_AggStep: {
 	pCtx->pOut = &t;
 	pCtx->is_aborted = false;
 	pCtx->skipFlag = 0;
-	assert(pCtx->func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	struct func_sql_builtin *func = (struct func_sql_builtin *)pCtx->func;
-	func->call(pCtx, pCtx->argc, pCtx->argv);
+	pCtx->call(pCtx, pCtx->argc, pCtx->argv);
 	if (pCtx->is_aborted) {
 		mem_destroy(&t);
 		goto abort_due_to_error;
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 073ac0b97..0a0e6cc97 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -169,9 +169,8 @@ struct VdbeFrame {
  * (Mem) which are only defined there.
  */
 struct sql_context {
+	char name[24];
 	Mem *pOut;		/* The return value is stored here */
-	/* A pointer to function implementation. */
-	struct func *func;
 	Mem *pMem;		/* Memory cell used to store aggregate context */
 	Vdbe *pVdbe;		/* The VM that owns this context */
 	/** Instruction number of OP_BuiltinFunction or OP_AggStep. */
@@ -183,6 +182,9 @@ struct sql_context {
 	bool is_aborted;
 	u8 skipFlag;		/* Skip accumulator loading if true */
 	u8 argc;		/* Number of arguments */
+	uint32_t flags;
+	/* Implementation of SQL built-in function. */
+	void (*call)(struct sql_context *ctx, int argc, struct Mem **argv);
 	sql_value *argv[1];	/* Argument set */
 };
 
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 662fbbf81..3913dc637 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1070,9 +1070,8 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
 		}
 #if defined(SQL_DEBUG) || defined(VDBE_PROFILE)
 	case P4_FUNCCTX:{
-			struct func *func = pOp->p4.pCtx->func;
-			sqlXPrintf(&x, "%s(%d)", func->def->name,
-				   func->def->param_count);
+			sqlXPrintf(&x, "%s(%d)", pOp->p4.pCtx->name,
+				   pOp->p4.pCtx->argc);
 			break;
 		}
 #endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Tarantool-patches] [PATCH v2 4/5] sql: do not use struct func for finalization
  2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
                   ` (2 preceding siblings ...)
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 3/5] sql: remove struct func from struct sql_context Mergen Imeev via Tarantool-patches
@ 2021-08-19  5:31 ` Mergen Imeev via Tarantool-patches
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 5/5] sql: remove unused code Mergen Imeev via Tarantool-patches
  4 siblings, 0 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

This patch removes struct func from finalization of SQL built-in aggregate
functions.

Part of #6105
---
 src/box/sql/func.c | 30 ++++++++++++++++++++++++++----
 src/box/sql/vdbe.c |  2 +-
 src/box/sql/vdbe.h |  2 ++
 3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index adbc6d5a4..e09224bb8 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -3008,9 +3008,31 @@ int
 sql_emit_func_finalize(struct Vdbe *vdbe, struct Expr *expr, int reg,
 		       uint8_t argc)
 {
-	struct func *func = sql_func_find(expr);
-	if (func == NULL)
-		return -1;
-	sqlVdbeAddOp4(vdbe, OP_AggFinal, reg, argc, 0, (char *)func, P4_FUNC);
+	void (*finalize)(sql_context *ctx);
+	switch(expr->func_id) {
+	case TK_AVG:
+		finalize = avgFinalize;
+		break;
+	case TK_SUM:
+		finalize = sumFinalize;
+		break;
+	case TK_COUNT:
+		finalize = countFinalize;
+		break;
+	case TK_TOTAL:
+		finalize = totalFinalize;
+		break;
+	case TK_GROUP_CONCAT:
+		finalize = groupConcatFinalize;
+		break;
+	case TK_MAX:
+	case TK_MIN:
+		finalize = minMaxFinalize;
+		break;
+	default:
+		unreachable();
+	}
+	sqlVdbeAddOp4(vdbe, OP_AggFinal, reg, argc, 0, (char *)finalize,
+		      P4_STATIC);
 	return 0;
 }
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index c63dbaa5a..f821ac98a 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4221,7 +4221,7 @@ case OP_AggFinal: {
 	mem_create(&t);
 	ctx.pOut = &t;
 	ctx.pMem = pMem;
-	((struct func_sql_builtin *)pOp->p4.func)->finalize(&ctx);
+	pOp->p4.finalize(&ctx);
 	if (ctx.is_aborted)
 		goto abort_due_to_error;
 	assert((pMem->flags & MEM_Dyn) == 0);
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index e40a1a0b3..1f6e566e1 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -97,6 +97,8 @@ struct VdbeOp {
 		 * Information about ephemeral space field types and key parts.
 		 */
 		struct sql_space_info *space_info;
+		/* Finalize method for SQL built-in aggregate function. */
+		void (*finalize)(sql_context *ctx);
 	} p4;
 #ifdef SQL_ENABLE_EXPLAIN_COMMENTS
 	char *zComment;		/* Comment to improve readability */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Tarantool-patches] [PATCH v2 5/5] sql: remove unused code
  2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
                   ` (3 preceding siblings ...)
  2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 4/5] sql: do not use struct func for finalization Mergen Imeev via Tarantool-patches
@ 2021-08-19  5:31 ` Mergen Imeev via Tarantool-patches
  4 siblings, 0 replies; 6+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-08-19  5:31 UTC (permalink / raw)
  To: vdavydov; +Cc: tarantool-patches

This patch removes code that become unused due to changes in SQL
built-in functions.

Part of #6105
---
 src/box/box.cc        |   1 -
 src/box/sql.c         |   1 -
 src/box/sql.h         |   9 -
 src/box/sql/func.c    | 837 ------------------------------------------
 src/box/sql/sqlInt.h  |  42 ---
 src/box/sql/vdbe.h    |   7 -
 src/box/sql/vdbeInt.h |   2 -
 src/box/sql/vdbeaux.c |   6 -
 8 files changed, 905 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index 0b12b1328..ce44df85b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -3056,7 +3056,6 @@ box_free(void)
 		gc_free();
 		engine_shutdown();
 		wal_free();
-		sql_built_in_functions_cache_free();
 	}
 }
 
diff --git a/src/box/sql.c b/src/box/sql.c
index d15159d6e..7cadb8db5 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -75,7 +75,6 @@ sql_init(void)
 		panic("failed to initialize SQL subsystem");
 
 	sql_stmt_cache_init();
-	sql_built_in_functions_cache_init();
 
 	assert(db != NULL);
 }
diff --git a/src/box/sql.h b/src/box/sql.h
index 3ff00e64a..40fef2903 100644
--- a/src/box/sql.h
+++ b/src/box/sql.h
@@ -56,15 +56,6 @@ sql_init(void);
 struct sql *
 sql_get(void);
 
-/** Initialize global cache for built-in functions. */
-void
-sql_built_in_functions_cache_init(void);
-
-/** Free global cache for built-in functions. */
-void
-sql_built_in_functions_cache_free(void);
-
-
 struct Expr;
 struct Parse;
 struct Select;
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index e09224bb8..dd2122436 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -50,8 +50,6 @@
 #include "box/user.h"
 #include "assoc.h"
 
-static struct mh_strnptr_t *built_in_functions = NULL;
-
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1913,16 +1911,6 @@ sql_is_like_func(struct Expr *expr)
 	return 1;
 }
 
-static int
-func_sql_builtin_call_stub(struct func *func, struct port *args,
-			   struct port *ret)
-{
-	(void) func; (void) args; (void) ret;
-	diag_set(ClientError, ER_UNSUPPORTED,
-		 "sql builtin function", "Lua frontend");
-	return -1;
-}
-
 static void
 sql_builtin_stub(sql_context *ctx, int argc, sql_value **argv)
 {
@@ -1931,831 +1919,6 @@ sql_builtin_stub(sql_context *ctx, int argc, sql_value **argv)
 	ctx->is_aborted = true;
 }
 
-/**
- * A sequence of SQL builtins definitions in
- * lexicographic order.
- */
-static struct {
-	/**
-	 * Name is used to find corresponding entry in array
-	 * sql_builtins applying binary search.
-	 */
-	const char *name;
-	/** Members below are related to struct func_sql_builtin. */
-	uint16_t flags;
-	void (*call)(sql_context *ctx, int argc, sql_value **argv);
-	void (*finalize)(sql_context *ctx);
-	/** Members below are related to struct func_def. */
-	bool is_deterministic;
-	int param_count;
-	enum field_type returns;
-	enum func_aggregate aggregate;
-	bool export_to_sql;
-} sql_builtins[] = {
-	{.name = "ABS",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_NUMBER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = absFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "AVG",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_NUMBER,
-	 .is_deterministic = false,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .flags = 0,
-	 .call = sum_step,
-	 .finalize = avgFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "CEIL",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "CEILING",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "CHAR",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_STRING,
-	 .is_deterministic = true,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .flags = 0,
-	 .call = charFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	 }, {
-	 .name = "CHARACTER_LENGTH",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = lengthFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "CHAR_LENGTH",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = lengthFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "COALESCE",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_COALESCE,
-	 .call = sql_builtin_stub,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "COUNT",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = countStep,
-	 .finalize = countFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "CURRENT_DATE",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "CURRENT_TIME",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "CURRENT_TIMESTAMP",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "DATE",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "DATETIME",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "EVERY",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "EXISTS",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "EXP",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "EXTRACT",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "FLOOR",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "GREATER",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "GREATEST",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX,
-	 .call = minmaxFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "GROUP_CONCAT",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = groupConcatStep,
-	 .finalize = groupConcatFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "HEX",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = hexFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "IFNULL",
-	 .param_count = 2,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_COALESCE,
-	 .call = sql_builtin_stub,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "JULIANDAY",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "LEAST",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN,
-	 .call = minmaxFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "LENGTH",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_LENGTH,
-	 .call = lengthFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "LESSER",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "LIKE",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_LIKE,
-	 .call = likeFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "LIKELIHOOD",
-	 .param_count = 2,
-	 .returns = FIELD_TYPE_BOOLEAN,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_UNLIKELY,
-	 .call = sql_builtin_stub,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "LIKELY",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_BOOLEAN,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_UNLIKELY,
-	 .call = sql_builtin_stub,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "LN",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "LOWER",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
-	 .call = LowerICUFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "MAX",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX,
-	 .call = minmaxStep,
-	 .finalize = minMaxFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "MIN",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN,
-	 .call = minmaxStep,
-	 .finalize = minMaxFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "MOD",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "NULLIF",
-	 .param_count = 2,
-	 .returns = FIELD_TYPE_SCALAR,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_NEEDCOLL,
-	 .call = nullifFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "OCTET_LENGTH",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "POSITION",
-	 .param_count = 2,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_NEEDCOLL,
-	 .call = position_func,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "POWER",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "PRINTF",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = printfFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "QUOTE",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = quoteFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "RANDOM",
-	 .param_count = 0,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = randomFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "RANDOMBLOB",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_VARBINARY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = randomBlob,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "REPLACE",
-	 .param_count = 3,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_DERIVEDCOLL,
-	 .call = replaceFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "ROUND",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = roundFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "ROW_COUNT",
-	 .param_count = 0,
-	 .returns = FIELD_TYPE_INTEGER,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = sql_row_count,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "SOME",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "SOUNDEX",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = soundexFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "SQRT",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "STRFTIME",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "SUBSTR",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_DERIVEDCOLL,
-	 .call = substrFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "SUM",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_NUMBER,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = sum_step,
-	 .finalize = sumFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "TIME",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "TOTAL",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_NUMBER,
-	 .aggregate = FUNC_AGGREGATE_GROUP,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = total_step,
-	 .finalize = totalFinalize,
-	 .export_to_sql = true,
-	}, {
-	 .name = "TRIM",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_DERIVEDCOLL,
-	 .call = trim_func,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "TYPEOF",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_TYPEOF,
-	 .call = typeofFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "UNICODE",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = unicodeFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "UNLIKELY",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_BOOLEAN,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_UNLIKELY,
-	 .call = sql_builtin_stub,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "UPPER",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
-	 .call = UpperICUFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "UUID",
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_UUID,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .call = sql_func_uuid,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "VERSION",
-	 .param_count = 0,
-	 .returns = FIELD_TYPE_STRING,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = sql_func_version,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "ZEROBLOB",
-	 .param_count = 1,
-	 .returns = FIELD_TYPE_VARBINARY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = true,
-	 .flags = 0,
-	 .call = zeroblobFunc,
-	 .finalize = NULL,
-	 .export_to_sql = true,
-	}, {
-	 .name = "_sql_stat_get",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "_sql_stat_init",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	}, {
-	 .name = "_sql_stat_push",
-	 .call = sql_builtin_stub,
-	 .export_to_sql = false,
-	 .param_count = -1,
-	 .returns = FIELD_TYPE_ANY,
-	 .aggregate = FUNC_AGGREGATE_NONE,
-	 .is_deterministic = false,
-	 .flags = 0,
-	 .finalize = NULL,
-	},
-};
-
-static struct func *
-built_in_func_get(const char *name)
-{
-	uint32_t len = strlen(name);
-	mh_int_t k = mh_strnptr_find_inp(built_in_functions, name, len);
-	if (k == mh_end(built_in_functions))
-		return NULL;
-	return mh_strnptr_node(built_in_functions, k)->val;
-}
-
-static void
-built_in_func_put(struct func *func)
-{
-	const char *name = func->def->name;
-	uint32_t len = strlen(name);
-	assert(built_in_func_get(name) == NULL);
-
-	uint32_t hash = mh_strn_hash(name, len);
-	const struct mh_strnptr_node_t strnode = {name, len, hash, func};
-	mh_int_t k = mh_strnptr_put(built_in_functions, &strnode, NULL, NULL);
-	if (k == mh_end(built_in_functions)) {
-		panic("Out of memory on insertion into SQL built-in functions "
-		      "hash");
-	}
-}
-
-struct func *
-sql_func_find(struct Expr *expr)
-{
-	const char *name = expr->u.zToken;
-	int n = expr->x.pList ? expr->x.pList->nExpr : 0;
-	struct func *func = built_in_func_get(name);
-	if (func != NULL) {
-		assert(func->def->exports.sql);
-		int param_count = func->def->param_count;
-		if (param_count != -1 && param_count != n) {
-			diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, name,
-				 tt_sprintf("%d", func->def->param_count), n);
-			return NULL;
-		}
-		return func;
-	}
-	func = func_by_name(name, strlen(name));
-	if (func == NULL) {
-		diag_set(ClientError, ER_NO_SUCH_FUNCTION, name);
-		return NULL;
-	}
-	if (!func->def->exports.sql) {
-		diag_set(ClientError, ER_SQL_PARSER_GENERIC,
-			 tt_sprintf("function %s() is not available in SQL",
-				     name));
-		return NULL;
-	}
-	if (func->def->param_count != n) {
-		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, name,
-			 tt_sprintf("%d", func->def->param_count), n);
-		return NULL;
-	}
-	return func;
-}
-
-static struct func_vtab func_sql_builtin_vtab;
-
-void
-sql_built_in_functions_cache_init(void)
-{
-	built_in_functions = mh_strnptr_new();
-	if (built_in_functions == NULL)
-		panic("Out of memory on creating SQL built-in functions hash");
-	for (uint32_t i = 0; i < nelem(sql_builtins); ++i) {
-		const char *name = sql_builtins[i].name;
-		if (!sql_builtins[i].export_to_sql)
-			continue;
-		uint32_t len = strlen(name);
-		uint32_t size = sizeof(struct func_def) + len + 1;
-		struct func_def *def = malloc(size);
-		if (def == NULL)
-			panic("Out of memory on creating SQL built-in");
-		def->fid = i;
-		def->uid = 1;
-		def->body = NULL;
-		def->comment = NULL;
-		def->setuid = true;
-		def->is_deterministic = sql_builtins[i].is_deterministic;
-		def->is_sandboxed = false;
-		def->param_count = sql_builtins[i].param_count;
-		def->returns = sql_builtins[i].returns;
-		def->aggregate = sql_builtins[i].aggregate;
-		def->language = FUNC_LANGUAGE_SQL_BUILTIN;
-		def->name_len = len;
-		def->exports.sql = sql_builtins[i].export_to_sql;
-		func_opts_create(&def->opts);
-		memcpy(def->name, name, len + 1);
-
-		struct func_sql_builtin *func = malloc(sizeof(*func));
-		if (func == NULL)
-			panic("Out of memory on creating SQL built-in");
-
-		func->base.def = def;
-		func->base.vtab = &func_sql_builtin_vtab;
-		credentials_create_empty(&func->base.owner_credentials);
-		memset(func->base.access, 0, sizeof(func->base.access));
-
-		func->flags = sql_builtins[i].flags;
-		func->call = sql_builtins[i].call;
-		func->finalize = sql_builtins[i].finalize;
-		built_in_func_put(&func->base);
-	}
-}
-
-void
-sql_built_in_functions_cache_free(void)
-{
-	if (built_in_functions == NULL)
-		return;
-	for (uint32_t i = 0; i < nelem(sql_builtins); ++i) {
-		const char *name = sql_builtins[i].name;
-		uint32_t len = strlen(name);
-		mh_int_t k = mh_strnptr_find_inp(built_in_functions, name, len);
-		if (k == mh_end(built_in_functions))
-			continue;
-		struct func *func = mh_strnptr_node(built_in_functions, k)->val;
-		mh_strnptr_del(built_in_functions, k, NULL);
-		func_delete(func);
-	}
-	assert(mh_size(built_in_functions) == 0);
-	mh_strnptr_delete(built_in_functions);
-}
-
-static void
-func_sql_builtin_destroy(struct func *func)
-{
-	assert(func->vtab == &func_sql_builtin_vtab);
-	assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
-	free(func);
-}
-
-static struct func_vtab func_sql_builtin_vtab = {
-	.call = func_sql_builtin_call_stub,
-	.destroy = func_sql_builtin_destroy,
-};
-
 uint32_t
 sql_func_flags(uint8_t id)
 {
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 8edee0cef..a4257fc0f 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4359,48 +4359,6 @@ Expr *sqlExprForVectorField(Parse *, Expr *, int);
  */
 extern int sqlSubProgramsRemaining;
 
-struct func_sql_builtin {
-	/** Function object base class. */
-	struct func base;
-	/** A bitmask of SQL flags. */
-	uint16_t flags;
-	/**
-	 * A VDBE-memory-compatible call method.
-	 * SQL built-ins don't use func base class "call"
-	 * method to provide a best performance for SQL requests.
-	 * Access checks are redundant, because all SQL built-ins
-	 * are predefined and are executed on SQL privilege level.
-	 */
-	void (*call)(sql_context *ctx, int argc, sql_value **argv);
-	/**
-	 * A VDBE-memory-compatible finalize method
-	 * (is valid only for aggregate function).
-	 */
-	void (*finalize)(sql_context *ctx);
-};
-
-/**
- * Test whether SQL-specific flag is set for given function.
- * Currently only SQL Builtin Functions have such hint flags,
- * so function returns false for other functions. Such approach
- * decreases code complexity and allows do not distinguish
- * functions by implementation details where it is unnecessary.
- *
- * Returns true when given flag is set for a given function and
- * false otherwise.
- */
-static inline bool
-sql_func_flag_is_set(struct func *func, uint16_t flag)
-{
-	if (func->def->language != FUNC_LANGUAGE_SQL_BUILTIN)
-		return false;
-	return (((struct func_sql_builtin *)func)->flags & flag) != 0;
-}
-
-/** Return a function that matches the parameters described in given expr. */
-struct func *
-sql_func_find(struct Expr *expr);
-
 /** Return user-defined function with given name and number of arguments. */
 struct func *
 sql_func_by_signature(const char *name, uint32_t argc);
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 1f6e566e1..eef472ed9 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -72,11 +72,6 @@ struct VdbeOp {
 		char *z;	/* Pointer to data for string (char array) types */
 		i64 *pI64;	/* Used when p4type is P4_INT64/UINT64 */
 		double *pReal;	/* Used when p4type is P4_REAL */
-		/**
-		 * A pointer to function implementation.
-		 * Used when p4type is P4_FUNC.
-		 */
-		struct func *func;
 		sql_context *pCtx;	/* Used when p4type is P4_FUNCCTX */
 		struct coll *pColl;	/* Used when p4type is P4_COLLSEQ */
 		Mem *pMem;	/* Used when p4type is P4_MEM */
@@ -132,8 +127,6 @@ struct SubProgram {
 #define P4_DYNAMIC  (-1)	/* Pointer to a string obtained from sqlMalloc() */
 #define P4_STATIC   (-2)	/* Pointer to a static string */
 #define P4_COLLSEQ  (-3)	/* P4 is a pointer to a CollSeq structure */
-/** P4 is a pointer to a func structure. */
-#define P4_FUNC     (-4)
 #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/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 0a0e6cc97..231605e61 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -46,8 +46,6 @@
  */
 typedef struct VdbeOp Op;
 
-struct func;
-
 /*
  * Boolean values
  */
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 3913dc637..0c37a30f9 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1062,12 +1062,6 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
 				sqlXPrintf(&x, "(binary)");
 			break;
 		}
-	case P4_FUNC:{
-			struct func *func = pOp->p4.func;
-			sqlXPrintf(&x, "%s(%d)", func->def->name,
-				   func->def->param_count);
-			break;
-		}
 #if defined(SQL_DEBUG) || defined(VDBE_PROFILE)
 	case P4_FUNCCTX:{
 			sqlXPrintf(&x, "%s(%d)", pOp->p4.pCtx->name,
-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-08-19  5:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-19  5:31 [Tarantool-patches] [PATCH v2 0/5] Change structure of SQL-built-in functions Mergen Imeev via Tarantool-patches
2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 1/5] sql: remove OP_BuiltinFunction0 and OP_AggStep0 Mergen Imeev via Tarantool-patches
2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 2/5] sql: remove unnecessary MEM finalization Mergen Imeev via Tarantool-patches
2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 3/5] sql: remove struct func from struct sql_context Mergen Imeev via Tarantool-patches
2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 4/5] sql: do not use struct func for finalization Mergen Imeev via Tarantool-patches
2021-08-19  5:31 ` [Tarantool-patches] [PATCH v2 5/5] sql: remove unused code Mergen Imeev via Tarantool-patches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox