[Tarantool-patches] [PATCH v2 1/6] sql: refactor resulting set metadata

Nikita Pettik korablev at tarantool.org
Wed Dec 11 16:44:53 MSK 2019


Move names and types of resulting set to a separate structure. Simplify
their storage by introducing separate members for name and type
(previously names and types were stored in one char * array). It will
allow us to add new metadata properties with ease.

Needed for #4407
---
 src/box/sql/delete.c  |  6 ++--
 src/box/sql/insert.c  |  5 ++--
 src/box/sql/legacy.c  |  2 +-
 src/box/sql/pragma.c  | 14 ++++-----
 src/box/sql/prepare.c |  9 +++---
 src/box/sql/select.c  | 81 ++++++++++++++++++++++++++-------------------------
 src/box/sql/update.c  |  6 ++--
 src/box/sql/vdbe.h    | 28 ++++++++++--------
 src/box/sql/vdbeInt.h |  8 ++++-
 src/box/sql/vdbeapi.c | 81 +++++++++------------------------------------------
 src/box/sql/vdbeaux.c | 81 +++++++++++++++++++++++++++------------------------
 11 files changed, 137 insertions(+), 184 deletions(-)

diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 91c2157ac..169814a2e 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -418,10 +418,8 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 	    parse->triggered_space != NULL) {
 		sqlVdbeAddOp2(v, OP_ResultRow, reg_count, 1);
 		sqlVdbeSetNumCols(v, 1);
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, "rows deleted",
-				      SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "integer",
-				  SQL_STATIC);
+		vdbe_metadata_set_col_name(v, 0, "rows deleted");
+		vdbe_metadata_set_col_type(v, 0, "integer");
 	}
 
  delete_from_cleanup:
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 70504c800..f1290e01c 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -785,9 +785,8 @@ sqlInsert(Parse * pParse,	/* Parser context */
 			column_name = "rows replaced";
 		else
 			column_name = "rows inserted";
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, column_name, SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "integer",
-				  SQL_STATIC);
+		vdbe_metadata_set_col_name(v, 0, column_name);
+		vdbe_metadata_set_col_type(v, 0, "integer");
 	}
 
  insert_cleanup:
diff --git a/src/box/sql/legacy.c b/src/box/sql/legacy.c
index 0b1370f4a..8eec096bf 100644
--- a/src/box/sql/legacy.c
+++ b/src/box/sql/legacy.c
@@ -103,7 +103,7 @@ sql_exec(sql * db,	/* The database on which the SQL executes */
 						    (char *)
 						    sql_column_name(pStmt,
 									i);
-						/* sqlVdbeSetColName() installs column names as UTF8
+						/* vdbe_metadata_set_col_name() installs column names as UTF8
 						 * strings so there is no way for sql_column_name() to fail.
 						 */
 						assert(azCols[i] != 0);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 92bcf4e68..00ecde0a9 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -120,10 +120,8 @@ vdbe_set_pragma_result_columns(struct Vdbe *v, const struct PragmaName *pragma)
 	assert(n > 0);
 	sqlVdbeSetNumCols(v, n);
 	for (int i = 0, j = pragma->iPragCName; i < n; ++i) {
-		sqlVdbeSetColName(v, i, COLNAME_NAME, pragCName[j++],
-				  SQL_STATIC);
-		sqlVdbeSetColName(v, i, COLNAME_DECLTYPE, pragCName[j++],
-				  SQL_STATIC);
+		vdbe_metadata_set_col_name(v, i, pragCName[j++]);
+		vdbe_metadata_set_col_type(v, i, pragCName[j++]);
 	}
 }
 
@@ -168,10 +166,10 @@ vdbe_emit_pragma_status(struct Parse *parse)
 	struct session *user_session = current_session();
 
 	sqlVdbeSetNumCols(v, 2);
-	sqlVdbeSetColName(v, 0, COLNAME_NAME, "pragma_name", SQL_STATIC);
-	sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "text", SQL_STATIC);
-	sqlVdbeSetColName(v, 1, COLNAME_NAME, "pragma_value", SQL_STATIC);
-	sqlVdbeSetColName(v, 1, COLNAME_DECLTYPE, "integer", SQL_STATIC);
+	vdbe_metadata_set_col_name(v, 0, "pragma_name");
+	vdbe_metadata_set_col_type(v, 0, "text");
+	vdbe_metadata_set_col_name(v, 1, "pragma_value");
+	vdbe_metadata_set_col_type(v, 1, "integer");
 
 	parse->nMem = 2;
 	for (int i = 0; i < ArraySize(aPragmaName); ++i) {
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index 0ecc676e2..39e897ba3 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -146,11 +146,10 @@ sqlPrepare(sql * db,	/* Database handle. */
 		sqlVdbeSetNumCols(sParse.pVdbe, name_count);
 		for (int i = 0; i < name_count; i++) {
 			int name_index = 2 * i + name_first;
-			sqlVdbeSetColName(sParse.pVdbe, i, COLNAME_NAME,
-					  azColName[name_index], SQL_STATIC);
-			sqlVdbeSetColName(sParse.pVdbe, i, COLNAME_DECLTYPE,
-					  azColName[name_index + 1],
-					  SQL_STATIC);
+			vdbe_metadata_set_col_name(sParse.pVdbe, i,
+						   azColName[name_index]);
+			vdbe_metadata_set_col_type(sParse.pVdbe, i,
+						   azColName[name_index + 1]);
 		}
 	}
 
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 8f93edd16..e4768121e 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1747,15 +1747,18 @@ generateSortTail(Parse * pParse,	/* Parsing context */
 	sqlVdbeResolveLabel(v, addrBreak);
 }
 
-/*
+/**
  * Generate code that will tell the VDBE the names of columns
- * in the result set.  This information is used to provide the
- * azCol[] values in the callback.
+ * in the result set. This information is used to provide the
+ * metadata during/after statement execution.
+ *
+ * @param pParse Parsing context.
+ * @param pTabList List of tables.
+ * @param pEList Expressions defining the result set.
  */
 static void
-generateColumnNames(Parse * pParse,	/* Parser context */
-		    SrcList * pTabList,	/* List of tables */
-		    ExprList * pEList)	/* Expressions defining the result set */
+generate_column_metadata(struct Parse *pParse, struct SrcList *pTabList,
+			 struct ExprList *pEList)
 {
 	Vdbe *v = pParse->pVdbe;
 	int i, j;
@@ -1789,13 +1792,9 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 			continue;
 		if (p->op == TK_VARIABLE)
 			var_pos[var_count++] = i;
-		sqlVdbeSetColName(v, i, COLNAME_DECLTYPE,
-				  field_type_strs[sql_expr_type(p)], SQL_TRANSIENT);
-		if (pEList->a[i].zName) {
-			char *zName = pEList->a[i].zName;
-			sqlVdbeSetColName(v, i, COLNAME_NAME, zName,
-					      SQL_TRANSIENT);
-		} else if (p->op == TK_COLUMN || p->op == TK_AGG_COLUMN) {
+		vdbe_metadata_set_col_type(v, i,
+					   field_type_strs[sql_expr_type(p)]);
+		if (p->op == TK_COLUMN || p->op == TK_AGG_COLUMN) {
 			char *zCol;
 			int iCol = p->iColumn;
 			for (j = 0; ALWAYS(j < pTabList->nSrc); j++) {
@@ -1806,28 +1805,30 @@ generateColumnNames(Parse * pParse,	/* Parser context */
 			struct space_def *space_def = pTabList->a[j].space->def;
 			assert(iCol >= 0 && iCol < (int)space_def->field_count);
 			zCol = space_def->fields[iCol].name;
-			if (!shortNames && !fullNames) {
-				sqlVdbeSetColName(v, i, COLNAME_NAME,
-						      sqlDbStrDup(db,
-								      pEList->a[i].zSpan),
-						      SQL_DYNAMIC);
-			} else if (fullNames) {
-				char *zName = 0;
-				zName = sqlMPrintf(db, "%s.%s",
-						       space_def->name, zCol);
-				sqlVdbeSetColName(v, i, COLNAME_NAME, zName,
-						      SQL_DYNAMIC);
+			const char *name = NULL;
+			if (pEList->a[i].zName != NULL) {
+				name = pEList->a[i].zName;
 			} else {
-				sqlVdbeSetColName(v, i, COLNAME_NAME, zCol,
-						      SQL_TRANSIENT);
+				if (!shortNames && !fullNames) {
+					name = pEList->a[i].zSpan;
+				} else if (fullNames) {
+					name = tt_sprintf("%s.%s",
+							  space_def->name,
+							  zCol);
+				} else {
+					name = zCol;
+				}
 			}
+			vdbe_metadata_set_col_name(v, i, name);
 		} else {
-			const char *z = pEList->a[i].zSpan;
-			z = z == 0 ? sqlMPrintf(db, "column%d",
-						    i + 1) : sqlDbStrDup(db,
-									     z);
-			sqlVdbeSetColName(v, i, COLNAME_NAME, z,
-					      SQL_DYNAMIC);
+			const char *z = NULL;
+			if (pEList->a[i].zName != NULL)
+				z = pEList->a[i].zName;
+			else if (pEList->a[i].zSpan != NULL)
+				z = pEList->a[i].zSpan;
+			else
+				z = tt_sprintf("column%d", i + 1);
+			vdbe_metadata_set_col_name(v, i, z);
 		}
 	}
 	if (var_count == 0)
@@ -2828,9 +2829,9 @@ multiSelect(Parse * pParse,	/* Parsing context */
 						Select *pFirst = p;
 						while (pFirst->pPrior)
 							pFirst = pFirst->pPrior;
-						generateColumnNames(pParse,
-								    pFirst->pSrc,
-								    pFirst->pEList);
+						generate_column_metadata(pParse,
+									 pFirst->pSrc,
+									 pFirst->pEList);
 					}
 					iBreak = sqlVdbeMakeLabel(v);
 					iCont = sqlVdbeMakeLabel(v);
@@ -2927,9 +2928,9 @@ multiSelect(Parse * pParse,	/* Parsing context */
 					Select *pFirst = p;
 					while (pFirst->pPrior)
 						pFirst = pFirst->pPrior;
-					generateColumnNames(pParse,
-							    pFirst->pSrc,
-							    pFirst->pEList);
+					generate_column_metadata(pParse,
+								 pFirst->pSrc,
+								 pFirst->pEList);
 				}
 				iBreak = sqlVdbeMakeLabel(v);
 				iCont = sqlVdbeMakeLabel(v);
@@ -3575,7 +3576,7 @@ multiSelectOrderBy(Parse * pParse,	/* Parsing context */
 		Select *pFirst = pPrior;
 		while (pFirst->pPrior)
 			pFirst = pFirst->pPrior;
-		generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
+		generate_column_metadata(pParse, pFirst->pSrc, pFirst->pEList);
 	}
 
 	/* Reassembly the compound query so that it will be freed correctly
@@ -6433,7 +6434,7 @@ sqlSelect(Parse * pParse,		/* The parser context */
 	/* Identify column names if results of the SELECT are to be output.
 	 */
 	if (rc == 0 && pDest->eDest == SRT_Output) {
-		generateColumnNames(pParse, pTabList, pEList);
+		generate_column_metadata(pParse, pTabList, pEList);
 	}
 
 	sqlDbFree(db, sAggInfo.aCol);
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 6d69b7252..c08777a2d 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -498,10 +498,8 @@ sqlUpdate(Parse * pParse,		/* The parser context */
 	    pParse->triggered_space == NULL) {
 		sqlVdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
 		sqlVdbeSetNumCols(v, 1);
-		sqlVdbeSetColName(v, 0, COLNAME_NAME, "rows updated",
-				      SQL_STATIC);
-		sqlVdbeSetColName(v, 0, COLNAME_DECLTYPE, "integer",
-				  SQL_STATIC);
+		vdbe_metadata_set_col_name(v, 0, "rows updated");
+		vdbe_metadata_set_col_type(v, 0, "integer");
 	}
 
  update_cleanup:
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 582d48a1f..ddced20e1 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -148,17 +148,6 @@ struct SubProgram {
 #define P5_ConstraintUnique  2
 #define P5_ConstraintFK      4
 
-/*
- * The Vdbe.aColName array contains 5n Mem structures, where n is the
- * number of columns of data returned by the statement.
- */
-#define COLNAME_NAME     0
-#define COLNAME_DECLTYPE 1
-#define COLNAME_DATABASE 2
-#define COLNAME_TABLE    3
-#define COLNAME_COLUMN   4
-#define COLNAME_N        2	/* Store the name and decltype */
-
 /*
  * The following macro converts a relative address in the p2 field
  * of a VdbeOp structure into a negative number.
@@ -238,6 +227,10 @@ sql_vdbe_set_p4_key_def(struct Parse *parse, struct key_def *key_def);
 VdbeOp *sqlVdbeGetOp(Vdbe *, int);
 int sqlVdbeMakeLabel(Vdbe *);
 void sqlVdbeRunOnlyOnce(Vdbe *);
+
+void
+vdbe_metadata_delete(struct Vdbe *v);
+
 void sqlVdbeDelete(Vdbe *);
 void sqlVdbeClearObject(sql *, Vdbe *);
 void sqlVdbeMakeReady(Vdbe *, Parse *);
@@ -248,7 +241,18 @@ void sqlVdbeResetStepResult(Vdbe *);
 void sqlVdbeRewind(Vdbe *);
 int sqlVdbeReset(Vdbe *);
 void sqlVdbeSetNumCols(Vdbe *, int);
-int sqlVdbeSetColName(Vdbe *, int, int, const char *, void (*)(void *));
+
+/**
+ * Set the name of the idx'th column to be returned by the SQL
+ * statement. @name must be a pointer to a nul terminated string.
+ * This call must be made after a call to sqlVdbeSetNumCols().
+ */
+int
+vdbe_metadata_set_col_name(struct Vdbe *v, int col_idx, const char *name);
+
+int
+vdbe_metadata_set_col_type(struct Vdbe *v, int col_idx, const char *type);
+
 void sqlVdbeCountChanges(Vdbe *);
 sql *sqlVdbeDb(Vdbe *);
 void sqlVdbeSetSql(Vdbe *, const char *z, int n, int);
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 0f32b4cd6..64250bee2 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -346,6 +346,11 @@ struct ScanStatus {
 	char *zName;		/* Name of table or index */
 };
 
+struct sql_column_metadata {
+	char *name;
+	char *type;
+};
+
 /*
  * An instance of the virtual machine.  This structure contains the complete
  * state of the virtual machine.
@@ -394,7 +399,8 @@ 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 */
-	Mem *aColName;		/* Column names to return */
+	/** SQL metadata for DML/DQL queries. */
+	struct sql_column_metadata *metadata;
 	Mem *pResultSet;	/* Pointer to an array of results */
 	VdbeCursor **apCsr;	/* One element of this array for each open cursor */
 	Mem *aVar;		/* Values for the OP_Variable opcode. */
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 685212d91..48db0bf43 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -725,77 +725,24 @@ sql_column_subtype(struct sql_stmt *stmt, int i)
 	return sql_value_subtype(columnMem(stmt, i));
 }
 
-/*
- * Convert the N-th element of pStmt->pColName[] into a string using
- * xFunc() then return that string.  If N is out of range, return 0.
- *
- * There are up to 5 names for each column.  useType determines which
- * name is returned.  Here are the names:
- *
- *    0      The column name as it should be displayed for output
- *    1      The datatype name for the column
- *    2      The name of the database that the column derives from
- *    3      The name of the table that the column derives from
- *    4      The name of the table column that the result column derives from
- *
- * If the result is not a simple column reference (if it is an expression
- * or a constant) then useTypes 2, 3, and 4 return NULL.
- */
-static const void *
-columnName(sql_stmt * pStmt,
-	   int N, const void *(*xFunc) (Mem *), int useType)
-{
-	const void *ret;
-	Vdbe *p;
-	int n;
-	sql *db;
-	ret = 0;
-	p = (Vdbe *) pStmt;
-	db = p->db;
-	assert(db != 0);
-	n = sql_column_count(pStmt);
-	if (N < n && N >= 0) {
-		N += useType * n;
-		assert(db->mallocFailed == 0);
-		ret = xFunc(&p->aColName[N]);
-		/* A malloc may have failed inside of the xFunc() call. If this
-		 * is the case, clear the mallocFailed flag and return NULL.
-		 */
-		if (db->mallocFailed) {
-			sqlOomClear(db);
-			ret = 0;
-		}
-	}
-	return ret;
-}
-
 /*
  * Return the name of the Nth column of the result set returned by SQL
  * statement pStmt.
  */
 const char *
-sql_column_name(sql_stmt * pStmt, int N)
-{
-	return columnName(pStmt, N, (const void *(*)(Mem *))sql_value_text,
-			  COLNAME_NAME);
-}
-
-const char *
-sql_column_datatype(sql_stmt *pStmt, int N)
+sql_column_name(sql_stmt *stmt, int n)
 {
-	return columnName(pStmt, N, (const void *(*)(Mem *))sql_value_text,
-			  COLNAME_DECLTYPE);
+	struct Vdbe *p = (struct Vdbe *) stmt;
+	assert(n < sql_column_count(stmt) && n >= 0);
+	return p->metadata[n].name;
 }
 
-/*
- * Return the column declaration type (if applicable) of the 'i'th column
- * of the result set of SQL statement pStmt.
- */
 const char *
-sql_column_decltype(sql_stmt * pStmt, int N)
+sql_column_datatype(sql_stmt *stmt, int n)
 {
-	return columnName(pStmt, N, (const void *(*)(Mem *))sql_value_text,
-			  COLNAME_DECLTYPE);
+	struct Vdbe *p = (struct Vdbe *) stmt;
+	assert(n < sql_column_count(stmt) && n >= 0);
+	return p->metadata[n].type;
 }
 
 /******************************* sql_bind_  **************************
@@ -853,17 +800,15 @@ sql_bind_type(struct Vdbe *v, uint32_t position, const char *type)
 	if (v->res_var_count < position)
 		return 0;
 	int rc = 0;
-	if (sqlVdbeSetColName(v, v->var_pos[position - 1], COLNAME_DECLTYPE,
-			      type, SQL_TRANSIENT) != 0)
+	if (vdbe_metadata_set_col_type(v, v->var_pos[position - 1], type) != 0)
 		rc = -1;
-	const char *bind_name = v->aColName[position - 1].z;
+	const char *bind_name = v->metadata[position - 1].name;
 	if (strcmp(bind_name, "?") == 0)
 		return rc;
 	for (uint32_t i = position; i < v->res_var_count; ++i) {
-		if (strcmp(bind_name,  v->aColName[i].z) == 0) {
-			if (sqlVdbeSetColName(v, v->var_pos[i],
-					      COLNAME_DECLTYPE, type,
-					      SQL_TRANSIENT) != 0)
+		if (strcmp(bind_name, v->metadata[i].name) == 0) {
+			if (vdbe_metadata_set_col_type(v, v->var_pos[i],
+						       type) != 0)
 				return -1;
 		}
 	}
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index a1d658648..f2cf386bb 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -1827,6 +1827,18 @@ Cleanup(Vdbe * p)
 	p->pResultSet = 0;
 }
 
+void
+vdbe_metadata_delete(struct Vdbe *v)
+{
+	if (v->metadata != NULL) {
+		for (int i = 0; i < v->nResColumn; ++i) {
+			free(v->metadata[i].name);
+			free(v->metadata[i].type);
+		}
+		free(v->metadata);
+	}
+}
+
 /*
  * Set the number of result columns that will be returned by this SQL
  * statement. This is now set at compile time, rather than during
@@ -1836,50 +1848,44 @@ Cleanup(Vdbe * p)
 void
 sqlVdbeSetNumCols(Vdbe * p, int nResColumn)
 {
-	int n;
-	sql *db = p->db;
-
-	releaseMemArray(p->aColName, p->nResColumn * COLNAME_N);
-	sqlDbFree(db, p->aColName);
-	n = nResColumn * COLNAME_N;
+	vdbe_metadata_delete(p);
 	p->nResColumn = (u16) nResColumn;
-	p->aColName = (Mem *) sqlDbMallocRawNN(db, sizeof(Mem) * n);
-	if (p->aColName == 0)
+	p->metadata = (struct sql_column_metadata *)
+		calloc(nResColumn, sizeof(struct sql_column_metadata));
+	if (p->metadata == NULL) {
+		diag_set(OutOfMemory,
+			 nResColumn * sizeof(struct sql_column_metadata),
+			 "calloc", "metadata");
 		return;
-	initMemArray(p->aColName, n, p->db, MEM_Null);
+	}
 }
 
-/*
- * Set the name of the idx'th column to be returned by the SQL statement.
- * zName must be a pointer to a nul terminated string.
- *
- * This call must be made after a call to sqlVdbeSetNumCols().
- *
- * The final parameter, xDel, must be one of SQL_DYNAMIC, SQL_STATIC
- * or SQL_TRANSIENT. If it is SQL_DYNAMIC, then the buffer pointed
- * to by zName will be freed by sqlDbFree() when the vdbe is destroyed.
- */
 int
-sqlVdbeSetColName(Vdbe * p,			/* Vdbe being configured */
-		      int idx,			/* Index of column zName applies to */
-		      int var,			/* One of the COLNAME_* constants */
-		      const char *zName,	/* Pointer to buffer containing name */
-		      void (*xDel) (void *))	/* Memory management strategy for zName */
-{
-	int rc;
-	Mem *pColName;
+vdbe_metadata_set_col_name(struct Vdbe *p, int idx, const char *name)
+{
 	assert(idx < p->nResColumn);
-	assert(var < COLNAME_N);
-	if (p->db->mallocFailed) {
-		assert(!zName || xDel != SQL_DYNAMIC);
+	if (p->metadata[idx].name != NULL)
+		free(p->metadata[idx].name);
+	p->metadata[idx].name = strdup(name);
+	if (p->metadata[idx].name == NULL) {
+		diag_set(OutOfMemory, strlen(name) + 1, "strdup", "name");
 		return -1;
 	}
-	assert(p->aColName != 0);
-	assert(var == COLNAME_NAME || var == COLNAME_DECLTYPE);
-	pColName = &(p->aColName[idx + var * p->nResColumn]);
-	rc = sqlVdbeMemSetStr(pColName, zName, -1, 1, xDel);
-	assert(rc != 0 || !zName || (pColName->flags & MEM_Term) != 0);
-	return rc;
+	return 0;
+}
+
+int
+vdbe_metadata_set_col_type(struct Vdbe *p, int idx, const char *type)
+{
+	assert(idx < p->nResColumn);
+	if (p->metadata[idx].type != NULL)
+		free(p->metadata[idx].type);
+	p->metadata[idx].type = strdup(type);
+	if (p->metadata[idx].type == NULL) {
+		diag_set(OutOfMemory, strlen(type) + 1, "strdup", "type");
+		return -1;
+	}
+	return 0;
 }
 
 /*
@@ -2230,7 +2236,7 @@ sqlVdbeClearObject(sql * db, Vdbe * p)
 {
 	SubProgram *pSub, *pNext;
 	assert(p->db == 0 || p->db == db);
-	releaseMemArray(p->aColName, p->nResColumn * COLNAME_N);
+	vdbe_metadata_delete(p);
 	for (pSub = p->pProgram; pSub; pSub = pNext) {
 		pNext = pSub->pNext;
 		vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
@@ -2242,7 +2248,6 @@ sqlVdbeClearObject(sql * db, Vdbe * p)
 		sqlDbFree(db, p->pFree);
 	}
 	vdbeFreeOpArray(db, p->aOp, p->nOp);
-	sqlDbFree(db, p->aColName);
 	sqlDbFree(db, p->zSql);
 }
 
-- 
2.15.1



More information about the Tarantool-patches mailing list