Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions
@ 2021-11-11 10:48 Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 01/21] sql: rework CHAR() function Mergen Imeev via Tarantool-patches
                   ` (21 more replies)
  0 siblings, 22 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch-set refactor the built-in SQL functions that were not refactored in
the previous two patch-sets. It also simplifies struct Mem.

https://github.com/tarantool/tarantool/issues/4145
https://github.com/tarantool/tarantool/tree/imeevma/gh-4145-row-sql-builtin-funcs

Mergen Imeev (21):
  sql: rework CHAR() function
  sql: refactor GREATEST() and LEAST() functions
  sql: refactor HEX() function
  sql: refactor LENGTH() function
  sql: refactor PRINTF() function
  sql: refactor RANDOM() function
  sql: rework RANDOMBLOB() function
  sql: refactor ZEROBLOB() function
  sql: refactor TYPEOF() function
  sql: refactor ROUND() function
  sql: refactor ROW_COUNT() function
  sql: rework UUID() function
  sql: refactor VERSION() function
  sql: refactor UNICODE() function
  sql: refactor SOUNDEX() function
  sql: refactor REPLACE() function
  sql: refactor QUOTE() function
  sql: remove unused code
  sql: remove MEM_Dyn flag
  sql: remove MEM_Term flag
  sql: make arguments to be const

 src/box/CMakeLists.txt     |   1 -
 src/box/bind.c             |   5 +-
 src/box/sql/func.c         | 978 ++++++++++++++++---------------------
 src/box/sql/main.c         |  10 -
 src/box/sql/mem.c          | 199 +-------
 src/box/sql/mem.h          | 170 +------
 src/box/sql/printf.c       |  24 +-
 src/box/sql/sqlInt.h       | 100 +---
 src/box/sql/trigger.c      |   7 +-
 src/box/sql/utf.c          |  95 ----
 src/box/sql/vdbe.h         |   9 +-
 src/box/sql/vdbeInt.h      |   1 -
 src/box/sql/vdbeapi.c      | 238 +--------
 src/box/sql/vdbeaux.c      |  57 +--
 src/box/sql/whereexpr.c    |  18 +-
 test/sql-tap/func.test.lua |   4 +-
 test/sql-tap/uuid.test.lua |  11 +-
 17 files changed, 523 insertions(+), 1404 deletions(-)
 delete mode 100644 src/box/sql/utf.c

-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 01/21] sql: rework CHAR() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 02/21] sql: refactor GREATEST() and LEAST() functions Mergen Imeev via Tarantool-patches
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

The CHAR() function now uses the ICU macro to get characters.

Part of #4145
---
 src/box/sql/func.c | 100 +++++++++++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 45 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 868d51145..0cd8f8f69 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -728,6 +728,60 @@ func_substr_characters(struct sql_context *ctx, int argc, struct Mem *argv)
 		ctx->is_aborted = true;
 }
 
+/**
+ * Implementation of the CHAR() function.
+ *
+ * This function takes zero or more arguments, each of which is an integer. It
+ * constructs a string where each character of the string is the unicode
+ * character for the corresponding integer argument.
+ *
+ * If an argument is negative or greater than 0x10ffff, the symbol "�" is used.
+ * Symbol '\0' used instead of NULL argument.
+ */
+static void
+func_char(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	if (argc == 0)
+		return mem_set_str_static(ctx->pOut, "", 0);
+	struct region *region = &fiber()->gc;
+	size_t svp = region_used(region);
+	uint32_t size;
+	UChar32 *buf = region_alloc_array(region, typeof(*buf), argc, &size);
+	if (buf == NULL) {
+		ctx->is_aborted = true;
+		diag_set(OutOfMemory, size, "region_alloc_array", "buf");
+		return;
+	}
+	int len = 0;
+	for (int i = 0; i < argc; ++i) {
+		if (mem_is_null(&argv[i]))
+			buf[i] = 0;
+		else if (!mem_is_uint(&argv[i]) || argv[i].u.u > 0x10ffff)
+			buf[i] = 0xfffd;
+		else
+			buf[i] = argv[i].u.u;
+		len += U8_LENGTH(buf[i]);
+	}
+
+	char *str = sqlDbMallocRawNN(sql_get(), len);
+	if (str == NULL) {
+		region_truncate(region, svp);
+		ctx->is_aborted = true;
+		return;
+	}
+	int pos = 0;
+	for (int i = 0; i < argc; ++i) {
+		UBool is_error = false;
+		U8_APPEND((uint8_t *)str, pos, len, buf[i], is_error);
+		assert(!is_error);
+		(void)is_error;
+	}
+	region_truncate(region, svp);
+	assert(pos == len);
+	(void)pos;
+	mem_set_str_allocated(ctx->pOut, str, len);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1461,50 +1515,6 @@ unicodeFunc(struct sql_context *context, int argc, struct Mem *argv)
 		sql_result_uint(context, sqlUtf8Read(&z));
 }
 
-/*
- * The char() function takes zero or more arguments, each of which is
- * an integer.  It constructs a string where each character of the string
- * is the unicode character for the corresponding integer argument.
- */
-static void
-charFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	unsigned char *z, *zOut;
-	int i;
-	zOut = z = sql_malloc64(argc * 4 + 1);
-	if (z == NULL) {
-		context->is_aborted = true;
-		return;
-	}
-	for (i = 0; i < argc; i++) {
-		uint64_t x;
-		unsigned c;
-		if (sql_value_type(&argv[i]) == MP_INT)
-			x = 0xfffd;
-		else
-			x = mem_get_uint_unsafe(&argv[i]);
-		if (x > 0x10ffff)
-			x = 0xfffd;
-		c = (unsigned)(x & 0x1fffff);
-		if (c < 0x00080) {
-			*zOut++ = (u8) (c & 0xFF);
-		} else if (c < 0x00800) {
-			*zOut++ = 0xC0 + (u8) ((c >> 6) & 0x1F);
-			*zOut++ = 0x80 + (u8) (c & 0x3F);
-		} else if (c < 0x10000) {
-			*zOut++ = 0xE0 + (u8) ((c >> 12) & 0x0F);
-			*zOut++ = 0x80 + (u8) ((c >> 6) & 0x3F);
-			*zOut++ = 0x80 + (u8) (c & 0x3F);
-		} else {
-			*zOut++ = 0xF0 + (u8) ((c >> 18) & 0x07);
-			*zOut++ = 0x80 + (u8) ((c >> 12) & 0x3F);
-			*zOut++ = 0x80 + (u8) ((c >> 6) & 0x3F);
-			*zOut++ = 0x80 + (u8) (c & 0x3F);
-		}
-	}
-	sql_result_text64(context, (char *)z, zOut - z, sql_free);
-}
-
 /*
  * The hex() function.  Interpret the argument as a blob.  Return
  * a hexadecimal rendering as text.
@@ -1857,7 +1867,7 @@ static struct sql_func_definition definitions[] = {
 	 NULL},
 	{"AVG", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, step_avg, fin_avg},
 	{"AVG", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, step_avg, fin_avg},
-	{"CHAR", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_STRING, charFunc, NULL},
+	{"CHAR", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_STRING, func_char, NULL},
 	{"CHAR_LENGTH", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER,
 	 func_char_length, NULL},
 	{"COALESCE", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_SCALAR, sql_builtin_stub,
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 02/21] sql: refactor GREATEST() and LEAST() functions
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 01/21] sql: rework CHAR() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 03/21] sql: refactor HEX() function Mergen Imeev via Tarantool-patches
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 113 +++++++++++++++++++++++----------------------
 1 file changed, 57 insertions(+), 56 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 0cd8f8f69..40bdbf739 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -782,6 +782,34 @@ func_char(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_str_allocated(ctx->pOut, str, len);
 }
 
+/**
+ * Implementation of the GREATEST() and LEAST() functions.
+ *
+ * The GREATEST() function returns the largest of the given arguments.
+ * The LEAST() function returns the smallest of the given arguments.
+ */
+static void
+func_greatest_least(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc > 1);
+	int mask = ctx->func->def->name[0] == 'G' ? -1 : 0;
+	assert(ctx->func->def->name[0] == 'G' ||
+	       ctx->func->def->name[0] == 'L');
+
+	if (mem_is_null(&argv[0]))
+		return;
+	int best = 0;
+	for (int i = 1; i < argc; ++i) {
+		if (mem_is_null(&argv[i]))
+			return;
+		int cmp = mem_cmp_scalar(&argv[best], &argv[i], ctx->coll);
+		if ((cmp ^ mask) >= 0)
+			best = i;
+	}
+	if (mem_copy(ctx->pOut, &argv[best]) != 0)
+		ctx->is_aborted = true;
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -829,37 +857,6 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uuid(ctx->pOut, &uuid);
 }
 
-/*
- * Implementation of the non-aggregate min() and max() functions
- */
-static void
-minmaxFunc(struct sql_context *context, int argc, struct Mem *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;
-	if (argc < 2) {
-		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT,
-		mask ? "GREATEST" : "LEAST", "at least two", argc);
-		context->is_aborted = true;
-		return;
-	}
-	pColl = context->coll;
-	assert(mask == -1 || mask == 0);
-	iBest = 0;
-	if (mem_is_null(&argv[0]))
-		return;
-	for (i = 1; i < argc; i++) {
-		if (mem_is_null(&argv[i]))
-			return;
-		if ((mem_cmp_scalar(&argv[iBest], &argv[i], pColl) ^ mask) >= 0)
-			iBest = i;
-	}
-	sql_result_value(context, &argv[iBest]);
-}
-
 /*
  * Return the type of the argument.
  */
@@ -1788,13 +1785,11 @@ static struct sql_func_dictionary dictionaries[] = {
 	{"CHAR_LENGTH", 1, 1, 0, true, 0, NULL},
 	{"COALESCE", 2, SQL_MAX_FUNCTION_ARG, SQL_FUNC_COALESCE, true, 0, NULL},
 	{"COUNT", 0, 1, SQL_FUNC_AGG, false, 0, NULL},
-	{"GREATEST", 2, SQL_MAX_FUNCTION_ARG, SQL_FUNC_MAX | SQL_FUNC_NEEDCOLL,
-	 true, 0, NULL},
+	{"GREATEST", 2, SQL_MAX_FUNCTION_ARG, SQL_FUNC_NEEDCOLL, true, 0, NULL},
 	{"GROUP_CONCAT", 1, 2, SQL_FUNC_AGG, false, 0, NULL},
 	{"HEX", 1, 1, 0, true, 0, NULL},
 	{"IFNULL", 2, 2, SQL_FUNC_COALESCE, true, 0, NULL},
-	{"LEAST", 2, SQL_MAX_FUNCTION_ARG, SQL_FUNC_MIN | SQL_FUNC_NEEDCOLL,
-	 true, 0, NULL},
+	{"LEAST", 2, SQL_MAX_FUNCTION_ARG, SQL_FUNC_NEEDCOLL, true, 0, NULL},
 	{"LENGTH", 1, 1, SQL_FUNC_LENGTH, true, 0, NULL},
 	{"LIKE", 2, 3, SQL_FUNC_LIKE | SQL_FUNC_NEEDCOLL, true, 0, NULL},
 	{"LIKELIHOOD", 2, 2, SQL_FUNC_UNLIKELY, true, 0, NULL},
@@ -1876,19 +1871,20 @@ static struct sql_func_definition definitions[] = {
 	{"COUNT", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_INTEGER, step_count,
 	 fin_count},
 
-	{"GREATEST", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, minmaxFunc,
-	 NULL},
-	{"GREATEST", -1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, minmaxFunc,
-	 NULL},
-	{"GREATEST", -1, {FIELD_TYPE_NUMBER}, FIELD_TYPE_NUMBER, minmaxFunc,
-	 NULL},
+	{"GREATEST", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER,
+	 func_greatest_least, NULL},
+	{"GREATEST", -1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE,
+	 func_greatest_least, NULL},
+	{"GREATEST", -1, {FIELD_TYPE_NUMBER}, FIELD_TYPE_NUMBER,
+	 func_greatest_least, NULL},
 	{"GREATEST", -1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_VARBINARY,
-	 minmaxFunc, NULL},
-	{"GREATEST", -1, {FIELD_TYPE_UUID}, FIELD_TYPE_UUID, minmaxFunc, NULL},
-	{"GREATEST", -1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, minmaxFunc,
-	 NULL},
-	{"GREATEST", -1, {FIELD_TYPE_SCALAR}, FIELD_TYPE_SCALAR, minmaxFunc,
-	 NULL},
+	 func_greatest_least, NULL},
+	{"GREATEST", -1, {FIELD_TYPE_UUID}, FIELD_TYPE_UUID,
+	 func_greatest_least, NULL},
+	{"GREATEST", -1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING,
+	 func_greatest_least, NULL},
+	{"GREATEST", -1, {FIELD_TYPE_SCALAR}, FIELD_TYPE_SCALAR,
+	 func_greatest_least, NULL},
 
 	{"GROUP_CONCAT", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING,
 	 step_group_concat, NULL},
@@ -1903,15 +1899,20 @@ static struct sql_func_definition definitions[] = {
 	{"IFNULL", 2, {FIELD_TYPE_ANY, FIELD_TYPE_ANY}, FIELD_TYPE_SCALAR,
 	 sql_builtin_stub, NULL},
 
-	{"LEAST", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER, minmaxFunc,
-	 NULL},
-	{"LEAST", -1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, minmaxFunc, NULL},
-	{"LEAST", -1, {FIELD_TYPE_NUMBER}, FIELD_TYPE_NUMBER, minmaxFunc, NULL},
-	{"LEAST", -1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_VARBINARY, minmaxFunc,
-	 NULL},
-	{"LEAST", -1, {FIELD_TYPE_UUID}, FIELD_TYPE_UUID, minmaxFunc, NULL},
-	{"LEAST", -1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, minmaxFunc, NULL},
-	{"LEAST", -1, {FIELD_TYPE_SCALAR}, FIELD_TYPE_SCALAR, minmaxFunc, NULL},
+	{"LEAST", -1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_INTEGER,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_NUMBER}, FIELD_TYPE_NUMBER,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_VARBINARY,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_UUID}, FIELD_TYPE_UUID,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING,
+	 func_greatest_least, NULL},
+	{"LEAST", -1, {FIELD_TYPE_SCALAR}, FIELD_TYPE_SCALAR,
+	 func_greatest_least, NULL},
 
 	{"LENGTH", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, func_char_length,
 	 NULL},
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 03/21] sql: refactor HEX() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 01/21] sql: rework CHAR() function Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 02/21] sql: refactor GREATEST() and LEAST() functions Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 04/21] sql: refactor LENGTH() function Mergen Imeev via Tarantool-patches
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 74 ++++++++++++++++++++++++----------------------
 1 file changed, 38 insertions(+), 36 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 40bdbf739..e4372de86 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -810,6 +810,43 @@ func_greatest_least(struct sql_context *ctx, int argc, struct Mem *argv)
 		ctx->is_aborted = true;
 }
 
+/**
+ * Implementation of the HEX() function.
+ *
+ * The HEX() function returns the hexadecimal representation of the argument.
+ */
+static const char hexdigits[] = {
+	'0', '1', '2', '3', '4', '5', '6', '7',
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static void
+func_hex(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	struct Mem *arg = &argv[0];
+	if (mem_is_null(arg))
+		return;
+
+	assert(mem_is_bin(arg) && arg->n >= 0);
+	if (arg->n == 0)
+		return mem_set_str0_static(ctx->pOut, "");
+
+	uint32_t size = 2 * arg->n;
+	char *str = sqlDbMallocRawNN(sql_get(), size);
+	if (str == NULL) {
+		ctx->is_aborted = true;
+		return;
+	}
+	for (int i = 0; i < arg->n; ++i) {
+		char c = arg->z[i];
+		str[2 * i] = hexdigits[(c >> 4) & 0xf];
+		str[2 * i + 1] = hexdigits[c & 0xf];
+	}
+	mem_set_str_allocated(ctx->pOut, str, size);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1395,14 +1432,6 @@ sql_func_version(struct sql_context *context, int argc, struct Mem *argv)
 	sql_result_text(context, tarantool_version(), -1, SQL_STATIC);
 }
 
-/* Array for converting from half-bytes (nybbles) into ASCII hex
- * digits.
- */
-static const char hexdigits[] = {
-	'0', '1', '2', '3', '4', '5', '6', '7',
-	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-};
-
 /*
  * Implementation of the QUOTE() function.  This function takes a single
  * argument.  If the argument is numeric, the return value is the same as
@@ -1512,33 +1541,6 @@ unicodeFunc(struct sql_context *context, int argc, struct Mem *argv)
 		sql_result_uint(context, sqlUtf8Read(&z));
 }
 
-/*
- * The hex() function.  Interpret the argument as a blob.  Return
- * a hexadecimal rendering as text.
- */
-static void
-hexFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	int i, n;
-	const unsigned char *pBlob;
-	char *zHex, *z;
-	assert(argc == 1);
-	UNUSED_PARAMETER(argc);
-	pBlob = mem_as_bin(&argv[0]);
-	n = mem_len_unsafe(&argv[0]);
-	assert(pBlob == mem_as_bin(&argv[0]));	/* No encoding change */
-	z = zHex = contextMalloc(context, ((i64) n) * 2 + 1);
-	if (zHex) {
-		for (i = 0; i < n; i++, pBlob++) {
-			unsigned char c = *pBlob;
-			*(z++) = hexdigits[(c >> 4) & 0xf];
-			*(z++) = hexdigits[c & 0xf];
-		}
-		*z = 0;
-		sql_result_text(context, zHex, n * 2, sql_free);
-	}
-}
-
 /*
  * The zeroblob(N) function returns a zero-filled blob of size N bytes.
  */
@@ -1895,7 +1897,7 @@ static struct sql_func_definition definitions[] = {
 	{"GROUP_CONCAT", 2, {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_VARBINARY, step_group_concat, NULL},
 
-	{"HEX", 1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_STRING, hexFunc, NULL},
+	{"HEX", 1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_STRING, func_hex, NULL},
 	{"IFNULL", 2, {FIELD_TYPE_ANY, FIELD_TYPE_ANY}, FIELD_TYPE_SCALAR,
 	 sql_builtin_stub, NULL},
 
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 04/21] sql: refactor LENGTH() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (2 preceding siblings ...)
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 03/21] sql: refactor HEX() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function Mergen Imeev via Tarantool-patches
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 55 +++++++++++++---------------------------------
 1 file changed, 15 insertions(+), 40 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index e4372de86..c0e8c4416 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -847,6 +847,19 @@ func_hex(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_str_allocated(ctx->pOut, str, size);
 }
 
+/** Implementation of the OCTET_LENGTH() function. */
+static void
+func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	struct Mem *arg = &argv[0];
+	if (mem_is_null(arg))
+		return;
+	assert(mem_is_bytes(arg) && arg->n >= 0);
+	mem_set_uint(ctx->pOut, arg->n);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -941,44 +954,6 @@ typeofFunc(struct sql_context *context, int argc, struct Mem *argv)
 	sql_result_text(context, z, -1, SQL_STATIC);
 }
 
-/*
- * Implementation of the length() function
- */
-static void
-lengthFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	int len;
-
-	assert(argc == 1);
-	UNUSED_PARAMETER(argc);
-	switch (sql_value_type(&argv[0])) {
-	case MP_BIN:
-	case MP_ARRAY:
-	case MP_MAP:
-	case MP_INT:
-	case MP_UINT:
-	case MP_BOOL:
-	case MP_DOUBLE:{
-			mem_as_bin(&argv[0]);
-			sql_result_uint(context, mem_len_unsafe(&argv[0]));
-			break;
-		}
-	case MP_EXT:
-	case MP_STR:{
-			const unsigned char *z = mem_as_ustr(&argv[0]);
-			if (z == 0)
-				return;
-			len = sql_utf8_char_count(z, mem_len_unsafe(&argv[0]));
-			sql_result_uint(context, len);
-			break;
-		}
-	default:{
-			sql_result_null(context);
-			break;
-		}
-	}
-}
-
 /*
  * Implementation of the printf() function.
  */
@@ -1918,8 +1893,8 @@ static struct sql_func_definition definitions[] = {
 
 	{"LENGTH", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, func_char_length,
 	 NULL},
-	{"LENGTH", 1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_INTEGER, lengthFunc,
-	 NULL},
+	{"LENGTH", 1, {FIELD_TYPE_VARBINARY}, FIELD_TYPE_INTEGER,
+	 func_octet_length, NULL},
 	{"LIKE", 2, {FIELD_TYPE_STRING, FIELD_TYPE_STRING},
 	 FIELD_TYPE_BOOLEAN, likeFunc, NULL},
 	{"LIKE", 3, {FIELD_TYPE_STRING, FIELD_TYPE_STRING, FIELD_TYPE_STRING},
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (3 preceding siblings ...)
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 04/21] sql: refactor LENGTH() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 06/21] sql: refactor RANDOM() function Mergen Imeev via Tarantool-patches
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c   | 62 +++++++++++++++++++-------------------------
 src/box/sql/printf.c |  6 ++---
 src/box/sql/sqlInt.h |  3 ++-
 3 files changed, 31 insertions(+), 40 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index c0e8c4416..603deb44e 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -860,6 +860,31 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uint(ctx->pOut, arg->n);
 }
 
+/** Implementation of the PRINTF() function. */
+static void
+func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	if (argc < 1 || mem_is_null(&argv[0]))
+		return;
+	if (argc == 1 || !mem_is_str(&argv[0])) {
+		struct Mem *mem = ctx->pOut;
+		if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0)
+			ctx->is_aborted = true;
+		return;
+	}
+	struct PrintfArguments pargs;
+	struct StrAccum acc;
+	char *format = argv[0].z;
+	pargs.nArg = argc - 1;
+	pargs.nUsed = 0;
+	pargs.apArg = argv + 1;
+	struct sql *db = sql_get();
+	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
+	acc.printfFlags = SQL_PRINTF_SQLFUNC;
+	sqlXPrintf(&acc, format, &pargs);
+	mem_set_str_allocated(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -954,40 +979,6 @@ typeofFunc(struct sql_context *context, int argc, struct Mem *argv)
 	sql_result_text(context, z, -1, SQL_STATIC);
 }
 
-/*
- * Implementation of the printf() function.
- */
-static void
-printfFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	PrintfArguments x;
-	StrAccum str;
-	const char *zFormat;
-	int n;
-	sql *db = sql_context_db_handle(context);
-
-	if (argc >= 1 && (zFormat = mem_as_str0(&argv[0])) != NULL) {
-		x.nArg = argc - 1;
-		x.nUsed = 0;
-		x.apArg = sqlDbMallocRawNN(sql_get(),
-					   (argc - 1) * sizeof(*x.apArg));
-		if (x.apArg == NULL) {
-			context->is_aborted = true;
-			return;
-		}
-		for (int i = 1; i < argc; ++i)
-			x.apArg[i - 1] = &argv[i];
-		sqlStrAccumInit(&str, db, 0, 0,
-				    db->aLimit[SQL_LIMIT_LENGTH]);
-		str.printfFlags = SQL_PRINTF_SQLFUNC;
-		sqlXPrintf(&str, zFormat, &x);
-		sqlDbFree(sql_get(), x.apArg);
-		n = str.nChar;
-		sql_result_text(context, sqlStrAccumFinish(&str), n,
-				    SQL_DYNAMIC);
-	}
-}
-
 /*
  * Implementation of the round() function
  */
@@ -1930,8 +1921,7 @@ static struct sql_func_definition definitions[] = {
 	 FIELD_TYPE_INTEGER, func_position_characters, NULL},
 	{"POSITION", 2, {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_INTEGER, func_position_octets, NULL},
-	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, printfFunc, 
-	 NULL},
+	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_printf, NULL},
 	{"QUOTE", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, quoteFunc, NULL},
 	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, randomFunc, NULL},
 	{"RANDOMBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
diff --git a/src/box/sql/printf.c b/src/box/sql/printf.c
index b4ab0d0f9..5b61646e3 100644
--- a/src/box/sql/printf.c
+++ b/src/box/sql/printf.c
@@ -144,7 +144,7 @@ getIntArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	return mem_get_int_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_int_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static double
@@ -152,7 +152,7 @@ getDoubleArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0.0;
-	return mem_get_double_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_double_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static char *
@@ -160,7 +160,7 @@ getTextArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	struct Mem *mem = p->apArg[p->nUsed++];
+	struct Mem *mem = &p->apArg[p->nUsed++];
 	return (char *)mem_as_str0(mem);
 }
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index cfdf71f1f..9361775b1 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2511,7 +2511,8 @@ int sqlIsNaN(double);
 struct PrintfArguments {
 	int nArg;		/* Total number of arguments */
 	int nUsed;		/* Number of arguments used so far */
-	sql_value **apArg;	/* The argument values */
+	/** The argument values. */
+	struct Mem *apArg;
 };
 
 void sqlVXPrintf(StrAccum *, const char *, va_list);
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 06/21] sql: refactor RANDOM() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (4 preceding siblings ...)
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:48 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 07/21] sql: rework RANDOMBLOB() function Mergen Imeev via Tarantool-patches
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:48 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 40 ++++++++++++++++------------------------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 603deb44e..2d83d52f8 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -885,6 +885,21 @@ func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_str_allocated(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar);
 }
 
+/**
+ * Implementation of the RANDOM() function.
+ *
+ * This function returns a random INT64 value.
+ */
+static void
+func_random(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	(void)argc;
+	(void)argv;
+	int64_t r;
+	sql_randomness(sizeof(r), &r);
+	mem_set_int(ctx->pOut, r, r < 0);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1050,29 +1065,6 @@ contextMalloc(struct sql_context *context, i64 nByte)
 	return z;
 }
 
-/*
- * Some functions like COALESCE() and IFNULL() and UNLIKELY() are implemented
- * as VDBE code so that unused argument values do not have to be computed.
- * However, we still need some kind of function implementation for this
- * routines in the function table.  The noopFunc macro provides this.
- * noopFunc will never be called so it doesn't matter what the implementation
- * is.  We might as well use the "version()" function as a substitute.
- */
-#define noopFunc sql_func_version /* Substitute function - never called */
-
-/*
- * Implementation of random().  Return a random integer.
- */
-static void
-randomFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	(void)argc;
-	(void)argv;
-	int64_t r;
-	sql_randomness(sizeof(r), &r);
-	sql_result_int(context, r);
-}
-
 /*
  * Implementation of randomblob(N).  Return a random blob
  * that is N bytes long.
@@ -1923,7 +1915,7 @@ static struct sql_func_definition definitions[] = {
 	 FIELD_TYPE_INTEGER, func_position_octets, NULL},
 	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_printf, NULL},
 	{"QUOTE", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, quoteFunc, NULL},
-	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, randomFunc, NULL},
+	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, func_random, NULL},
 	{"RANDOMBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
 	 randomBlob, NULL},
 	{"REPLACE", 3,
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 07/21] sql: rework RANDOMBLOB() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (5 preceding siblings ...)
  2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 06/21] sql: refactor RANDOM() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 08/21] sql: refactor ZEROBLOB() function Mergen Imeev via Tarantool-patches
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch refactors RANDOMBLOB() function. Also, RANDOMBLOB(0) now
returns empty string.

part of #4145
---
 src/box/sql/func.c         | 57 +++++++++++++++++++-------------------
 test/sql-tap/func.test.lua |  4 +--
 2 files changed, 30 insertions(+), 31 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 2d83d52f8..408c56e45 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -900,6 +900,33 @@ func_random(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_int(ctx->pOut, r, r < 0);
 }
 
+/**
+ * Implementation of the RANDOMBLOB() function.
+ *
+ * This function returns a random VARBINARY value. The size of this value is
+ * specified as an argument of the function.
+ */
+static void
+func_randomblob(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	struct Mem *arg = &argv[0];
+	assert(mem_is_null(arg) || mem_is_int(arg));
+	if (mem_is_null(arg) || !mem_is_uint(arg))
+		return;
+	if (arg->u.u == 0)
+		return mem_set_bin_static(ctx->pOut, "", 0);
+	uint64_t len = arg->u.u;
+	char *res = sqlDbMallocRawNN(sql_get(), len);
+	if (res == NULL) {
+		ctx->is_aborted = true;
+		return;
+	}
+	sql_randomness(len, res);
+	mem_set_bin_allocated(ctx->pOut, res, len);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1065,34 +1092,6 @@ contextMalloc(struct sql_context *context, i64 nByte)
 	return z;
 }
 
-/*
- * Implementation of randomblob(N).  Return a random blob
- * that is N bytes long.
- */
-static void
-randomBlob(struct sql_context *context, int argc, struct Mem *argv)
-{
-	int64_t n;
-	unsigned char *p;
-	assert(argc == 1);
-	UNUSED_PARAMETER(argc);
-	if (mem_is_bin(&argv[0]) || mem_is_map(&argv[0]) ||
-	    mem_is_array(&argv[0])) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 mem_str(&argv[0]), "number");
-		context->is_aborted = true;
-		return;
-	}
-	n = mem_get_int_unsafe(&argv[0]);
-	if (n < 1)
-		return;
-	p = contextMalloc(context, n);
-	if (p) {
-		sql_randomness(n, p);
-		sql_result_blob(context, (char *)p, n, sql_free);
-	}
-}
-
 #define Utf8Read(s, e) \
 	ucnv_getNextUChar(icu_utf8_conv, &(s), (e), &status)
 
@@ -1917,7 +1916,7 @@ static struct sql_func_definition definitions[] = {
 	{"QUOTE", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, quoteFunc, NULL},
 	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, func_random, NULL},
 	{"RANDOMBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
-	 randomBlob, NULL},
+	 func_randomblob, NULL},
 	{"REPLACE", 3,
 	 {FIELD_TYPE_STRING, FIELD_TYPE_STRING, FIELD_TYPE_STRING},
 	 FIELD_TYPE_STRING, replaceFunc, NULL},
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index b52d5bd4c..e2e905907 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -2545,8 +2545,8 @@ test:do_execsql_test(
 
 test:do_execsql_test(
     "func-36",
-    [[VALUES (LENGTH(RANDOMBLOB(0)))]],
-    {""})
+    [[VALUES (RANDOMBLOB(0))]],
+    {''})
 
 -- gh-3542
 -- In SQL '\0' is NOT a end-of-string signal. Tests below ensures
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 08/21] sql: refactor ZEROBLOB() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (6 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 07/21] sql: rework RANDOMBLOB() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 09/21] sql: refactor TYPEOF() function Mergen Imeev via Tarantool-patches
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 54 +++++++++++++++++++++++-----------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 408c56e45..842e4e766 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -927,6 +927,32 @@ func_randomblob(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_bin_allocated(ctx->pOut, res, len);
 }
 
+/**
+ * Implementation of the ZEROBLOB() function.
+ *
+ * This function returns a zero-filled VARBINARY value. The size of this value
+ * is specified as an argument of the function.
+ */
+static void
+func_zeroblob(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	struct Mem *arg = &argv[0];
+	assert(mem_is_null(arg) || mem_is_int(arg));
+	if (mem_is_null(arg) || !mem_is_uint(arg))
+		return;
+	if (arg->u.u == 0)
+		return mem_set_bin_static(ctx->pOut, "", 0);
+	uint64_t len = arg->u.u;
+	char *res = sqlDbMallocZero(sql_get(), len);
+	if (res == NULL) {
+		ctx->is_aborted = true;
+		return;
+	}
+	mem_set_bin_allocated(ctx->pOut, res, len);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1498,32 +1524,6 @@ unicodeFunc(struct sql_context *context, int argc, struct Mem *argv)
 		sql_result_uint(context, sqlUtf8Read(&z));
 }
 
-/*
- * The zeroblob(N) function returns a zero-filled blob of size N bytes.
- */
-static void
-zeroblobFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	int64_t n;
-	assert(argc == 1);
-	UNUSED_PARAMETER(argc);
-	n = mem_get_int_unsafe(&argv[0]);
-	if (n < 0)
-		n = 0;
-	if (n > sql_get()->aLimit[SQL_LIMIT_LENGTH]) {
-		diag_set(ClientError, ER_SQL_EXECUTE, "string or binary string"\
-			 "is too big");
-		context->is_aborted = true;
-		return;
-	}
-	char *str = sqlDbMallocZero(sql_get(), n);
-	if (str == NULL) {
-		context->is_aborted = true;
-		return;
-	}
-	mem_set_bin_allocated(context->pOut, str, n);
-}
-
 /*
  * The replace() function.  Three arguments are all strings: call
  * them A, B, and C. The result is also a string which is derived
@@ -1967,7 +1967,7 @@ static struct sql_func_definition definitions[] = {
 	{"UUID", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_UUID, sql_func_uuid, NULL},
 	{"VERSION", 0, {}, FIELD_TYPE_STRING, sql_func_version, NULL},
 	{"ZEROBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
-	 zeroblobFunc, NULL},
+	 func_zeroblob, NULL},
 };
 
 static struct sql_func_dictionary *
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 09/21] sql: refactor TYPEOF() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (7 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 08/21] sql: refactor ZEROBLOB() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 10/21] sql: refactor ROUND() function Mergen Imeev via Tarantool-patches
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 58 ++++++++--------------------------------------
 1 file changed, 10 insertions(+), 48 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 842e4e766..3a788b450 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -953,6 +953,15 @@ func_zeroblob(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_bin_allocated(ctx->pOut, res, len);
 }
 
+/** Implementation of the TYPEOF() function. */
+static void
+func_typeof(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	return mem_set_str0_static(ctx->pOut, mem_type_to_str(&argv[0]));
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1000,53 +1009,6 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uuid(ctx->pOut, &uuid);
 }
 
-/*
- * Return the type of the argument.
- */
-static void
-typeofFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	(void)argc;
-	const char *z = 0;
-	if ((argv[0].flags & MEM_Number) != 0)
-		return mem_set_str0_static(context->pOut, "number");
-	if ((argv[0].flags & MEM_Scalar) != 0)
-		return mem_set_str0_static(context->pOut, "scalar");
-	switch (argv[0].type) {
-	case MEM_TYPE_INT:
-	case MEM_TYPE_UINT:
-		z = "integer";
-		break;
-	case MEM_TYPE_DEC:
-		z = "decimal";
-		break;
-	case MEM_TYPE_STR:
-		z = "string";
-		break;
-	case MEM_TYPE_DOUBLE:
-		z = "double";
-		break;
-	case MEM_TYPE_BIN:
-	case MEM_TYPE_ARRAY:
-	case MEM_TYPE_MAP:
-		z = "varbinary";
-		break;
-	case MEM_TYPE_BOOL:
-		z = "boolean";
-		break;
-	case MEM_TYPE_NULL:
-		z = "NULL";
-		break;
-	case MEM_TYPE_UUID:
-		z = "uuid";
-		break;
-	default:
-		unreachable();
-		break;
-	}
-	sql_result_text(context, z, -1, SQL_STATIC);
-}
-
 /*
  * Implementation of the round() function
  */
@@ -1956,7 +1918,7 @@ static struct sql_func_definition definitions[] = {
 	 {FIELD_TYPE_VARBINARY, FIELD_TYPE_INTEGER, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_VARBINARY, func_trim_bin, NULL},
 
-	{"TYPEOF", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, typeofFunc, NULL},
+	{"TYPEOF", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_typeof, NULL},
 	{"UNICODE", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, unicodeFunc,
 	 NULL},
 	{"UNLIKELY", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_BOOLEAN, sql_builtin_stub,
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 10/21] sql: refactor ROUND() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (8 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 09/21] sql: refactor TYPEOF() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 11/21] sql: refactor ROW_COUNT() function Mergen Imeev via Tarantool-patches
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 75 +++++++++++++++++-----------------------------
 1 file changed, 28 insertions(+), 47 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 3a788b450..c5428d87b 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -962,6 +962,32 @@ func_typeof(struct sql_context *ctx, int argc, struct Mem *argv)
 	return mem_set_str0_static(ctx->pOut, mem_type_to_str(&argv[0]));
 }
 
+/** Implementation of the ROUND() function. */
+static void
+func_round(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1 || argc == 2);
+	if (mem_is_null(&argv[0]) || (argc == 2 && mem_is_null(&argv[1])))
+		return;
+	assert(mem_is_double(&argv[0]));
+	assert(argc == 1 || mem_is_int(&argv[1]));
+	uint64_t n = (argc == 2 && mem_is_uint(&argv[1])) ? argv[1].u.u : 0;
+
+	double d = argv[0].u.r;
+	struct Mem *res = ctx->pOut;
+	if (n != 0)
+		return mem_set_double(res, atof(tt_sprintf("%.*f", n, d)));
+	/*
+	 * DOUBLE values greater than 2^53 or less than -2^53 have no digits
+	 * after the decimal point.
+	 */
+	assert(9007199254740992 == (int64_t)1 << 53);
+	if (d <= -9007199254740992.0 || d >= 9007199254740992.0)
+		return mem_set_double(res, d);
+	double delta = d < 0 ? -0.5 : 0.5;
+	return mem_set_double(res, (double)(int64_t)(d + delta));
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1009,51 +1035,6 @@ sql_func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uuid(ctx->pOut, &uuid);
 }
 
-/*
- * Implementation of the round() function
- */
-static void
-roundFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	int64_t n = 0;
-	double r;
-	if (argc != 1 && argc != 2) {
-		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "ROUND",
-			 "1 or 2", argc);
-		context->is_aborted = true;
-		return;
-	}
-	if (argc == 2) {
-		if (mem_is_null(&argv[1]))
-			return;
-		n = mem_get_int_unsafe(&argv[1]);
-		if (n < 0)
-			n = 0;
-	}
-	if (mem_is_null(&argv[0]))
-		return;
-	if (!mem_is_num(&argv[0]) && !mem_is_str(&argv[0])) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 mem_str(&argv[0]), "number");
-		context->is_aborted = true;
-		return;
-	}
-	r = mem_get_double_unsafe(&argv[0]);
-	/* If Y==0 and X will fit in a 64-bit int,
-	 * handle the rounding directly,
-	 * otherwise use printf.
-	 */
-	if (n == 0 && r >= 0 && r < (double)(LARGEST_INT64 - 1)) {
-		r = (double)((sql_int64) (r + 0.5));
-	} else if (n == 0 && r < 0 && (-r) < (double)(LARGEST_INT64 - 1)) {
-		r = -(double)((sql_int64) ((-r) + 0.5));
-	} else {
-		const char *rounded_value = tt_sprintf("%.*f", n, r);
-		sqlAtoF(rounded_value, &r, sqlStrlen30(rounded_value));
-	}
-	sql_result_double(context, r);
-}
-
 /*
  * Allocate nByte bytes of space using sqlMalloc(). If the
  * allocation fails, return NULL. If nByte is larger than the
@@ -1885,9 +1866,9 @@ static struct sql_func_definition definitions[] = {
 	{"REPLACE", 3,
 	 {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_VARBINARY, replaceFunc, NULL},
-	{"ROUND", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, roundFunc, NULL},
+	{"ROUND", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, func_round, NULL},
 	{"ROUND", 2, {FIELD_TYPE_DOUBLE, FIELD_TYPE_INTEGER}, FIELD_TYPE_DOUBLE,
-	 roundFunc, NULL},
+	 func_round, NULL},
 	{"ROW_COUNT", 0, {}, FIELD_TYPE_INTEGER, sql_row_count, NULL},
 	{"SOUNDEX", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, soundexFunc,
 	 NULL},
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 11/21] sql: refactor ROW_COUNT() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (9 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 10/21] sql: refactor ROUND() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 12/21] sql: rework UUID() function Mergen Imeev via Tarantool-patches
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c   | 12 +++++++++++-
 src/box/sql/main.c   | 10 ----------
 src/box/sql/sqlInt.h |  8 +-------
 3 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index c5428d87b..014fd9af2 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -988,6 +988,16 @@ func_round(struct sql_context *ctx, int argc, struct Mem *argv)
 	return mem_set_double(res, (double)(int64_t)(d + delta));
 }
 
+/** Implementation of the ROW_COUNT() function. */
+static void
+func_row_count(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	(void)argc;
+	(void)argv;
+	assert(sql_get()->nChange >= 0);
+	return mem_set_uint(ctx->pOut, sql_get()->nChange);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1869,7 +1879,7 @@ static struct sql_func_definition definitions[] = {
 	{"ROUND", 1, {FIELD_TYPE_DOUBLE}, FIELD_TYPE_DOUBLE, func_round, NULL},
 	{"ROUND", 2, {FIELD_TYPE_DOUBLE, FIELD_TYPE_INTEGER}, FIELD_TYPE_DOUBLE,
 	 func_round, NULL},
-	{"ROW_COUNT", 0, {}, FIELD_TYPE_INTEGER, sql_row_count, NULL},
+	{"ROW_COUNT", 0, {}, FIELD_TYPE_INTEGER, func_row_count, NULL},
 	{"SOUNDEX", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, soundexFunc,
 	 NULL},
 	{"SUBSTR", 2, {FIELD_TYPE_STRING, FIELD_TYPE_INTEGER},
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index a4247c760..ae872aaa1 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -220,16 +220,6 @@ setupLookaside(sql * db, void *pBuf, int sz, int cnt)
 	return 0;
 }
 
-void
-sql_row_count(struct sql_context *context, int argc, struct Mem *argv)
-{
-	(void)argc;
-	(void)argv;
-	sql *db = sql_context_db_handle(context);
-	assert(db->nChange >= 0);
-	sql_result_uint(context, db->nChange);
-}
-
 /*
  * Close all open savepoints.
  * This procedure is trivial as savepoints are allocated on the "region" and
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 9361775b1..c8f711ed2 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -470,12 +470,6 @@ enum sql_subtype {
 void
 sql_randomness(int N, void *P);
 
-/**
- * Return the number of affected rows in the last SQL statement.
- */
-void
-sql_row_count(struct sql_context *context, int argc, struct Mem *argv);
-
 int
 sql_column_count(sql_stmt * pStmt);
 
@@ -1065,7 +1059,7 @@ struct sql {
 	u8 dfltLockMode;	/* Default locking-mode for attached dbs */
 	u8 mTrace;		/* zero or more sql_TRACE flags */
 	u32 magic;		/* Magic number for detect library misuse */
-	/** Value returned by sql_row_count(). */
+	/** Value returned by ROW_COUNT(). */
 	int nChange;
 	int aLimit[SQL_N_LIMIT];	/* Limits */
 	int nMaxSorterMmap;	/* Maximum size of regions mapped by sorter */
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 12/21] sql: rework UUID() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (10 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 11/21] sql: refactor ROW_COUNT() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 13/21] sql: refactor VERSION() function Mergen Imeev via Tarantool-patches
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch refactors UUID() function. Also, UUID(NULL) now returns NULL.

Part of #4145
---
 src/box/sql/func.c         | 56 +++++++++++++++++---------------------
 test/sql-tap/uuid.test.lua | 11 +++++++-
 2 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 014fd9af2..dcd0157d0 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -998,6 +998,29 @@ func_row_count(struct sql_context *ctx, int argc, struct Mem *argv)
 	return mem_set_uint(ctx->pOut, sql_get()->nChange);
 }
 
+/**
+ * Implementation of the UUID() function.
+ *
+ * Returns a randomly generated UUID value.
+ */
+static void
+func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	if (argc == 1) {
+		if (mem_is_null(&argv[0]))
+			return;
+		if (!mem_is_uint(&argv[0]) || argv[0].u.u != 4) {
+			diag_set(ClientError, ER_UNSUPPORTED, "Function UUID",
+				 "versions other than 4");
+			ctx->is_aborted = true;
+			return;
+		}
+	}
+	struct tt_uuid uuid;
+	tt_uuid_create(&uuid);
+	mem_set_uuid(ctx->pOut, &uuid);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1016,35 +1039,6 @@ mem_as_bin(struct Mem *mem)
 	return s;
 }
 
-static void
-sql_func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
-{
-	if (argc > 1) {
-		diag_set(ClientError, ER_FUNC_WRONG_ARG_COUNT, "UUID",
-			 "one or zero", argc);
-		ctx->is_aborted = true;
-		return;
-	}
-	if (argc == 1) {
-		uint64_t version;
-		if (mem_get_uint(&argv[0], &version) != 0) {
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 mem_str(&argv[0]), "integer");
-			ctx->is_aborted = true;
-			return;
-		}
-		if (version != 4) {
-			diag_set(ClientError, ER_UNSUPPORTED, "Function UUID",
-				 "versions other than 4");
-			ctx->is_aborted = true;
-			return;
-		}
-	}
-	struct tt_uuid uuid;
-	tt_uuid_create(&uuid);
-	mem_set_uuid(ctx->pOut, &uuid);
-}
-
 /*
  * Allocate nByte bytes of space using sqlMalloc(). If the
  * allocation fails, return NULL. If nByte is larger than the
@@ -1916,8 +1910,8 @@ static struct sql_func_definition definitions[] = {
 	 NULL},
 	{"UPPER", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_STRING, func_lower_upper,
 	 NULL},
-	{"UUID", 0, {}, FIELD_TYPE_UUID, sql_func_uuid, NULL},
-	{"UUID", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_UUID, sql_func_uuid, NULL},
+	{"UUID", 0, {}, FIELD_TYPE_UUID, func_uuid, NULL},
+	{"UUID", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_UUID, func_uuid, NULL},
 	{"VERSION", 0, {}, FIELD_TYPE_STRING, sql_func_version, NULL},
 	{"ZEROBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
 	 func_zeroblob, NULL},
diff --git a/test/sql-tap/uuid.test.lua b/test/sql-tap/uuid.test.lua
index d6c53d123..884b1daf9 100755
--- a/test/sql-tap/uuid.test.lua
+++ b/test/sql-tap/uuid.test.lua
@@ -3,7 +3,7 @@ local build_path = os.getenv("BUILDDIR")
 package.cpath = build_path..'/test/sql-tap/?.so;'..build_path..'/test/sql-tap/?.dylib;'..package.cpath
 
 local test = require("sqltester")
-test:plan(146)
+test:plan(147)
 
 local uuid = require("uuid")
 local uuid1 = uuid.fromstr("11111111-1111-1111-1111-111111111111")
@@ -1290,6 +1290,15 @@ test:do_execsql_test(
         true
     })
 
+-- Make sure the uuid(NULL) returns NULL.
+test:do_execsql_test(
+    "uuid-16.7",
+    [[
+        SELECT uuid(NULL) IS NULL;
+    ]], {
+        true
+    })
+
 -- Make sure STRING of wrong length cannot be cast to UUID.
 test:do_catchsql_test(
     "uuid-17.1",
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 13/21] sql: refactor VERSION() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (11 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 12/21] sql: rework UUID() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 14/21] sql: refactor UNICODE() function Mergen Imeev via Tarantool-patches
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index dcd0157d0..59447df56 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1021,6 +1021,15 @@ func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uuid(ctx->pOut, &uuid);
 }
 
+/** Implementation of the VERSION() function. */
+static void
+func_version(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	(void)argc;
+	(void)argv;
+	return mem_set_str0_static(ctx->pOut, (char *)tarantool_version());
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1346,22 +1355,6 @@ likeFunc(sql_context *context, int argc, struct Mem *argv)
 	mem_set_bool(context->pOut, res == MATCH);
 }
 
-/**
- * Implementation of the version() function.  The result is the
- * version of the Tarantool that is running.
- *
- * @param context Context being used.
- * @param unused1 Unused.
- * @param unused2 Unused.
- */
-static void
-sql_func_version(struct sql_context *context, int argc, struct Mem *argv)
-{
-	(void)argc;
-	(void)argv;
-	sql_result_text(context, tarantool_version(), -1, SQL_STATIC);
-}
-
 /*
  * Implementation of the QUOTE() function.  This function takes a single
  * argument.  If the argument is numeric, the return value is the same as
@@ -1912,7 +1905,7 @@ static struct sql_func_definition definitions[] = {
 	 NULL},
 	{"UUID", 0, {}, FIELD_TYPE_UUID, func_uuid, NULL},
 	{"UUID", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_UUID, func_uuid, NULL},
-	{"VERSION", 0, {}, FIELD_TYPE_STRING, sql_func_version, NULL},
+	{"VERSION", 0, {}, FIELD_TYPE_STRING, func_version, NULL},
 	{"ZEROBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
 	 func_zeroblob, NULL},
 };
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 14/21] sql: refactor UNICODE() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (12 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 13/21] sql: refactor VERSION() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 15/21] sql: refactor SOUNDEX() function Mergen Imeev via Tarantool-patches
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 39 +++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 59447df56..69d4e7347 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1030,6 +1030,30 @@ func_version(struct sql_context *ctx, int argc, struct Mem *argv)
 	return mem_set_str0_static(ctx->pOut, (char *)tarantool_version());
 }
 
+/**
+ * Implementation of the UNICODE() function.
+ *
+ * Return the Unicode code point value for the first character of the input
+ * string.
+ */
+static void
+func_unicode(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	assert(argc == 1);
+	(void)argc;
+	struct Mem *arg = &argv[0];
+	if (mem_is_null(arg))
+		return;
+	assert(mem_is_str(arg));
+	if (arg->n == 0)
+		return mem_set_uint(ctx->pOut, 0);
+	int pos = 0;
+	UChar32 c;
+	U8_NEXT((uint8_t *)arg->z, pos, arg->n, c);
+	(void)pos;
+	mem_set_uint(ctx->pOut, (uint64_t)c);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -1451,19 +1475,6 @@ quoteFunc(struct sql_context *context, int argc, struct Mem *argv)
 	}
 }
 
-/*
- * The unicode() function.  Return the integer unicode code-point value
- * for the first character of the input string.
- */
-static void
-unicodeFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	const unsigned char *z = mem_as_ustr(&argv[0]);
-	(void)argc;
-	if (z && z[0])
-		sql_result_uint(context, sqlUtf8Read(&z));
-}
-
 /*
  * The replace() function.  Three arguments are all strings: call
  * them A, B, and C. The result is also a string which is derived
@@ -1897,7 +1908,7 @@ static struct sql_func_definition definitions[] = {
 	 FIELD_TYPE_VARBINARY, func_trim_bin, NULL},
 
 	{"TYPEOF", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_typeof, NULL},
-	{"UNICODE", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, unicodeFunc,
+	{"UNICODE", 1, {FIELD_TYPE_STRING}, FIELD_TYPE_INTEGER, func_unicode,
 	 NULL},
 	{"UNLIKELY", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_BOOLEAN, sql_builtin_stub,
 	 NULL},
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 15/21] sql: refactor SOUNDEX() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (13 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 14/21] sql: refactor UNICODE() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 16/21] sql: refactor REPLACE() function Mergen Imeev via Tarantool-patches
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 69d4e7347..ed4d681fc 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1591,16 +1591,11 @@ soundexFunc(struct sql_context *context, int argc, struct Mem *argv)
 		1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
 	};
 	assert(argc == 1);
-	if (mem_is_bin(&argv[0]) || mem_is_map(&argv[0]) ||
-	    mem_is_array(&argv[0])) {
-		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-			 mem_str(&argv[0]), "string");
-		context->is_aborted = true;
-		return;
-	}
-	zIn = (u8 *) mem_as_ustr(&argv[0]);
-	if (zIn == 0)
+	assert(mem_is_null(&argv[0]) || mem_is_str(&argv[0]));
+	if (mem_is_null(&argv[0]) || argv[0].n == 0)
 		zIn = (u8 *) "";
+	else
+		zIn = (unsigned char *)argv[0].z;
 	for (i = 0; zIn[i] && !sqlIsalpha(zIn[i]); i++) {
 	}
 	if (zIn[i]) {
@@ -1621,12 +1616,10 @@ soundexFunc(struct sql_context *context, int argc, struct Mem *argv)
 			zResult[j++] = '0';
 		}
 		zResult[j] = 0;
-		sql_result_text(context, zResult, 4, SQL_TRANSIENT);
+		if (mem_copy_str(context->pOut, zResult, 4) != 0)
+			context->is_aborted = true;
 	} else {
-		/* IMP: R-64894-50321 The string "?000" is returned if the argument
-		 * is NULL or contains no ASCII alphabetic characters.
-		 */
-		sql_result_text(context, "?000", 4, SQL_STATIC);
+		mem_set_str_static(context->pOut, "?000", 4);
 	}
 }
 
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 16/21] sql: refactor REPLACE() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (14 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 15/21] sql: refactor SOUNDEX() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 17/21] sql: refactor QUOTE() function Mergen Imeev via Tarantool-patches
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 59 +++++++++++++++++-----------------------------
 1 file changed, 21 insertions(+), 38 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index ed4d681fc..3b1e62ebf 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1496,34 +1496,27 @@ replaceFunc(struct sql_context *context, int argc, struct Mem *argv)
 	int i, j;		/* Loop counters */
 
 	assert(argc == 3);
-	UNUSED_PARAMETER(argc);
-	zStr = mem_as_ustr(&argv[0]);
-	if (zStr == 0)
-		return;
-	nStr = mem_len_unsafe(&argv[0]);
-	assert(zStr == mem_as_ustr(&argv[0]));	/* No encoding change */
-	zPattern = mem_as_ustr(&argv[1]);
-	if (zPattern == 0) {
-		assert(mem_is_null(&argv[1])
-		       || sql_context_db_handle(context)->mallocFailed);
+	(void)argc;
+	if (mem_is_any_null(&argv[0], &argv[1]) || mem_is_null(&argv[2]))
 		return;
-	}
-	nPattern = mem_len_unsafe(&argv[1]);
+	assert(mem_is_bytes(&argv[0]) && mem_is_bytes(&argv[1]) &&
+	       mem_is_bytes(&argv[2]));
+	zStr = (const unsigned char *)argv[0].z;
+	nStr = argv[0].n;
+	zPattern = (const unsigned char *)argv[1].z;
+	nPattern = argv[1].n;
 	if (nPattern == 0) {
-		assert(!mem_is_null(&argv[1]));
-		sql_result_value(context, &argv[0]);
+		if (mem_copy(context->pOut, &argv[0]) != 0)
+			context->is_aborted = true;
 		return;
 	}
-	assert(zPattern == mem_as_ustr(&argv[1]));	/* No encoding change */
-	zRep = mem_as_ustr(&argv[2]);
-	if (zRep == 0)
-		return;
-	nRep = mem_len_unsafe(&argv[2]);
-	assert(zRep == mem_as_ustr(&argv[2]));
+	zRep = (const unsigned char *)argv[2].z;
+	nRep = argv[2].n;
 	nOut = nStr + 1;
-	assert(nOut < SQL_MAX_LENGTH);
-	zOut = contextMalloc(context, (i64) nOut);
-	if (zOut == 0) {
+	struct sql *db = sql_get();
+	zOut = sqlDbMallocRawNN(db, nOut);
+	if (zOut == NULL) {
+		context->is_aborted = true;
 		return;
 	}
 	loopLimit = nStr - nPattern;
@@ -1533,22 +1526,12 @@ replaceFunc(struct sql_context *context, int argc, struct Mem *argv)
 			zOut[j++] = zStr[i];
 		} else {
 			u8 *zOld;
-			sql *db = sql_context_db_handle(context);
 			nOut += nRep - nPattern;
-			testcase(nOut - 1 == db->aLimit[SQL_LIMIT_LENGTH]);
-			testcase(nOut - 2 == db->aLimit[SQL_LIMIT_LENGTH]);
-			if (nOut - 1 > db->aLimit[SQL_LIMIT_LENGTH]) {
-				diag_set(ClientError, ER_SQL_EXECUTE, "string "\
-					 "or binary string is too big");
-				context->is_aborted = true;
-				sql_free(zOut);
-				return;
-			}
 			zOld = zOut;
-			zOut = sql_realloc64(zOut, (int)nOut);
-			if (zOut == 0) {
+			zOut = sqlDbRealloc(db, zOut, nOut);
+			if (zOut == NULL) {
 				context->is_aborted = true;
-				sql_free(zOld);
+				sqlDbFree(db, zOld);
 				return;
 			}
 			memcpy(&zOut[j], zRep, nRep);
@@ -1562,9 +1545,9 @@ replaceFunc(struct sql_context *context, int argc, struct Mem *argv)
 	assert(j <= nOut);
 	zOut[j] = 0;
 	if (context->func->def->returns == FIELD_TYPE_STRING)
-		mem_set_str_dynamic(context->pOut, (char *)zOut, j);
+		mem_set_str_allocated(context->pOut, (char *)zOut, j);
 	else
-		mem_set_bin_dynamic(context->pOut, (char *)zOut, j);
+		mem_set_bin_allocated(context->pOut, (char *)zOut, j);
 }
 
 /*
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 17/21] sql: refactor QUOTE() function
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (15 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 16/21] sql: refactor REPLACE() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 18/21] sql: remove unused code Mergen Imeev via Tarantool-patches
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

---
 src/box/sql/func.c | 154 +++++++++++++++------------------------------
 1 file changed, 50 insertions(+), 104 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 3b1e62ebf..a0e599b5e 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -1054,50 +1054,6 @@ func_unicode(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uint(ctx->pOut, (uint64_t)c);
 }
 
-static const unsigned char *
-mem_as_ustr(struct Mem *mem)
-{
-	return (const unsigned char *)mem_as_str0(mem);
-}
-
-static const void *
-mem_as_bin(struct Mem *mem)
-{
-	const char *s;
-	if (mem_cast_explicit(mem, FIELD_TYPE_VARBINARY) != 0 &&
-	    mem_to_str(mem) != 0)
-		return NULL;
-	if (mem_get_bin(mem, &s) != 0)
-		return NULL;
-	return s;
-}
-
-/*
- * Allocate nByte bytes of space using sqlMalloc(). If the
- * allocation fails, return NULL. If nByte is larger than the
- * maximum string or blob length, then raise an error and return
- * NULL.
- */
-static void *
-contextMalloc(struct sql_context *context, i64 nByte)
-{
-	char *z;
-	sql *db = sql_context_db_handle(context);
-	assert(nByte > 0);
-	testcase(nByte == db->aLimit[SQL_LIMIT_LENGTH]);
-	testcase(nByte == db->aLimit[SQL_LIMIT_LENGTH] + 1);
-	if (nByte > db->aLimit[SQL_LIMIT_LENGTH]) {
-		diag_set(ClientError, ER_SQL_EXECUTE, "string or blob too big");
-		context->is_aborted = true;
-		z = 0;
-	} else {
-		z = sqlMalloc(nByte);
-		if (z == NULL)
-			context->is_aborted = true;
-	}
-	return z;
-}
-
 #define Utf8Read(s, e) \
 	ucnv_getNextUChar(icu_utf8_conv, &(s), (e), &status)
 
@@ -1395,83 +1351,73 @@ quoteFunc(struct sql_context *context, int argc, struct Mem *argv)
 	case MEM_TYPE_UUID: {
 		char buf[UUID_STR_LEN + 1];
 		tt_uuid_to_string(&argv[0].u.uuid, &buf[0]);
-		sql_result_text(context, buf, UUID_STR_LEN, SQL_TRANSIENT);
+		if (mem_copy_str(context->pOut, buf, UUID_STR_LEN) != 0)
+			context->is_aborted = true;
 		break;
 	}
 	case MEM_TYPE_DOUBLE:
 	case MEM_TYPE_DEC:
 	case MEM_TYPE_UINT:
 	case MEM_TYPE_INT: {
-			sql_result_value(context, &argv[0]);
-			break;
-		}
+		if (mem_copy(context->pOut, &argv[0]) != 0)
+			context->is_aborted = true;
+		break;
+	}
 	case MEM_TYPE_BIN:
 	case MEM_TYPE_ARRAY:
 	case MEM_TYPE_MAP: {
-			char *zText = 0;
-			char const *zBlob = mem_as_bin(&argv[0]);
-			int nBlob = mem_len_unsafe(&argv[0]);
-			assert(zBlob == mem_as_bin(&argv[0]));	/* No encoding change */
-			zText =
-			    (char *)contextMalloc(context,
-						  (2 * (i64) nBlob) + 4);
-			if (zText) {
-				int i;
-				for (i = 0; i < nBlob; i++) {
-					zText[(i * 2) + 2] =
-					    hexdigits[(zBlob[i] >> 4) & 0x0F];
-					zText[(i * 2) + 3] =
-					    hexdigits[(zBlob[i]) & 0x0F];
-				}
-				zText[(nBlob * 2) + 2] = '\'';
-				zText[(nBlob * 2) + 3] = '\0';
-				zText[0] = 'X';
-				zText[1] = '\'';
-				sql_result_text(context, zText, -1,
-						    SQL_TRANSIENT);
-				sql_free(zText);
-			}
-			break;
+		const char *zBlob = argv[0].z;
+		int nBlob = argv[0].n;
+		uint32_t size = 2 * nBlob + 3;
+		char *zText = zText = sqlDbMallocRawNN(sql_get(), size);
+		if (zText == NULL) {
+			context->is_aborted = true;
+			return;
 		}
+		for (int i = 0; i < nBlob; i++) {
+			zText[(i * 2) + 2] = hexdigits[(zBlob[i] >> 4) & 0x0F];
+			zText[(i * 2) + 3] = hexdigits[(zBlob[i]) & 0x0F];
+		}
+		zText[(nBlob * 2) + 2] = '\'';
+		zText[0] = 'X';
+		zText[1] = '\'';
+		mem_set_str_allocated(context->pOut, zText, size);
+		break;
+	}
 	case MEM_TYPE_STR: {
-			int i, j;
-			u64 n;
-			const unsigned char *zArg = mem_as_ustr(&argv[0]);
-			char *z;
+		const char *str = argv[0].z;
+		uint32_t len = argv[0].n;
+		uint32_t count = 0;
+		for (uint32_t i = 0; i < len; ++i) {
+			if (str[i] == '\'')
+				++count;
+		}
+		uint32_t size = len + count + 2;
 
-			if (zArg == 0)
-				return;
-			for (i = 0, n = 0; zArg[i]; i++) {
-				if (zArg[i] == '\'')
-					n++;
-			}
-			z = contextMalloc(context, ((i64) i) + ((i64) n) + 3);
-			if (z) {
-				z[0] = '\'';
-				for (i = 0, j = 1; zArg[i]; i++) {
-					z[j++] = zArg[i];
-					if (zArg[i] == '\'') {
-						z[j++] = '\'';
-					}
-				}
-				z[j++] = '\'';
-				z[j] = 0;
-				sql_result_text(context, z, j,
-						    sql_free);
-			}
-			break;
+		char *res = sqlDbMallocRawNN(sql_get(), size);
+		if (res == NULL) {
+			context->is_aborted = true;
+			return;
+		}
+		res[0] = '\'';
+		for (uint32_t i = 0, j = 1; i < len; ++i) {
+			res[j++] = str[i];
+			if (str[i] == '\'')
+				res[j++] = '\'';
 		}
+		res[size - 1] = '\'';
+		mem_set_str_allocated(context->pOut, res, size);
+		break;
+	}
 	case MEM_TYPE_BOOL: {
-		sql_result_text(context,
-				SQL_TOKEN_BOOLEAN(argv[0].u.b),
-				-1, SQL_TRANSIENT);
+		mem_set_str0_static(context->pOut,
+				    SQL_TOKEN_BOOLEAN(argv[0].u.b));
 		break;
 	}
 	default:{
-			assert(mem_is_null(&argv[0]));
-			sql_result_text(context, "NULL", 4, SQL_STATIC);
-			break;
-		}
+		assert(mem_is_null(&argv[0]));
+		mem_set_str0_static(context->pOut, "NULL");
+	}
 	}
 }
 
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 18/21] sql: remove unused code
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (16 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 17/21] sql: refactor QUOTE() function Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 19/21] sql: remove MEM_Dyn flag Mergen Imeev via Tarantool-patches
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

Some of the code is no longer used after changes in the SQL built-in
functions. This patch removes part of the unused code.

Needed for #4145
---
 src/box/CMakeLists.txt |   1 -
 src/box/bind.c         |   5 +-
 src/box/sql/mem.c      |  11 --
 src/box/sql/mem.h      |  78 --------------
 src/box/sql/sqlInt.h   |  73 +------------
 src/box/sql/trigger.c  |   7 +-
 src/box/sql/utf.c      |  95 ----------------
 src/box/sql/vdbe.h     |   5 +-
 src/box/sql/vdbeInt.h  |   1 -
 src/box/sql/vdbeapi.c  | 238 +++--------------------------------------
 src/box/sql/vdbeaux.c  |  26 ++---
 11 files changed, 33 insertions(+), 507 deletions(-)
 delete mode 100644 src/box/sql/utf.c

diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 957290bdd..17f1e60ba 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -55,7 +55,6 @@ set(sql_sources
     sql/tokenize.c
     sql/treeview.c
     sql/trigger.c
-    sql/utf.c
     sql/update.c
     sql/util.c
     sql/vdbe.c
diff --git a/src/box/bind.c b/src/box/bind.c
index 58fff0b98..e75e36283 100644
--- a/src/box/bind.c
+++ b/src/box/bind.c
@@ -185,12 +185,11 @@ sql_bind_column(struct sql_stmt *stmt, const struct sql_bind *p,
 		 * there is no need to copy the packet and we can
 		 * use SQL_STATIC.
 		 */
-		return sql_bind_text64(stmt, pos, p->s, p->bytes, SQL_STATIC);
+		return sql_bind_str_static(stmt, pos, p->s, p->bytes);
 	case MP_NIL:
 		return sql_bind_null(stmt, pos);
 	case MP_BIN:
-		return sql_bind_blob64(stmt, pos, (const void *) p->s, p->bytes,
-				       SQL_STATIC);
+		return sql_bind_bin_static(stmt, pos, p->s, p->bytes);
 	case MP_EXT:
 		assert(p->ext_type == MP_UUID || p->ext_type == MP_DECIMAL);
 		if (p->ext_type == MP_UUID)
diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index dc629aee3..70ca9e1b2 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -2638,17 +2638,6 @@ mem_mp_type(const struct Mem *mem)
 	return MP_NIL;
 }
 
-/* EVIDENCE-OF: R-12793-43283 Every value in sql has one of five
- * fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
- * point number string BLOB NULL
- */
-enum mp_type
-sql_value_type(sql_value *pVal)
-{
-	struct Mem *mem = (struct Mem *) pVal;
-	return mem_mp_type(mem);
-}
-
 #ifdef SQL_DEBUG
 /*
  * Check invariants on a Mem object.
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 242f910db..9533833f2 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -359,54 +359,6 @@ mem_set_str0_dynamic(struct Mem *mem, char *value);
 void
 mem_set_str0_allocated(struct Mem *mem, char *value);
 
-static inline void
-mem_set_strl_ephemeral(struct Mem *mem, char *value, int len_hint)
-{
-	if (len_hint < 0)
-		mem_set_str0_ephemeral(mem, value);
-	else
-		mem_set_str_ephemeral(mem, value, len_hint);
-}
-
-static inline void
-mem_set_strl_static(struct Mem *mem, char *value, int len_hint)
-{
-	if (len_hint < 0)
-		mem_set_str0_static(mem, value);
-	else
-		mem_set_str_static(mem, value, len_hint);
-}
-
-static inline void
-mem_set_strl_dynamic(struct Mem *mem, char *value, int len_hint)
-{
-	if (len_hint < 0)
-		mem_set_str0_dynamic(mem, value);
-	else
-		mem_set_str_dynamic(mem, value, len_hint);
-}
-
-static inline void
-mem_set_strl_allocated(struct Mem *mem, char *value, int len_hint)
-{
-	if (len_hint < 0)
-		mem_set_str0_allocated(mem, value);
-	else
-		mem_set_str_allocated(mem, value, len_hint);
-}
-
-static inline void
-mem_set_strl(struct Mem *mem, char *value, int len_hint,
-	     void (*custom_free)(void *))
-{
-	if (custom_free == SQL_STATIC)
-		return mem_set_strl_static(mem, value, len_hint);
-	if (custom_free == SQL_DYNAMIC)
-		return mem_set_strl_allocated(mem, value, len_hint);
-	if (custom_free != SQL_TRANSIENT)
-		return mem_set_strl_dynamic(mem, value, len_hint);
-}
-
 /** Copy string to a newly allocated memory. The MEM type becomes STRING. */
 int
 mem_copy_str(struct Mem *mem, const char *value, uint32_t len);
@@ -418,14 +370,6 @@ mem_copy_str(struct Mem *mem, const char *value, uint32_t len);
 int
 mem_copy_str0(struct Mem *mem, const char *value);
 
-static inline int
-mem_copy_strl(struct Mem *mem, const char *value, int len_hint)
-{
-	if (len_hint < 0)
-		return mem_copy_str0(mem, value);
-	return mem_copy_str(mem, value, len_hint);
-}
-
 /**
  * Clear MEM and set it to VARBINARY. The binary value belongs to another
  * object.
@@ -454,18 +398,6 @@ mem_set_bin_dynamic(struct Mem *mem, char *value, uint32_t size);
 void
 mem_set_bin_allocated(struct Mem *mem, char *value, uint32_t size);
 
-static inline void
-mem_set_binl(struct Mem *mem, char *value, uint32_t size,
-	     void (*custom_free)(void *))
-{
-	if (custom_free == SQL_STATIC)
-		return mem_set_bin_static(mem, value, size);
-	if (custom_free == SQL_DYNAMIC)
-		return mem_set_bin_allocated(mem, value, size);
-	if (custom_free != SQL_TRANSIENT)
-		return mem_set_bin_dynamic(mem, value, size);
-}
-
 /**
  * Copy binary value to a newly allocated memory. The MEM type becomes
  * VARBINARY.
@@ -891,13 +823,6 @@ mem_len_unsafe(const struct Mem *mem)
 	return len;
 }
 
-/**
- * Return address of memory allocated for accumulation structure of the
- * aggregate function.
- */
-int
-mem_get_agg(const struct Mem *mem, void **accum);
-
 /**
  * Simple type to str convertor. It is used to simplify
  * error reporting.
@@ -913,9 +838,6 @@ mem_type_to_str(const struct Mem *p);
 enum mp_type
 mem_mp_type(const struct Mem *mem);
 
-enum mp_type
-sql_value_type(struct Mem *);
-
 #ifdef SQL_DEBUG
 int sqlVdbeCheckMemInvariants(struct Mem *);
 void sqlVdbeMemPrettyPrint(Mem * pMem, char *zBuf);
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index c8f711ed2..22a4aa5cd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -355,45 +355,6 @@ sql_stricmp(const char *, const char *);
 int
 sql_strnicmp(const char *, const char *, int);
 
-sql *
-sql_context_db_handle(sql_context *);
-
-
-void
-sql_result_blob(sql_context *, const void *,
-		    int, void (*)(void *));
-
-void
-sql_result_blob64(sql_context *, const void *,
-		      sql_uint64, void (*)(void *));
-
-void
-sql_result_double(sql_context *, double);
-
-void
-sql_result_uint(sql_context *ctx, uint64_t u_val);
-
-void
-sql_result_int(sql_context *ctx, int64_t val);
-
-void
-sql_result_bool(struct sql_context *ctx, bool value);
-
-void
-sql_result_null(sql_context *);
-
-void
-sql_result_text(sql_context *, const char *,
-		    int, void (*)(void *));
-
-void
-sql_result_text64(sql_context *, const char *,
-		      sql_uint64, void (*)(void *));
-
-void
-sql_result_value(sql_context *,
-		     sql_value *);
-
 char *
 sql_mprintf(const char *, ...);
 char *
@@ -567,14 +528,6 @@ sql_vfs_register(sql_vfs *, int makeDflt);
 void
 sql_unbind(struct sql_stmt *stmt);
 
-int
-sql_bind_blob(sql_stmt *, int, const void *,
-		  int n, void (*)(void *));
-
-int
-sql_bind_blob64(sql_stmt *, int, const void *,
-		    sql_uint64, void (*)(void *));
-
 int
 sql_bind_double(sql_stmt *, int, double);
 
@@ -602,8 +555,10 @@ int
 sql_bind_null(sql_stmt *, int);
 
 int
-sql_bind_text64(sql_stmt *, int, const char *,
-		    sql_uint64, void (*)(void *));
+sql_bind_str_static(sql_stmt *stmt, int i, const char *str, uint32_t len);
+
+int
+sql_bind_bin_static(sql_stmt *stmt, int i, const char *str, uint32_t size);
 
 int
 sql_bind_uuid(struct sql_stmt *stmt, int i, const struct tt_uuid *uuid);
@@ -3697,26 +3652,6 @@ void sqlDetach(Parse *, Expr *);
 int sqlAtoF(const char *z, double *, int);
 int sqlGetInt32(const char *, int *);
 
-/**
- * Return number of symbols in the given string.
- *
- * Number of symbols != byte size of string because some symbols
- * are encoded with more than one byte. Also note that all
- * symbols from 'str' to 'str + byte_len' would be counted,
- * even if there is a '\0' somewhere between them.
- *
- * This function is implemented to be fast and indifferent to
- * correctness of string being processed. If input string has
- * even one invalid utf-8 sequence, then the resulting length
- * could be arbitary in these boundaries (0 < len < byte_len).
- * @param str String to be counted.
- * @param byte_len Byte length of given string.
- * @return number of symbols in the given string.
- */
-int
-sql_utf8_char_count(const unsigned char *str, int byte_len);
-
-u32 sqlUtf8Read(const u8 **);
 LogEst sqlLogEst(u64);
 LogEst sqlLogEstAdd(LogEst, LogEst);
 u64 sqlLogEstToInt(LogEst);
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index 7c983fea5..fbd159126 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -805,11 +805,8 @@ sql_row_trigger_program(struct Parse *parser, struct sql_trigger *trigger,
 
 		if (!parser->is_aborted)
 			parser->is_aborted = pSubParse->is_aborted;
-		if (db->mallocFailed == 0) {
-			pProgram->aOp =
-			    sqlVdbeTakeOpArray(v, &pProgram->nOp,
-						   &pTop->nMaxArg);
-		}
+		if (db->mallocFailed == 0)
+			pProgram->aOp = sqlVdbeTakeOpArray(v, &pProgram->nOp);
 		pProgram->nMem = pSubParse->nMem;
 		pProgram->nCsr = pSubParse->nTab;
 		pProgram->token = (void *)trigger;
diff --git a/src/box/sql/utf.c b/src/box/sql/utf.c
deleted file mode 100644
index 2d9a12806..000000000
--- a/src/box/sql/utf.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- *    copyright notice, this list of conditions and the
- *    following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * This file contains routines used to translate between UTF-8.
- *
- * Notes on UTF-8:
- *
- *   Byte-0    Byte-1    Byte-2    Byte-3    Value
- *  0xxxxxxx                                 00000000 00000000 0xxxxxxx
- *  110yyyyy  10xxxxxx                       00000000 00000yyy yyxxxxxx
- *  1110zzzz  10yyyyyy  10xxxxxx             00000000 zzzzyyyy yyxxxxxx
- *  11110uuu  10uuzzzz  10yyyyyy  10xxxxxx   000uuuuu zzzzyyyy yyxxxxxx
- *
- *
- */
-#include "sqlInt.h"
-
-/*
- * This lookup table is used to help decode the first byte of
- * a multi-byte UTF8 character.
- */
-static const unsigned char sqlUtf8Trans1[] = {
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-	0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
-};
-
-u32
-sqlUtf8Read(const unsigned char **pz	/* Pointer to string from which to read char */
-    )
-{
-	unsigned int c;
-
-	/* Same as READ_UTF8() above but without the zTerm parameter.
-	 * For this routine, we assume the UTF8 string is always zero-terminated.
-	 */
-	c = *((*pz)++);
-	if (c >= 0xc0) {
-		c = sqlUtf8Trans1[c - 0xc0];
-		while ((*(*pz) & 0xc0) == 0x80) {
-			c = (c << 6) + (0x3f & *((*pz)++));
-		}
-		if (c < 0x80
-		    || (c & 0xFFFFF800) == 0xD800
-		    || (c & 0xFFFFFFFE) == 0xFFFE) {
-			c = 0xFFFD;
-		}
-	}
-	return c;
-}
-
-int
-sql_utf8_char_count(const unsigned char *str, int byte_len)
-{
-	int symbol_count = 0;
-	for (int i = 0; i < byte_len;) {
-		SQL_UTF8_FWD_1(str, i, byte_len);
-		symbol_count++;
-	}
-	return symbol_count;
-}
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 121b86029..106555bb1 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -264,7 +264,10 @@ void sqlVdbeCountChanges(Vdbe *);
 sql *sqlVdbeDb(Vdbe *);
 void sqlVdbeSetSql(Vdbe *, const char *z, int n);
 void sqlVdbeSwap(Vdbe *, Vdbe *);
-VdbeOp *sqlVdbeTakeOpArray(Vdbe *, int *, int *);
+
+struct VdbeOp *
+sqlVdbeTakeOpArray(struct Vdbe *p, int *pnOp);
+
 sql_value *sqlVdbeGetBoundValue(Vdbe *, int);
 char *sqlVdbeExpandSql(Vdbe *, const char *);
 
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 8dbba4908..c45cc9301 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -262,7 +262,6 @@ struct Vdbe {
 
 	Op *aOp;		/* Space to hold the virtual machine's program */
 	Mem *aMem;		/* The memory locations */
-	Mem **apArg;		/* Arguments to currently executing user function */
 	/** SQL metadata for DML/DQL queries. */
 	struct sql_column_metadata *metadata;
 	Mem *pResultSet;	/* Pointer to an array of results */
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 486f797fb..3894bb943 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -107,135 +107,6 @@ sql_metadata_is_full()
 	return current_session()->sql_flags & SQL_FullMetadata;
 }
 
-/**************************** sql_result_  ******************************
- * The following routines are used by user-defined functions to specify
- * the function result.
- *
- * The setStrOrError() function sets the result as a string or blob but
- * if the string or blob is too large, it then sets the error code.
- *
- * The invokeValueDestructor(P,X) routine invokes destructor function X()
- * on value P is not going to be used and need to be destroyed.
- */
-static void
-setResultStrOrError(sql_context * pCtx,	/* Function context */
-		    const char *z,	/* String pointer */
-		    int n,	/* Bytes in string, or negative */
-		    void (*xDel) (void *)	/* Destructor function */
-    )
-{
-	if (xDel != SQL_TRANSIENT)
-		return mem_set_strl(pCtx->pOut, (char *)z, n, xDel);
-	if (mem_copy_strl(pCtx->pOut, z, n) != 0)
-		pCtx->is_aborted = true;
-}
-
-static int
-invokeValueDestructor(const void *p,	/* Value to destroy */
-		      void (*xDel) (void *),	/* The destructor */
-		      sql_context *pCtx	/* Set an error if no NULL */
-    )
-{
-	assert(xDel != SQL_DYNAMIC);
-	if (xDel == 0) {
-		/* noop */
-	} else if (xDel == SQL_TRANSIENT) {
-		/* noop */
-	} else {
-		xDel((void *)p);
-	}
-	if (pCtx) {
-		diag_set(ClientError, ER_SQL_EXECUTE, "string or binary string"\
-			 "is too big");
-		pCtx->is_aborted = true;
-	}
-	return -1;
-}
-
-void
-sql_result_blob(sql_context * pCtx,
-		    const void *z, int n, void (*xDel) (void *)
-    )
-{
-	assert(n >= 0);
-	if (xDel != SQL_TRANSIENT)
-		mem_set_binl(pCtx->pOut, (char *)z, n, xDel);
-	else if (mem_copy_bin(pCtx->pOut, z, n) != 0)
-		pCtx->is_aborted = true;
-}
-
-void
-sql_result_blob64(sql_context * pCtx,
-		      const void *z, sql_uint64 n, void (*xDel) (void *)
-    )
-{
-	assert(xDel != SQL_DYNAMIC);
-	if (n > 0x7fffffff) {
-		(void)invokeValueDestructor(z, xDel, pCtx);
-	} else {
-		setResultStrOrError(pCtx, z, (int)n, xDel);
-	}
-}
-
-void
-sql_result_double(sql_context * pCtx, double rVal)
-{
-	mem_set_double(pCtx->pOut, rVal);
-}
-
-void
-sql_result_uint(sql_context *ctx, uint64_t u_val)
-{
-	mem_set_uint(ctx->pOut, u_val);
-}
-
-void
-sql_result_int(sql_context *ctx, int64_t val)
-{
-	mem_set_int(ctx->pOut, val, val < 0);
-}
-
-void
-sql_result_bool(struct sql_context *ctx, bool value)
-{
-	mem_set_bool(ctx->pOut, value);
-}
-
-void
-sql_result_null(sql_context * pCtx)
-{
-	mem_set_null(pCtx->pOut);
-}
-
-void
-sql_result_text(sql_context * pCtx,
-		    const char *z, int n, void (*xDel) (void *)
-    )
-{
-	setResultStrOrError(pCtx, z, n, xDel);
-}
-
-void
-sql_result_text64(sql_context * pCtx,
-		      const char *z,
-		      sql_uint64 n,
-		      void (*xDel) (void *))
-{
-	assert(xDel != SQL_DYNAMIC);
-	if (n > 0x7fffffff) {
-		(void)invokeValueDestructor(z, xDel, pCtx);
-	} else {
-		setResultStrOrError(pCtx, z, (int)n, xDel);
-	}
-}
-
-void
-sql_result_value(sql_context * pCtx, sql_value * pValue)
-{
-	if (mem_copy(pCtx->pOut, pValue) != 0)
-		pCtx->is_aborted = true;
-}
-
 /*
  * Execute the statement pStmt, either until a row of data is ready, the
  * statement is completely executed or an error occurs.
@@ -313,23 +184,6 @@ sql_step(sql_stmt * pStmt)
 	return sqlStep(v);
 }
 
-/*
- * Extract the user data from a sql_context structure and return a
- * pointer to it.
- *
- * IMPLEMENTATION-OF: R-46798-50301 The sql_context_db_handle() interface
- * returns a copy of the pointer to the database connection (the 1st
- * parameter) of the sql_create_function() and
- * sql_create_function16() routines that originally registered the
- * application defined function.
- */
-sql *
-sql_context_db_handle(sql_context * p)
-{
-	assert(p && p->pOut);
-	return p->pOut->db;
-}
-
 /*
  * Return the number of columns in the result set for the statement pStmt.
  */
@@ -582,73 +436,6 @@ sql_unbind(struct sql_stmt *stmt)
 	}
 }
 
-/*
- * Bind a text or BLOB value.
- */
-static int
-bindText(sql_stmt * pStmt,	/* The statement to bind against */
-	 int i,			/* Index of the parameter to bind */
-	 const void *zData,	/* Pointer to the data to be bound */
-	 int nData,		/* Number of bytes of data to be bound */
-	 void (*xDel) (void *)	/* Destructor for the data */
-    )
-{
-	Vdbe *p = (Vdbe *) pStmt;
-	Mem *pVar;
-	if (vdbeUnbind(p, i) != 0) {
-		if (xDel != SQL_STATIC && xDel != SQL_TRANSIENT)
-			xDel((void *)zData);
-		return -1;
-	}
-	if (zData == NULL)
-		return 0;
-	pVar = &p->aVar[i - 1];
-	if (xDel != SQL_TRANSIENT)
-		mem_set_strl(pVar, (char *)zData, nData, xDel);
-	else if (mem_copy_strl(pVar, zData, nData) != 0)
-		return -1;
-	return sql_bind_type(p, i, "text");
-}
-
-/*
- * Bind a blob value to an SQL statement variable.
- */
-int
-sql_bind_blob(sql_stmt * pStmt,
-		  int i, const void *zData, int nData, void (*xDel) (void *)
-    )
-{
-	struct Vdbe *p = (Vdbe *) pStmt;
-	if (vdbeUnbind(p, i) != 0) {
-		if (xDel != SQL_STATIC && xDel != SQL_TRANSIENT)
-			xDel((void *)zData);
-		return -1;
-	}
-	if (zData == NULL)
-		return 0;
-	struct Mem *var = &p->aVar[i - 1];
-	if (xDel != SQL_TRANSIENT)
-		mem_set_binl(var, (char *)zData, nData, xDel);
-	else if (mem_copy_bin(var, zData, nData) != 0)
-		return -1;
-	return sql_bind_type(p, i, "varbinary");
-}
-
-int
-sql_bind_blob64(sql_stmt * pStmt,
-		    int i,
-		    const void *zData,
-		    sql_uint64 nData, void (*xDel) (void *)
-    )
-{
-	assert(xDel != SQL_DYNAMIC);
-	if (nData > 0x7fffffff) {
-		return invokeValueDestructor(zData, xDel, 0);
-	} else {
-		return sql_bind_blob(pStmt, i, zData, (int)nData, xDel);
-	}
-}
-
 int
 sql_bind_double(sql_stmt * pStmt, int i, double rValue)
 {
@@ -722,18 +509,19 @@ sql_bind_ptr(struct sql_stmt *stmt, int i, void *ptr)
 }
 
 int
-sql_bind_text64(sql_stmt * pStmt,
-		    int i,
-		    const char *zData,
-		    sql_uint64 nData,
-		    void (*xDel) (void *))
-{
-	assert(xDel != SQL_DYNAMIC);
-	if (nData > 0x7fffffff) {
-		return invokeValueDestructor(zData, xDel, 0);
-	} else {
-		return bindText(pStmt, i, zData, (int)nData, xDel);
-	}
+sql_bind_str_static(sql_stmt *stmt, int i, const char *str, uint32_t len)
+{
+	struct Vdbe *vdbe = (struct Vdbe *)stmt;
+	mem_set_str_static(&vdbe->aVar[i - 1], (char *)str, len);
+	return sql_bind_type(vdbe, i, "text");
+}
+
+int
+sql_bind_bin_static(sql_stmt *stmt, int i, const char *str, uint32_t size)
+{
+	struct Vdbe *vdbe = (struct Vdbe *)stmt;
+	mem_set_bin_static(&vdbe->aVar[i - 1], (char *)str, size);
+	return sql_bind_type(vdbe, i, "text");
 }
 
 int
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 1a429e7f1..b71f65966 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -447,21 +447,17 @@ sqlVdbeRunOnlyOnce(Vdbe * p)
  * (1) For each jump instruction with a negative P2 value (a label)
  *     resolve the P2 value to an actual address.
  *
- * (2) Compute the maximum number of arguments used by any SQL function
- *     and store that value in *pMaxFuncArgs.
+ * (2) Initialize the p4.xAdvance pointer on opcodes that use it.
  *
- * (3) Initialize the p4.xAdvance pointer on opcodes that use it.
- *
- * (4) Reclaim the memory allocated for storing labels.
+ * (3) Reclaim the memory allocated for storing labels.
  *
  * This routine will only function correctly if the mkopcodeh.sh generator
  * script numbers the opcodes correctly.  Changes to this routine must be
  * coordinated with changes to mkopcodeh.sh.
  */
 static void
-resolveP2Values(Vdbe * p, int *pMaxFuncArgs)
+resolveP2Values(Vdbe * p)
 {
-	int nMaxArgs = *pMaxFuncArgs;
 	Op *pOp;
 	Parse *pParse = p->pParse;
 	int *aLabel = pParse->aLabel;
@@ -506,7 +502,6 @@ resolveP2Values(Vdbe * p, int *pMaxFuncArgs)
 	sqlDbFree(p->db, pParse->aLabel);
 	pParse->aLabel = 0;
 	pParse->nLabel = 0;
-	*pMaxFuncArgs = nMaxArgs;
 }
 
 /*
@@ -526,17 +521,15 @@ sqlVdbeCurrentAddr(Vdbe * p)
  * vdbeFreeOpArray() function.
  *
  * Before returning, *pnOp is set to the number of entries in the returned
- * array. Also, *pnMaxArg is set to the larger of its current value and
- * the number of entries in the Vdbe.apArg[] array required to execute the
- * returned program.
+ * array.
  */
-VdbeOp *
-sqlVdbeTakeOpArray(Vdbe * p, int *pnOp, int *pnMaxArg)
+struct VdbeOp *
+sqlVdbeTakeOpArray(struct Vdbe *p, int *pnOp)
 {
 	VdbeOp *aOp = p->aOp;
 	assert(aOp && !p->db->mallocFailed);
 
-	resolveP2Values(p, pnMaxArg);
+	resolveP2Values(p);
 	*pnOp = p->nOp;
 	p->aOp = 0;
 	return aOp;
@@ -1490,7 +1483,6 @@ sqlVdbeMakeReady(Vdbe * p,	/* The VDBE */
 	int nVar;		/* Number of parameters */
 	int nMem;		/* Number of VM memory registers */
 	int nCursor;		/* Number of cursors required */
-	int nArg;		/* Number of arguments in subprograms */
 	int n;			/* Loop counter */
 	struct ReusableSpace x;	/* Reusable bulk memory */
 
@@ -1504,7 +1496,6 @@ sqlVdbeMakeReady(Vdbe * p,	/* The VDBE */
 	nVar = pParse->nVar;
 	nMem = pParse->nMem;
 	nCursor = pParse->nTab;
-	nArg = pParse->nMaxArg;
 
 	/* Each cursor uses a memory cell.  The first cursor (cursor 0) can
 	 * use aMem[0] which is not otherwise used by the VDBE program.  Allocate
@@ -1526,7 +1517,7 @@ sqlVdbeMakeReady(Vdbe * p,	/* The VDBE */
 	assert(x.nFree >= 0);
 	assert(EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]));
 
-	resolveP2Values(p, &nArg);
+	resolveP2Values(p);
 	if (pParse->explain && nMem < 10) {
 		nMem = 10;
 	}
@@ -1546,7 +1537,6 @@ sqlVdbeMakeReady(Vdbe * p,	/* The VDBE */
 		x.nNeeded = 0;
 		p->aMem = allocSpace(&x, p->aMem, nMem * sizeof(Mem));
 		p->aVar = allocSpace(&x, p->aVar, nVar * sizeof(Mem));
-		p->apArg = allocSpace(&x, p->apArg, nArg * sizeof(Mem *));
 		p->apCsr =
 		    allocSpace(&x, p->apCsr, nCursor * sizeof(VdbeCursor *));
 		if (x.nNeeded == 0)
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 19/21] sql: remove MEM_Dyn flag
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (17 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 18/21] sql: remove unused code Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 20/21] sql: remove MEM_Term flag Mergen Imeev via Tarantool-patches
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch removes the MEM_Dyn flag, because after changes in the SQL
built-in functions, this flag is no longer used.

Needed for #4145
---
 src/box/sql/mem.c    | 110 +++++++------------------------------------
 src/box/sql/mem.h    |  56 +---------------------
 src/box/sql/sqlInt.h |  14 ------
 3 files changed, 18 insertions(+), 162 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 70ca9e1b2..4150a24f0 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -207,7 +207,6 @@ mem_create(struct Mem *mem)
 	mem->szMalloc = 0;
 	mem->uTemp = 0;
 	mem->db = sql_get();
-	mem->xDel = NULL;
 #ifdef SQL_DEBUG
 	mem->pScopyFrom = NULL;
 	mem->pFiller = NULL;
@@ -217,15 +216,10 @@ mem_create(struct Mem *mem)
 static inline void
 mem_clear(struct Mem *mem)
 {
-	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);
-		} else {
-			struct VdbeFrame *frame = mem->u.pFrame;
-			frame->pParent = frame->v->pDelFrame;
-			frame->v->pDelFrame = frame;
-		}
+	if (mem->type == MEM_TYPE_FRAME) {
+		struct VdbeFrame *frame = mem->u.pFrame;
+		frame->pParent = frame->v->pDelFrame;
+		frame->v->pDelFrame = frame;
 	}
 	mem->type = MEM_TYPE_NULL;
 	mem->flags = 0;
@@ -320,21 +314,14 @@ set_str_const(struct Mem *mem, char *value, uint32_t len, int alloc_type)
 static inline void
 set_str_dynamic(struct Mem *mem, char *value, uint32_t len, int alloc_type)
 {
-	assert((mem->flags & MEM_Dyn) == 0 || value != mem->z);
 	assert(mem->szMalloc == 0 || value != mem->zMalloc);
-	assert(alloc_type == MEM_Dyn || alloc_type == 0);
 	mem_destroy(mem);
 	mem->z = value;
 	mem->n = len;
 	mem->type = MEM_TYPE_STR;
 	mem->flags = alloc_type;
-	if (alloc_type == MEM_Dyn) {
-		mem->xDel = sql_free;
-	} else {
-		mem->xDel = NULL;
-		mem->zMalloc = mem->z;
-		mem->szMalloc = sqlDbMallocSize(mem->db, mem->zMalloc);
-	}
+	mem->zMalloc = mem->z;
+	mem->szMalloc = sqlDbMallocSize(mem->db, mem->zMalloc);
 }
 
 void
@@ -349,12 +336,6 @@ mem_set_str_static(struct Mem *mem, char *value, uint32_t len)
 	set_str_const(mem, value, len, MEM_Static);
 }
 
-void
-mem_set_str_dynamic(struct Mem *mem, char *value, uint32_t len)
-{
-	set_str_dynamic(mem, value, len, MEM_Dyn);
-}
-
 void
 mem_set_str_allocated(struct Mem *mem, char *value, uint32_t len)
 {
@@ -375,13 +356,6 @@ mem_set_str0_static(struct Mem *mem, char *value)
 	mem->flags |= MEM_Term;
 }
 
-void
-mem_set_str0_dynamic(struct Mem *mem, char *value)
-{
-	set_str_dynamic(mem, value, strlen(value), MEM_Dyn);
-	mem->flags |= MEM_Term;
-}
-
 void
 mem_set_str0_allocated(struct Mem *mem, char *value)
 {
@@ -436,21 +410,14 @@ set_bin_const(struct Mem *mem, char *value, uint32_t size, int alloc_type)
 static inline void
 set_bin_dynamic(struct Mem *mem, char *value, uint32_t size, int alloc_type)
 {
-	assert((mem->flags & MEM_Dyn) == 0 || value != mem->z);
 	assert(mem->szMalloc == 0 || value != mem->zMalloc);
-	assert(alloc_type == MEM_Dyn || alloc_type == 0);
 	mem_destroy(mem);
 	mem->z = value;
 	mem->n = size;
 	mem->type = MEM_TYPE_BIN;
 	mem->flags = alloc_type;
-	if (alloc_type == MEM_Dyn) {
-		mem->xDel = sql_free;
-	} else {
-		mem->xDel = NULL;
-		mem->zMalloc = mem->z;
-		mem->szMalloc = sqlDbMallocSize(mem->db, mem->zMalloc);
-	}
+	mem->zMalloc = mem->z;
+	mem->szMalloc = sqlDbMallocSize(mem->db, mem->zMalloc);
 }
 
 void
@@ -465,12 +432,6 @@ mem_set_bin_static(struct Mem *mem, char *value, uint32_t size)
 	set_bin_const(mem, value, size, MEM_Static);
 }
 
-void
-mem_set_bin_dynamic(struct Mem *mem, char *value, uint32_t size)
-{
-	set_bin_dynamic(mem, value, size, MEM_Dyn);
-}
-
 void
 mem_set_bin_allocated(struct Mem *mem, char *value, uint32_t size)
 {
@@ -524,13 +485,6 @@ mem_set_map_static(struct Mem *mem, char *value, uint32_t size)
 	set_msgpack_value(mem, value, size, MEM_Static, MEM_TYPE_MAP);
 }
 
-void
-mem_set_map_dynamic(struct Mem *mem, char *value, uint32_t size)
-{
-	assert(mp_typeof(*value) == MP_MAP);
-	set_msgpack_value(mem, value, size, MEM_Dyn, MEM_TYPE_MAP);
-}
-
 void
 mem_set_map_allocated(struct Mem *mem, char *value, uint32_t size)
 {
@@ -552,13 +506,6 @@ mem_set_array_static(struct Mem *mem, char *value, uint32_t size)
 	set_msgpack_value(mem, value, size, MEM_Static, MEM_TYPE_ARRAY);
 }
 
-void
-mem_set_array_dynamic(struct Mem *mem, char *value, uint32_t size)
-{
-	assert(mp_typeof(*value) == MP_ARRAY);
-	set_msgpack_value(mem, value, size, MEM_Dyn, MEM_TYPE_ARRAY);
-}
-
 void
 mem_set_array_allocated(struct Mem *mem, char *value, uint32_t size)
 {
@@ -1907,7 +1854,7 @@ mem_append(struct Mem *mem, const char *value, uint32_t len)
 	if (len == 0)
 		return 0;
 	int new_size = mem->n + len;
-	if (((mem->flags & (MEM_Static | MEM_Dyn | MEM_Ephem)) != 0) ||
+	if (((mem->flags & (MEM_Static | MEM_Ephem)) != 0) ||
 	    mem->szMalloc < new_size) {
 		/*
 		 * Force exponential buffer size growth to avoid having to call
@@ -2648,18 +2595,6 @@ mem_mp_type(const struct Mem *mem)
 int
 sqlVdbeCheckMemInvariants(Mem * p)
 {
-	/* If MEM_Dyn is set then Mem.xDel!=0.
-	 * Mem.xDel is might not be initialized if MEM_Dyn is clear.
-	 */
-	assert((p->flags & MEM_Dyn) == 0 || p->xDel != 0);
-
-	/* MEM_Dyn may only be set if Mem.szMalloc==0.  In this way we
-	 * ensure that if Mem.szMalloc>0 then it is safe to do
-	 * Mem.z = Mem.zMalloc without having to check Mem.flags&MEM_Dyn.
-	 * That saves a few cycles in inner loops.
-	 */
-	assert((p->flags & MEM_Dyn) == 0 || p->szMalloc == 0);
-
 	/* The szMalloc field holds the correct memory allocation size */
 	assert(p->szMalloc == 0 ||
 	       p->szMalloc == sqlDbMallocSize(p->db, p->zMalloc));
@@ -2674,7 +2609,6 @@ sqlVdbeCheckMemInvariants(Mem * p)
 	 */
 	if ((p->type & (MEM_TYPE_STR | MEM_TYPE_BIN)) != 0 && p->n > 0) {
 		assert(((p->szMalloc > 0 && p->z == p->zMalloc) ? 1 : 0) +
-		       ((p->flags & MEM_Dyn) != 0 ? 1 : 0) +
 		       ((p->flags & MEM_Ephem) != 0 ? 1 : 0) +
 		       ((p->flags & MEM_Static) != 0 ? 1 : 0) == 1);
 	}
@@ -2694,15 +2628,12 @@ sqlVdbeMemPrettyPrint(Mem *pMem, char *zBuf)
 	if (pMem->type == MEM_TYPE_BIN) {
 		int i;
 		char c;
-		if (f & MEM_Dyn) {
-			c = 'z';
-			assert((f & (MEM_Static|MEM_Ephem))==0);
-		} else if (f & MEM_Static) {
+		if ((f & MEM_Static) != 0) {
 			c = 't';
-			assert((f & (MEM_Dyn|MEM_Ephem))==0);
+			assert((f & MEM_Ephem) == 0);
 		} else if (f & MEM_Ephem) {
 			c = 'e';
-			assert((f & (MEM_Static|MEM_Dyn))==0);
+			assert((f & MEM_Static) == 0);
 		} else {
 			c = 's';
 		}
@@ -2726,15 +2657,12 @@ sqlVdbeMemPrettyPrint(Mem *pMem, char *zBuf)
 	} else if (pMem->type == MEM_TYPE_STR) {
 		int j, k;
 		zBuf[0] = ' ';
-		if (f & MEM_Dyn) {
-			zBuf[1] = 'z';
-			assert((f & (MEM_Static|MEM_Ephem))==0);
-		} else if (f & MEM_Static) {
+		if ((f & MEM_Static) != 0) {
 			zBuf[1] = 't';
-			assert((f & (MEM_Dyn|MEM_Ephem))==0);
+			assert((f & MEM_Ephem) == 0);
 		} else if (f & MEM_Ephem) {
 			zBuf[1] = 'e';
-			assert((f & (MEM_Static|MEM_Dyn))==0);
+			assert((f & MEM_Static) == 0);
 		} else {
 			zBuf[1] = 's';
 		}
@@ -2847,13 +2775,9 @@ sqlVdbeMemGrow(struct Mem *pMem, int n, int bPreserve)
 	if (bPreserve && pMem->z && pMem->z != pMem->zMalloc) {
 		memcpy(pMem->zMalloc, pMem->z, pMem->n);
 	}
-	if ((pMem->flags & MEM_Dyn) != 0) {
-		assert(pMem->xDel != 0 && pMem->xDel != SQL_DYNAMIC);
-		pMem->xDel((void *)(pMem->z));
-	}
 
 	pMem->z = pMem->zMalloc;
-	pMem->flags &= ~(MEM_Dyn | MEM_Ephem | MEM_Static);
+	pMem->flags &= ~(MEM_Ephem | MEM_Static);
 	return 0;
 }
 
@@ -2872,11 +2796,9 @@ int
 sqlVdbeMemClearAndResize(Mem * pMem, int szNew)
 {
 	assert(szNew > 0);
-	assert((pMem->flags & MEM_Dyn) == 0 || pMem->szMalloc == 0);
 	if (pMem->szMalloc < szNew) {
 		return sqlVdbeMemGrow(pMem, szNew, 0);
 	}
-	assert((pMem->flags & MEM_Dyn) == 0);
 	pMem->z = pMem->zMalloc;
 	return 0;
 }
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 9533833f2..d2e9cc135 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -87,7 +87,6 @@ struct Mem {
 	int szMalloc;		/* Size of the zMalloc allocation */
 	u32 uTemp;		/* Transient storage for serial_type in OP_MakeRecord */
 	sql *db;		/* The associated database connection */
-	void (*xDel) (void *);	/* Destructor for Mem.z - only valid if MEM_Dyn */
 #ifdef SQL_DEBUG
 	Mem *pScopyFrom;	/* This Mem is a shallow copy of pScopyFrom */
 	void *pFiller;		/* So that sizeof(Mem) is a multiple of 8 */
@@ -106,7 +105,6 @@ struct Mem {
  * string is \000 or \u0000 terminated
  */
 #define MEM_Term      0x0400	/* String rep is nul terminated */
-#define MEM_Dyn       0x0800	/* Need to call Mem.xDel() on Mem.z */
 #define MEM_Static    0x1000	/* Mem.z points to a static string */
 #define MEM_Ephem     0x2000	/* Mem.z points to an ephemeral string */
 
@@ -217,13 +215,6 @@ mem_is_ephemeral(const struct Mem *mem)
 	return (mem->flags & MEM_Ephem) != 0;
 }
 
-static inline bool
-mem_is_dynamic(const struct Mem *mem)
-{
-	assert(mem_is_bytes(mem));
-	return (mem->flags & MEM_Dyn) != 0;
-}
-
 static inline bool
 mem_is_allocated(const struct Mem *mem)
 {
@@ -234,8 +225,7 @@ mem_is_allocated(const struct Mem *mem)
 static inline bool
 mem_is_trivial(const struct Mem *mem)
 {
-	return mem->szMalloc == 0 && (mem->flags & MEM_Dyn) == 0 &&
-	       mem->type != MEM_TYPE_FRAME;
+	return mem->szMalloc == 0 && mem->type != MEM_TYPE_FRAME;
 }
 
 static inline bool
@@ -314,14 +304,6 @@ mem_set_str_ephemeral(struct Mem *mem, char *value, uint32_t len);
 void
 mem_set_str_static(struct Mem *mem, char *value, uint32_t len);
 
-/**
- * Clear MEM and set it to STRING. The string was allocated by another object
- * and passed to MEM. MEMs with this allocation type must free given memory
- * whenever the MEM changes.
- */
-void
-mem_set_str_dynamic(struct Mem *mem, char *value, uint32_t len);
-
 /**
  * Clear MEM and set it to STRING. The string was allocated by another object
  * and passed to MEM. MEMs with this allocation type only deallocate the string
@@ -342,14 +324,6 @@ mem_set_str0_ephemeral(struct Mem *mem, char *value);
 void
 mem_set_str0_static(struct Mem *mem, char *value);
 
-/**
- * Clear MEM and set it to NULL-terminated STRING. The string was allocated by
- * another object and passed to MEM. MEMs with this allocation type must free
- * given memory whenever the MEM changes.
- */
-void
-mem_set_str0_dynamic(struct Mem *mem, char *value);
-
 /**
  * Clear MEM and set it to NULL-terminated STRING. The string was allocated by
  * another object and passed to MEM. MEMs with this allocation type only
@@ -381,14 +355,6 @@ mem_set_bin_ephemeral(struct Mem *mem, char *value, uint32_t size);
 void
 mem_set_bin_static(struct Mem *mem, char *value, uint32_t size);
 
-/**
- * Clear MEM and set it to VARBINARY. The binary value was allocated by another
- * object and passed to MEM. MEMs with this allocation type must free given
- * memory whenever the MEM changes.
- */
-void
-mem_set_bin_dynamic(struct Mem *mem, char *value, uint32_t size);
-
 /**
  * Clear MEM and set it to VARBINARY. The binary value was allocated by another
  * object and passed to MEM. MEMs with this allocation type only deallocate the
@@ -419,14 +385,6 @@ mem_set_map_ephemeral(struct Mem *mem, char *value, uint32_t size);
 void
 mem_set_map_static(struct Mem *mem, char *value, uint32_t size);
 
-/**
- * Clear MEM and set it to MAP. The binary value was allocated by another object
- * and passed to MEM. The binary value must be msgpack of MAP type. MEMs with
- * this allocation type must free given memory whenever the MEM changes.
- */
-void
-mem_set_map_dynamic(struct Mem *mem, char *value, uint32_t size);
-
 /**
  * Clear MEM and set it to MAP. The binary value was allocated by another object
  * and passed to MEM. The binary value must be msgpack of MAP type. MEMs with
@@ -451,15 +409,6 @@ mem_set_array_ephemeral(struct Mem *mem, char *value, uint32_t size);
 void
 mem_set_array_static(struct Mem *mem, char *value, uint32_t size);
 
-/**
- * Clear MEM and set it to ARRAY. The binary value was allocated by another
- * object and passed to MEM. The binary value must be msgpack of ARRAY type.
- * MEMs with this allocation type must free given memory whenever the MEM
- * changes.
- */
-void
-mem_set_array_dynamic(struct Mem *mem, char *value, uint32_t size);
-
 /**
  * Clear MEM and set it to ARRAY. The binary value was allocated by another
  * object and passed to MEM. The binary value must be msgpack of ARRAY type.
@@ -869,8 +818,7 @@ int sqlVdbeMemTooBig(Mem *);
 /* Return TRUE if Mem X contains dynamically allocated content - anything
  * that needs to be deallocated to avoid a leak.
  */
-#define VdbeMemDynamic(X) (((X)->flags & MEM_Dyn) != 0 ||\
-			   ((X)->type & MEM_TYPE_FRAME) != 0)
+#define VdbeMemDynamic(X) (((X)->type & MEM_TYPE_FRAME) != 0)
 
 /**
  * Perform comparison of two tuples: unpacked (key1) and packed (key2)
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 22a4aa5cd..148350d05 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -370,10 +370,6 @@ sql_vsnprintf(int, char *, const char *, va_list);
 #define MATCH_ONE_WILDCARD '_'
 #define MATCH_ALL_WILDCARD '%'
 
-typedef void (*sql_destructor_type) (void *);
-#define SQL_STATIC      ((sql_destructor_type)0)
-#define SQL_TRANSIENT   ((sql_destructor_type)-1)
-
 /**
  * Compile the UTF-8 encoded SQL statement into
  * a statement handle (struct Vdbe).
@@ -873,16 +869,6 @@ typedef u64 uptr;
  */
 #define IsPowerOfTwo(X) (((X)&((X)-1))==0)
 
-/*
- * The following value as a destructor means to use sqlDbFree().
- * The sqlDbFree() routine requires two parameters instead of the
- * one parameter that destructors normally want.  So we have to introduce
- * this magic value that the code knows to handle differently.  Any
- * pointer will work here as long as it is distinct from sql_STATIC
- * and sql_TRANSIENT.
- */
-#define SQL_DYNAMIC   ((sql_destructor_type)sqlMallocSize)
-
 /*
  * The usual case where Writable Static Data (WSD) is supported,
  * the sql_WSD and GLOBAL macros become no-ops and have zero
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 20/21] sql: remove MEM_Term flag
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (18 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 19/21] sql: remove MEM_Dyn flag Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 21/21] sql: make arguments to be const Mergen Imeev via Tarantool-patches
  2021-11-11 11:00 ` [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Kirill Yukhin via Tarantool-patches
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch removes the MEM_Term flag, because after changes in the SQL
built-in functions, this flag is no longer used.

Needed for #4145
---
 src/box/sql/mem.c       | 78 +++--------------------------------------
 src/box/sql/mem.h       | 36 -------------------
 src/box/sql/printf.c    | 20 +++++++++--
 src/box/sql/vdbe.h      |  4 ++-
 src/box/sql/vdbeaux.c   | 31 ++++------------
 src/box/sql/whereexpr.c | 18 +++++++---
 6 files changed, 43 insertions(+), 144 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 4150a24f0..1f5df3332 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -346,21 +346,18 @@ void
 mem_set_str0_ephemeral(struct Mem *mem, char *value)
 {
 	set_str_const(mem, value, strlen(value), MEM_Ephem);
-	mem->flags |= MEM_Term;
 }
 
 void
 mem_set_str0_static(struct Mem *mem, char *value)
 {
 	set_str_const(mem, value, strlen(value), MEM_Static);
-	mem->flags |= MEM_Term;
 }
 
 void
 mem_set_str0_allocated(struct Mem *mem, char *value)
 {
 	set_str_dynamic(mem, value, strlen(value), 0);
-	mem->flags |= MEM_Term;
 }
 
 int
@@ -392,7 +389,6 @@ mem_copy_str0(struct Mem *mem, const char *value)
 	if (mem_copy_str(mem, value, len + 1) != 0)
 		return -1;
 	mem->n = len;
-	mem->flags |= MEM_Term;
 	return 0;
 }
 
@@ -657,24 +653,12 @@ int_to_str0(struct Mem *mem)
 	return mem_copy_str0(mem, str);
 }
 
-static inline int
-str_to_str0(struct Mem *mem)
-{
-	assert(mem->type == MEM_TYPE_STR);
-	if (sqlVdbeMemGrow(mem, mem->n + 1, 1) != 0)
-		return -1;
-	mem->z[mem->n] = '\0';
-	mem->flags |= MEM_Term;
-	mem->flags &= ~MEM_Scalar;
-	return 0;
-}
-
 static inline int
 str_to_bin(struct Mem *mem)
 {
 	assert(mem->type == MEM_TYPE_STR);
 	mem->type = MEM_TYPE_BIN;
-	mem->flags &= ~(MEM_Term | MEM_Scalar);
+	mem->flags &= ~MEM_Scalar;
 	return 0;
 }
 
@@ -725,18 +709,6 @@ bin_to_str(struct Mem *mem)
 	return 0;
 }
 
-static inline int
-bin_to_str0(struct Mem *mem)
-{
-	assert(mem->type == MEM_TYPE_BIN);
-	if (sqlVdbeMemGrow(mem, mem->n + 1, 1) != 0)
-		return -1;
-	mem->z[mem->n] = '\0';
-	mem->type = MEM_TYPE_STR;
-	mem->flags = MEM_Term;
-	return 0;
-}
-
 static inline int
 bin_to_uuid(struct Mem *mem)
 {
@@ -1002,7 +974,7 @@ double_to_str0(struct Mem *mem)
 	sql_snprintf(BUF_SIZE, mem->z, "%!.15g", mem->u.r);
 	mem->n = strlen(mem->z);
 	mem->type = MEM_TYPE_STR;
-	mem->flags = MEM_Term;
+	mem->flags = 0;
 	return 0;
 }
 
@@ -1284,39 +1256,6 @@ mem_to_number(struct Mem *mem)
 	return -1;
 }
 
-int
-mem_to_str0(struct Mem *mem)
-{
-	assert(mem->type < MEM_TYPE_INVALID);
-	switch (mem->type) {
-	case MEM_TYPE_STR:
-		if ((mem->flags & MEM_Term) != 0) {
-			mem->flags &= ~MEM_Scalar;
-			return 0;
-		}
-		return str_to_str0(mem);
-	case MEM_TYPE_INT:
-	case MEM_TYPE_UINT:
-		return int_to_str0(mem);
-	case MEM_TYPE_DOUBLE:
-		return double_to_str0(mem);
-	case MEM_TYPE_BOOL:
-		return bool_to_str0(mem);
-	case MEM_TYPE_BIN:
-		return bin_to_str0(mem);
-	case MEM_TYPE_MAP:
-		return map_to_str0(mem);
-	case MEM_TYPE_ARRAY:
-		return array_to_str0(mem);
-	case MEM_TYPE_UUID:
-		return uuid_to_str0(mem);
-	case MEM_TYPE_DEC:
-		return dec_to_str0(mem);
-	default:
-		return -1;
-	}
-}
-
 int
 mem_to_str(struct Mem *mem)
 {
@@ -1763,15 +1702,6 @@ mem_get_bool(const struct Mem *mem, bool *b)
 	return -1;
 }
 
-int
-mem_get_str0(const struct Mem *mem, const char **s)
-{
-	if (mem->type != MEM_TYPE_STR || (mem->flags & MEM_Term) == 0)
-		return -1;
-	*s = mem->z;
-	return 0;
-}
-
 int
 mem_get_bin(const struct Mem *mem, const char **s)
 {
@@ -1814,7 +1744,7 @@ mem_copy(struct Mem *to, const struct Mem *from)
 	to->szMalloc = sqlDbMallocSize(to->db, to->zMalloc);
 	memcpy(to->zMalloc, to->z, to->n);
 	to->z = to->zMalloc;
-	to->flags &= MEM_Term;
+	to->flags = 0;
 	return 0;
 }
 
@@ -1831,7 +1761,7 @@ mem_copy_as_ephemeral(struct Mem *to, const struct Mem *from)
 		return;
 	if ((to->flags & (MEM_Static | MEM_Ephem)) != 0)
 		return;
-	to->flags &= MEM_Term;
+	to->flags = 0;
 	to->flags |= MEM_Ephem;
 	return;
 }
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index d2e9cc135..1ef8a945b 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -98,13 +98,6 @@ struct Mem {
 /** MEM is of SCALAR meta-type. */
 #define MEM_Scalar    0x0002
 #define MEM_Cleared   0x0200	/* NULL set by OP_Null, not from data */
-
-/* Whenever Mem contains a valid string or blob representation, one of
- * the following flags must be set to determine the memory management
- * policy for Mem.z.  The MEM_Term flag tells us whether or not the
- * string is \000 or \u0000 terminated
- */
-#define MEM_Term      0x0400	/* String rep is nul terminated */
 #define MEM_Static    0x1000	/* Mem.z points to a static string */
 #define MEM_Ephem     0x2000	/* Mem.z points to an ephemeral string */
 
@@ -610,14 +603,6 @@ mem_to_number(struct Mem *mem);
 int
 mem_to_str(struct Mem *mem);
 
-/**
- * Convert the given MEM to STRING. This function and the function above define
- * the rules that are used to convert values of all other types to STRING. In
- * this function, the string received after convertion is NULL-terminated.
- */
-int
-mem_to_str0(struct Mem *mem);
-
 /** Convert the given MEM to given type according to explicit cast rules. */
 int
 mem_cast_explicit(struct Mem *mem, enum field_type type);
@@ -722,27 +707,6 @@ mem_get_bool_unsafe(const struct Mem *mem)
 	return b;
 }
 
-/**
- * Return value for MEM of STRING type if MEM contains a NULL-terminated string.
- * Otherwise convert value of the MEM to NULL-terminated string if possible and
- * return converted value. Original MEM is not changed.
- */
-int
-mem_get_str0(const struct Mem *mem, const char **s);
-
-/**
- * Return value for MEM of STRING type if MEM contains NULL-terminated string.
- * Otherwise convert MEM to MEM of string type that contains NULL-terminated
- * string and return its value. Return NULL if conversion is impossible.
- */
-static inline const char *
-mem_as_str0(struct Mem *mem)
-{
-	if (mem_to_str0(mem) != 0)
-		return NULL;
-	return mem->z;
-}
-
 /**
  * Return value for MEM of VARBINARY type. For MEM of all other types convert
  * value of the MEM to VARBINARY if possible and return converted value.
diff --git a/src/box/sql/printf.c b/src/box/sql/printf.c
index 5b61646e3..8da7c9878 100644
--- a/src/box/sql/printf.c
+++ b/src/box/sql/printf.c
@@ -160,8 +160,20 @@ getTextArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	struct Mem *mem = &p->apArg[p->nUsed++];
-	return (char *)mem_as_str0(mem);
+	struct Mem mem;
+	mem_create(&mem);
+	mem_copy_as_ephemeral(&mem, &p->apArg[p->nUsed++]);
+	if (mem_to_str(&mem) != 0) {
+		mem_destroy(&mem);
+		return NULL;
+	}
+	char *str = sqlDbMallocRawNN(sql_get(), mem.n + 1);
+	if (str == NULL)
+		return NULL;
+	memcpy(str, mem.z, mem.n);
+	str[mem.n] = '\0';
+	mem_destroy(&mem);
+	return str;
 }
 
 /*
@@ -677,6 +689,7 @@ sqlVXPrintf(StrAccum * pAccum,	/* Accumulate results here */
 			if (bArgList) {
 				bufpt = getTextArg(pArgList);
 				c = bufpt ? bufpt[0] : 0;
+				zExtra = bufpt;
 			} else {
 				c = va_arg(ap, int);
 			}
@@ -697,7 +710,7 @@ sqlVXPrintf(StrAccum * pAccum,	/* Accumulate results here */
 		case etDYNSTRING:
 			if (bArgList) {
 				bufpt = getTextArg(pArgList);
-				xtype = etSTRING;
+				xtype = etDYNSTRING;
 			} else {
 				bufpt = va_arg(ap, char *);
 			}
@@ -727,6 +740,7 @@ sqlVXPrintf(StrAccum * pAccum,	/* Accumulate results here */
 
 				if (bArgList) {
 					escarg = getTextArg(pArgList);
+					zExtra = escarg;
 				} else {
 					escarg = va_arg(ap, char *);
 				}
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 106555bb1..48e687d49 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -260,6 +260,9 @@ vdbe_metadata_set_col_autoincrement(struct Vdbe *p, int idx);
 int
 vdbe_metadata_set_col_span(struct Vdbe *p, int idx, const char *span);
 
+const struct Mem *
+vdbe_get_bound_value(struct Vdbe *vdbe, int id);
+
 void sqlVdbeCountChanges(Vdbe *);
 sql *sqlVdbeDb(Vdbe *);
 void sqlVdbeSetSql(Vdbe *, const char *z, int n);
@@ -268,7 +271,6 @@ void sqlVdbeSwap(Vdbe *, Vdbe *);
 struct VdbeOp *
 sqlVdbeTakeOpArray(struct Vdbe *p, int *pnOp);
 
-sql_value *sqlVdbeGetBoundValue(Vdbe *, int);
 char *sqlVdbeExpandSql(Vdbe *, const char *);
 
 /**
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index b71f65966..109ab1446 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -2285,31 +2285,12 @@ sqlVdbeDb(Vdbe * v)
 	return v->db;
 }
 
-/*
- * Return a pointer to an sql_value structure containing the value bound
- * parameter iVar of VM v. Except, if the value is an SQL NULL, return
- * 0 instead. Unless it is NULL, apply type to the value before returning it.
- *
- * The returned value must be freed by the caller using sqlValueFree().
- */
-sql_value *
-sqlVdbeGetBoundValue(struct Vdbe *v, int iVar)
-{
-	assert(iVar > 0);
-	if (v) {
-		Mem *pMem = &v->aVar[iVar - 1];
-		if (!mem_is_null(pMem)) {
-			sql_value *pRet = sqlValueNew(v->db);
-			if (pRet == NULL)
-				return NULL;
-			if (mem_copy(pRet, pMem) != 0) {
-				sqlValueFree(pRet);
-				return NULL;
-			}
-			return pRet;
-		}
-	}
-	return 0;
+const struct Mem *
+vdbe_get_bound_value(struct Vdbe *vdbe, int id)
+{
+	if (vdbe == NULL || id < 0 || id >= vdbe->nVar)
+		return NULL;
+	return &vdbe->aVar[id];
 }
 
 void
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index 6849f13ec..08a1b4e3a 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -268,7 +268,6 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 	int cnt;
 	/* Database connection. */
 	sql *db = pParse->db;
-	sql_value *pVal = 0;
 	/* Opcode of pRight. */
 	int op;
 	/* Result code to return. */
@@ -306,13 +305,22 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 		return 0;
 
 	op = pRight->op;
+	struct region *region = &pParse->region;
+	size_t svp = region_used(region);
 	if (op == TK_VARIABLE) {
 		Vdbe *pReprepare = pParse->pReprepare;
 		int iCol = pRight->iColumn;
-		pVal = sqlVdbeGetBoundValue(pReprepare, iCol);
-		if (pVal != NULL && mem_is_str(pVal)) {
-			if (mem_as_str0(pVal) == NULL)
+		const struct Mem *var = vdbe_get_bound_value(pReprepare, iCol);
+		if (var != NULL && mem_is_str(var)) {
+			uint32_t size = var->n + 1;
+			char *str = region_alloc(region, size);
+			if (str == NULL) {
+				diag_set(OutOfMemory, size, "region", "str");
 				return -1;
+			}
+			memcpy(str, var->z, var->n);
+			str[var->n] = '\0';
+			z = str;
 		}
 		assert(pRight->op == TK_VARIABLE || pRight->op == TK_REGISTER);
 	} else if (op == TK_STRING) {
@@ -356,8 +364,8 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 		}
 	}
 
+	region_truncate(region, svp);
 	rc = (z != 0);
-	sqlValueFree(pVal);
 	return rc;
 }
 
-- 
2.25.1


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

* [Tarantool-patches] [PATCH v1 21/21] sql: make arguments to be const
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (19 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 20/21] sql: remove MEM_Term flag Mergen Imeev via Tarantool-patches
@ 2021-11-11 10:49 ` Mergen Imeev via Tarantool-patches
  2021-11-11 11:00 ` [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Kirill Yukhin via Tarantool-patches
  21 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-11-11 10:49 UTC (permalink / raw)
  To: kyukhin; +Cc: tarantool-patches

This patch forces SQL built-in function implementations to accept
'const struct Mem *' instead of just 'struct Mem *'.

Needed for #4145
---
 src/box/sql/func.c   | 94 ++++++++++++++++++++++----------------------
 src/box/sql/sqlInt.h |  4 +-
 2 files changed, 50 insertions(+), 48 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index a0e599b5e..8fb225c0c 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -55,7 +55,7 @@ static struct func_sql_builtin **functions;
 
 /** Implementation of the SUM() function. */
 static void
-step_sum(struct sql_context *ctx, int argc, struct Mem *argv)
+step_sum(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
@@ -70,7 +70,7 @@ step_sum(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the TOTAL() function. */
 static void
-step_total(struct sql_context *ctx, int argc, struct Mem *argv)
+step_total(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
@@ -95,7 +95,7 @@ fin_total(struct Mem *mem)
 
 /** Implementation of the AVG() function. */
 static void
-step_avg(struct sql_context *ctx, int argc, struct Mem *argv)
+step_avg(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
@@ -143,7 +143,7 @@ fin_avg(struct Mem *mem)
 
 /** Implementation of the COUNT() function. */
 static void
-step_count(struct sql_context *ctx, int argc, struct Mem *argv)
+step_count(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 0 || argc == 1);
 	if (mem_is_null(ctx->pOut))
@@ -166,7 +166,7 @@ fin_count(struct Mem *mem)
 
 /** Implementation of the MIN() and MAX() functions. */
 static void
-step_minmax(struct sql_context *ctx, int argc, struct Mem *argv)
+step_minmax(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
@@ -199,7 +199,7 @@ step_minmax(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the GROUP_CONCAT() function. */
 static void
-step_group_concat(struct sql_context *ctx, int argc, struct Mem *argv)
+step_group_concat(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1 || argc == 2);
 	(void)argc;
@@ -234,11 +234,11 @@ step_group_concat(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementations of the ABS() function. */
 static void
-func_abs_int(struct sql_context *ctx, int argc, struct Mem *argv)
+func_abs_int(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_int(arg));
@@ -247,11 +247,11 @@ func_abs_int(struct sql_context *ctx, int argc, struct Mem *argv)
 }
 
 static void
-func_abs_double(struct sql_context *ctx, int argc, struct Mem *argv)
+func_abs_double(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_double(arg));
@@ -260,11 +260,11 @@ func_abs_double(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the CHAR_LENGTH() function. */
 static void
-func_char_length(struct sql_context *ctx, int argc, struct Mem *argv)
+func_char_length(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_str(arg) && arg->n >= 0);
@@ -280,11 +280,11 @@ func_char_length(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the UPPER() and LOWER() functions. */
 static void
-func_lower_upper(struct sql_context *ctx, int argc, struct Mem *argv)
+func_lower_upper(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_str(arg) && arg->n >= 0);
@@ -333,7 +333,7 @@ func_lower_upper(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the NULLIF() function. */
 static void
-func_nullif(struct sql_context *ctx, int argc, struct Mem *argv)
+func_nullif(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 2);
 	(void)argc;
@@ -382,7 +382,7 @@ trim_bin_start(const char *str, int end, const char *octets, int octets_size,
 }
 
 static void
-func_trim_bin(struct sql_context *ctx, int argc, struct Mem *argv)
+func_trim_bin(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	if (mem_is_null(&argv[0]) || (argc == 3 && mem_is_null(&argv[2])))
 		return;
@@ -461,7 +461,7 @@ trim_str_start(const char *str, int end, const char *chars, uint8_t *chars_len,
 }
 
 static void
-func_trim_str(struct sql_context *ctx, int argc, struct Mem *argv)
+func_trim_str(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	if (mem_is_null(&argv[0]) || (argc == 3 && mem_is_null(&argv[2])))
 		return;
@@ -511,7 +511,7 @@ func_trim_str(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the POSITION() function. */
 static void
-func_position_octets(struct sql_context *ctx, int argc, struct Mem *argv)
+func_position_octets(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 2);
 	(void)argc;
@@ -530,7 +530,8 @@ func_position_octets(struct sql_context *ctx, int argc, struct Mem *argv)
 }
 
 static void
-func_position_characters(struct sql_context *ctx, int argc, struct Mem *argv)
+func_position_characters(struct sql_context *ctx, int argc,
+			 const struct Mem *argv)
 {
 	assert(argc == 2);
 	(void)argc;
@@ -610,7 +611,7 @@ substr_normalize(int64_t base_start, bool is_start_neg, uint64_t base_length,
 }
 
 static void
-func_substr_octets(struct sql_context *ctx, int argc, struct Mem *argv)
+func_substr_octets(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 2 || argc == 3);
 	if (mem_is_any_null(&argv[0], &argv[1]))
@@ -666,7 +667,8 @@ func_substr_octets(struct sql_context *ctx, int argc, struct Mem *argv)
 }
 
 static void
-func_substr_characters(struct sql_context *ctx, int argc, struct Mem *argv)
+func_substr_characters(struct sql_context *ctx, int argc, const
+		       struct Mem *argv)
 {
 	assert(argc == 2 || argc == 3);
 	(void)argc;
@@ -739,7 +741,7 @@ func_substr_characters(struct sql_context *ctx, int argc, struct Mem *argv)
  * Symbol '\0' used instead of NULL argument.
  */
 static void
-func_char(struct sql_context *ctx, int argc, struct Mem *argv)
+func_char(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	if (argc == 0)
 		return mem_set_str_static(ctx->pOut, "", 0);
@@ -789,7 +791,7 @@ func_char(struct sql_context *ctx, int argc, struct Mem *argv)
  * The LEAST() function returns the smallest of the given arguments.
  */
 static void
-func_greatest_least(struct sql_context *ctx, int argc, struct Mem *argv)
+func_greatest_least(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc > 1);
 	int mask = ctx->func->def->name[0] == 'G' ? -1 : 0;
@@ -821,11 +823,11 @@ static const char hexdigits[] = {
 };
 
 static void
-func_hex(struct sql_context *ctx, int argc, struct Mem *argv)
+func_hex(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 
@@ -849,11 +851,11 @@ func_hex(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the OCTET_LENGTH() function. */
 static void
-func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
+func_octet_length(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_bytes(arg) && arg->n >= 0);
@@ -862,7 +864,7 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the PRINTF() function. */
 static void
-func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
+func_printf(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	if (argc < 1 || mem_is_null(&argv[0]))
 		return;
@@ -891,7 +893,7 @@ func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
  * This function returns a random INT64 value.
  */
 static void
-func_random(struct sql_context *ctx, int argc, struct Mem *argv)
+func_random(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	(void)argc;
 	(void)argv;
@@ -907,11 +909,11 @@ func_random(struct sql_context *ctx, int argc, struct Mem *argv)
  * specified as an argument of the function.
  */
 static void
-func_randomblob(struct sql_context *ctx, int argc, struct Mem *argv)
+func_randomblob(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	assert(mem_is_null(arg) || mem_is_int(arg));
 	if (mem_is_null(arg) || !mem_is_uint(arg))
 		return;
@@ -934,11 +936,11 @@ func_randomblob(struct sql_context *ctx, int argc, struct Mem *argv)
  * is specified as an argument of the function.
  */
 static void
-func_zeroblob(struct sql_context *ctx, int argc, struct Mem *argv)
+func_zeroblob(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	assert(mem_is_null(arg) || mem_is_int(arg));
 	if (mem_is_null(arg) || !mem_is_uint(arg))
 		return;
@@ -955,7 +957,7 @@ func_zeroblob(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the TYPEOF() function. */
 static void
-func_typeof(struct sql_context *ctx, int argc, struct Mem *argv)
+func_typeof(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
@@ -964,7 +966,7 @@ func_typeof(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the ROUND() function. */
 static void
-func_round(struct sql_context *ctx, int argc, struct Mem *argv)
+func_round(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1 || argc == 2);
 	if (mem_is_null(&argv[0]) || (argc == 2 && mem_is_null(&argv[1])))
@@ -990,7 +992,7 @@ func_round(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the ROW_COUNT() function. */
 static void
-func_row_count(struct sql_context *ctx, int argc, struct Mem *argv)
+func_row_count(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	(void)argc;
 	(void)argv;
@@ -1004,7 +1006,7 @@ func_row_count(struct sql_context *ctx, int argc, struct Mem *argv)
  * Returns a randomly generated UUID value.
  */
 static void
-func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
+func_uuid(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	if (argc == 1) {
 		if (mem_is_null(&argv[0]))
@@ -1023,7 +1025,7 @@ func_uuid(struct sql_context *ctx, int argc, struct Mem *argv)
 
 /** Implementation of the VERSION() function. */
 static void
-func_version(struct sql_context *ctx, int argc, struct Mem *argv)
+func_version(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	(void)argc;
 	(void)argv;
@@ -1037,11 +1039,11 @@ func_version(struct sql_context *ctx, int argc, struct Mem *argv)
  * string.
  */
 static void
-func_unicode(struct sql_context *ctx, int argc, struct Mem *argv)
+func_unicode(struct sql_context *ctx, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	(void)argc;
-	struct Mem *arg = &argv[0];
+	const struct Mem *arg = &argv[0];
 	if (mem_is_null(arg))
 		return;
 	assert(mem_is_str(arg));
@@ -1274,7 +1276,7 @@ sql_utf8_pattern_compare(const char *pattern,
  * is NULL then result is NULL as well.
  */
 static void
-likeFunc(sql_context *context, int argc, struct Mem *argv)
+likeFunc(sql_context *context, int argc, const struct Mem *argv)
 {
 	u32 escape = SQL_END_OF_STRING;
 	int nPat;
@@ -1343,7 +1345,7 @@ likeFunc(sql_context *context, int argc, struct Mem *argv)
  * single-quote escapes.
  */
 static void
-quoteFunc(struct sql_context *context, int argc, struct Mem *argv)
+quoteFunc(struct sql_context *context, int argc, const struct Mem *argv)
 {
 	assert(argc == 1);
 	UNUSED_PARAMETER(argc);
@@ -1428,7 +1430,7 @@ quoteFunc(struct sql_context *context, int argc, struct Mem *argv)
  * must be exact.  Collating sequences are not used.
  */
 static void
-replaceFunc(struct sql_context *context, int argc, struct Mem *argv)
+replaceFunc(struct sql_context *context, int argc, const struct Mem *argv)
 {
 	const unsigned char *zStr;	/* The input string A */
 	const unsigned char *zPattern;	/* The pattern string B */
@@ -1503,7 +1505,7 @@ replaceFunc(struct sql_context *context, int argc, struct Mem *argv)
  * soundex encoding of the string X.
  */
 static void
-soundexFunc(struct sql_context *context, int argc, struct Mem *argv)
+soundexFunc(struct sql_context *context, int argc, const struct Mem *argv)
 {
 	(void) argc;
 	char zResult[8];
@@ -1576,7 +1578,7 @@ func_sql_builtin_call_stub(struct func *func, struct port *args,
 }
 
 static void
-sql_builtin_stub(sql_context *ctx, int argc, struct Mem *argv)
+sql_builtin_stub(sql_context *ctx, int argc, const struct Mem *argv)
 {
 	(void) argc; (void) argv;
 	diag_set(ClientError, ER_SQL_EXECUTE,
@@ -1678,7 +1680,7 @@ struct sql_func_definition {
 	/** Type of the result of the implementation. */
 	enum field_type result;
 	/** Call implementation with given arguments. */
-	void (*call)(sql_context *ctx, int argc, struct Mem *argv);
+	void (*call)(sql_context *ctx, int argc, const struct Mem *argv);
 	/** Call finalization function for this implementation. */
 	int (*finalize)(struct Mem *mem);
 };
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 148350d05..dcd71e5bd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2447,7 +2447,7 @@ struct PrintfArguments {
 	int nArg;		/* Total number of arguments */
 	int nUsed;		/* Number of arguments used so far */
 	/** The argument values. */
-	struct Mem *apArg;
+	const struct Mem *apArg;
 };
 
 void sqlVXPrintf(StrAccum *, const char *, va_list);
@@ -4270,7 +4270,7 @@ struct func_sql_builtin {
 	 * Access checks are redundant, because all SQL built-ins
 	 * are predefined and are executed on SQL privilege level.
 	 */
-	void (*call)(struct sql_context *ctx, int argc, struct Mem *argv);
+	void (*call)(struct sql_context *ctx, int argc, const struct Mem *argv);
 	/**
 	 * A VDBE-memory-compatible finalize method
 	 * (is valid only for aggregate function).
-- 
2.25.1


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

* Re: [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions
  2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
                   ` (20 preceding siblings ...)
  2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 21/21] sql: make arguments to be const Mergen Imeev via Tarantool-patches
@ 2021-11-11 11:00 ` Kirill Yukhin via Tarantool-patches
  21 siblings, 0 replies; 26+ messages in thread
From: Kirill Yukhin via Tarantool-patches @ 2021-11-11 11:00 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

Hello,

On 11 ноя 13:48, imeevma@tarantool.org wrote:
> This patch-set refactor the built-in SQL functions that were not refactored in
> the previous two patch-sets. It also simplifies struct Mem.
> 
> https://github.com/tarantool/tarantool/issues/4145
> https://github.com/tarantool/tarantool/tree/imeevma/gh-4145-row-sql-builtin-funcs

LGTM. I've checked your patchset into master.

--
Regards, Kirill Yukhin

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

* Re: [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function
  2021-10-14 22:44   ` Vladislav Shpilevoy via Tarantool-patches
@ 2021-10-25  8:33     ` Mergen Imeev via Tarantool-patches
  0 siblings, 0 replies; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-10-25  8:33 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

Thank you for the review! My answer, diff and new patch below. I also simplified
the code a bit.

On Fri, Oct 15, 2021 at 12:44:08AM +0200, Vladislav Shpilevoy wrote:
> Thanks for the patch!
> 
> > diff --git a/src/box/sql/func.c b/src/box/sql/func.c
> > index 863dbf1c4..f5040fb6e 100644
> > --- a/src/box/sql/func.c
> > +++ b/src/box/sql/func.c
> > @@ -846,6 +846,40 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
> >  	mem_set_uint(ctx->pOut, arg->n);
> >  }
> >  
> > +/** Implementation of the PRINTF() function. */
> > +static void
> > +func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
> > +{
> > +	if (argc < 1 || mem_is_null(&argv[0]))
> > +		return;
> > +	if (argc == 1 || !mem_is_str(&argv[0])) {
> > +		struct Mem *mem = ctx->pOut;
> > +		if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0)
> > +			ctx->is_aborted = true;
> > +		return;
> > +	}
> > +	struct PrintfArguments pargs;
> > +	struct StrAccum acc;
> > +	char *format = argv[0].z;
> > +	struct sql *db = sql_get();
> > +
> > +	pargs.nArg = argc - 1;
> > +	pargs.nUsed = 0;
> > +	pargs.apArg = sqlDbMallocRawNN(db, (argc - 1) * sizeof(*pargs.apArg));
> > +	if (pargs.apArg == NULL) {
> > +		ctx->is_aborted = true;
> > +		return;
> > +	}
> > +	for (int i = 1; i < argc; ++i)
> > +		pargs.apArg[i - 1] = &argv[i];
> > +	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
> > +	acc.printfFlags = SQL_PRINTF_SQLFUNC;
> > +	sqlXPrintf(&acc, format, &pargs);
> > +	sqlDbFree(db, pargs.apArg);
> > +	if (mem_copy_str(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar) != 0)
> 
> It leaks now, because sqlStrAccumFinish is not destroyed. Previously it
> was 'moved' into the mem via SQL_DYNAMIC. But now you copy it and the
> original is not freed.
Thanks, fixed.


Diff:

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 48d248568..de2bbb20e 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -861,23 +861,14 @@ func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
 	struct PrintfArguments pargs;
 	struct StrAccum acc;
 	char *format = argv[0].z;
-	struct sql *db = sql_get();
-
 	pargs.nArg = argc - 1;
 	pargs.nUsed = 0;
-	pargs.apArg = sqlDbMallocRawNN(db, (argc - 1) * sizeof(*pargs.apArg));
-	if (pargs.apArg == NULL) {
-		ctx->is_aborted = true;
-		return;
-	}
-	for (int i = 1; i < argc; ++i)
-		pargs.apArg[i - 1] = &argv[i];
+	pargs.apArg = argv + 1;
+	struct sql *db = sql_get();
 	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
 	acc.printfFlags = SQL_PRINTF_SQLFUNC;
 	sqlXPrintf(&acc, format, &pargs);
-	sqlDbFree(db, pargs.apArg);
-	if (mem_copy_str(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar) != 0)
-		ctx->is_aborted = true;
+	mem_set_str_allocated(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar);
 }
 
 static const unsigned char *
diff --git a/src/box/sql/printf.c b/src/box/sql/printf.c
index b4ab0d0f9..5b61646e3 100644
--- a/src/box/sql/printf.c
+++ b/src/box/sql/printf.c
@@ -144,7 +144,7 @@ getIntArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	return mem_get_int_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_int_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static double
@@ -152,7 +152,7 @@ getDoubleArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0.0;
-	return mem_get_double_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_double_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static char *
@@ -160,7 +160,7 @@ getTextArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	struct Mem *mem = p->apArg[p->nUsed++];
+	struct Mem *mem = &p->apArg[p->nUsed++];
 	return (char *)mem_as_str0(mem);
 }
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index cfdf71f1f..9361775b1 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2511,7 +2511,8 @@ int sqlIsNaN(double);
 struct PrintfArguments {
 	int nArg;		/* Total number of arguments */
 	int nUsed;		/* Number of arguments used so far */
-	sql_value **apArg;	/* The argument values */
+	/** The argument values. */
+	struct Mem *apArg;
 };
 
 void sqlVXPrintf(StrAccum *, const char *, va_list);


New patch:

commit 8d7ab164e7c69faf1a6f74b75deb769da0a0ee27
Author: Mergen Imeev <imeevma@gmail.com>
Date:   Tue Oct 5 18:25:55 2021 +0300

    sql: refactor PRINTF() function
    
    Part of #4145

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 8eb3400bf..de2bbb20e 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -846,6 +846,31 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uint(ctx->pOut, arg->n);
 }
 
+/** Implementation of the PRINTF() function. */
+static void
+func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	if (argc < 1 || mem_is_null(&argv[0]))
+		return;
+	if (argc == 1 || !mem_is_str(&argv[0])) {
+		struct Mem *mem = ctx->pOut;
+		if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0)
+			ctx->is_aborted = true;
+		return;
+	}
+	struct PrintfArguments pargs;
+	struct StrAccum acc;
+	char *format = argv[0].z;
+	pargs.nArg = argc - 1;
+	pargs.nUsed = 0;
+	pargs.apArg = argv + 1;
+	struct sql *db = sql_get();
+	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
+	acc.printfFlags = SQL_PRINTF_SQLFUNC;
+	sqlXPrintf(&acc, format, &pargs);
+	mem_set_str_allocated(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar);
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -940,40 +965,6 @@ typeofFunc(struct sql_context *context, int argc, struct Mem *argv)
 	sql_result_text(context, z, -1, SQL_STATIC);
 }
 
-/*
- * Implementation of the printf() function.
- */
-static void
-printfFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	PrintfArguments x;
-	StrAccum str;
-	const char *zFormat;
-	int n;
-	sql *db = sql_context_db_handle(context);
-
-	if (argc >= 1 && (zFormat = mem_as_str0(&argv[0])) != NULL) {
-		x.nArg = argc - 1;
-		x.nUsed = 0;
-		x.apArg = sqlDbMallocRawNN(sql_get(),
-					   (argc - 1) * sizeof(*x.apArg));
-		if (x.apArg == NULL) {
-			context->is_aborted = true;
-			return;
-		}
-		for (int i = 1; i < argc; ++i)
-			x.apArg[i - 1] = &argv[i];
-		sqlStrAccumInit(&str, db, 0, 0,
-				    db->aLimit[SQL_LIMIT_LENGTH]);
-		str.printfFlags = SQL_PRINTF_SQLFUNC;
-		sqlXPrintf(&str, zFormat, &x);
-		sqlDbFree(sql_get(), x.apArg);
-		n = str.nChar;
-		sql_result_text(context, sqlStrAccumFinish(&str), n,
-				    SQL_DYNAMIC);
-	}
-}
-
 /*
  * Implementation of the round() function
  */
@@ -1916,8 +1907,7 @@ static struct sql_func_definition definitions[] = {
 	 FIELD_TYPE_INTEGER, func_position_characters, NULL},
 	{"POSITION", 2, {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_INTEGER, func_position_octets, NULL},
-	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, printfFunc, 
-	 NULL},
+	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_printf, NULL},
 	{"QUOTE", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, quoteFunc, NULL},
 	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, randomFunc, NULL},
 	{"RANDOMBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
diff --git a/src/box/sql/printf.c b/src/box/sql/printf.c
index b4ab0d0f9..5b61646e3 100644
--- a/src/box/sql/printf.c
+++ b/src/box/sql/printf.c
@@ -144,7 +144,7 @@ getIntArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	return mem_get_int_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_int_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static double
@@ -152,7 +152,7 @@ getDoubleArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0.0;
-	return mem_get_double_unsafe(p->apArg[p->nUsed++]);
+	return mem_get_double_unsafe(&p->apArg[p->nUsed++]);
 }
 
 static char *
@@ -160,7 +160,7 @@ getTextArg(PrintfArguments * p)
 {
 	if (p->nArg <= p->nUsed)
 		return 0;
-	struct Mem *mem = p->apArg[p->nUsed++];
+	struct Mem *mem = &p->apArg[p->nUsed++];
 	return (char *)mem_as_str0(mem);
 }
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index cfdf71f1f..9361775b1 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -2511,7 +2511,8 @@ int sqlIsNaN(double);
 struct PrintfArguments {
 	int nArg;		/* Total number of arguments */
 	int nUsed;		/* Number of arguments used so far */
-	sql_value **apArg;	/* The argument values */
+	/** The argument values. */
+	struct Mem *apArg;
 };
 
 void sqlVXPrintf(StrAccum *, const char *, va_list);

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

* Re: [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function
  2021-10-08 17:31 ` [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function Mergen Imeev via Tarantool-patches
@ 2021-10-14 22:44   ` Vladislav Shpilevoy via Tarantool-patches
  2021-10-25  8:33     ` Mergen Imeev via Tarantool-patches
  0 siblings, 1 reply; 26+ messages in thread
From: Vladislav Shpilevoy via Tarantool-patches @ 2021-10-14 22:44 UTC (permalink / raw)
  To: imeevma; +Cc: tarantool-patches

Thanks for the patch!

> diff --git a/src/box/sql/func.c b/src/box/sql/func.c
> index 863dbf1c4..f5040fb6e 100644
> --- a/src/box/sql/func.c
> +++ b/src/box/sql/func.c
> @@ -846,6 +846,40 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
>  	mem_set_uint(ctx->pOut, arg->n);
>  }
>  
> +/** Implementation of the PRINTF() function. */
> +static void
> +func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
> +{
> +	if (argc < 1 || mem_is_null(&argv[0]))
> +		return;
> +	if (argc == 1 || !mem_is_str(&argv[0])) {
> +		struct Mem *mem = ctx->pOut;
> +		if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0)
> +			ctx->is_aborted = true;
> +		return;
> +	}
> +	struct PrintfArguments pargs;
> +	struct StrAccum acc;
> +	char *format = argv[0].z;
> +	struct sql *db = sql_get();
> +
> +	pargs.nArg = argc - 1;
> +	pargs.nUsed = 0;
> +	pargs.apArg = sqlDbMallocRawNN(db, (argc - 1) * sizeof(*pargs.apArg));
> +	if (pargs.apArg == NULL) {
> +		ctx->is_aborted = true;
> +		return;
> +	}
> +	for (int i = 1; i < argc; ++i)
> +		pargs.apArg[i - 1] = &argv[i];
> +	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
> +	acc.printfFlags = SQL_PRINTF_SQLFUNC;
> +	sqlXPrintf(&acc, format, &pargs);
> +	sqlDbFree(db, pargs.apArg);
> +	if (mem_copy_str(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar) != 0)

It leaks now, because sqlStrAccumFinish is not destroyed. Previously it
was 'moved' into the mem via SQL_DYNAMIC. But now you copy it and the
original is not freed.

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

* [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function
  2021-10-08 17:31 Mergen Imeev via Tarantool-patches
@ 2021-10-08 17:31 ` Mergen Imeev via Tarantool-patches
  2021-10-14 22:44   ` Vladislav Shpilevoy via Tarantool-patches
  0 siblings, 1 reply; 26+ messages in thread
From: Mergen Imeev via Tarantool-patches @ 2021-10-08 17:31 UTC (permalink / raw)
  To: v.shpilevoy; +Cc: tarantool-patches

Part of #4145
---
 src/box/sql/func.c | 71 +++++++++++++++++++++++-----------------------
 1 file changed, 35 insertions(+), 36 deletions(-)

diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 863dbf1c4..f5040fb6e 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -846,6 +846,40 @@ func_octet_length(struct sql_context *ctx, int argc, struct Mem *argv)
 	mem_set_uint(ctx->pOut, arg->n);
 }
 
+/** Implementation of the PRINTF() function. */
+static void
+func_printf(struct sql_context *ctx, int argc, struct Mem *argv)
+{
+	if (argc < 1 || mem_is_null(&argv[0]))
+		return;
+	if (argc == 1 || !mem_is_str(&argv[0])) {
+		struct Mem *mem = ctx->pOut;
+		if (mem_copy(mem, &argv[0]) != 0 || mem_to_str(mem) != 0)
+			ctx->is_aborted = true;
+		return;
+	}
+	struct PrintfArguments pargs;
+	struct StrAccum acc;
+	char *format = argv[0].z;
+	struct sql *db = sql_get();
+
+	pargs.nArg = argc - 1;
+	pargs.nUsed = 0;
+	pargs.apArg = sqlDbMallocRawNN(db, (argc - 1) * sizeof(*pargs.apArg));
+	if (pargs.apArg == NULL) {
+		ctx->is_aborted = true;
+		return;
+	}
+	for (int i = 1; i < argc; ++i)
+		pargs.apArg[i - 1] = &argv[i];
+	sqlStrAccumInit(&acc, db, 0, 0, db->aLimit[SQL_LIMIT_LENGTH]);
+	acc.printfFlags = SQL_PRINTF_SQLFUNC;
+	sqlXPrintf(&acc, format, &pargs);
+	sqlDbFree(db, pargs.apArg);
+	if (mem_copy_str(ctx->pOut, sqlStrAccumFinish(&acc), acc.nChar) != 0)
+		ctx->is_aborted = true;
+}
+
 static const unsigned char *
 mem_as_ustr(struct Mem *mem)
 {
@@ -940,40 +974,6 @@ typeofFunc(struct sql_context *context, int argc, struct Mem *argv)
 	sql_result_text(context, z, -1, SQL_STATIC);
 }
 
-/*
- * Implementation of the printf() function.
- */
-static void
-printfFunc(struct sql_context *context, int argc, struct Mem *argv)
-{
-	PrintfArguments x;
-	StrAccum str;
-	const char *zFormat;
-	int n;
-	sql *db = sql_context_db_handle(context);
-
-	if (argc >= 1 && (zFormat = mem_as_str0(&argv[0])) != NULL) {
-		x.nArg = argc - 1;
-		x.nUsed = 0;
-		x.apArg = sqlDbMallocRawNN(sql_get(),
-					   (argc - 1) * sizeof(*x.apArg));
-		if (x.apArg == NULL) {
-			context->is_aborted = true;
-			return;
-		}
-		for (int i = 1; i < argc; ++i)
-			x.apArg[i - 1] = &argv[i];
-		sqlStrAccumInit(&str, db, 0, 0,
-				    db->aLimit[SQL_LIMIT_LENGTH]);
-		str.printfFlags = SQL_PRINTF_SQLFUNC;
-		sqlXPrintf(&str, zFormat, &x);
-		sqlDbFree(sql_get(), x.apArg);
-		n = str.nChar;
-		sql_result_text(context, sqlStrAccumFinish(&str), n,
-				    SQL_DYNAMIC);
-	}
-}
-
 /*
  * Implementation of the round() function
  */
@@ -1916,8 +1916,7 @@ static struct sql_func_definition definitions[] = {
 	 FIELD_TYPE_INTEGER, func_position_characters, NULL},
 	{"POSITION", 2, {FIELD_TYPE_VARBINARY, FIELD_TYPE_VARBINARY},
 	 FIELD_TYPE_INTEGER, func_position_octets, NULL},
-	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, printfFunc, 
-	 NULL},
+	{"PRINTF", -1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, func_printf, NULL},
 	{"QUOTE", 1, {FIELD_TYPE_ANY}, FIELD_TYPE_STRING, quoteFunc, NULL},
 	{"RANDOM", 0, {}, FIELD_TYPE_INTEGER, randomFunc, NULL},
 	{"RANDOMBLOB", 1, {FIELD_TYPE_INTEGER}, FIELD_TYPE_VARBINARY,
-- 
2.25.1


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

end of thread, other threads:[~2021-11-11 11:03 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-11 10:48 [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 01/21] sql: rework CHAR() function Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 02/21] sql: refactor GREATEST() and LEAST() functions Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 03/21] sql: refactor HEX() function Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 04/21] sql: refactor LENGTH() function Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function Mergen Imeev via Tarantool-patches
2021-11-11 10:48 ` [Tarantool-patches] [PATCH v1 06/21] sql: refactor RANDOM() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 07/21] sql: rework RANDOMBLOB() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 08/21] sql: refactor ZEROBLOB() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 09/21] sql: refactor TYPEOF() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 10/21] sql: refactor ROUND() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 11/21] sql: refactor ROW_COUNT() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 12/21] sql: rework UUID() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 13/21] sql: refactor VERSION() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 14/21] sql: refactor UNICODE() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 15/21] sql: refactor SOUNDEX() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 16/21] sql: refactor REPLACE() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 17/21] sql: refactor QUOTE() function Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 18/21] sql: remove unused code Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 19/21] sql: remove MEM_Dyn flag Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 20/21] sql: remove MEM_Term flag Mergen Imeev via Tarantool-patches
2021-11-11 10:49 ` [Tarantool-patches] [PATCH v1 21/21] sql: make arguments to be const Mergen Imeev via Tarantool-patches
2021-11-11 11:00 ` [Tarantool-patches] [PATCH v1 00/21] Refactor non-standard and non-aggragate functions Kirill Yukhin via Tarantool-patches
  -- strict thread matches above, loose matches on Subject: below --
2021-10-08 17:31 Mergen Imeev via Tarantool-patches
2021-10-08 17:31 ` [Tarantool-patches] [PATCH v1 05/21] sql: refactor PRINTF() function Mergen Imeev via Tarantool-patches
2021-10-14 22:44   ` Vladislav Shpilevoy via Tarantool-patches
2021-10-25  8:33     ` Mergen Imeev via Tarantool-patches

Tarantool development patches archive

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://lists.tarantool.org/tarantool-patches/0 tarantool-patches/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 tarantool-patches tarantool-patches/ https://lists.tarantool.org/tarantool-patches \
		tarantool-patches@dev.tarantool.org.
	public-inbox-index tarantool-patches

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git