[tarantool-patches] [PATCH v1 3/3] sql: get rid of Column structure

  • From: Kirill Shcherbatov <kshcherbatov@xxxxxxxxxxxxx>
  • To: tarantool-patches@xxxxxxxxxxxxx
  • Date: Wed, 18 Jul 2018 19:52:22 +0300

Get rid of is_primkey in Column structure as it become
redundant. Moved the last member coll with collation pointer
to field_def structure. Finally, dropped Column.
---
 src/box/alter.cc                |   3 +
 src/box/field_def.c             |   1 +
 src/box/field_def.h             |   2 +
 src/box/sql/alter.c             |  27 ++-------
 src/box/sql/build.c             | 130 ++++++++++++++++------------------------
 src/box/sql/resolve.c           |  11 ++--
 src/box/sql/select.c            |  43 +++++--------
 src/box/sql/sqliteInt.h         |  11 ----
 test/sql-tap/conflict3.test.lua |  10 ++--
 9 files changed, 87 insertions(+), 151 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 7b6bd1a..444bc48 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -407,6 +407,9 @@ field_def_decode(struct field_def *field, const char **data,
                          tt_sprintf("collation is reasonable only for "
                                     "string, scalar and any fields"));
        }
+       struct coll_id *collation = coll_by_id(field->coll_id);
+       if (collation != NULL)
+               field->coll = collation->coll;
 
        const char *dv = field->default_value;
        if (dv != NULL) {
diff --git a/src/box/field_def.c b/src/box/field_def.c
index 8dbead6..12cc3b2 100644
--- a/src/box/field_def.c
+++ b/src/box/field_def.c
@@ -106,6 +106,7 @@ const struct field_def field_def_default = {
        .is_nullable = false,
        .nullable_action = ON_CONFLICT_ACTION_DEFAULT,
        .coll_id = COLL_NONE,
+       .coll = NULL,
        .default_value = NULL,
        .default_value_expr = NULL
 };
diff --git a/src/box/field_def.h b/src/box/field_def.h
index 05f80d4..c8f158c 100644
--- a/src/box/field_def.h
+++ b/src/box/field_def.h
@@ -123,6 +123,8 @@ struct field_def {
        enum on_conflict_action nullable_action;
        /** Collation ID for string comparison. */
        uint32_t coll_id;
+       /** Collating sequence for string comparison. */
+       struct coll *coll;
        /** 0-terminated SQL expression for DEFAULT value. */
        char *default_value;
        /** AST for parsed default value. */
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index fe54e55..38c36e8 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -146,7 +146,6 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
        Table *pNew;            /* Copy of pParse->pNewTable */
        Table *pTab;            /* Table being altered */
        const char *zTab;       /* Table name */
-       Column *pCol;           /* The new column */
        Expr *pDflt;            /* Default value for the new column */
        sqlite3 *db;            /* The database connection; */
        Vdbe *v = pParse->pVdbe;        /* The prepared statement under 
construction */
@@ -161,7 +160,6 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 
        /* Skip the "sqlite_altertab_" prefix on the name. */
        zTab = &pNew->def->name[16];
-       pCol = &pNew->aCol[pNew->def->field_count - 1];
        assert(pNew->def != NULL);
        pDflt = space_column_default_expr(SQLITE_PAGENO_TO_SPACEID(pNew->tnum),
                                          pNew->def->field_count - 1);
@@ -181,7 +179,10 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * 
pColDef)
         * If there is a NOT NULL constraint, then the default value for the
         * column must not be NULL.
         */
-       if (pCol->is_primkey) {
+       struct Index *pk = sqlite3PrimaryKeyIndex(pTab);
+       assert(pk != NULL);
+       struct key_def *pk_key_def = pk->def->key_def;
+       if (key_def_find(pk_key_def, pNew->def->field_count - 1) != NULL) {
                sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column");
                return;
        }
@@ -258,8 +259,6 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
        Table *pNew;
        Table *pTab;
        Vdbe *v;
-       uint32_t i;
-       int nAlloc;
        sqlite3 *db = pParse->db;
 
        /* Look up the table being altered. */
@@ -296,24 +295,10 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
        }
        pParse->pNewTable = pNew;
        assert(pNew->def->field_count > 0);
-       nAlloc = (((pNew->def->field_count - 1) / 8) * 8) + 8;
-       assert((uint32_t)nAlloc >= pNew->def->field_count && nAlloc % 8 == 0 &&
-              nAlloc - pNew->def->field_count < 8);
-       pNew->aCol =
-           (Column *) sqlite3DbMallocZero(db, sizeof(Column) * nAlloc);
        /* FIXME: pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", 
pTab->zName); */
        /* FIXME: if (!pNew->aCol || !pNew->zName) { */
-       if (!pNew->aCol) {
-               assert(db->mallocFailed);
-               goto exit_begin_add_column;
-       }
-       memcpy(pNew->aCol, pTab->aCol, sizeof(Column) * pNew->def->field_count);
-       for (i = 0; i < pNew->def->field_count; i++) {
-               Column *pCol = &pNew->aCol[i];
-               /* FIXME: pNew->def->name = sqlite3DbStrDup(db, pCol->zName); */
-               pCol->coll = NULL;
-               pNew->def->fields[i].coll_id = COLL_NONE;
-       }
+       for (uint32_t i = 0; i < pNew->def->field_count; i++)
+               pNew->def->fields[i] = field_def_default;
        pNew->pSchema = db->pSchema;
        pNew->addColOffset = pTab->addColOffset;
        pNew->nTabRef = 1;
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index ee97ef9..ed104e4 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -116,38 +116,48 @@ sql_finish_coding(struct Parse *parse_context)
 
 /**
  * This is a function which should be called during execution
- * of sqlite3EndTable. It ensures that only PRIMARY KEY
- * constraint may have ON CONFLICT REPLACE clause.
+ * of sqlite3EndTable. It set defaults for columns having no
+ * separate NULL/NOT NULL specifiers and ensures that only
+ * PRIMARY KEY constraint may have ON CONFLICT REPLACE clause.
  *
+ * @param parser SQL Parser object.
  * @param table Space which should be checked.
- * @retval False, if only primary key constraint has
- *         ON CONFLICT REPLACE clause or if there are no indexes
- *         with REPLACE as error action. True otherwise.
+ * @retval -1 on error. Parser SQL_TARANTOOL_ERROR is set.
+ * @retval 0 on success.
  */
-static bool
-check_on_conflict_replace_entries(struct Table *table)
-{
-       /* Check all NOT NULL constraints. */
-       for (int i = 0; i < (int)table->def->field_count; i++) {
-               enum on_conflict_action on_error =
-                       table->def->fields[i].nullable_action;
-               if (on_error == ON_CONFLICT_ACTION_REPLACE &&
-                   table->aCol[i].is_primkey == false) {
-                       return true;
+static int
+actualize_on_conflict_actions(struct Parse *parser, struct Table *table)
+{
+       const char *err_msg = NULL;
+       struct field_def *field = table->def->fields;
+       struct Index *pk = sqlite3PrimaryKeyIndex(table);
+       for (uint32_t i = 0; i < table->def->field_count; ++i, ++field) {
+               if (field->nullable_action == on_conflict_action_MAX) {
+                       /* Set default. */
+                       field->nullable_action = ON_CONFLICT_ACTION_NONE;
+                       field->is_nullable = true;
                }
+               if (field->nullable_action == ON_CONFLICT_ACTION_REPLACE &&
+                   (pk == NULL || key_def_find(pk->def->key_def, i) == NULL))
+                       goto non_pk_on_conflict_error;
        }
-       /* Check all UNIQUE constraints. */
+
        for (struct Index *idx = table->pIndex; idx; idx = idx->pNext) {
                if (idx->onError == ON_CONFLICT_ACTION_REPLACE &&
-                   !IsPrimaryKeyIndex(idx)) {
-                       return true;
-               }
+                   !IsPrimaryKeyIndex(idx))
+                       goto non_pk_on_conflict_error;
        }
-       /*
-        * CHECK constraints are not allowed to have REPLACE as
-        * error action and therefore can be skipped.
-        */
-       return false;
+
+       return 0;
+
+non_pk_on_conflict_error:
+       err_msg = tt_sprintf("only PRIMARY KEY constraint can have "
+                            "ON CONFLICT REPLACE clause - %s",
+                            table->def->name);
+       diag_set(ClientError, ER_SQL, err_msg);
+       parser->rc = SQL_TARANTOOL_ERROR;
+       parser->nErr++;
+       return -1;
 }
 
 /*
@@ -340,7 +350,6 @@ deleteTable(sqlite3 * db, Table * pTable)
        /* Delete the Table structure itself.
         */
        sqlite3HashClear(&pTable->idxHash);
-       sqlite3DbFree(db, pTable->aCol);
        sqlite3DbFree(db, pTable->zColAff);
        assert(pTable->def != NULL);
        /* Do not delete pTable->def allocated on region. */
@@ -604,7 +613,6 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * 
pType)
        int i;
        char *z;
        char *zType;
-       Column *pCol;
        sqlite3 *db = pParse->db;
        if ((p = pParse->pNewTable) == 0)
                return;
@@ -642,17 +650,6 @@ sqlite3AddColumn(Parse * pParse, Token * pName, Token * 
pType)
                        return;
                }
        }
-       if ((p->def->field_count & 0x7) == 0) {
-               Column *aNew =
-                       sqlite3DbRealloc(db, p->aCol,
-                                        (p->def->field_count + 8) *
-                                        sizeof(p->aCol[0]));
-               if (aNew == NULL)
-                       return;
-               p->aCol = aNew;
-       }
-       pCol = &p->aCol[p->def->field_count];
-       memset(pCol, 0, sizeof(p->aCol[0]));
        struct field_def *column_def = &p->def->fields[p->def->field_count];
        memcpy(column_def, &field_def_default, sizeof(field_def_default));
        column_def->name = z;
@@ -890,7 +887,6 @@ sqlite3AddPrimaryKey(Parse * pParse,        /* Parsing 
context */
     )
 {
        Table *pTab = pParse->pNewTable;
-       Column *pCol = 0;
        int iCol = -1, i;
        int nTerm;
        if (pTab == 0)
@@ -904,8 +900,6 @@ sqlite3AddPrimaryKey(Parse * pParse,        /* Parsing 
context */
        pTab->tabFlags |= TF_HasPrimaryKey;
        if (pList == 0) {
                iCol = pTab->def->field_count - 1;
-               pCol = &pTab->aCol[iCol];
-               pCol->is_primkey = 1;
                nTerm = 1;
        } else {
                nTerm = pList->nExpr;
@@ -914,25 +908,22 @@ sqlite3AddPrimaryKey(Parse * pParse,      /* Parsing 
context */
                            sqlite3ExprSkipCollate(pList->a[i].pExpr);
                        assert(pCExpr != 0);
                        if (pCExpr->op != TK_ID) {
-                               sqlite3ErrorMsg(pParse, "expressions prohibited 
in PRIMARY KEY");
+                               sqlite3ErrorMsg(pParse, "expressions prohibited"
+                                                       " in PRIMARY KEY");
                                goto primary_key_exit;
                        }
-                       const char *zCName = pCExpr->u.zToken;
-                       for (iCol = 0;
-                               iCol < (int)pTab->def->field_count; iCol++) {
-                               if (strcmp
-                                   (zCName,
-                                    pTab->def->fields[iCol].name) == 0) {
-                                       pCol = &pTab->aCol[iCol];
-                                       pCol->is_primkey = 1;
+                       const char *name = pCExpr->u.zToken;
+                       struct space_def *def = pTab->def;
+                       for (uint32_t idx = 0; idx < def->field_count; idx++) {
+                               if (strcmp(name, def->fields[idx].name) == 0) {
+                                       iCol = idx;
                                        break;
                                }
                        }
                }
        }
-       assert(pCol == NULL || pCol == &pTab->aCol[iCol]);
-       if (nTerm == 1 && pCol != NULL &&
-           (pTab->def->fields[iCol].type == FIELD_TYPE_INTEGER) &&
+       if (nTerm == 1 && iCol != -1 &&
+           pTab->def->fields[iCol].type == FIELD_TYPE_INTEGER &&
            sortOrder != SORT_ORDER_DESC) {
                assert(autoInc == 0 || autoInc == 1);
                pTab->iPKey = iCol;
@@ -1002,8 +993,8 @@ sqlite3AddCollateType(Parse * pParse, Token * pToken)
        if (!zColl)
                return;
        uint32_t *id = &p->def->fields[i].coll_id;
-       p->aCol[i].coll = sql_get_coll_seq(pParse, zColl, id);
-       if (p->aCol[i].coll != NULL) {
+       p->def->fields[i].coll = sql_get_coll_seq(pParse, zColl, id);
+       if (p->def->fields[i].coll != NULL) {
                /* If the column is declared as "<name> PRIMARY KEY COLLATE 
<type>",
                 * then an index may have been created on this column before the
                 * collation type was added. Correct this if it is the case.
@@ -1163,14 +1154,11 @@ identPut(char *z, int *pIdx, char *zSignedIdent)
 static char *
 createTableStmt(sqlite3 * db, Table * p)
 {
-       int i, k, n;
        char *zStmt;
        char *zSep, *zSep2, *zEnd;
-       Column *pCol;
-       n = 0;
-       for (pCol = p->aCol, i = 0; i < (int)p->def->field_count; i++, pCol++) {
+       int n = 0;
+       for (uint32_t i = 0; i < p->def->field_count; i++)
                n += identLength(p->def->fields[i].name) + 5;
-       }
        n += identLength(p->def->name);
        if (n < 50) {
                zSep = "";
@@ -1188,10 +1176,10 @@ createTableStmt(sqlite3 * db, Table * p)
                return 0;
        }
        sqlite3_snprintf(n, zStmt, "CREATE TABLE ");
-       k = sqlite3Strlen30(zStmt);
+       int k = sqlite3Strlen30(zStmt);
        identPut(zStmt, &k, p->def->name);
        zStmt[k++] = '(';
-       for (pCol = p->aCol, i = 0; i < (int)p->def->field_count; i++, pCol++) {
+       for (uint32_t i = 0; i < p->def->field_count; i++) {
                static const char *const azType[] = {
                        /* AFFINITY_BLOB    */ "",
                        /* AFFINITY_TEXT    */ " TEXT",
@@ -1692,22 +1680,9 @@ sqlite3EndTable(Parse * pParse,  /* Parse context */
                }
        }
 
-       /* Set default on_nullable action if required. */
-       struct field_def *field = p->def->fields;
-       for (uint32_t i = 0; i < p->def->field_count; ++i, ++field) {
-               if (field->nullable_action == on_conflict_action_MAX) {
-                       field->nullable_action = ON_CONFLICT_ACTION_NONE;
-                       field->is_nullable = true;
-               }
-       }
-
-       if (check_on_conflict_replace_entries(p)) {
-               sqlite3ErrorMsg(pParse,
-                               "only PRIMARY KEY constraint can "
-                               "have ON CONFLICT REPLACE clause "
-                               "- %s", p->def->name);
+       if (actualize_on_conflict_actions(pParse, p))
                goto cleanup;
-       }
+
        if (db->init.busy) {
                /*
                 * As rebuild creates a new ExpList tree and
@@ -1882,12 +1857,9 @@ sql_create_view(struct Parse *parse_context, struct 
Token *begin,
                sqlite3SelectAddColumnTypeAndCollation(parse_context, p,
                                                       select);
        } else {
-               assert(p->aCol == NULL);
                assert(sel_tab->def->opts.is_temporary);
                p->def->fields = sel_tab->def->fields;
                p->def->field_count = sel_tab->def->field_count;
-               p->aCol = sel_tab->aCol;
-               sel_tab->aCol = NULL;
                sel_tab->def->fields = NULL;
                sel_tab->def->field_count = 0;
        }
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index a185473..2c49e2c 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -219,7 +219,6 @@ lookupName(Parse * pParse,  /* The parsing context */
        NameContext *pTopNC = pNC;      /* First namecontext in the list */
        int isTrigger = 0;      /* True if resolved to a trigger column */
        Table *pTab = 0;        /* Table hold the row */
-       Column *pCol;           /* A column of pTab */
 
        assert(pNC);            /* the name context cannot be NULL. */
        assert(zCol);           /* The Z in X.Y.Z cannot be NULL */
@@ -272,9 +271,8 @@ lookupName(Parse * pParse,  /* The parsing context */
                                if (0 == (cntTab++)) {
                                        pMatch = pItem;
                                }
-                               for (j = 0, pCol = pTab->aCol;
-                                       j < (int)pTab->def->field_count;
-                                       j++, pCol++) {
+                               for (j = 0; j < (int)pTab->def->field_count;
+                                    j++) {
                                        if (strcmp(pTab->def->fields[j].name,
                                                   zCol) == 0) {
                                                /* If there has been exactly 
one prior match and this match
@@ -331,9 +329,8 @@ lookupName(Parse * pParse,  /* The parsing context */
                        if (pTab) {
                                int iCol;
                                cntTab++;
-                               for (iCol = 0, pCol = pTab->aCol;
-                                    iCol < (int)pTab->def->field_count;
-                                    iCol++, pCol++) {
+                               for (iCol = 0; iCol <
+                                    (int)pTab->def->field_count; iCol++) {
                                        if (strcmp(pTab->def->fields[iCol].name,
                                                   zCol) == 0) {
                                                if (iCol == pTab->iPKey) {
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 34d5329..d577648 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1811,25 +1811,15 @@ sqlite3ColumnsFromExprList(Parse * parse, ExprList * 
expr_list, Table *table)
 {
        /* Database connection */
        sqlite3 *db = parse->db;
-       int i, j;               /* Loop counters */
        u32 cnt;                /* Index added to make the name unique */
-       Column *aCol, *pCol;    /* For looping over result columns */
-       int nCol;               /* Number of columns in the result set */
        Expr *p;                /* Expression for a single result column */
        char *zName;            /* Column name */
        int nName;              /* Size of name in zName[] */
        Hash ht;                /* Hash table of column names */
 
        sqlite3HashInit(&ht);
-       if (expr_list) {
-               nCol = expr_list->nExpr;
-               aCol = sqlite3DbMallocZero(db, sizeof(aCol[0]) * nCol);
-               testcase(aCol == 0);
-       } else {
-               nCol = 0;
-               aCol = NULL;
-       }
-       assert(nCol == (i16) nCol);
+       uint32_t column_count =
+               expr_list != NULL ? (uint32_t)expr_list->nExpr : 0;
        /*
         * This should be a table without resolved columns.
         * sqlite3ViewGetColumnNames could use it to resolve
@@ -1838,21 +1828,21 @@ sqlite3ColumnsFromExprList(Parse * parse, ExprList * 
expr_list, Table *table)
        assert(table->def->fields == NULL);
        struct region *region = &parse->region;
        table->def->fields =
-               region_alloc(region, nCol * sizeof(table->def->fields[0]));
+               region_alloc(region,
+                            column_count * sizeof(table->def->fields[0]));
        if (table->def->fields == NULL) {
                sqlite3OomFault(db);
                goto cleanup;
        }
-       for (int i = 0; i < nCol; i++) {
+       for (uint32_t i = 0; i < column_count; i++) {
                memcpy(&table->def->fields[i], &field_def_default,
                       sizeof(field_def_default));
                table->def->fields[i].nullable_action = ON_CONFLICT_ACTION_NONE;
                table->def->fields[i].is_nullable = true;
        }
-       table->def->field_count = (uint32_t)nCol;
-       table->aCol = aCol;
+       table->def->field_count = column_count;
 
-       for (i = 0, pCol = aCol; i < nCol; i++, pCol++) {
+       for (uint32_t i = 0; i < column_count; i++) {
                /* Get an appropriate name for the column
                 */
                p = sqlite3ExprSkipCollate(expr_list->a[i].pExpr);
@@ -1889,9 +1879,9 @@ sqlite3ColumnsFromExprList(Parse * parse, ExprList * 
expr_list, Table *table)
                while (zName && sqlite3HashFind(&ht, zName) != 0) {
                        nName = sqlite3Strlen30(zName);
                        if (nName > 0) {
+                               int j;
                                for (j = nName - 1;
-                                    j > 0 && sqlite3Isdigit(zName[j]); j--) {
-                               }
+                                    j > 0 && sqlite3Isdigit(zName[j]); j--);
                                if (zName[j] == ':')
                                        nName = j;
                        }
@@ -1901,7 +1891,9 @@ sqlite3ColumnsFromExprList(Parse * parse, ExprList * 
expr_list, Table *table)
                                sqlite3_randomness(sizeof(cnt), &cnt);
                }
                size_t name_len = strlen(zName);
-               if (zName != NULL && sqlite3HashInsert(&ht, zName, pCol) == 
pCol)
+               void *field = &table->def->fields[i];
+               if (zName != NULL &&
+                   sqlite3HashInsert(&ht, zName, field) == field)
                        sqlite3OomFault(db);
                table->def->fields[i].name =
                        region_alloc(region, name_len + 1);
@@ -1921,10 +1913,8 @@ cleanup:
                 * pTable->def could be not temporal in
                 * sqlite3ViewGetColumnNames so we need clean-up.
                 */
-               sqlite3DbFree(db, aCol);
                table->def->fields = NULL;
                table->def->field_count = 0;
-               table->aCol = NULL;
                rc = SQLITE_NOMEM_BKPT;
        }
        return rc;
@@ -1949,8 +1939,6 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,    
        /* Parsing contexts */
 {
        sqlite3 *db = pParse->db;
        NameContext sNC;
-       Column *pCol;
-       int i;
        Expr *p;
        struct ExprList_item *a;
 
@@ -1963,8 +1951,7 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,    
        /* Parsing contexts */
        memset(&sNC, 0, sizeof(sNC));
        sNC.pSrcList = pSelect->pSrc;
        a = pSelect->pEList->a;
-       for (i = 0, pCol = pTab->aCol;
-               i < (int)pTab->def->field_count; i++, pCol++) {
+       for (uint32_t i = 0; i < pTab->def->field_count; i++) {
                enum field_type type;
                p = a[i].pExpr;
                type = columnType(&sNC, p, 0, 0);
@@ -1977,8 +1964,8 @@ sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,    
        /* Parsing contexts */
                bool unused;
                uint32_t id;
                struct coll *coll = sql_expr_coll(pParse, p, &unused, &id);
-               if (coll != NULL && pCol->coll == NULL) {
-                       pCol->coll = coll;
+               if (coll != NULL && pTab->def->fields[i].coll == NULL) {
+                       pTab->def->fields[i].coll = coll;
                        pTab->def->fields[i].coll_id = id;
                }
        }
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 9f6e97e..984bec9 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1872,16 +1872,6 @@ struct Savepoint {
 #define SAVEPOINT_RELEASE    1
 #define SAVEPOINT_ROLLBACK   2
 
-/*
- * information about each column of an SQL table is held in an instance
- * of this structure.
- */
-struct Column {
-       /** Collating sequence. */
-       struct coll *coll;
-       u8 is_primkey;          /* Boolean propertie for being PK */
-};
-
 #define sqlite3IsNumericAffinity(X)  ((X)>=AFFINITY_NUMERIC)
 
 /*
@@ -1910,7 +1900,6 @@ struct Column {
  * by an instance of the following structure.
  */
 struct Table {
-       Column *aCol;           /* Information about each column */
        Index *pIndex;          /* List of SQL indexes on this table. */
        FKey *pFKey;            /* Linked list of all foreign keys in this 
table */
        char *zColAff;          /* String defining the affinity of each column 
*/
diff --git a/test/sql-tap/conflict3.test.lua b/test/sql-tap/conflict3.test.lua
index 345537e..9b55550 100755
--- a/test/sql-tap/conflict3.test.lua
+++ b/test/sql-tap/conflict3.test.lua
@@ -359,7 +359,7 @@ test:do_catchsql_test(
         CREATE TABLE t3(a PRIMARY KEY ON CONFLICT REPLACE,
                         b UNIQUE ON CONFLICT REPLACE);
     ]], {
-        1, "only PRIMARY KEY constraint can have ON CONFLICT REPLACE clause - 
T3"
+        1, "SQL error: only PRIMARY KEY constraint can have ON CONFLICT 
REPLACE clause - T3"
     })
 
 test:do_catchsql_test(
@@ -368,7 +368,7 @@ test:do_catchsql_test(
         CREATE TABLE t3(a PRIMARY KEY,
                         b UNIQUE ON CONFLICT REPLACE);
     ]], {
-        1, "only PRIMARY KEY constraint can have ON CONFLICT REPLACE clause - 
T3"
+        1, "SQL error: only PRIMARY KEY constraint can have ON CONFLICT 
REPLACE clause - T3"
     })
 
 test:do_catchsql_test(
@@ -378,7 +378,7 @@ test:do_catchsql_test(
                         b UNIQUE ON CONFLICT REPLACE,
                         c UNIQUE ON CONFLICT REPLACE);
     ]], {
-        1, "only PRIMARY KEY constraint can have ON CONFLICT REPLACE clause - 
T3"
+        1, "SQL error: only PRIMARY KEY constraint can have ON CONFLICT 
REPLACE clause - T3"
     })
 
 test:do_catchsql_test(
@@ -387,7 +387,7 @@ test:do_catchsql_test(
         CREATE TABLE t3(a PRIMARY KEY,
                         b NOT NULL ON CONFLICT REPLACE DEFAULT 1488);
     ]], {
-        1, "only PRIMARY KEY constraint can have ON CONFLICT REPLACE clause - 
T3"
+        1, "SQL error: only PRIMARY KEY constraint can have ON CONFLICT 
REPLACE clause - T3"
     })
 
 test:do_catchsql_test(
@@ -396,7 +396,7 @@ test:do_catchsql_test(
         CREATE TABLE t3(a PRIMARY KEY ON CONFLICT REPLACE,
                         b NOT NULL ON CONFLICT REPLACE DEFAULT 1488);
     ]], {
-        1, "only PRIMARY KEY constraint can have ON CONFLICT REPLACE clause - 
T3"
+        1, "SQL error: only PRIMARY KEY constraint can have ON CONFLICT 
REPLACE clause - T3"
     })
 
 test:finish_test()
-- 
2.7.4


Other related posts: