[patches] [PATCH 5/7] sql: store column meta in a special structure instead of Mem
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Wed Feb 28 22:36:52 MSK 2018
Struct Mem is a too common data structure to store column meta.
Original SQLite stores column names, table names, column type
in separate structs Mem. And to get other metadata like
nullability, belonging to a primary key, autoincrement flag it
is necessary to lookup struct Table by name, lookup column in a
table by a column name, and do this steps for each result set
column.
To speed up meta info looking up, decrease memory usage and
increase count of characteristics store meta in a special
structure that stores all needed values on creation.
Needed for #2620
Signed-off-by: Vladislav Shpilevoy <v.shpilevoy at tarantool.org>
---
src/box/sql/delete.c | 4 +-
src/box/sql/insert.c | 4 +-
src/box/sql/legacy.c | 3 -
src/box/sql/pragma.c | 8 +--
src/box/sql/prepare.c | 6 +-
src/box/sql/select.c | 143 ++++++++++++++++++++----------------------------
src/box/sql/sqlite3.h | 13 ++++-
src/box/sql/sqliteInt.h | 44 +++++++++++++++
src/box/sql/update.c | 4 +-
src/box/sql/vdbe.h | 5 +-
src/box/sql/vdbeInt.h | 3 +-
src/box/sql/vdbeapi.c | 35 ++++--------
src/box/sql/vdbeaux.c | 114 ++++++++++++++++++++++++--------------
13 files changed, 218 insertions(+), 168 deletions(-)
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 832af89fd..6f3d3f881 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -581,8 +581,8 @@ sqlite3DeleteFrom(Parse * pParse, /* The parser context */
!pParse->nested && !pParse->pTriggerTab) {
sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted",
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(v, 0, "rows deleted", SQLITE_STATIC, NULL,
+ 0);
}
delete_from_cleanup:
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index b20a47970..ac11a5f34 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -906,8 +906,8 @@ sqlite3Insert(Parse * pParse, /* Parser context */
&& !pParse->pTriggerTab) {
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted",
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(v, 0, "rows inserted", SQLITE_STATIC,
+ NULL, 0);
}
insert_cleanup:
diff --git a/src/box/sql/legacy.c b/src/box/sql/legacy.c
index e75709551..ed3ead5db 100644
--- a/src/box/sql/legacy.c
+++ b/src/box/sql/legacy.c
@@ -113,9 +113,6 @@ sqlite3_exec(sqlite3 * db, /* The database on which the SQL executes */
(char *)
sqlite3_column_name(pStmt,
i);
- /* sqlite3VdbeSetColName() installs column names as UTF8
- * strings so there is no way for sqlite3_column_name() to fail.
- */
assert(azCols[i] != 0);
}
callbackIsInit = 1;
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 40c6e5302..85aaf42d5 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -128,13 +128,13 @@ setPragmaResultColumnNames(Vdbe * v, /* The query under construction */
u8 n = pPragma->nPragCName;
sqlite3VdbeSetNumCols(v, n == 0 ? 1 : n);
if (n == 0) {
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName,
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(v, 0, pPragma->zName, SQLITE_STATIC, NULL,
+ 0);
} else {
int i, j;
for (i = 0, j = pPragma->iPragCName; i < n; i++, j++) {
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j],
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(v, i, pragCName[j], SQLITE_STATIC,
+ NULL, 0);
}
}
}
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index 36965a727..60d4de43c 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -434,9 +434,9 @@ sqlite3Prepare(sqlite3 * db, /* Database handle. */
mx = 8;
}
for (i = iFirst; i < mx; i++) {
- sqlite3VdbeSetColName(sParse.pVdbe, i - iFirst,
- COLNAME_NAME, azColName[i],
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(sParse.pVdbe, i - iFirst,
+ azColName[i], SQLITE_STATIC, NULL,
+ 0);
}
}
#endif
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 660423d76..8dad5cb32 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1569,35 +1569,36 @@ generateSortTail(Parse * pParse, /* Parsing context */
sqlite3VdbeResolveLabel(v, addrBreak);
}
-/*
- * Return a pointer to a string containing the 'declaration type' of the
- * expression pExpr. The string may be treated as static by the caller.
- *
- * Also try to estimate the size of the returned value and return that
- * result in *pEstWidth.
- *
- * The declaration type is the exact datatype definition extracted from the
- * original CREATE TABLE statement if the expression is a column.
- * Exactly when an expression is considered a column can be complex
- * in the presence of subqueries. The result-set expression in all
- * of the following SELECT statements is considered a column by this function.
- *
- * SELECT col FROM tbl;
- * SELECT (SELECT col FROM tbl;
- * SELECT (SELECT col FROM tbl);
- * SELECT abc FROM (SELECT col AS abc FROM tbl);
- *
- * The declaration type for any expression other than a column is NULL.
+/**
+ * Get a declaration type of an expression and its estimated size.
+ * The result string may be treated as static by the caller.
+ *
+ * The declaration type is the exact datatype definition extracted
+ * from the original CREATE TABLE statement if the expression is a
+ * column. Exactly when an expression is considered a column can
+ * be complex in the presence of subqueries. The result-set
+ * expression in all of the following SELECT statements is
+ * considered a column by this function. Only table columns has
+ * declaration type - for others NULL is returned.
+ * @param pNC Parser context with tables list.
+ * @param pExpr Expression to detect type.
+ * @param[out] table Table containing the found column. Can be
+ * NULL.
+ * @param[out] fieldno Index of a column in a table. Can be NULL.
+ * @param[out] pEstWidth Estimated column value size. Can be NULL.
+ *
+ * @retval not NULL Table column declaration type.
+ * @retval NULL An expression is not column.
*/
static const char *
-columnType(NameContext *pNC, Expr *pExpr, const char **pzOrigTab,
- const char **pzOrigCol, u8 *pEstWidth)
+columnType(NameContext *pNC, Expr *pExpr, const struct Table **table,
+ uint32_t *fieldno, u8 *pEstWidth)
{
char const *zType = 0;
int j;
u8 estWidth = 1;
- char const *zOrigTab = 0;
- char const *zOrigCol = 0;
+ const struct Table *found_table = NULL;
+ uint32_t found_fieldno = 0;
assert(pExpr != 0);
assert(pNC->pSrcList != 0);
@@ -1667,17 +1668,18 @@ columnType(NameContext *pNC, Expr *pExpr, const char **pzOrigTab,
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType =
- columnType(&sNC, p, &zOrigTab,
- &zOrigCol, &estWidth);
+ columnType(&sNC, p, &found_table,
+ &found_fieldno,
+ &estWidth);
}
} else if (pTab->pSchema) {
/* A real table */
assert(!pS);
assert(iCol >= 0 && iCol < pTab->nCol);
- zOrigCol = pTab->aCol[iCol].zName;
+ found_fieldno = iCol;
zType = sqlite3ColumnType(&pTab->aCol[iCol], 0);
estWidth = pTab->aCol[iCol].szEst;
- zOrigTab = pTab->zName;
+ found_table = pTab;
}
break;
}
@@ -1695,51 +1697,23 @@ columnType(NameContext *pNC, Expr *pExpr, const char **pzOrigTab,
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
zType =
- columnType(&sNC, p, &zOrigTab, &zOrigCol,
+ columnType(&sNC, p, &found_table, &found_fieldno,
&estWidth);
break;
}
#endif
}
- if (pzOrigTab) {
- assert(pzOrigTab && pzOrigCol);
- *pzOrigTab = zOrigTab;
- *pzOrigCol = zOrigCol;
+ if (table != NULL) {
+ assert(table != NULL && fieldno != NULL);
+ *table = found_table;
+ *fieldno = found_fieldno;
}
if (pEstWidth)
*pEstWidth = estWidth;
return zType;
}
-/*
- * Generate code that will tell the VDBE the declaration types of columns
- * in the result set.
- */
-static void
-generateColumnTypes(Parse * pParse, /* Parser context */
- SrcList * pTabList, /* List of tables */
- ExprList * pEList) /* Expressions defining the result set */
-{
- Vdbe *v = pParse->pVdbe;
- int i;
- NameContext sNC;
- sNC.pSrcList = pTabList;
- sNC.pParse = pParse;
- for (i = 0; i < pEList->nExpr; i++) {
- Expr *p = pEList->a[i].pExpr;
- const char *zType;
- const char *zOrigTab = 0;
- const char *zOrigCol = 0;
- zType = columnType(&sNC, p, &zOrigTab, &zOrigCol, 0);
-
- sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab,
- SQLITE_TRANSIENT);
- sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol,
- SQLITE_TRANSIENT);
- }
-}
-
/*
* Generate code that will tell the VDBE the names of columns
* in the result set. This information is used to provide the
@@ -1770,16 +1744,22 @@ generateColumnNames(Parse * pParse, /* Parser context */
pParse->colNamesSet = 1;
fullNames = (user_session->sql_flags & SQLITE_FullColNames) != 0;
shortNames = (user_session->sql_flags & SQLITE_ShortColNames) != 0;
+ NameContext sNC;
+ sNC.pSrcList = pTabList;
+ sNC.pParse = pParse;
sqlite3VdbeSetNumCols(v, pEList->nExpr);
for (i = 0; i < pEList->nExpr; i++) {
- Expr *p;
- p = pEList->a[i].pExpr;
+ const struct Table *table;
+ uint32_t fieldno;
+ char *alias;
+ void *destructor;
+ Expr *p = pEList->a[i].pExpr;
if (NEVER(p == 0))
continue;
+ columnType(&sNC, p, &table, &fieldno, NULL);
if (pEList->a[i].zName) {
- char *zName = pEList->a[i].zName;
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName,
- SQLITE_TRANSIENT);
+ alias = pEList->a[i].zName;
+ destructor = SQLITE_TRANSIENT;
} else if (p->op == TK_COLUMN || p->op == TK_AGG_COLUMN) {
Table *pTab;
char *zCol;
@@ -1795,31 +1775,26 @@ generateColumnNames(Parse * pParse, /* Parser context */
assert(iCol >= 0 && iCol < pTab->nCol);
zCol = pTab->aCol[iCol].zName;
if (!shortNames && !fullNames) {
- sqlite3VdbeSetColName(v, i, COLNAME_NAME,
- sqlite3DbStrDup(db,
- pEList->a[i].zSpan),
- SQLITE_DYNAMIC);
+ alias = sqlite3DbStrDup(db, pEList->a[i].zSpan);
+ destructor = SQLITE_DYNAMIC;
} else if (fullNames) {
- char *zName = 0;
- zName =
- sqlite3MPrintf(db, "%s.%s", pTab->zName,
- zCol);
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName,
- SQLITE_DYNAMIC);
+ alias = sqlite3MPrintf(db, "%s.%s", pTab->zName,
+ zCol);
+ destructor = SQLITE_DYNAMIC;
} else {
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol,
- SQLITE_TRANSIENT);
+ alias = zCol;
+ destructor = SQLITE_TRANSIENT;
}
} else {
- const char *z = pEList->a[i].zSpan;
- z = z == 0 ? sqlite3MPrintf(db, "column%d",
- i + 1) : sqlite3DbStrDup(db,
- z);
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, z,
- SQLITE_DYNAMIC);
+ alias = pEList->a[i].zSpan;
+ if (alias == NULL)
+ alias = sqlite3MPrintf(db, "column%d", i + 1);
+ else
+ alias = sqlite3DbStrDup(db, alias);
+ destructor = SQLITE_DYNAMIC;
}
+ sqlite3VdbeSetColMeta(v, i, alias, destructor, table, fieldno);
}
- generateColumnTypes(pParse, pTabList, pEList);
}
/*
diff --git a/src/box/sql/sqlite3.h b/src/box/sql/sqlite3.h
index ab0c8761a..90a77e5df 100644
--- a/src/box/sql/sqlite3.h
+++ b/src/box/sql/sqlite3.h
@@ -3925,12 +3925,19 @@ sqlite3_column_name(sqlite3_stmt *, int N);
* occurs. ^Otherwise, they return the name of the attached database, table,
* or column that query result column was extracted from.
*/
-SQLITE_API const char *
-sqlite3_column_table_name(sqlite3_stmt *, int);
-
SQLITE_API const char *
sqlite3_column_origin_name(sqlite3_stmt *, int);
+/**
+ * Get column meta information.
+ * @param stmt Prepared statement.
+ * @param fieldno Field number of a column to get meta of.
+ * @return Column meta.
+ */
+struct sql_column_meta;
+const struct sql_column_meta *
+sqlite3_column_meta(sqlite3_stmt *stmt, int fieldno);
+
/*
* CAPI3REF: Evaluate An SQL Statement
* METHOD: sqlite3_stmt
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index aebb61029..3258c8edc 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1359,6 +1359,50 @@ struct Column {
u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
+/**
+ * Column meta information, generated on DML/SQL requests. On DDL
+ * operations no columns and no meta.
+ * On DML column meta is restricted by "rows inserted",
+ * "rows deleted" and other aggregated information that in general
+ * does not depend on a request type.
+ * On DQL (SELECT) each column has a meta. A result set column can
+ * be directly reflected to a column of a table, or be a result of
+ * an expression, or be a constant.
+ * If a column does not belong to a table, then meta stores only
+ * its alias (SELECT ... as <alias> ...). If a column belongs to
+ * a table, then before a request execution in a meta some info
+ * is aggregated.
+ * Meta can not simply store direct pointers to a Table or Column
+ * objects, since in a future we will add iterators, prepared
+ * statements and other things, that must survive after DDL.
+ * Moreover Vinyl engine can yield in DQL, and during a yield DDL
+ * is possible too.
+ */
+struct sql_column_meta {
+ /** Column name, visible to a user. */
+ char *alias;
+ /**
+ * Alias can be reference to a static memory - do not free
+ * it in such a case.
+ */
+ bool need_free_alias;
+ /**
+ * Original column name stored in a table, if a column
+ * belongs to a table. Else NULL.
+ */
+ char *name;
+ union {
+ /** Some meta, aggregated for a table column. */
+ struct PACKED {
+ bool is_nullable : 1;
+ bool is_primary_part : 1;
+ bool is_autoincrement : 1;
+ bool is_case_sensitive : 1;
+ };
+ uint8_t flags;
+ };
+};
+
/* Allowed values for Column.colFlags:
*/
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 85d18cbde..aa53c426f 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -688,8 +688,8 @@ sqlite3Update(Parse * pParse, /* The parser context */
!pParse->pTriggerTab && !pParse->nested) {
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated",
- SQLITE_STATIC);
+ sqlite3VdbeSetColMeta(v, 0, "rows updated", SQLITE_STATIC, NULL,
+ 0);
}
update_cleanup:
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index e66e4f9bf..7c49a67bd 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -233,7 +233,10 @@ void sqlite3VdbeResetStepResult(Vdbe *);
void sqlite3VdbeRewind(Vdbe *);
int sqlite3VdbeReset(Vdbe *);
void sqlite3VdbeSetNumCols(Vdbe *, int);
-int sqlite3VdbeSetColName(Vdbe *, int, int, const char *, void (*)(void *));
+void
+sqlite3VdbeSetColMeta(Vdbe *p, int idx,
+ const char *alias, void *destructor,
+ const struct Table *space, uint32_t fieldno);
void sqlite3VdbeCountChanges(Vdbe *);
sqlite3 *sqlite3VdbeDb(Vdbe *);
void sqlite3VdbeSetSql(Vdbe *, const char *z, int n, int);
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index 1f7fdd37b..b3c8acf17 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -406,7 +406,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 */
+ /* Column meta to return. */
+ struct sql_column_meta *columns;
Mem *pResultSet; /* Pointer to an array of results */
char *zErrMsg; /* Error message written here */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index d995a534b..2d0efbda0 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -1166,18 +1166,10 @@ columnName(sqlite3_stmt *pStmt, int N, int useType)
assert(db != NULL);
n = sqlite3_column_count(pStmt);
if (N < n && N >= 0) {
- N += useType * n;
- sqlite3_mutex_enter(db->mutex);
- assert(db->mallocFailed == 0);
- ret = (const char *) sqlite3_value_text(&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) {
- sqlite3OomClear(db);
- ret = NULL;
- }
- sqlite3_mutex_leave(db->mutex);
+ if (useType == COLNAME_NAME)
+ ret = p->columns[N].alias;
+ else
+ ret = p->columns[N].name;
}
return ret;
}
@@ -1192,17 +1184,6 @@ sqlite3_column_name(sqlite3_stmt * pStmt, int N)
return columnName(pStmt, N, COLNAME_NAME);
}
-/*
- * Return the name of the table from which a result column derives.
- * NULL is returned if the result column is an expression or constant or
- * anything else which is not an unambiguous reference to a database column.
- */
-const char *
-sqlite3_column_table_name(sqlite3_stmt * pStmt, int N)
-{
- return columnName(pStmt, N, COLNAME_TABLE);
-}
-
/*
* Return the name of the table column from which a result column derives.
* NULL is returned if the result column is an expression or constant or
@@ -1214,6 +1195,14 @@ sqlite3_column_origin_name(sqlite3_stmt * pStmt, int N)
return columnName(pStmt, N, COLNAME_COLUMN);
}
+const struct sql_column_meta *
+sqlite3_column_meta(sqlite3_stmt *stmt, int fieldno)
+{
+ Vdbe *p = (Vdbe *) stmt;
+ assert(fieldno < p->nResColumn);
+ return &p->columns[fieldno];
+}
+
/******************************* sqlite3_bind_ **************************
*
* Routines used to attach values to wildcards in a compiled SQL statement.
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index d7546ab43..9d13a6449 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -38,6 +38,7 @@
#include "box/schema.h"
#include "box/tuple_format.h"
#include "box/txn.h"
+#include "box/coll_cache.h"
#include "msgpuck/msgpuck.h"
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -2370,51 +2371,85 @@ Cleanup(Vdbe * p)
* be called on an SQL statement before sqlite3_step().
*/
void
-sqlite3VdbeSetNumCols(Vdbe * p, int nResColumn)
+sqlite3VdbeSetNumCols(Vdbe *p, int n)
{
- int n;
sqlite3 *db = p->db;
-
- releaseMemArray(p->aColName, p->nResColumn * COLNAME_N);
- sqlite3DbFree(db, p->aColName);
- n = nResColumn * COLNAME_N;
- p->nResColumn = (u16) nResColumn;
- p->aColName = (Mem *) sqlite3DbMallocRawNN(db, sizeof(Mem) * n);
- if (p->aColName == 0)
- return;
- initMemArray(p->aColName, n, p->db, MEM_Null);
+ struct sql_column_meta *col = p->columns;
+ for (uint32_t i = 0; i < p->nResColumn; ++i, ++col) {
+ if (col->need_free_alias)
+ sqlite3DbFree(db, col->alias);
+ sqlite3DbFree(db, col->name);
+ col->alias = NULL;
+ col->name = NULL;
+ }
+ if (n == 0) {
+ sqlite3DbFree(db, p->columns);
+ } else {
+ uint32_t size = sizeof(p->columns[0]) * n;
+ struct sql_column_meta *new_meta = (struct sql_column_meta *)
+ sqlite3DbRealloc(db, p->columns, size);
+ if (new_meta == NULL)
+ return;
+ p->columns = new_meta;
+ memset(new_meta, 0, size);
+ }
+ p->nResColumn = (u16) n;
}
-/*
- * 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 sqlite3VdbeSetNumCols().
- *
- * The final parameter, xDel, must be one of SQLITE_DYNAMIC, SQLITE_STATIC
- * or SQLITE_TRANSIENT. If it is SQLITE_DYNAMIC, then the buffer pointed
- * to by zName will be freed by sqlite3DbFree() when the vdbe is destroyed.
+/**
+ * Store column meta in VDBE.
+ * @param p VDBE to store in.
+ * @param idx Column 0-based index.
+ * @param alias Alias visible to a user.
+ * @param destructor Type of an alias: it can be static memory,
+ * memory that must be duplicated, and already duplicated.
+ * @param table Table containing a column, or NULL.
+ * @param fieldno Column number in a table.
*/
-int
-sqlite3VdbeSetColName(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;
+void
+sqlite3VdbeSetColMeta(Vdbe *p, int idx,
+ const char *alias, void *destructor,
+ const struct Table *table, uint32_t fieldno)
+{
assert(idx < p->nResColumn);
- assert(var < COLNAME_N);
- if (p->db->mallocFailed) {
- assert(!zName || xDel != SQLITE_DYNAMIC);
- return SQLITE_NOMEM_BKPT;
+ struct sql_column_meta *meta = &p->columns[idx];
+ if (table != NULL) {
+ assert(fieldno < (uint32_t) table->nCol);
+ const struct Column *column = &table->aCol[fieldno];
+ meta->name = sqlite3DbStrDup(p->db, column->zName);
+ meta->is_nullable = column->notNull == ON_CONFLICT_ACTION_NONE;
+ meta->is_primary_part =
+ (column->colFlags & COLFLAG_PRIMKEY) != 0;
+ meta->is_autoincrement =
+ meta->is_primary_part &&
+ (table->tabFlags & TF_Autoincrement) != 0;
+ if (column->zColl != NULL) {
+ struct coll *coll = coll_by_name(column->zColl,
+ strlen(column->zColl));
+ if (coll != NULL) {
+ meta->is_case_sensitive =
+ coll_is_case_sensitive(coll);
+ } else {
+ meta->is_case_sensitive = true;
+ }
+ } else {
+ meta->is_case_sensitive = true;
+ }
+ if (column->zName == alias) {
+ /*
+ * If a column is selected with no alias,
+ * then do not copy it twice. Store two
+ * pointers to the same name.
+ */
+ destructor = SQLITE_STATIC;
+ alias = meta->name;
+ }
}
- assert(p->aColName != 0);
- pColName = &(p->aColName[idx + var * p->nResColumn]);
- rc = sqlite3VdbeMemSetStr(pColName, zName, -1, 1, xDel);
- assert(rc != 0 || !zName || (pColName->flags & MEM_Term) != 0);
- return rc;
+ if (destructor == SQLITE_TRANSIENT)
+ meta->alias = sqlite3DbStrDup(p->db, alias);
+ else
+ meta->alias = (char *) alias;
+ meta->need_free_alias = destructor != SQLITE_STATIC;
}
/*
@@ -2999,7 +3034,6 @@ sqlite3VdbeClearObject(sqlite3 * db, Vdbe * p)
{
SubProgram *pSub, *pNext;
assert(p->db == 0 || p->db == db);
- releaseMemArray(p->aColName, p->nResColumn * COLNAME_N);
for (pSub = p->pProgram; pSub; pSub = pNext) {
pNext = pSub->pNext;
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
@@ -3011,7 +3045,7 @@ sqlite3VdbeClearObject(sqlite3 * db, Vdbe * p)
sqlite3DbFree(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
- sqlite3DbFree(db, p->aColName);
+ sqlite3VdbeSetNumCols(p, 0);
sqlite3DbFree(db, p->zSql);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
{
--
2.14.3 (Apple Git-98)
More information about the Tarantool-patches
mailing list