From ca18b29886e5486fa95f4b820b3c572e7a244b04 Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Mon, 6 Sep 2021 13:49:47 +0300
Subject: [PATCH] sql: introduce mem_append()

This patch introduces the mem_append() function. This function appends
the specified string to the end of the STRING or VARBINARY contained in
MEM. In case MEM needs to increase the size of allocated memory,
extra memory is allocated in an attempt to reduce the total number of
allocations.

Needed for #4145
---
 src/box/sql/mem.c     | 21 +++++++++++++++++++++
 src/box/sql/mem.h     |  8 ++++++++
 src/box/sql/vdbeaux.c |  9 ++-------
 3 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/src/box/sql/mem.c b/src/box/sql/mem.c
index 99ac4d8e72..44ac5ad1e5 100644
--- a/src/box/sql/mem.c
+++ b/src/box/sql/mem.c
@@ -1929,6 +1929,27 @@ mem_move(struct Mem *to, struct Mem *from)
 	from->zMalloc = NULL;
 }
 
+int
+mem_append(struct Mem *mem, const char *value, uint32_t len)
+{
+	assert((mem->type & (MEM_TYPE_BIN | MEM_TYPE_STR)) != 0);
+	if (len == 0)
+		return 0;
+	int new_size = mem->n + len;
+	if (((mem->flags & (MEM_Static | MEM_Dyn | MEM_Ephem)) != 0) ||
+	    mem->szMalloc < new_size) {
+		/*
+		 * Force exponential buffer size growth to avoid having to call
+		 * this routine too often.
+		 */
+		if (sqlVdbeMemGrow(mem, new_size + mem->n, 1) != 0)
+			return -1;
+	}
+	memcpy(&mem->z[mem->n], value, len);
+	mem->n = new_size;
+	return 0;
+}
+
 int
 mem_concat(const struct Mem *a, const struct Mem *b, struct Mem *result)
 {
diff --git a/src/box/sql/mem.h b/src/box/sql/mem.h
index 1574da22d9..b567aea50d 100644
--- a/src/box/sql/mem.h
+++ b/src/box/sql/mem.h
@@ -582,6 +582,14 @@ mem_copy_as_ephemeral(struct Mem *to, const struct Mem *from);
 void
 mem_move(struct Mem *to, struct Mem *from);
 
+/**
+ * Append the given string to the end of the STRING or VARBINARY contained in
+ * MEM. In case MEM needs to increase the size of allocated memory, additional
+ * memory is allocated in an attempt to reduce the total number of allocations.
+ */
+int
+mem_append(struct Mem *mem, const char *value, uint32_t len);
+
 /**
  * Concatenate strings or binaries from the first and the second MEMs and write
  * to the result MEM. In case the first MEM or the second MEM is NULL, the
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index 4c2bd11ba9..3015760e1a 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1294,14 +1294,9 @@ sqlVdbeList(Vdbe * p)
 					if (mem_copy_bin(pSub, bin, size) != 0)
 						return -1;
 				} else if (j == nSub) {
-					struct Mem tmp;
-					mem_create(&tmp);
-					uint32_t size = sizeof(SubProgram *);
 					char *bin = (char *)&pOp->p4.pProgram;
-					mem_set_bin_ephemeral(&tmp, bin, size);
-					int rc = mem_concat(pSub, &tmp, pSub);
-					mem_destroy(&tmp);
-					if (rc != 0)
+					uint32_t size = sizeof(SubProgram *);
+					if (mem_append(pSub, bin, size) != 0)
 						return -1;
 				}
 			}
-- 
GitLab