From e1a7cb7f030be8f13545c48121dc29fe8adfa51c Mon Sep 17 00:00:00 2001
From: Kirill Shcherbatov <kshcherbatov@tarantool.org>
Date: Mon, 1 Jul 2019 14:03:52 +0300
Subject: [PATCH] sql: put analyze helpers to FuncDef cache

Previously analyze functions refer to statically defined
service FuncDef context. We need to change this approach due we
going to rework the builtins functions machinery in following
patches.

Needed for #4113, #2200, #2233
---
 src/box/sql/analyze.c | 62 ++++++++++++++++---------------------------
 src/box/sql/func.c    |  2 +-
 src/box/sql/sqlInt.h  |  4 +++
 src/box/sql/vdbemem.c | 50 ----------------------------------
 4 files changed, 28 insertions(+), 90 deletions(-)

diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 9af23e9855..512904cc19 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -350,18 +350,6 @@ statInit(sql_context * context, int argc, sql_value ** argv)
 	sql_result_blob(context, p, sizeof(*p), stat4Destructor);
 }
 
-static const FuncDef statInitFuncdef = {
-	3,			/* nArg */
-	0,			/* funcFlags */
-	0,			/* pUserData */
-	0,			/* pNext */
-	statInit,		/* xSFunc */
-	0,			/* xFinalize */
-	"stat_init",		/* zName */
-	{0},
-	0, false
-};
-
 /*
  * pNew and pOld are both candidate non-periodic samples selected for
  * the same column (pNew->iCol==pOld->iCol). Ignoring this column and
@@ -606,18 +594,6 @@ statPush(sql_context * context, int argc, sql_value ** argv)
 	}
 }
 
-static const FuncDef statPushFuncdef = {
-	3,			/* nArg */
-	0,			/* funcFlags */
-	0,			/* pUserData */
-	0,			/* pNext */
-	statPush,		/* xSFunc */
-	0,			/* xFinalize */
-	"stat_push",		/* zName */
-	{0},
-	0, false
-};
-
 #define STAT_GET_STAT1 0	/* "stat" column of stat1 table */
 #define STAT_GET_KEY   1	/* "key" column of stat4 entry */
 #define STAT_GET_NEQ   2	/* "neq" column of stat4 entry */
@@ -734,25 +710,16 @@ UNUSED_PARAMETER(argc);
 #endif
 }
 
-static const FuncDef statGetFuncdef = {
-	2,			/* nArg */
-	0,			/* funcFlags */
-	0,			/* pUserData */
-	0,			/* pNext */
-	statGet,		/* xSFunc */
-	0,			/* xFinalize */
-	"stat_get",		/* zName */
-	{0},
-	0, false
-};
-
 static void
 callStatGet(Vdbe * v, int regStat4, int iParam, int regOut)
 {
 	assert(regOut != regStat4 && regOut != regStat4 + 1);
 	sqlVdbeAddOp2(v, OP_Integer, iParam, regStat4 + 1);
+	struct FuncDef *func =
+		sqlFindFunction(sql_get(), "_sql_stat_get", 2, 0);
+	assert(func != NULL);
 	sqlVdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
-			  (char *)&statGetFuncdef, P4_FUNCDEF);
+		      (char *)func, P4_FUNCDEF);
 	sqlVdbeChangeP5(v, 2);
 }
 
@@ -888,8 +855,11 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		sqlVdbeAddOp2(v, OP_Count, idx_cursor, stat4_reg + 3);
 		sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 1);
 		sqlVdbeAddOp2(v, OP_Integer, part_count, stat4_reg + 2);
+		struct FuncDef *init_func =
+			sqlFindFunction(sql_get(), "_sql_stat_init", 3, 0);
+		assert(init_func != NULL);
 		sqlVdbeAddOp4(v, OP_Function0, 0, stat4_reg + 1, stat4_reg,
-				  (char *)&statInitFuncdef, P4_FUNCDEF);
+			      (char *)init_func, P4_FUNCDEF);
 		sqlVdbeChangeP5(v, 3);
 		/*
 		 * Implementation of the following:
@@ -986,8 +956,11 @@ vdbe_emit_analyze_space(struct Parse *parse, struct space *space)
 		sqlVdbeAddOp3(v, OP_MakeRecord, stat_key_reg,
 				  pk_part_count, key_reg);
 		assert(chng_reg == (stat4_reg + 1));
+		struct FuncDef *push_func =
+			sqlFindFunction(sql_get(), "_sql_stat_push", 3, 0);
+		assert(push_func != NULL);
 		sqlVdbeAddOp4(v, OP_Function0, 1, stat4_reg, tmp_reg,
-				  (char *)&statPushFuncdef, P4_FUNCDEF);
+			      (char *)push_func, P4_FUNCDEF);
 		sqlVdbeChangeP5(v, 3);
 		sqlVdbeAddOp2(v, OP_Next, idx_cursor, next_row_addr);
 		/* Add the entry to the stat1 table. */
@@ -1774,3 +1747,14 @@ sql_analysis_load(struct sql *db)
 	box_txn_rollback();
 	return -1;
 }
+
+void
+sql_register_analyze_builtins(void)
+{
+	static FuncDef funcs[] = {
+		FUNCTION(_sql_stat_get, 2, 0, 0, statGet, FIELD_TYPE_ANY),
+		FUNCTION(_sql_stat_push, 3, 0, 0, statPush, FIELD_TYPE_ANY),
+		FUNCTION(_sql_stat_init, 3, 0, 0, statInit, FIELD_TYPE_ANY),
+	};
+	sqlInsertBuiltinFuncs(funcs, nelem(funcs));
+}
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ad6eb0586a..d84a670c36 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1906,7 +1906,7 @@ sqlRegisterBuiltinFunctions(void)
 		FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQL_FUNC_COALESCE,
 			  FIELD_TYPE_SCALAR),
 	};
-	sqlAnalyzeFunctions();
+	sql_register_analyze_builtins();
 	sqlRegisterDateTimeFunctions();
 	sqlInsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 9305f7d5c8..db372b74e2 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -4512,6 +4512,10 @@ Expr *sqlExprForVectorField(Parse *, Expr *, int);
  */
 extern int sqlSubProgramsRemaining;
 
+/** Register built-in functions to work with ANALYZE data. */
+void
+sql_register_analyze_builtins(void);
+
 /**
  * Generate VDBE code to halt execution with correct error if
  * the object with specified key is already present (or doesn't
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index 4e4bd597d9..f52035b0ee 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -1466,56 +1466,6 @@ sqlValueFromExpr(sql * db,	/* The database connection */
 	return pExpr ? valueFromExpr(db, pExpr, type, ppVal, 0) : 0;
 }
 
-/*
- * The implementation of the sql_record() function. This function accepts
- * a single argument of any type. The return value is a formatted database
- * record (a blob) containing the argument value.
- *
- * This is used to convert the value stored in the 'sample' column of the
- * sql_stat4 table to the record format sql uses internally.
- */
-static void
-recordFunc(sql_context * context, int argc, sql_value ** argv)
-{
-	const int file_format = 1;
-	u32 iSerial;		/* Serial type */
-	int nSerial;		/* Bytes of space for iSerial as varint */
-	u32 nVal;		/* Bytes of space required for argv[0] */
-	int nRet;
-	sql *db;
-	u8 *aRet;
-
-	UNUSED_PARAMETER(argc);
-	iSerial = sqlVdbeSerialType(argv[0], file_format, &nVal);
-	nSerial = sqlVarintLen(iSerial);
-	db = sql_context_db_handle(context);
-
-	nRet = 1 + nSerial + nVal;
-	aRet = sqlDbMallocRawNN(db, nRet);
-	if (aRet == 0) {
-		context->is_aborted = true;
-	} else {
-		aRet[0] = nSerial + 1;
-		putVarint32(&aRet[1], iSerial);
-		sqlVdbeSerialPut(&aRet[1 + nSerial], argv[0], iSerial);
-		sql_result_blob(context, aRet, nRet, SQL_TRANSIENT);
-		sqlDbFree(db, aRet);
-	}
-}
-
-/*
- * Register built-in functions used to help read ANALYZE data.
- */
-void
-sqlAnalyzeFunctions(void)
-{
-	static FuncDef aAnalyzeTableFuncs[] = {
-		FUNCTION(sql_record, 1, 0, 0, recordFunc, 0),
-	};
-	sqlInsertBuiltinFuncs(aAnalyzeTableFuncs,
-				  ArraySize(aAnalyzeTableFuncs));
-}
-
 /*
  * Attempt to extract a value from pExpr and use it to construct *ppVal.
  *
-- 
GitLab