On 9 Jul 2018, at 13:46, Ivan Koptelov <ivan.koptelov@xxxxxxxxxxxxx> wrote:
Sorry, in both previous letters patch was not properly formatted. Now I
checked it
sending it to myself, it should be ok.
--
sql: add index_def to Index
Now every sqlite struct Index is created with tnt struct
index_def inside. This allows us to use tnt index_def
in work with sqlite indexes in the same manner as with
tnt index and is a step to remove sqlite Index with
tnt index.
Fields coll_array, coll_id_array, aiColumn, sort_order,
aiRowLogEst and zName are removed from Index. All usages
of this fields changed to usage of corresponding index_def
or index_def->opts fields.
index_is_unique(), sql_index_collation() and
index_column_count() are removed with calls of
index_def corresponding fields.
Also there is small change in user-visible behavior:
before the patch a statement like
CREATE TABLE t1(a,b, PRIMARY KEY(a,b), UNIQUE(a,b))
created only one constraint index (for primary key)
and no index for UNIQUE constraint (since it is upon the
same columns), neither it is named or non-named constraint.
After the patch index will be always created for named
constraints. It is a temporary solution. In future it's
preferable not to create an index, but to make some record
in _constraints space that this named unique constraint
implemented with the same index as primary key constraint.
@@ -2511,44 +2431,11 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex,
int memRootPage)
sqlite3VdbeAddOp1(v, OP_Close, iSorter);
}
-/*
- * Allocate heap space to hold an Index object with nCol columns.
- *
- * Increase the allocation size to provide an extra nExtra bytes
- * of 8-byte aligned space after the Index object and return a
- * pointer to this extra space in *ppExtra.
- */
-Index *
-sqlite3AllocateIndexObject(sqlite3 * db, /* Database connection */
- i16 nCol, /* Total number of columns in the index
*/
- int nExtra, /* Number of bytes of extra space to
alloc */
- char **ppExtra /* Pointer to the "extra" space
*/
- )
+struct Index *
+sql_index_alloc(struct sqlite3 *db)
{
- Index *p; /* Allocated index object */
- int nByte; /* Bytes of space for Index object + arrays */
-
- nByte = ROUND8(sizeof(Index)) + /* Index structure */
- ROUND8(sizeof(struct coll *) * nCol) + /* Index.coll_array */
- ROUND8(sizeof(uint32_t) * nCol) + /* Index.coll_id_array*/
- ROUND8(sizeof(LogEst) * (nCol + 1) + /* Index.aiRowLogEst */
- sizeof(i16) * nCol + /* Index.aiColumn */
- sizeof(enum sort_order) * nCol); /* Index.sort_order */
- p = sqlite3DbMallocZero(db, nByte + nExtra);
- if (p) {
- char *pExtra = ((char *)p) + ROUND8(sizeof(Index));
- p->coll_array = (struct coll **)pExtra;
- pExtra += ROUND8(sizeof(struct coll **) * nCol);
- p->coll_id_array = (uint32_t *) pExtra;
- pExtra += ROUND8(sizeof(uint32_t) * nCol);
- p->aiRowLogEst = (LogEst *) pExtra;
- pExtra += sizeof(LogEst) * (nCol + 1);
- p->aiColumn = (i16 *) pExtra;
- pExtra += sizeof(i16) * nCol;
- p->sort_order = (enum sort_order *) pExtra;
- p->nColumn = nCol;
- *ppExtra = ((char *)p) + nByte;
- }
+ int index_size = ROUND8(sizeof(struct Index));
+ struct Index *p = sqlite3DbMallocZero(db, index_size);
return p;
}
@@ -2635,48 +2522,132 @@ addIndexToTable(Index * pIndex, Table * pTab)
+static int
+index_fill_def(struct Parse *parse, struct Index *index,
+ struct Table *table, uint32_t iid, const char *name,
+ uint32_t name_len, struct ExprList *expr_list,
+ enum sql_index_type idx_type, char *sql_stmt)
+{
- return tnt_index->def->opts.is_unique;
+ struct key_def *pk_key_def;
+ if (idx_type == SQL_INDEX_TYPE_UNIQUE ||
+ idx_type == SQL_INDEX_TYPE_NON_UNIQUE)
+ pk_key_def = table->pIndex->def->key_def;
+ else
+ pk_key_def = NULL;
+
+ index->def = index_def_new(space_def->id, iid, name, name_len, TREE,
+ &opts, key_def, pk_key_def);
+ if (index->def == NULL)
+ goto tnt_error;
+ rc = 0;
+cleanup:
+ if (key_def != NULL)
+ key_def_delete(key_def);
+ return rc;
+tnt_error:
+ parse->rc = SQL_TARANTOOL_ERROR;
+ ++parse->nErr;
+ goto cleanup;
}
void
sql_create_index(struct Parse *parse, struct Token *token,
struct SrcList *tbl_name, struct ExprList *col_list,
- int on_error, struct Token *start, struct Expr *where,
- enum sort_order sort_order, bool if_not_exist, u8 idx_type)
-{
- Table *pTab = 0; /* Table to be indexed */
- Index *pIndex = 0; /* The index to be created */
- char *zName = 0; /* Name of the index */
- int nName; /* Number of characters in zName */
- int i, j;
- DbFixer sFix; /* For assigning database names to pTable */
- sqlite3 *db = parse->db;
- struct ExprList_item *col_listItem; /* For looping over col_list */
- int nExtra = 0; /* Space allocated for zExtra[] */
- char *zExtra = 0; /* Extra space after the Index object */
+ enum on_conflict_action on_error, struct Token *start,
+ struct Expr *where, enum sort_order sort_order,
+ bool if_not_exist, enum sql_index_type idx_type) {
+ /* The index to be created. */
+ struct Index *index = NULL;
+ /* Name of the index. */
+ char *name = NULL;
+ struct sqlite3 *db = parse->db;
struct session *user_session = current_session();
- if (db->mallocFailed || parse->nErr > 0) {
+ if (db->mallocFailed || parse->nErr > 0)
goto exit_create_index;
- }
- /* Do not account nested operations: the count of such
- * operations depends on Tarantool data dictionary internals,
- * such as data layout in system spaces. Also do not account
- * PRIMARY KEY and UNIQUE constraint - they had been accounted
- * in CREATE TABLE already.
+ /*
+ * Do not account nested operations: the count of such
+ * operations depends on Tarantool data dictionary
+ * internals, such as data layout in system spaces. Also
+ * do not account PRIMARY KEY and UNIQUE constraint - they
+ * had been accounted in CREATE TABLE already.
*/
- if (!parse->nested && idx_type == SQLITE_IDXTYPE_APPDEF) {
+ if (!parse->nested && (idx_type == SQL_INDEX_TYPE_UNIQUE ||
+ idx_type == SQL_INDEX_TYPE_NON_UNIQUE)) {
Vdbe *v = sqlite3GetVdbe(parse);
if (v == NULL)
goto exit_create_index;
@@ -2685,39 +2656,30 @@ sql_create_index(struct Parse *parse, struct Token
*token,
assert(db->pSchema != NULL);
/*
- * Find the table that is to be indexed. Return early if not found.
+ * Find the table that is to be indexed.
+ * Return early if not found.
*/
+ struct Table *table = NULL;
if (tbl_name != NULL) {
-
- /* Use the two-part index name to determine the database
- * to search for the table. 'Fix' the table name to this db
- * before looking up the table.
+ /*
+ * Use the two-part index name to determine the
+ * database to search for the table. 'Fix' the
+ * table name to this db before looking up the
+ * table.
*/
- assert(token && token->z);
-
- sqlite3FixInit(&sFix, parse, "index", token);
- if (sqlite3FixSrcList(&sFix, tbl_name)) {
- /* Because the parser constructs tbl_name from a single
identifier,
- * sqlite3FixSrcList can never fail.
- */
- assert(0);
- }
- pTab = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName);
- assert(db->mallocFailed == 0 || pTab == 0);
- if (pTab == 0)
- goto exit_create_index;
- sqlite3PrimaryKeyIndex(pTab);
+ assert(token != NULL && token->z != NULL);
+ table = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName);
+ assert(db->mallocFailed == 0 || table == NULL);
} else {
assert(token == NULL);
assert(start == NULL);
- pTab = parse->pNewTable;
- if (!pTab)
- goto exit_create_index;
+ table = parse->pNewTable;
}
- assert(pTab != 0);
- assert(parse->nErr == 0);
- if (pTab->def->opts.is_view) {
+ if (table == NULL || parse->nErr > 0)
+ goto exit_create_index;
+
+ if (table->def->opts.is_view) {
sqlite3ErrorMsg(parse, "views may not be indexed");
goto exit_create_index;
}
@@ -2734,45 +2696,68 @@ sql_create_index(struct Parse *parse, struct Token
*token,
* If token == NULL it means that we are dealing with a
* primary key or UNIQUE constraint. We have to invent
* our own name.
+ *
+ * In case of UNIQUE constraint we have two options:
+ * 1) UNIQUE constraint is named and this name will
+ * be a part of index name.
+ * 2) UNIQUE constraint is non-named and standard
+ * auto-index name will be generated.
*/
- if (token) {
- zName = sqlite3NameFromToken(db, token);
- if (zName == 0)
+ bool is_constraint_named = false;
+ if (token != NULL) {
+ name = sqlite3NameFromToken(db, token);
+ if (name == NULL)
goto exit_create_index;
- assert(token->z != 0);
- if (!db->init.busy) {
- if (sqlite3HashFind(&db->pSchema->tblHash, zName) !=
- NULL) {
- sqlite3ErrorMsg(parse,
- "there is already a table named
%s",
- zName);
- goto exit_create_index;
- }
- }
- if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) {
+ assert(token->z != NULL);
+ if (sqlite3HashFind(&table->idxHash, name) != NULL) {
if (!if_not_exist) {
sqlite3ErrorMsg(parse,
"index %s.%s already exists",
- pTab->def->name, zName);
+ table->def->name, name);
} else {
assert(!db->init.busy);
}
goto exit_create_index;
}
} else {
- int n;
- Index *pLoop;
- for (pLoop = pTab->pIndex, n = 1; pLoop;
- pLoop = pLoop->pNext, n++) {
+ char *constraint_name = NULL;
+ if (parse->constraintName.z != NULL)
+ constraint_name =
+ sqlite3NameFromToken(db,
&parse->constraintName);
+
+ if (constraint_name == NULL ||
+ strcmp(constraint_name, "") == 0) {
+ int n = 1;
+ for (struct Index *idx = table->pIndex;
+ idx != NULL;
+ idx = idx->pNext, n++) {
+ }
+ name = sqlite3MPrintf(db, "sql_autoindex_%s_%d",
+ table->def->name, n);
+ } else {
+ name = sqlite3MPrintf(db, "sql_autoindex_%s",
+ constraint_name);
+ is_constraint_named = true;
}
- zName =
- sqlite3MPrintf(db, "sqlite_autoindex_%s_%d",
pTab->def->name,
- n);
- if (zName == 0) {
- goto exit_create_index;
+ if (constraint_name != NULL) {
+ sqlite3DbFree(db, constraint_name);
+ if (table == parse->pNewTable) {
+ for (struct Index *idx = table->pIndex; idx != NULL;
+ idx = idx->pNext) {
+ uint32_t k;
+ assert(IsUniqueIndex(idx));
+ assert(IsUniqueIndex(index));
+
+ if (idx->def->key_def->part_count !=
+ index->def->key_def->part_count)
continue;
- for (k = 0; k < pIdx->nColumn; k++) {
- assert(pIdx->aiColumn[k] >= 0);
- if (pIdx->aiColumn[k] != pIndex->aiColumn[k])
+ for (k = 0; k < idx->def->key_def->part_count; k++) {
+ if (idx->def->key_def->parts[k].fieldno !=
+ index->def->key_def->parts[k].fieldno)
break;
struct coll *coll1, *coll2;
- uint32_t id;
- coll1 = sql_index_collation(pIdx, k, &id);
- coll2 = sql_index_collation(pIndex, k, &id);
+ coll1 = idx->def->key_def->parts[k].coll;
+ coll2 = index->def->key_def->parts[k].coll;
if (coll1 != coll2)
break;
}
- if (k == pIdx->nColumn) {
- if (pIdx->onError != pIndex->onError) {
- /* This constraint creates the same
index as a previous
- * constraint specified somewhere in
the CREATE TABLE statement.
- * However the ON CONFLICT clauses are
different. If both this
- * constraint and the previous
equivalent constraint have explicit
- * ON CONFLICT clauses this is an
error. Otherwise, use the
- * explicitly specified behavior for
the index.
+ if (k == idx->def->key_def->part_count) {
+ if (idx->onError != index->onError) {
+ /*
+ * This constraint creates
+ * the same index as a
+ * previous
+ * constraint specified
+ * somewhere in the CREATE
+ * TABLE statement.
+ * However the ON CONFLICT
+ * clauses are different.
+ * If both this constraint
+ * and the previous
+ * equivalent constraint
+ * have explicit
+ * ON CONFLICT clauses
+ * this is an error.
+ * Otherwise, use the
+ * explicitly specified
+ * behavior for the index.
*/
- if (!
- (pIdx->onError ==
ON_CONFLICT_ACTION_DEFAULT
- || pIndex->onError ==
- ON_CONFLICT_ACTION_DEFAULT)) {
+ if (idx->onError !=
+ ON_CONFLICT_ACTION_DEFAULT &&
+ index->onError !=
+ ON_CONFLICT_ACTION_DEFAULT) {
sqlite3ErrorMsg(parse,
- "conflicting ON
CONFLICT clauses specified",
- 0);
- }
- if (pIdx->onError ==
ON_CONFLICT_ACTION_DEFAULT) {
- pIdx->onError = pIndex->onError;
+ "conflicting "\
+ "ON CONFLICT "\
+ "clauses "\
+ "specified”);
}
+ if (idx->onError ==
+ ON_CONFLICT_ACTION_DEFAULT)
+ idx->onError = index->onError;
+ }
+ if (idx_type == SQL_INDEX_TYPE_CONSTRAINT_PK)
+ idx->index_type = idx_type;
@@ -2880,9 +2865,7 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder, /*
WHERE clause information */
{
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
- Index sPk; /* A fake index object for the primary key */
- LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */
- i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */
+ Index fake_index; /* A fake index object for the primary
key */
SrcList *pTabList; /* The FROM clause */
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
WhereLoop *pNew; /* Template WhereLoop object */
@@ -2903,31 +2886,62 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,
/* WHERE clause information */
if (pSrc->pIBIndex) {
/* An INDEXED BY clause specifies a particular index to use */
pProbe = pSrc->pIBIndex;
+ fake_index.def = NULL;
} else if (pTab->pIndex) {
pProbe = pTab->pIndex;
+ fake_index.def = NULL;
} else {
/* There is no INDEXED BY clause. Create a fake Index object
in local
- * variable sPk to represent the primary key index. Make this
+ * variable fake_index to represent the primary key index.
Make this
* fake index the first in a chain of Index objects with all of
the real
* indices to follow
*/
Index *pFirst; /* First of real indices on the table */
- memset(&sPk, 0, sizeof(Index));
- sPk.nColumn = 1;
- sPk.aiColumn = &aiColumnPk;
- sPk.aiRowLogEst = aiRowEstPk;
- sPk.onError = ON_CONFLICT_ACTION_REPLACE;
- sPk.pTable = pTab;
- aiRowEstPk[0] = sql_space_tuple_log_count(pTab);
- aiRowEstPk[1] = 0;
+ memset(&fake_index, 0, sizeof(Index));
+ fake_index.onError = ON_CONFLICT_ACTION_REPLACE;
+ fake_index.pTable = pTab;
+
+ struct key_def *key_def = key_def_new(1);
+ if (key_def == NULL) {
+ pWInfo->pParse->nErr++;
+ pWInfo->pParse->rc = SQL_TARANTOOL_ERROR;
+ return SQL_TARANTOOL_ERROR;
+ }
+
+ key_def_set_part(key_def, 0, 0, pTab->def->fields[0].type,
+ ON_CONFLICT_ACTION_ABORT,
+ NULL, COLL_NONE, SORT_ORDER_ASC);
+
+ struct index_opts opts;
+ index_opts_create(&opts);
+ opts.sql = "fake_autoindex";
+ fake_index.def = index_def_new(pTab->def->id, 0,
"fake_autoindex”,