[tarantool-patches] Re: [PATCH v2] sql: add index_def to struct Index

  • From: "n.pettik" <korablev@xxxxxxxxxxxxx>
  • To: tarantool-patches@xxxxxxxxxxxxx
  • Date: Fri, 13 Jul 2018 22:19:08 +0300


+     /*
+      * Here we handle cases like
+      * CREATE TABLE t1(a UNIQUE, PRIMARY KEY(a))
+      * In these cases (where UNIQUE constraints precede
+      * PRIMARY constraint) appropriate Index->def->cmp_def
+      * can not be set 'on the fly' for indexes implementing
+      * UNIQUE constraints as PK key_def is missing and
+      * needed for it.
+      * At this point we can set appropriate cmp_def, since
+      * all indexes (from CREATE TABLE statement) is created.
+      */
+     if (!p->def->opts.is_view) {
+             assert(p->pIndex != NULL);
+             struct Index *pk;
+             for (struct Index *idx = p->pIndex; idx != NULL;
+                  idx = idx->pNext) {
+                     if (idx->index_type == SQL_INDEX_TYPE_CONSTRAINT_PK)
+                             pk = idx;
+             }
+             struct key_def *pk_def = pk->def->key_def;
+
+             for (struct Index *idx = p->pIndex; idx != NULL;
+                  idx = idx->pNext) {
+                     if (idx->index_type != SQL_INDEX_TYPE_CONSTRAINT_PK) {
+                             struct index_def *def = idx->def;
+                             struct key_def *cmp_def =
+                                     key_def_merge(def->key_def,
+                                                   pk_def);
+                             if (cmp_def == NULL) {
+                                     pParse->rc = SQL_TARANTOOL_ERROR;
+                                     ++pParse->nErr;
+                                     return;
+                             }
+                             if (!def->opts.is_unique) {
+                                     def->cmp_def->unique_part_count =
+                                             def->cmp_def->part_count;
+                             } else {
+                                     def->cmp_def->unique_part_count =
+                                             def->key_def->part_count;
+                             }
+                     }
+             }
+     }
I don’t understand: why do you need at all this cmp_def?
In SQL it is extremely unlikely to be useful.
      if (db->init.busy) {
              /*
               * As rebuild creates a new ExpList tree and
@@ -2398,8 +2441,7 @@
 struct Index *
 sql_index_alloc(struct sqlite3 *db)
 {
-     int index_size = ROUND8(sizeof(struct Index));
-     struct Index *p = sqlite3DbMallocZero(db, index_size);
+     struct Index *p = sqlite3DbMallocZero(db, sizeof(struct Index));
      return p;
 }
 
@@ -2566,12 +2608,25 @@
      if (parse->nErr > 0)
              goto cleanup;
 
-     struct key_def *pk_key_def;
-     if (idx_type == SQL_INDEX_TYPE_UNIQUE ||
-         idx_type == SQL_INDEX_TYPE_NON_UNIQUE)
+     struct key_def *pk_key_def = NULL;
+     if (idx_type != SQL_INDEX_TYPE_CONSTRAINT_PK &&
+         parse->pNewTable == NULL)
              pk_key_def = table->pIndex->def->key_def;
-     else
-             pk_key_def = NULL;
+     /*
+      * In cases like CREATE TABLE t1(a UNIQUE, PRIMARY KEY(a))
+      * fill_index_def() will be firstly executed for creating
+      * index_def for UNIQUE constraint and then for creating
+      * index_def for PRIMARY KEY constraint. So when
+      * fill_index_def will be called for UNIQUE constraint
+      * there will be no PK, while PK->def->key_def is needed
+      * to create cmp_def (inside index_def_new()). 
Again: explain pls why do you need cmp_def on client-side (i.e. parser)?
To handle
+      * this case we set here pk_key_def to key_def and later
+      * in sqlite3EndTable (when PK index is already created)
+      * we go over all indexes and set appropriate cmp_def in
+      * them.
+      */
+     if (parse->pNewTable != NULL)
+             pk_key_def = key_def;
 
      index->def = index_def_new(space_def->id, iid, name, name_len, TREE,
                                 &opts, key_def, pk_key_def);
@@ -2618,12 +2673,6 @@
       */
      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.
-              */
              assert(token != NULL && token->z != NULL);
              table = sqlite3LocateTable(parse, 0, tbl_name->a[0].zName);
              assert(db->mallocFailed == 0 || table == NULL);
@@ -2642,7 +2691,7 @@
      }
      /*
       * Find the name of the index.  Make sure there is not
-      * already another index or table with the same name.
+      * already another index with the same name.
       *
       * Exception:  If we are reading the names of permanent
       * indices from the Tarantool schema (because some other
@@ -2660,7 +2709,7 @@
       * 2) UNIQUE constraint is non-named and standard
       *    auto-index name will be generated.
       */
-     bool is_constraint_named = false;
+     bool is_constraint_named;
      if (token != NULL) {
              name = sqlite3NameFromToken(db, token);
              if (name == NULL)
@@ -2691,14 +2740,26 @@
                      }
                      name = sqlite3MPrintf(db, "sql_autoindex_%s_%d",
                                            table->def->name, n);
+                     is_constraint_named = false;
              } else {
-                     name = sqlite3MPrintf(db, "sql_autoindex_%s",
-                                           constraint_name);
+                     /*
+                      * This naming is temporary. Now it's not
+                      * possible (since we implement UNIQUE
+                      * and PK constraints with indexes and
+                      * indexes can not have same names), but
+                      * in future we would use names exactly
+                      * as they are set by user.
+                      */
+                     if (idx_type == SQL_INDEX_TYPE_CONSTRAINT_UNIQUE)
+                             name = sqlite3MPrintf(db,
+                                                   "unique_constraint_%s",
+                                                   constraint_name);
+                     if (idx_type == SQL_INDEX_TYPE_CONSTRAINT_PK)
+                             name = sqlite3MPrintf(db, "pk_constraint_%s",
+                                                   constraint_name);
                      is_constraint_named = true;
              }
-             if (constraint_name != NULL) {
-                     sqlite3DbFree(db, constraint_name);
-             }
+             sqlite3DbFree(db, constraint_name);
      }
 
      if (name == NULL)
@@ -2708,7 +2769,8 @@
                             table->def->id < BOX_SYSTEM_ID_MAX;
      if (is_system_space && (idx_type == SQL_INDEX_TYPE_NON_UNIQUE ||
                              idx_type == SQL_INDEX_TYPE_UNIQUE)) {
-             diag_set(ClientError, ER_MODIFY_INDEX, name, table->def->name,
+             diag_set(ClientError, ER_MODIFY_INDEX, name,
+                      table->def->name,
                       "can't create index on system space");
              parse->nErr++;
              parse->rc = SQL_TARANTOOL_ERROR;
@@ -2745,7 +2807,7 @@
 
      index->pTable = table;
      index->onError = (u8) on_error;
-     index->index_type = idx_type;
+     index->index_type = idx_type;
      index->pSchema = db->pSchema;
      /* Tarantool have access to each column by any index. */
      if (where != NULL) {
@@ -2775,8 +2837,22 @@
                      goto exit_create_index;
      }
 
-     /* If it is parsing stage, then iid may have any value. */
-     uint32_t iid = 1;
+     /*
+      * We set no SQL statement for indexes created during
+      * CREATE TABLE statement. Instead we use
+      * Index->index_def->opts.sql to store information if
+      * this index implements named or non-named constraint.
+      */
+     if (tbl_name == NULL &&
+         idx_type == SQL_INDEX_TYPE_CONSTRAINT_UNIQUE)
If idx_type == SQL_INDEX_TYPE_CONSTRAINT_UNIQUE than tbl_name must be NULL:
you can’t declare unique constraint outside CREATE TABLE statement.

+             sql_stmt = is_constraint_named ?
+                        "named constraint" : "non-named constraint”;
You can set ‘sql_stmt’ only for name constraints:

sql_stmt = is_constraint_name ? “_named_constr” :  “”;

And use strncmp when comparing with it. 

Also, if <if-clause> contains mode than one row,
we wrap it in brackets.
+
+     /*
+      * If it is parsing stage, then iid may have any value,
+      * but PK still must have iid == 0
+      */
+     uint32_t iid = idx_type == SQL_INDEX_TYPE_CONSTRAINT_PK ? 0 : 1;
      if (db->init.busy)
              iid = SQLITE_PAGENO_TO_INDEXID(db->init.newTnum);
You can just do this:

uint32_t iid = idx_type == SQL_INDEX_TYPE_CONSTRAINT_PK;
+
+                     if (k != key_def->part_count)
+                             continue;
+
+                     if (index->onError != existing_idx->onError) {
+                             if (index->onError !=
+                                 ON_CONFLICT_ACTION_DEFAULT &&
+                                 existing_idx->onError !=
+                                 ON_CONFLICT_ACTION_DEFAULT)
+                                     sqlite3ErrorMsg(parse,
+                                                     "conflicting "\
+                                                     "ON CONFLICT "\
+                                                     "clauses specified”);
Again: here you have already set error. What is the reason to
continue process smth? You are able to go to exit_create_index.

Other related posts: