From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 9002925D7C for ; Thu, 31 Jan 2019 14:33:01 -0500 (EST) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XgTPpWAhpHQg for ; Thu, 31 Jan 2019 14:33:01 -0500 (EST) Received: from smtpng1.m.smailru.net (smtpng1.m.smailru.net [94.100.181.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 2E1B52621C for ; Thu, 31 Jan 2019 14:33:00 -0500 (EST) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.2 \(3445.102.3\)) Subject: [tarantool-patches] Re: [PATCH v2 1/5] sql: introduce structs assembling DDL arguments during parsing From: "n.pettik" In-Reply-To: Date: Thu, 31 Jan 2019 22:32:57 +0300 Content-Transfer-Encoding: quoted-printable Message-Id: <45655E85-4DBB-4AC4-8161-5B783C66C688@tarantool.org> References: <0fcc585532a1f1200a7dfd4a8e911ecf9f2c94aa.1548265148.git.korablev@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Vladislav Shpilevoy I=E2=80=99ve took into consideration your comments and pushed new version of this patch: Branch: np/gh-3914-fix-create-index-v2 If it is OK (except for minor things mb) I will add it to the main patch-set and rebase the rest. Author: Nikita Pettik Date: Wed Jan 9 12:28:09 2019 +0200 sql: introduce structs assembling DDL arguments during parsing =20 Parser's rules implementing DDL have a lot in common. For instance, to drop any entity it is enough to know its name and name of table = it is related to. Thus, it was suggested to arrange arguments of DDL rules into hierarchical structure. The root of chain always includes name of = table to be altered: all existing entities are related to some table. = Then comes one of drop/create/rename rules. Indeed, each DDL operation = can be classified in these terms, at least until we introduce ALTER TABLE = ALTER CONSTRAINT statement. Drop is represented by single structure (as it = was mentioned); rename can be applied only to table; create can be = applied to CONSTRAINT (indexes are considered as constraints) and TRIGGER, = which in turn are different in arguments required to create those objects. = And so forth. =20 What is more, we are going to introduce ALTER TABLE ADD CONSTRAINT UNIQUE With new hierarchy we can extend ALTER TABLE statement with = ease: basic structures (alter -> create entity -> create constraint) are = the same for .. FOREIGN KEY/UNIQUE, but the last one will be different. =20 Patch itself is made up of refactoring; no functional changes are provided. =20 Needed for #3097 diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c index d0ce9d893..e88b57b59 100644 --- a/src/box/sql/alter.c +++ b/src/box/sql/alter.c @@ -38,12 +38,14 @@ #include "box/schema.h" =20 void -sql_alter_table_rename(struct Parse *parse, struct SrcList *src_tab, - struct Token *new_name_tk) +sql_alter_table_rename(struct Parse *parse) { + struct rename_entity_def rename_def =3D = parse->rename_entity_def; + struct SrcList *src_tab =3D rename_def.base.entity_name; + assert(rename_def.base.entity_type =3D=3D ENTITY_TYPE_TABLE); assert(src_tab->nSrc =3D=3D 1); struct sqlite3 *db =3D parse->db; - char *new_name =3D sqlite3NameFromToken(db, new_name_tk); + char *new_name =3D sqlite3NameFromToken(db, = &rename_def.new_name); if (new_name =3D=3D NULL) goto exit_rename_table; /* Check that new name isn't occupied by another table. */ diff --git a/src/box/sql/build.c b/src/box/sql/build.c index f92f39d8e..b6f099cf5 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -383,18 +383,16 @@ sql_table_new(Parse *parser, char *name) * when the "TEMP" or "TEMPORARY" keyword occurs in between * CREATE and TABLE. * - * The new table record is initialized and put in pParse->pNewTable. + * The new table record is initialized and put in pParse->new_table. * As more of the CREATE TABLE statement is parsed, additional action * routines will be called to add more information to this record. * At the end of the CREATE TABLE statement, the sqlite3EndTable() = routine * is called to complete the construction of the new table record. * * @param pParse Parser context. - * @param pName1 First part of the name of the table or view. - * @param noErr Do nothing if table already exists. */ void -sqlite3StartTable(Parse *pParse, Token *pName, int noErr) +sqlite3StartTable(struct Parse *pParse) { Table *pTable; char *zName =3D 0; /* The name of the new table */ @@ -403,8 +401,9 @@ sqlite3StartTable(Parse *pParse, Token *pName, int = noErr) if (v =3D=3D NULL) goto cleanup; sqlite3VdbeCountChanges(v); - - zName =3D sqlite3NameFromToken(db, pName); + struct Token name =3D + ((struct create_entity_def *) = &pParse->create_table_def)->name; + zName =3D sqlite3NameFromToken(db, &name); =20 if (zName =3D=3D 0) return; @@ -413,7 +412,7 @@ sqlite3StartTable(Parse *pParse, Token *pName, int = noErr) =20 struct space *space =3D space_by_name(zName); if (space !=3D NULL) { - if (!noErr) { + if (!pParse->create_table_def.base.if_not_exist) { sqlite3ErrorMsg(pParse, "table %s already = exists", zName); } else { @@ -426,8 +425,7 @@ sqlite3StartTable(Parse *pParse, Token *pName, int = noErr) if (pTable =3D=3D NULL) goto cleanup; =20 - assert(pParse->pNewTable =3D=3D 0); - pParse->pNewTable =3D pTable; + pParse->create_table_def.new_table =3D pTable; =20 if (!db->init.busy && (v =3D sqlite3GetVdbe(pParse)) !=3D 0) sql_set_multi_write(pParse, true); @@ -516,7 +514,7 @@ sqlite3AddColumn(Parse * pParse, Token * pName, = struct type_def *type_def) int i; char *z; sqlite3 *db =3D pParse->db; - if ((p =3D pParse->pNewTable) =3D=3D 0) + if ((p =3D pParse->create_table_def.new_table) =3D=3D NULL) return; #if SQLITE_MAX_COLUMN if ((int)p->def->field_count + 1 > = db->aLimit[SQLITE_LIMIT_COLUMN]) { @@ -565,14 +563,13 @@ sqlite3AddColumn(Parse * pParse, Token * pName, = struct type_def *type_def) column_def->affinity =3D type_def->type; column_def->type =3D = sql_affinity_to_field_type(column_def->affinity); p->def->field_count++; - pParse->constraintName.n =3D 0; } =20 void sql_column_add_nullable_action(struct Parse *parser, enum on_conflict_action nullable_action) { - struct Table *p =3D parser->pNewTable; + struct Table *p =3D parser->create_table_def.new_table; if (p =3D=3D NULL || NEVER(p->def->field_count < 1)) return; struct field_def *field =3D &p->def->fields[p->def->field_count = - 1]; @@ -609,7 +606,7 @@ sqlite3AddDefaultValue(Parse * pParse, ExprSpan * = pSpan) { Table *p; sqlite3 *db =3D pParse->db; - p =3D pParse->pNewTable; + p =3D pParse->create_table_def.new_table; assert(p->def->opts.is_temporary); if (p !=3D 0) { if (!sqlite3ExprIsConstantOrFunction @@ -673,11 +670,10 @@ field_def_create_for_pk(struct Parse *parser, = struct field_def *field, void sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ ExprList * pList, /* List of field names to be = indexed */ - int autoInc, /* True if the AUTOINCREMENT = keyword is present */ enum sort_order sortOrder ) { - Table *pTab =3D pParse->pNewTable; + Table *pTab =3D pParse->create_table_def.new_table; int iCol =3D -1, i; int nTerm; if (pTab =3D=3D 0) @@ -712,11 +708,12 @@ sqlite3AddPrimaryKey(Parse * pParse, /* = Parsing context */ } } } + pParse->create_index_def.idx_type =3D = SQL_INDEX_TYPE_CONSTRAINT_PK; + pParse->create_index_def.sort_order =3D sortOrder; + entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX); if (nTerm =3D=3D 1 && iCol !=3D -1 && pTab->def->fields[iCol].type =3D=3D FIELD_TYPE_INTEGER && sortOrder !=3D SORT_ORDER_DESC) { - assert(autoInc =3D=3D 0 || autoInc =3D=3D 1); - pParse->is_new_table_autoinc =3D autoInc; struct sqlite3 *db =3D pParse->db; struct ExprList *list; struct Token token; @@ -726,17 +723,17 @@ sqlite3AddPrimaryKey(Parse * pParse, /* = Parsing context */ &token, = 0)); if (list =3D=3D NULL) goto primary_key_exit; - sql_create_index(pParse, 0, 0, list, 0, SORT_ORDER_ASC, - false, SQL_INDEX_TYPE_CONSTRAINT_PK); + pParse->create_index_def.cols =3D list; + sql_create_index(pParse); if (db->mallocFailed) goto primary_key_exit; - } else if (autoInc) { + } else if (pParse->create_table_def.has_autoinc) { sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed = on an " "INTEGER PRIMARY KEY or INT PRIMARY = KEY"); goto primary_key_exit; } else { - sql_create_index(pParse, 0, 0, pList, 0, sortOrder, = false, - SQL_INDEX_TYPE_CONSTRAINT_PK); + pParse->create_index_def.cols =3D pList; + sql_create_index(pParse); pList =3D 0; if (pParse->nErr > 0) goto primary_key_exit; @@ -756,14 +753,21 @@ primary_key_exit: } =20 void -sql_add_check_constraint(struct Parse *parser, struct ExprSpan *span) -{ - struct Expr *expr =3D span->pExpr; - struct Table *table =3D parser->pNewTable; +sql_add_check_constraint(struct Parse *parser) +{ + struct create_ck_def *ck_def =3D &parser->create_ck_def; + struct alter_entity_def *alter_def =3D + (struct alter_entity_def *) &parser->create_ck_def; + assert(alter_def->entity_type =3D=3D ENTITY_TYPE_CK); + (void) alter_def; + struct Expr *expr =3D ck_def->expr->pExpr; + struct Table *table =3D parser->create_table_def.new_table; if (table !=3D NULL) { expr->u.zToken =3D - sqlite3DbStrNDup(parser->db, (char = *)span->zStart, - (int)(span->zEnd - = span->zStart)); + sqlite3DbStrNDup(parser->db, + (char *) ck_def->expr->zStart, + (int) (ck_def->expr->zEnd - + ck_def->expr->zStart)); if (expr->u.zToken =3D=3D NULL) goto release_expr; table->def->opts.checks =3D @@ -773,9 +777,11 @@ sql_add_check_constraint(struct Parse *parser, = struct ExprSpan *span) sqlite3DbFree(parser->db, expr->u.zToken); goto release_expr; } - if (parser->constraintName.n) { + struct create_entity_def *entity_def =3D + (struct create_entity_def *) ck_def; + if (entity_def->name.n > 0) { sqlite3ExprListSetName(parser, = table->def->opts.checks, - &parser->constraintName, = 1); + &entity_def->name, 1); } } else { release_expr: @@ -790,7 +796,7 @@ release_expr: void sqlite3AddCollateType(Parse * pParse, Token * pToken) { - Table *p =3D pParse->pNewTable; + Table *p =3D pParse->create_table_def.new_table; if (p =3D=3D NULL) return; uint32_t i =3D p->def->field_count - 1; @@ -923,7 +929,7 @@ vdbe_emit_create_index(struct Parse *parse, struct = space_def *def, memcpy(raw, index_parts, index_parts_sz); index_parts =3D raw; =20 - if (parse->pNewTable !=3D NULL) { + if (parse->create_table_def.new_table !=3D NULL) { sqlite3VdbeAddOp2(v, OP_SCopy, space_id_reg, entry_reg); sqlite3VdbeAddOp2(v, OP_Integer, idx_def->iid, entry_reg = + 1); } else { @@ -963,7 +969,7 @@ error: static void createSpace(Parse * pParse, int iSpaceId) { - struct Table *table =3D pParse->pNewTable; + struct Table *table =3D pParse->create_table_def.new_table; Vdbe *v =3D sqlite3GetVdbe(pParse); int iFirstCol =3D ++pParse->nMem; int iRecord =3D (pParse->nMem +=3D 7); @@ -1113,14 +1119,15 @@ vdbe_emit_fkey_create(struct Parse = *parse_context, const struct fkey_def *fk) * of statement, we don't have child * id, but we know register where it will be stored. */ - if (parse_context->pNewTable !=3D NULL) { + if (parse_context->create_table_def.new_table !=3D NULL) { sqlite3VdbeAddOp2(vdbe, OP_SCopy, fk->child_id, constr_tuple_reg + 1); } else { sqlite3VdbeAddOp2(vdbe, OP_Integer, fk->child_id, constr_tuple_reg + 1); } - if (parse_context->pNewTable !=3D NULL && = fkey_is_self_referenced(fk)) { + if (parse_context->create_table_def.new_table !=3D NULL && + fkey_is_self_referenced(fk)) { sqlite3VdbeAddOp2(vdbe, OP_SCopy, fk->parent_id, constr_tuple_reg + 2); } else { @@ -1183,7 +1190,7 @@ vdbe_emit_fkey_create(struct Parse *parse_context, = const struct fkey_def *fk) constr_tuple_reg + 9); sqlite3VdbeAddOp3(vdbe, OP_SInsert, BOX_FK_CONSTRAINT_ID, 0, constr_tuple_reg + 9); - if (parse_context->pNewTable =3D=3D NULL) + if (parse_context->create_table_def.new_table =3D=3D NULL) sqlite3VdbeChangeP5(vdbe, OPFLAG_NCHANGE); save_record(parse_context, BOX_FK_CONSTRAINT_ID, = constr_tuple_reg, 2, vdbe->nOp - 1); @@ -1257,7 +1264,7 @@ sqlite3EndTable(Parse * pParse, /* Parse context = */ return; } assert(!db->mallocFailed); - p =3D pParse->pNewTable; + p =3D pParse->create_table_def.new_table; if (p =3D=3D 0) return; =20 @@ -1306,7 +1313,7 @@ sqlite3EndTable(Parse * pParse, /* Parse context = */ * Check to see if we need to create an _sequence table * for keeping track of autoincrement keys. */ - if (pParse->is_new_table_autoinc) { + if (pParse->create_table_def.has_autoinc) { assert(reg_space_id !=3D 0); /* Do an insertion into _sequence. */ int reg_seq_id =3D ++pParse->nMem; @@ -1329,7 +1336,8 @@ sqlite3EndTable(Parse * pParse, /* Parse context = */ } /* Code creation of FK constraints, if any. */ struct fkey_parse *fk_parse; - rlist_foreach_entry(fk_parse, &pParse->new_fkey, link) { + rlist_foreach_entry(fk_parse, = &pParse->create_table_def.new_fkey, + link) { struct fkey_def *fk =3D fk_parse->fkey; if (fk_parse->selfref_cols !=3D NULL) { struct ExprList *cols =3D = fk_parse->selfref_cols; @@ -1369,8 +1377,7 @@ cleanup: =20 void sql_create_view(struct Parse *parse_context, struct Token *begin, - struct Token *name, struct ExprList *aliases, - struct Select *select, bool if_exists) + struct ExprList *aliases, struct Select *select) { struct sqlite3 *db =3D parse_context->db; struct Table *sel_tab =3D NULL; @@ -1379,8 +1386,8 @@ sql_create_view(struct Parse *parse_context, = struct Token *begin, "parameters are not allowed in views"); goto create_view_fail; } - sqlite3StartTable(parse_context, name, if_exists); - struct Table *p =3D parse_context->pNewTable; + sqlite3StartTable(parse_context); + struct Table *p =3D parse_context->create_table_def.new_table; if (p =3D=3D NULL || parse_context->nErr !=3D 0) goto create_view_fail; sel_tab =3D sqlite3ResultSetOfSelect(parse_context, select); @@ -1683,14 +1690,14 @@ sql_code_drop_table(struct Parse *parse_context, = struct space *space, * This routine is called to do the work of a DROP TABLE statement. * * @param parse_context Current parsing context. - * @param table_name_list List containing table name. * @param is_view True, if statement is really 'DROP VIEW'. - * @param if_exists True, if statement contains 'IF EXISTS' clause. */ void -sql_drop_table(struct Parse *parse_context, struct SrcList = *table_name_list, - bool is_view, bool if_exists) +sql_drop_table(struct Parse *parse_context, bool is_view) { + struct drop_entity_def drop_def =3D = parse_context->drop_entity_def; + assert(drop_def.base.entity_type =3D=3D ENTITY_TYPE_TABLE); + struct SrcList *table_name_list =3D drop_def.base.entity_name; struct Vdbe *v =3D sqlite3GetVdbe(parse_context); struct sqlite3 *db =3D parse_context->db; if (v =3D=3D NULL || db->mallocFailed) { @@ -1702,10 +1709,10 @@ sql_drop_table(struct Parse *parse_context, = struct SrcList *table_name_list, const char *space_name =3D table_name_list->a[0].zName; struct space *space =3D space_by_name(space_name); if (space =3D=3D NULL) { - if (!is_view && !if_exists) + if (!is_view && !drop_def.if_exist) sqlite3ErrorMsg(parse_context, "no such table: = %s", space_name); - if (is_view && !if_exists) + if (is_view && !drop_def.if_exist) sqlite3ErrorMsg(parse_context, "no such view: = %s", space_name); goto exit_drop_table; @@ -1788,12 +1795,14 @@ columnno_by_name(struct Parse *parse_context, = const struct space *space, } =20 void -sql_create_foreign_key(struct Parse *parse_context, struct SrcList = *child, - struct Token *constraint, struct ExprList = *child_cols, - struct Token *parent, struct ExprList = *parent_cols, - bool is_deferred, int actions) +sql_create_foreign_key(struct Parse *parse_context) { struct sqlite3 *db =3D parse_context->db; + struct create_fk_def create_fk_def =3D = parse_context->create_fk_def; + struct create_constraint_def create_constr_def =3D = create_fk_def.base; + struct create_entity_def create_def =3D create_constr_def.base; + struct alter_entity_def alter_def =3D create_def.base; + assert(alter_def.entity_type =3D=3D ENTITY_TYPE_FK); /* * When this function is called second time during * statement (i.e. at VDBE runtime), @@ -1812,20 +1821,21 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, * Table under construction during CREATE TABLE * processing. NULL for ALTER TABLE statement handling. */ - struct Table *new_tab =3D parse_context->pNewTable; + struct create_table_def *table_def =3D = &parse_context->create_table_def; + struct Table *new_tab =3D table_def->new_table; /* Whether we are processing ALTER TABLE or CREATE TABLE. */ bool is_alter =3D new_tab =3D=3D NULL; uint32_t child_cols_count; + struct ExprList *child_cols =3D create_fk_def.child_cols; if (child_cols =3D=3D NULL) { assert(!is_alter); child_cols_count =3D 1; } else { child_cols_count =3D child_cols->nExpr; } - assert(!is_alter || (child !=3D NULL && child->nSrc =3D=3D 1)); struct space *child_space =3D NULL; if (is_alter) { - const char *child_name =3D child->a[0].zName; + const char *child_name =3D = alter_def.entity_name->a[0].zName; child_space =3D space_by_name(child_name); if (child_space =3D=3D NULL) { diag_set(ClientError, ER_NO_SUCH_SPACE, = child_name); @@ -1840,8 +1850,9 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, goto tnt_error; } memset(fk, 0, sizeof(*fk)); - rlist_add_entry(&parse_context->new_fkey, fk, link); + rlist_add_entry(&table_def->new_fkey, fk, link); } + struct Token *parent =3D create_fk_def.parent_name; assert(parent !=3D NULL); parent_name =3D sqlite3NameFromToken(db, parent); if (parent_name =3D=3D NULL) @@ -1853,11 +1864,12 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, */ is_self_referenced =3D !is_alter && strcmp(parent_name, new_tab->def->name) =3D=3D= 0; + struct ExprList *parent_cols =3D create_fk_def.parent_cols; struct space *parent_space =3D space_by_name(parent_name); if (parent_space =3D=3D NULL) { if (is_self_referenced) { struct fkey_parse *fk =3D - = rlist_first_entry(&parse_context->new_fkey, + rlist_first_entry(&table_def->new_fkey, struct fkey_parse, = link); fk->selfref_cols =3D parent_cols; fk->is_self_referenced =3D true; @@ -1872,18 +1884,19 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, goto exit_create_fk; } } - if (constraint =3D=3D NULL && !is_alter) { - if (parse_context->constraintName.n =3D=3D 0) { + if (!is_alter) { + if (create_def.name.n =3D=3D 0) { constraint_name =3D sqlite3MPrintf(db, = "FK_CONSTRAINT_%d_%s", - = ++parse_context->fkey_count, + ++table_def->fkey_count, new_tab->def->name); } else { - struct Token *cnstr_nm =3D = &parse_context->constraintName; - constraint_name =3D sqlite3NameFromToken(db, = cnstr_nm); + constraint_name =3D + sqlite3NameFromToken(db, = &create_def.name); } } else { - constraint_name =3D sqlite3NameFromToken(db, = constraint); + constraint_name =3D + sqlite3NameFromToken(db, &create_def.name); } if (constraint_name =3D=3D NULL) goto exit_create_fk; @@ -1916,10 +1929,11 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, diag_set(OutOfMemory, fk_size, "region", "struct fkey"); goto tnt_error; } + int actions =3D create_fk_def.actions; fk->field_count =3D child_cols_count; fk->child_id =3D child_space !=3D NULL ? child_space->def->id : = 0; fk->parent_id =3D parent_space !=3D NULL ? parent_space->def->id = : 0; - fk->is_deferred =3D is_deferred; + fk->is_deferred =3D create_constr_def.is_deferred; fk->match =3D (enum fkey_match) ((actions >> 16) & 0xff); fk->on_update =3D (enum fkey_action) ((actions >> 8) & 0xff); fk->on_delete =3D (enum fkey_action) (actions & 0xff); @@ -1973,7 +1987,7 @@ sql_create_foreign_key(struct Parse = *parse_context, struct SrcList *child, */ if (!is_alter) { struct fkey_parse *parse_fk =3D - rlist_first_entry(&parse_context->new_fkey, + rlist_first_entry(&table_def->new_fkey, struct fkey_parse, link); parse_fk->fkey =3D fk; } else { @@ -1997,18 +2011,20 @@ void fkey_change_defer_mode(struct Parse *parse_context, bool is_deferred) { if (parse_context->db->init.busy || - rlist_empty(&parse_context->new_fkey)) + rlist_empty(&parse_context->create_table_def.new_fkey)) return; - rlist_first_entry(&parse_context->new_fkey, struct fkey_parse, - link)->fkey->is_deferred =3D is_deferred; + rlist_first_entry(&parse_context->create_table_def.new_fkey, + struct fkey_parse, link)->fkey->is_deferred =3D + is_deferred; } =20 void -sql_drop_foreign_key(struct Parse *parse_context, struct SrcList = *table, - struct Token *constraint) +sql_drop_foreign_key(struct Parse *parse_context) { - assert(table !=3D NULL && table->nSrc =3D=3D 1); - const char *table_name =3D table->a[0].zName; + struct drop_entity_def drop_def =3D = parse_context->drop_entity_def; + assert(drop_def.base.entity_type =3D=3D ENTITY_TYPE_FK); + const char *table_name =3D = drop_def.base.entity_name->a[0].zName; + assert(table_name !=3D NULL); struct space *child =3D space_by_name(table_name); if (child =3D=3D NULL) { diag_set(ClientError, ER_NO_SUCH_SPACE, table_name); @@ -2017,7 +2033,7 @@ sql_drop_foreign_key(struct Parse *parse_context, = struct SrcList *table, return; } char *constraint_name =3D = sqlite3NameFromToken(parse_context->db, - constraint); + &drop_def.name); if (constraint_name !=3D NULL) vdbe_emit_fkey_drop(parse_context, constraint_name, child->def->id); @@ -2211,19 +2227,29 @@ constraint_is_named(const char *name) } =20 void -sql_create_index(struct Parse *parse, struct Token *token, - struct SrcList *tbl_name, struct ExprList *col_list, - MAYBE_UNUSED struct Token *start, enum sort_order = sort_order, - bool if_not_exist, enum sql_index_type idx_type) { +sql_create_index(struct Parse *parse) { /* The index to be created. */ struct index *index =3D NULL; /* Name of the index. */ char *name =3D NULL; struct sqlite3 *db =3D parse->db; assert(!db->init.busy); + struct create_index_def create_idx_def =3D = parse->create_index_def; + struct create_entity_def *create_entity_def =3D + (struct create_entity_def *) &create_idx_def; + struct alter_entity_def alter_entity_def =3D = create_entity_def->base; + assert(alter_entity_def.entity_type =3D=3D ENTITY_TYPE_INDEX); + /* + * Get list of columns to be indexed. It will be NULL if + * this is a primary key or unique-constraint on the most + * recent column added to the table under construction. + */ + struct ExprList *col_list =3D create_idx_def.cols; + struct SrcList *tbl_name =3D alter_entity_def.entity_name; =20 if (db->mallocFailed || parse->nErr > 0) goto exit_create_index; + enum sql_index_type idx_type =3D create_idx_def.idx_type; if (idx_type =3D=3D SQL_INDEX_TYPE_UNIQUE || idx_type =3D=3D SQL_INDEX_TYPE_NON_UNIQUE) { Vdbe *v =3D sqlite3GetVdbe(parse); @@ -2238,12 +2264,13 @@ sql_create_index(struct Parse *parse, struct = Token *token, */ struct space *space =3D NULL; struct space_def *def =3D NULL; + struct Token token =3D create_entity_def->name; if (tbl_name !=3D NULL) { - assert(token !=3D NULL && token->z !=3D NULL); + assert(token.n > 0 && token.z !=3D NULL); const char *name =3D tbl_name->a[0].zName; space =3D space_by_name(name); if (space =3D=3D NULL) { - if (! if_not_exist) { + if (! create_entity_def->if_not_exist) { diag_set(ClientError, ER_NO_SUCH_SPACE, = name); parse->rc =3D SQL_TARANTOOL_ERROR; parse->nErr++; @@ -2252,12 +2279,10 @@ sql_create_index(struct Parse *parse, struct = Token *token, } def =3D space->def; } else { - if (parse->pNewTable =3D=3D NULL) + if (parse->create_table_def.new_table =3D=3D NULL) goto exit_create_index; - assert(token =3D=3D NULL); - assert(start =3D=3D NULL); - space =3D parse->pNewTable->space; - def =3D parse->pNewTable->def; + space =3D parse->create_table_def.new_table->space; + def =3D parse->create_table_def.new_table->def; } =20 if (def->opts.is_view) { @@ -2284,13 +2309,13 @@ sql_create_index(struct Parse *parse, struct = Token *token, * 2) UNIQUE constraint is non-named and standard * auto-index name will be generated. */ - if (token !=3D NULL) { - assert(token->z !=3D NULL); - name =3D sqlite3NameFromToken(db, token); + if (parse->create_table_def.new_table =3D=3D NULL) { + assert(token.z !=3D NULL); + name =3D sqlite3NameFromToken(db, &token); if (name =3D=3D NULL) goto exit_create_index; if (sql_space_index_by_name(space, name) !=3D NULL) { - if (!if_not_exist) { + if (! create_entity_def->if_not_exist) { sqlite3ErrorMsg(parse, "index %s.%s already = exists", def->name, name); @@ -2299,11 +2324,10 @@ sql_create_index(struct Parse *parse, struct = Token *token, } } else { char *constraint_name =3D NULL; - if (parse->constraintName.z !=3D NULL) + if (create_entity_def->name.n > 0) constraint_name =3D sqlite3NameFromToken(db, - = &parse->constraintName); - + = &create_entity_def->name); /* * This naming is temporary. Now it's not * possible (since we implement UNIQUE @@ -2361,7 +2385,8 @@ sql_create_index(struct Parse *parse, struct Token = *token, if (col_list =3D=3D NULL) goto exit_create_index; assert(col_list->nExpr =3D=3D 1); - sqlite3ExprListSetSortOrder(col_list, sort_order); + sqlite3ExprListSetSortOrder(col_list, + create_idx_def.sort_order); } else { sqlite3ExprListCheckLength(parse, col_list, "index"); } @@ -2442,7 +2467,7 @@ sql_create_index(struct Parse *parse, struct Token = *token, * constraint, but has different onError (behavior on * constraint violation), then an error is raised. */ - if (parse->pNewTable !=3D NULL) { + if (parse->create_table_def.new_table !=3D NULL) { for (uint32_t i =3D 0; i < space->index_count; ++i) { struct index *existing_idx =3D space->index[i]; uint32_t iid =3D existing_idx->def->iid; @@ -2509,8 +2534,6 @@ sql_create_index(struct Parse *parse, struct Token = *token, (void *)space_by_id(BOX_INDEX_ID), P4_SPACEPTR); sqlite3VdbeChangeP5(vdbe, OPFLAG_SEEKEQ); - - assert(start !=3D NULL); int index_id =3D getNewIid(parse, def->id, cursor); sqlite3VdbeAddOp1(vdbe, OP_Close, cursor); vdbe_emit_create_index(parse, def, index->def, @@ -2534,30 +2557,32 @@ sql_create_index(struct Parse *parse, struct = Token *token, } =20 void -sql_drop_index(struct Parse *parse_context, struct SrcList = *index_name_list, - struct Token *table_token, bool if_exists) +sql_drop_index(struct Parse *parse_context) { + struct drop_entity_def drop_def =3D = parse_context->drop_entity_def; + assert(drop_def.base.entity_type =3D=3D ENTITY_TYPE_INDEX); struct Vdbe *v =3D sqlite3GetVdbe(parse_context); assert(v !=3D NULL); struct sqlite3 *db =3D parse_context->db; /* Never called with prior errors. */ assert(parse_context->nErr =3D=3D 0); - assert(table_token !=3D NULL); - const char *table_name =3D sqlite3NameFromToken(db, = table_token); + struct SrcList *table_list =3D drop_def.base.entity_name; + assert(table_list->nSrc =3D=3D 1); + char *table_name =3D table_list->a[0].zName; + const char *index_name =3D NULL; if (db->mallocFailed) { goto exit_drop_index; } sqlite3VdbeCountChanges(v); - assert(index_name_list->nSrc =3D=3D 1); - assert(table_token->n > 0); struct space *space =3D space_by_name(table_name); + bool if_exists =3D drop_def.if_exist; if (space =3D=3D NULL) { if (!if_exists) sqlite3ErrorMsg(parse_context, "no such space: = %s", table_name); goto exit_drop_index; } - const char *index_name =3D index_name_list->a[0].zName; + index_name =3D sqlite3NameFromToken(db, &drop_def.name); uint32_t index_id =3D box_index_id_by_name(space->def->id, = index_name, strlen(index_name)); if (index_id =3D=3D BOX_ID_NIL) { @@ -2583,8 +2608,8 @@ sql_drop_index(struct Parse *parse_context, struct = SrcList *index_name_list, sqlite3VdbeAddOp2(v, OP_SDelete, BOX_INDEX_ID, record_reg); sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE); exit_drop_index: - sqlite3SrcListDelete(db, index_name_list); - sqlite3DbFree(db, (void *) table_name); + sqlite3SrcListDelete(db, table_list); + sqlite3DbFree(db, (void *) index_name); } =20 /* diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index 0bcf41594..e8b053361 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -168,7 +168,9 @@ cmd ::=3D ROLLBACK TO savepoint_opt nm(X). { // cmd ::=3D create_table create_table_args. create_table ::=3D createkw TABLE ifnotexists(E) nm(Y). { - sqlite3StartTable(pParse,&Y,E); + alter_entity_def_init(&pParse->create_table_def, NULL, = ENTITY_TYPE_TABLE); + create_entity_def_init(&pParse->create_table_def, Y, E); + sqlite3StartTable(pParse); } createkw(A) ::=3D CREATE(A). {disableLookaside(pParse);} =20 @@ -237,8 +239,15 @@ nm(A) ::=3D id(A). { carglist ::=3D carglist cconsdef. carglist ::=3D . cconsdef ::=3D cconsname ccons. -cconsname ::=3D CONSTRAINT nm(X). {pParse->constraintName =3D = X;} -cconsname ::=3D . {pParse->constraintName.n =3D= 0;} +cconsname ::=3D cconsname_start cconsname_parse . +cconsname_start ::=3D . { + /* Prepare base members for re-usage. */ + memset(&pParse->create_index_def, 0, sizeof(struct = create_index_def)); +} +cconsname_parse ::=3D CONSTRAINT nm(X). { + create_entity_def_init(&pParse->create_index_def, X, false); +} +cconsname_parse ::=3D . ccons ::=3D DEFAULT term(X). = {sqlite3AddDefaultValue(pParse,&X);} ccons ::=3D DEFAULT LP expr(X) RP. = {sqlite3AddDefaultValue(pParse,&X);} ccons ::=3D DEFAULT PLUS term(X). = {sqlite3AddDefaultValue(pParse,&X);} @@ -260,14 +269,29 @@ ccons ::=3D NULL onconf(R). { sql_column_add_nullable_action(pParse, R); } ccons ::=3D NOT NULL onconf(R). = {sql_column_add_nullable_action(pParse, R);} -ccons ::=3D PRIMARY KEY sortorder(Z) autoinc(I). - {sqlite3AddPrimaryKey(pParse,0,I,Z);} -ccons ::=3D UNIQUE. {sql_create_index(pParse,0,0,0,0, - SORT_ORDER_ASC, = false, - = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE);} -ccons ::=3D CHECK LP expr(X) RP. = {sql_add_check_constraint(pParse,&X);} -ccons ::=3D REFERENCES nm(T) eidlist_opt(TA) refargs(R). - {sql_create_foreign_key(pParse, NULL, = NULL, NULL, &T, TA, false, R);} +ccons ::=3D PRIMARY KEY sortorder(Z) autoinc(I). { + pParse->create_table_def.has_autoinc =3D I; + sqlite3AddPrimaryKey(pParse,0,Z); +} +ccons ::=3D UNIQUE. { + pParse->create_index_def.idx_type =3D = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE; + entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX); + sql_create_index(pParse); +} + +ccons ::=3D check_constraint_def . + +check_constraint_def ::=3D CHECK LP expr(X) RP. { + pParse->create_ck_def.expr =3D &X; + entity_set_type(&pParse->create_index_def, ENTITY_TYPE_CK); + sql_add_check_constraint(pParse); +} + +ccons ::=3D REFERENCES nm(T) eidlist_opt(TA) refargs(R). { + create_fk_def_init(&pParse->create_fk_def, NULL, &T, TA, R); + entity_set_type(&pParse->create_fk_def, ENTITY_TYPE_FK); + sql_create_foreign_key(pParse); +} ccons ::=3D defer_subclause(D). {fkey_change_defer_mode(pParse, D);} ccons ::=3D COLLATE id(C). {sqlite3AddCollateType(pParse, &C);} =20 @@ -307,20 +331,24 @@ init_deferred_pred_opt(A) ::=3D . = {A =3D 0;} init_deferred_pred_opt(A) ::=3D INITIALLY DEFERRED. {A =3D 1;} init_deferred_pred_opt(A) ::=3D INITIALLY IMMEDIATE. {A =3D 0;} =20 -tconsdef ::=3D tconsname tcons. -tconsname ::=3D CONSTRAINT nm(X). {pParse->constraintName =3D X;} -tconsname ::=3D . {pParse->constraintName.n =3D = 0;} -tcons ::=3D PRIMARY KEY LP sortlist(X) autoinc(I) RP. - {sqlite3AddPrimaryKey(pParse,X,I,0);} -tcons ::=3D UNIQUE LP sortlist(X) RP. - {sql_create_index(pParse,0,0,X,0, - = SORT_ORDER_ASC,false, - = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE);} -tcons ::=3D CHECK LP expr(E) RP onconf. - {sql_add_check_constraint(pParse,&E);} +tconsdef ::=3D cconsname tcons. +tcons ::=3D PRIMARY KEY LP sortlist(X) autoinc(I) RP. { + pParse->create_table_def.has_autoinc =3D I; + sqlite3AddPrimaryKey(pParse, X, 0); +} +tcons ::=3D UNIQUE LP sortlist(X) RP. { + pParse->create_index_def.cols =3D X; + pParse->create_index_def.idx_type =3D = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE; + entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX); + sql_create_index(pParse); +} +tcons ::=3D check_constraint_def . tcons ::=3D FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) = defer_subclause_opt(D). { - sql_create_foreign_key(pParse, NULL, NULL, FA, &T, TA, D, R); + create_fk_def_init(&pParse->create_fk_def, FA, &T, TA, R); + entity_set_defer_mode(&pParse->create_fk_def, D); + entity_set_type(&pParse->create_fk_def, ENTITY_TYPE_FK); + sql_create_foreign_key(pParse); } %type defer_subclause_opt {int} defer_subclause_opt(A) ::=3D . {A =3D 0;} @@ -343,9 +371,20 @@ resolvetype(A) ::=3D REPLACE. {A =3D= ON_CONFLICT_ACTION_REPLACE;} =20 ////////////////////////// The DROP TABLE = ///////////////////////////////////// // -cmd ::=3D DROP TABLE ifexists(E) fullname(X). { - sql_drop_table(pParse, X, 0, E); + +cmd ::=3D drop_start(X) drop_table . { + sql_drop_table(pParse, X); } + +drop_table ::=3D ifexists(E) fullname(X) . { + alter_entity_def_init(&pParse->drop_entity_def, X, = ENTITY_TYPE_TABLE); + pParse->drop_entity_def.if_exist =3D E; +} + +%type drop_start {bool} +drop_start(X) ::=3D DROP VIEW . { X =3D true; } +drop_start(X) ::=3D DROP TABLE . { X =3D false; } + %type ifexists {int} ifexists(A) ::=3D IF EXISTS. {A =3D 1;} ifexists(A) ::=3D . {A =3D 0;} @@ -354,13 +393,13 @@ ifexists(A) ::=3D . {A =3D 0;} // cmd ::=3D createkw(X) VIEW ifnotexists(E) nm(Y) eidlist_opt(C) AS select(S). { - if (!pParse->parse_only) - sql_create_view(pParse, &X, &Y, C, S, E); - else + if (!pParse->parse_only) { + alter_entity_def_init(&pParse->create_table_def, NULL, = ENTITY_TYPE_TABLE); + create_entity_def_init(&pParse->create_table_def, Y, E); + sql_create_view(pParse, &X, C, S); + } else { sql_store_select(pParse, S); -} -cmd ::=3D DROP VIEW ifexists(E) fullname(X). { - sql_drop_table(pParse, X, 1, E); + } } =20 //////////////////////// The SELECT statement = ///////////////////////////////// @@ -1198,10 +1237,15 @@ paren_exprlist(A) ::=3D LP exprlist(X) RP. {A =3D= X;} =20 ///////////////////////////// The CREATE INDEX command = /////////////////////// // -cmd ::=3D createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) +cmd ::=3D createkw uniqueflag(U) INDEX ifnotexists(NE) nm(X) ON nm(Y) LP sortlist(Z) RP. { - sql_create_index(pParse, &X, sqlite3SrcListAppend(pParse->db,0,&Y), = Z, &S, - SORT_ORDER_ASC, NE, U); + alter_entity_def_init(&pParse->create_index_def, + sqlite3SrcListAppend(pParse->db, 0, &Y), + ENTITY_TYPE_INDEX); + create_entity_def_init(&pParse->create_index_def, X, NE); + pParse->create_index_def.idx_type =3D U; + pParse->create_index_def.cols =3D Z; + sql_create_index(pParse); } =20 %type uniqueflag {int} @@ -1263,8 +1307,10 @@ collate(C) ::=3D COLLATE id. {C =3D 1;} =20 ///////////////////////////// The DROP INDEX command = ///////////////////////// // -cmd ::=3D DROP INDEX ifexists(E) fullname(X) ON nm(Y). { - sql_drop_index(pParse, X, &Y, E); +cmd ::=3D DROP INDEX ifexists(E) nm(X) ON fullname(Y). { + alter_entity_def_init(&pParse->drop_entity_def, Y, = ENTITY_TYPE_INDEX); + drop_entity_def_init(&pParse->drop_entity_def, X, E); + sql_drop_index(pParse); } =20 ///////////////////////////// The PRAGMA command = ///////////////////////////// @@ -1315,7 +1361,14 @@ cmd ::=3D createkw trigger_decl(A) BEGIN = trigger_cmd_list(S) END(Z). { trigger_decl(A) ::=3D TRIGGER ifnotexists(NOERR) nm(B) trigger_time(C) trigger_event(D) ON fullname(E) foreach_clause when_clause(G). { - sql_trigger_begin(pParse, &B, C, D.a, D.b, E, G, NOERR); + struct create_trigger_def *trigger_def =3D = &pParse->create_trigger_def; + alter_entity_def_init(trigger_def, E, ENTITY_TYPE_TRIGGER); + create_entity_def_init(trigger_def, B, NOERR); + trigger_def->tr_tm =3D C; + trigger_def->op =3D D.a; + trigger_def->cols =3D D.b; + trigger_def->when =3D G; + sql_trigger_begin(pParse); A =3D B; /*A-overwrites-T*/ } =20 @@ -1425,7 +1478,9 @@ raisetype(A) ::=3D FAIL. {A =3D = ON_CONFLICT_ACTION_FAIL;} =20 //////////////////////// DROP TRIGGER statement = ////////////////////////////// cmd ::=3D DROP TRIGGER ifexists(NOERR) fullname(X). { - sql_drop_trigger(pParse,X,NOERR); + alter_entity_def_init(&pParse->drop_entity_def, X, = ENTITY_TYPE_TRIGGER); + drop_entity_def_init(&pParse->drop_entity_def, (struct Token){}, = NOERR); + sql_drop_trigger(pParse); } =20 /////////////////////////////////// ANALYZE = /////////////////////////////////// @@ -1434,17 +1489,25 @@ cmd ::=3D ANALYZE nm(X). = {sqlite3Analyze(pParse, &X);} =20 //////////////////////// ALTER TABLE table ... = //////////////////////////////// cmd ::=3D ALTER TABLE fullname(X) RENAME TO nm(Z). { - sql_alter_table_rename(pParse,X,&Z); + alter_entity_def_init(&pParse->rename_entity_def, X, = ENTITY_TYPE_TABLE); + pParse->rename_entity_def.new_name =3D Z; + sql_alter_table_rename(pParse); } =20 cmd ::=3D ALTER TABLE fullname(X) ADD CONSTRAINT nm(Z) FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { - sql_create_foreign_key(pParse, X, &Z, FA, &T, TA, D, R); + alter_entity_def_init(&pParse->create_fk_def, X, ENTITY_TYPE_FK); + create_entity_def_init(&pParse->create_fk_def, Z, false); + entity_set_defer_mode(&pParse->create_fk_def, D); + create_fk_def_init(&pParse->create_fk_def, FA, &T, TA, R); + sql_create_foreign_key(pParse); } =20 cmd ::=3D ALTER TABLE fullname(X) DROP CONSTRAINT nm(Z). { - sql_drop_foreign_key(pParse, X, &Z); + alter_entity_def_init(&pParse->drop_entity_def, X, ENTITY_TYPE_FK); + drop_entity_def_init(&pParse->drop_entity_def, Z, false); + sql_drop_foreign_key(pParse); } =20 //////////////////////// COMMON TABLE EXPRESSIONS = //////////////////////////// diff --git a/src/box/sql/parse_def.h b/src/box/sql/parse_def.h new file mode 100644 index 000000000..7a61a27e0 --- /dev/null +++ b/src/box/sql/parse_def.h @@ -0,0 +1,260 @@ +#ifndef TARANTOOL_BOX_SQL_PARSE_DEF_H_INCLUDED +#define TARANTOOL_BOX_SQL_PARSE_DEF_H_INCLUDED +/* + * Copyright 2010-2019, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "box/fkey.h" + +/** + * This file contains auxiliary structures and functions which + * are used only during parsing routine (see parse.y). + * Their main purpose is to assemble common parts of altered + * entities (such as name, or IF EXISTS clause) and pass them + * as a one object to further functions. + * + * Hierarchy is following: + * + * Base structure is ALTER. + * ALTER is omitted only for CREATE TABLE since table is filled + * with meta-information just-in-time of parsing: + * for instance, as soon as field's name and type are recognized + * they are added to space definition. + * + * DROP is general for all existing objects and includes + * name of object itself, name of parent object (table), + * IF EXISTS clause and may contain on-drop behaviour + * (CASCADE/RESTRICT, but now it is always RESTRICT). + * Hence, it terms of grammar - it is a terminal symbol. + * + * RENAME can be applied only to table (at least now, since it is + * ANSI extension), so it is also terminal symbol. + * + * CREATE in turn can be expanded to nonterminal symbol + * CREATE CONSTRAINT or to terminal CREATE TABLE/INDEX/TRIGGER. + * CREATE CONSTRAINT unfolds to FOREIGN KEY or UNIQUE/PRIMARY KEY. + * + * For instance: + * ALTER TABLE t ADD CONSTRAINT c FOREIGN KEY REFERENCES t2(id); + * ALTER *TABLE* -> CREATE ENTITY -> CREATE CONSTRAINT -> CREATE FK + * + * CREATE TRIGGER tr1 ... + * ALTER *TABLE* -> CREATE ENTITY -> CREATE TRIGGER + * + * All terminal symbols are stored as a union within + * parsing context (struct Parse). + */ + +/** + * Each token coming out of the lexer is an instance of + * this structure. Tokens are also used as part of an expression. + * + * Note if Token.z is NULL then Token.n is undefined. + */ +struct Token { + /** Text of the token. Not NULL-terminated! */ + const char *z; + /** Number of characters in this token. */ + unsigned int n; + bool isReserved; +}; + +/** + * Possible SQL index types. Note that PK and UNIQUE constraints + * are implemented as indexes and have their own types: + * _CONSTRAINT_PK and _CONSTRAINT_UNIQUE. + */ +enum sql_index_type { + SQL_INDEX_TYPE_NON_UNIQUE =3D 0, + SQL_INDEX_TYPE_UNIQUE, + SQL_INDEX_TYPE_CONSTRAINT_UNIQUE, + SQL_INDEX_TYPE_CONSTRAINT_PK, + sql_index_type_MAX +}; + +enum entity_type { + ENTITY_TYPE_TABLE =3D 0, + ENTITY_TYPE_INDEX, + ENTITY_TYPE_TRIGGER, + ENTITY_TYPE_CK, + ENTITY_TYPE_FK, + entity_type_MAX +}; + +struct alter_entity_def { + /** Type of topmost entity. */ + enum entity_type entity_type; + /** As a rule it is a name of table to be altered. */ + struct SrcList *entity_name; +}; + +struct rename_entity_def { + struct alter_entity_def base; + struct Token new_name; +}; + +struct create_entity_def { + struct alter_entity_def base; + struct Token name; + /** Statement comes with IF NOT EXISTS clause. */ + bool if_not_exist; +}; + +struct create_table_def { + struct create_entity_def base; + struct Table *new_table; + /** + * Number of FK constraints declared within + * CREATE TABLE statement. + */ + uint32_t fkey_count; + /** + * Foreign key constraint appeared in CREATE TABLE stmt. + */ + struct rlist new_fkey; + /** True, if table to be created has AUTOINCREMENT PK. */ + bool has_autoinc; +}; + +struct drop_entity_def { + struct alter_entity_def base; + /** Name of index/trigger/constraint to be dropped. */ + struct Token name; + /** Statement comes with IF EXISTS clause. */ + bool if_exist; +}; + +struct create_trigger_def { + struct create_entity_def base; + /** One of TK_BEFORE, TK_AFTER, TK_INSTEAD. */ + int tr_tm; + /** One of TK_INSERT, TK_UPDATE, TK_DELETE. */ + int op; + /** Column list if this is an UPDATE trigger. */ + struct IdList *cols; + /** When clause. */ + struct Expr *when; +}; + +struct create_constraint_def { + struct create_entity_def base; + /** One of DEFERRED, IMMEDIATE. */ + bool is_deferred; +}; + +struct create_ck_def { + struct create_constraint_def base; + /** AST representing check expression. */ + struct ExprSpan *expr; +}; + +struct create_fk_def { + struct create_constraint_def base; + struct ExprList *child_cols; + struct Token *parent_name; + struct ExprList *parent_cols; + /** + * Encoded actions for MATCH, ON DELETE and + * ON UPDATE clauses. + */ + int actions; +}; + +struct create_index_def { + struct create_constraint_def base; + /** List of indexed columns. */ + struct ExprList *cols; + /** One of _PRIMARY_KEY, _UNIQUE, _NON_UNIQUE. */ + enum sql_index_type idx_type; + enum sort_order sort_order; +}; + +/** + * In those functions which accept void * instead of certain type + * it was made on purpose: it allows to avoid explicit cast before + * passing parameter to function. Hence, we can invoke it like: + * entity_set_type(create_fk_def, ...); instead of + * entity_set_type((struct alter_entity_def *) create_fk_def, ...); + */ +static inline void +entity_set_type(void *entity_def, enum entity_type type) +{ + struct alter_entity_def *alter_def =3D + (struct alter_entity_def *) entity_def; + alter_def->entity_type =3D type; +} + +static inline void +entity_set_defer_mode(void *entity_def, bool is_deferred) +{ + struct create_constraint_def *constr_def =3D + (struct create_constraint_def *) entity_def; + constr_def->is_deferred =3D is_deferred; +} + +static inline void +alter_entity_def_init(void *entity_def, struct SrcList *entity_name, + enum entity_type type) +{ + struct alter_entity_def *alter_def =3D + (struct alter_entity_def *) entity_def; + alter_def->entity_name =3D entity_name; + alter_def->entity_type =3D type; +} + +static inline void +create_entity_def_init(void *entity_def, struct Token name, bool = if_not_exist) +{ + struct create_entity_def *create_def =3D + (struct create_entity_def *) entity_def; + create_def->name =3D name; + create_def->if_not_exist =3D if_not_exist; +} + +static inline void +drop_entity_def_init(struct drop_entity_def *drop_def, struct Token = name, + bool if_exist) +{ + drop_def->name =3D name; + drop_def->if_exist =3D if_exist; +} + +static inline void +create_fk_def_init(struct create_fk_def *fk_def, struct ExprList = *child_cols, + struct Token *parent_name, struct ExprList = *parent_cols, + int actions) +{ + assert(fk_def !=3D NULL); + fk_def->child_cols =3D child_cols; + fk_def->parent_name =3D parent_name; + fk_def->parent_cols =3D parent_cols; + fk_def->actions =3D actions; +} + +#endif /* TARANTOOL_BOX_SQL_PARSE_DEF_H_INCLUDED */ diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c index 824578e45..3343c2942 100644 --- a/src/box/sql/prepare.c +++ b/src/box/sql/prepare.c @@ -273,7 +273,7 @@ sql_parser_create(struct Parse *parser, sqlite3 *db) { memset(parser, 0, sizeof(struct Parse)); parser->db =3D db; - rlist_create(&parser->new_fkey); + rlist_create(&parser->create_table_def.new_fkey); rlist_create(&parser->record_list); region_create(&parser->region, &cord()->slabc); } @@ -287,7 +287,7 @@ sql_parser_destroy(Parse *parser) sqlite3DbFree(db, parser->aLabel); sql_expr_list_delete(db, parser->pConstExpr); struct fkey_parse *fk; - rlist_foreach_entry(fk, &parser->new_fkey, link) + rlist_foreach_entry(fk, &parser->create_table_def.new_fkey, = link) sql_expr_list_delete(db, fk->selfref_cols); if (db !=3D NULL) { assert(db->lookaside.bDisable >=3D diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c index 6462467bc..e66f0d6db 100644 --- a/src/box/sql/resolve.c +++ b/src/box/sql/resolve.c @@ -1616,9 +1616,9 @@ void sql_resolve_self_reference(struct Parse *parser, struct Table *table, = int type, struct Expr *expr, struct ExprList = *expr_list) { - /* Fake SrcList for parser->pNewTable */ + /* Fake SrcList for parser->new_table */ SrcList sSrc; - /* Name context for parser->pNewTable */ + /* Name context for parser->new_table */ NameContext sNC; =20 assert(type =3D=3D NC_IsCheck || type =3D=3D NC_IdxExpr); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index bc617d7ce..4ee2ed5cf 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -67,6 +67,7 @@ =20 #include =20 +#include "parse_def.h" #include "box/field_def.h" #include "box/sql.h" #include "box/txn.h" @@ -1915,19 +1916,6 @@ struct UnpackedRecord { */ }; =20 -/* - * Possible SQL index types. Note that PK and UNIQUE constraints - * are implemented as indexes and have their own types: - * SQL_INDEX_TYPE_CONSTRAINT_PK and - * SQL_INDEX_TYPE_CONSTRAINT_UNIQUE. - */ -enum sql_index_type { - SQL_INDEX_TYPE_NON_UNIQUE =3D 0, - SQL_INDEX_TYPE_UNIQUE, - SQL_INDEX_TYPE_CONSTRAINT_UNIQUE, - SQL_INDEX_TYPE_CONSTRAINT_PK, -}; - /** * Fetch statistics concerning tuples to be selected: * logarithm of number of tuples which has the same key as for @@ -1957,20 +1945,6 @@ index_field_tuple_est(const struct index_def = *idx, uint32_t field); /** [10*log_{2}(1048576)] =3D=3D 200 */ #define DEFAULT_TUPLE_LOG_COUNT 200 =20 -/* - * Each token coming out of the lexer is an instance of - * this structure. Tokens are also used as part of an expression. - * - * Note if Token.z=3D=3D0 then Token.dyn and Token.n are undefined and - * may contain random values. Do not make any assumptions about = Token.dyn - * and Token.n when Token.z=3D=3D0. - */ -struct Token { - const char *z; /* Text of the token. Not = NULL-terminated! */ - unsigned int n; /* Number of characters in this token */ - bool isReserved; /* If reserved keyword or not */ -}; - /* * An instance of this structure contains information needed to = generate * code for a SELECT that contains aggregate functions. @@ -2728,7 +2702,6 @@ struct Parse { int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr; /* Constant expressions */ - Token constraintName; /* Name of the constraint currently = being parsed */ int nMaxArg; /* Max args passed to user function by = sub-program */ int nSelect; /* Number of SELECT statements seen */ int nSelectIndent; /* How far to indent SELECTTRACE() = output */ @@ -2775,28 +2748,30 @@ struct Parse { VList *pVList; /* Mapping between variable names and = numbers */ Vdbe *pReprepare; /* VM being reprepared = (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon = parsed */ - Table *pNewTable; /* A table being constructed by CREATE = TABLE */ Table *pZombieTab; /* List of Table objects to delete after = code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers = */ With *pWith; /* Current WITH clause, or NULL */ With *pWithToFree; /* Free this WITH object at the end of = the parse */ /** - * Number of FK constraints declared within - * CREATE TABLE statement. - */ - uint32_t fkey_count; - /** - * Foreign key constraint appeared in CREATE TABLE stmt. + * One of parse_def structures which are used to + * assemble and carry arguments of DDL routines + * from parse.y */ - struct rlist new_fkey; + union { + struct create_ck_def create_ck_def; + struct create_fk_def create_fk_def; + struct create_index_def create_index_def; + struct create_trigger_def create_trigger_def; + struct rename_entity_def rename_entity_def; + struct drop_entity_def drop_entity_def; + }; + struct create_table_def create_table_def; /** * List of all records that were inserted in system spaces * in current statement. */ struct rlist record_list; bool initiateTTrans; /* Initiate Tarantool transaction */ - /** True, if table to be created has AUTOINCREMENT PK. */ - bool is_new_table_autoinc; /** If set - do not emit byte code at all, just parse. */ bool parse_only; /** Type of parsed_ast member. */ @@ -3357,7 +3332,7 @@ Table *sqlite3ResultSetOfSelect(Parse *, Select = *); struct index * sql_table_primary_key(const struct Table *tab); =20 -void sqlite3StartTable(Parse *, Token *, int); +void sqlite3StartTable(Parse *); void sqlite3AddColumn(Parse *, Token *, struct type_def *); =20 /** @@ -3375,16 +3350,15 @@ void sql_column_add_nullable_action(struct Parse *parser, enum on_conflict_action nullable_action); =20 -void sqlite3AddPrimaryKey(Parse *, ExprList *, int, enum sort_order); +void sqlite3AddPrimaryKey(Parse *, ExprList *, enum sort_order); =20 /** * Add a new CHECK constraint to the table currently under * construction. * @param parser Parsing context. - * @param span Expression span object. */ void -sql_add_check_constraint(Parse *parser, ExprSpan *span); +sql_add_check_constraint(Parse *parser); =20 void sqlite3AddDefaultValue(Parse *, ExprSpan *); void sqlite3AddCollateType(Parse *, Token *); @@ -3432,15 +3406,12 @@ int sqlite3FaultSim(int); * * @param parse_context Current parsing context. * @param begin The CREATE token that begins the statement. - * @param name The token that holds the name of the view. * @param aliases Optional list of view column names. * @param select A SELECT statement that will become the new view. - * @param if_exists Suppress error messages if VIEW already exists. */ void sql_create_view(struct Parse *parse_context, struct Token *begin, - struct Token *name, struct ExprList *aliases, - struct Select *select, bool if_exists); + struct ExprList *aliases, struct Select *select); =20 /** * Helper to convert SQLite affinity to corresponding @@ -3472,7 +3443,7 @@ void sql_store_select(struct Parse *parse_context, struct Select *select); =20 void -sql_drop_table(struct Parse *, struct SrcList *, bool, bool); +sql_drop_table(struct Parse *, bool); void sqlite3DeleteTable(sqlite3 *, Table *); void sqlite3Insert(Parse *, SrcList *, Select *, IdList *, enum on_conflict_action); @@ -3501,36 +3472,19 @@ void sqlite3IdListDelete(sqlite3 *, IdList *); * parse->pNewTable is a table that is currently being * constructed by a CREATE TABLE statement. * - * col_list is a list of columns to be indexed. col_list will be - * NULL if this is a primary key or unique-constraint on the most - * recent column added to the table currently under construction. - * * @param parse All information about this parse. - * @param token Index name. May be NULL. - * @param tbl_name Table to index. Use pParse->pNewTable ifNULL. - * @param col_list A list of columns to be indexed. - * @param start The CREATE token that begins this statement. - * @param sort_order Sort order of primary key when pList=3D=3DNULL. - * @param if_not_exist Omit error if index already exists. - * @param idx_type The index type. */ void -sql_create_index(struct Parse *parse, struct Token *token, - struct SrcList *tbl_name, struct ExprList *col_list, - struct Token *start, enum sort_order sort_order, - bool if_not_exist, enum sql_index_type idx_type); +sql_create_index(struct Parse *parse); =20 /** * This routine will drop an existing named index. This routine * implements the DROP INDEX statement. * * @param parse_context Current parsing context. - * @param index_name_list List containing index name. - * @param table_token Token representing table name. - * @param if_exists True, if statement contains 'IF EXISTS' clause. */ void -sql_drop_index(struct Parse *, struct SrcList *, struct Token *, bool); +sql_drop_index(struct Parse *parse_context); =20 int sqlite3Select(Parse *, Select *, SelectDest *); Select *sqlite3SelectNew(Parse *, ExprList *, SrcList *, Expr *, = ExprList *, @@ -3932,20 +3886,9 @@ sql_materialize_view(struct Parse *parse, const = char *name, struct Expr *where, * After the trigger actions have been parsed, the * sql_trigger_finish() function is called to complete the trigger * construction process. - * - * @param parse The parse context of the CREATE TRIGGER statement. - * @param name The name of the trigger. - * @param tr_tm One of TK_BEFORE, TK_AFTER, TK_INSTEAD. - * @param op One of TK_INSERT, TK_UPDATE, TK_DELETE. - * @param columns column list if this is an UPDATE OF trigger. - * @param table The name of the table/view the trigger applies to. - * @param when WHEN clause. - * @param no_err Suppress errors if the trigger already exists. */ void -sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm, - int op, struct IdList *columns, struct SrcList *table, - struct Expr *when, int no_err); +sql_trigger_begin(struct Parse *parse); =20 /** * This routine is called after all of the trigger actions have @@ -3965,11 +3908,9 @@ sql_trigger_finish(struct Parse *parse, struct = TriggerStep *step_list, * VDBE code. * * @param parser Parser context. - * @param name The name of trigger to drop. - * @param no_err Suppress errors if the trigger already exists. */ void -sql_drop_trigger(struct Parse *parser, struct SrcList *name, bool = no_err); +sql_drop_trigger(struct Parse *parser); =20 /** * Drop a trigger given a pointer to that trigger. @@ -4149,38 +4090,18 @@ fkey_change_defer_mode(struct Parse = *parse_context, bool is_deferred); * OR to handle * * @param parse_context Parsing context. - * @param child Name of table to be altered. NULL on CREATE TABLE - * statement processing. - * @param constraint Name of the constraint to be created. May be - * NULL on CREATE TABLE statement processing. - * Then, auto-generated name is used. - * @param child_cols Columns of child table involved in FK. - * May be NULL on CREATE TABLE statement processing. - * If so, the last column added is used. - * @param parent Name of referenced table. - * @param parent_cols List of referenced columns. If NULL, columns - * which make up PK of referenced table are used. - * @param is_deferred Is FK constraint initially deferred. - * @param actions ON DELETE, UPDATE and INSERT resolution - * algorithms (e.g. CASCADE, RESTRICT etc). */ void -sql_create_foreign_key(struct Parse *parse_context, struct SrcList = *child, - struct Token *constraint, struct ExprList = *child_cols, - struct Token *parent, struct ExprList = *parent_cols, - bool is_deferred, int actions); +sql_create_foreign_key(struct Parse *parse_context); =20 /** * Function called from parser to handle * SQL statement. * * @param parse_context Parsing context. - * @param table Table to be altered. - * @param constraint Name of constraint to be dropped. */ void -sql_drop_foreign_key(struct Parse *parse_context, struct SrcList = *table, - struct Token *constraint); +sql_drop_foreign_key(struct Parse *parse_context); =20 void sqlite3Detach(Parse *, Expr *); int sqlite3AtoF(const char *z, double *, int); @@ -4398,12 +4319,9 @@ extern int sqlite3PendingByte; * command. * * @param parse Current parsing context. - * @param src_tab The table to rename. - * @param new_name_tk Token containing new name of the table. */ void -sql_alter_table_rename(struct Parse *parse, struct SrcList *src_tab, - struct Token *new_name_tk); +sql_alter_table_rename(struct Parse *parse); =20 /** * Return the length (in bytes) of the token that begins at z[0]. diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c index 4eebfe527..f2088f118 100644 --- a/src/box/sql/tokenize.c +++ b/src/box/sql/tokenize.c @@ -449,7 +449,7 @@ sqlite3RunParser(Parse * pParse, const char *zSql, = char **pzErrMsg) sqlite3OomFault(db); return SQLITE_NOMEM_BKPT; } - assert(pParse->pNewTable =3D=3D 0); + assert(pParse->create_table_def.new_table =3D=3D NULL); assert(pParse->parsed_ast.trigger =3D=3D NULL); assert(pParse->nVar =3D=3D 0); assert(pParse->pVList =3D=3D 0); @@ -529,7 +529,7 @@ sqlite3RunParser(Parse * pParse, const char *zSql, = char **pzErrMsg) sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe =3D 0; } - sqlite3DeleteTable(db, pParse->pNewTable); + sqlite3DeleteTable(db, pParse->create_table_def.new_table); =20 if (pParse->pWithToFree) sqlite3WithDelete(db, pParse->pWithToFree); diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 7d5dc9e23..33b5ea7c4 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -62,34 +62,30 @@ sqlite3DeleteTriggerStep(sqlite3 * db, TriggerStep * = pTriggerStep) } =20 void -sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm, - int op, struct IdList *columns, struct SrcList *table, - struct Expr *when, int no_err) +sql_trigger_begin(struct Parse *parse) { /* The new trigger. */ struct sql_trigger *trigger =3D NULL; /* The database connection. */ struct sqlite3 *db =3D parse->db; - /* The name of the Trigger. */ - char *trigger_name =3D NULL; - - /* pName->z might be NULL, but not pName itself. */ - assert(name !=3D NULL); - assert(op =3D=3D TK_INSERT || op =3D=3D TK_UPDATE || op =3D=3D = TK_DELETE); - assert(op > 0 && op < 0xff); + struct create_trigger_def trigger_def =3D = parse->create_trigger_def; + struct create_entity_def create_def =3D trigger_def.base; + struct alter_entity_def alter_def =3D create_def.base; + assert(alter_def.entity_type =3D=3D ENTITY_TYPE_TRIGGER); =20 - if (table =3D=3D NULL || db->mallocFailed) + char *trigger_name =3D NULL; + if (alter_def.entity_name =3D=3D NULL || db->mallocFailed) goto trigger_cleanup; - assert(table->nSrc =3D=3D 1); - - trigger_name =3D sqlite3NameFromToken(db, name); + assert(alter_def.entity_name->nSrc =3D=3D 1); + assert(create_def.name.n > 0); + trigger_name =3D sqlite3NameFromToken(db, &create_def.name); if (trigger_name =3D=3D NULL) goto trigger_cleanup; =20 if (sqlite3CheckIdentifierName(parse, trigger_name) !=3D = SQLITE_OK) goto trigger_cleanup; =20 - const char *table_name =3D table->a[0].zName; + const char *table_name =3D alter_def.entity_name->a[0].zName; uint32_t space_id; if (schema_find_id(BOX_SPACE_ID, 2, table_name, = strlen(table_name), &space_id) !=3D 0) @@ -112,6 +108,7 @@ sql_trigger_begin(struct Parse *parse, struct Token = *name, int tr_tm, int name_reg =3D ++parse->nMem; sqlite3VdbeAddOp4(parse->pVdbe, OP_String8, 0, name_reg, = 0, name_copy, P4_DYNAMIC); + bool no_err =3D create_def.if_not_exist; if (vdbe_emit_halt_with_presence_test(parse, = BOX_TRIGGER_ID, 0, name_reg, 1, ER_TRIGGER_EXISTS, @@ -129,13 +126,14 @@ sql_trigger_begin(struct Parse *parse, struct = Token *name, int tr_tm, trigger->space_id =3D space_id; trigger->zName =3D trigger_name; trigger_name =3D NULL; - - trigger->op =3D (u8) op; - trigger->tr_tm =3D tr_tm; - trigger->pWhen =3D sqlite3ExprDup(db, when, EXPRDUP_REDUCE); - trigger->pColumns =3D sqlite3IdListDup(db, columns); - if ((when !=3D NULL && trigger->pWhen =3D=3D NULL) || - (columns !=3D NULL && trigger->pColumns =3D=3D NULL)) + assert(trigger_def.op =3D=3D TK_INSERT || trigger_def.op =3D=3D = TK_UPDATE || + trigger_def.op=3D=3D TK_DELETE); + trigger->op =3D (u8) trigger_def.op; + trigger->tr_tm =3D trigger_def.tr_tm; + trigger->pWhen =3D sqlite3ExprDup(db, trigger_def.when, = EXPRDUP_REDUCE); + trigger->pColumns =3D sqlite3IdListDup(db, trigger_def.cols); + if ((trigger->pWhen !=3D NULL && trigger->pWhen =3D=3D NULL) || + (trigger->pColumns !=3D NULL && trigger->pColumns =3D=3D = NULL)) goto trigger_cleanup; assert(parse->parsed_ast.trigger =3D=3D NULL); parse->parsed_ast.trigger =3D trigger; @@ -143,9 +141,9 @@ sql_trigger_begin(struct Parse *parse, struct Token = *name, int tr_tm, =20 trigger_cleanup: sqlite3DbFree(db, trigger_name); - sqlite3SrcListDelete(db, table); - sqlite3IdListDelete(db, columns); - sql_expr_delete(db, when, false); + sqlite3SrcListDelete(db, alter_def.entity_name); + sqlite3IdListDelete(db, trigger_def.cols); + sql_expr_delete(db, trigger_def.when, false); if (parse->parsed_ast.trigger =3D=3D NULL) sql_trigger_delete(db, trigger); else @@ -424,9 +422,13 @@ vdbe_code_drop_trigger(struct Parse *parser, const = char *trigger_name, } =20 void -sql_drop_trigger(struct Parse *parser, struct SrcList *name, bool = no_err) +sql_drop_trigger(struct Parse *parser) { - + struct drop_entity_def drop_def =3D parser->drop_entity_def; + struct alter_entity_def alter_def =3D drop_def.base; + assert(alter_def.entity_type =3D=3D ENTITY_TYPE_TRIGGER); + struct SrcList *name =3D alter_def.entity_name; + bool no_err =3D drop_def.if_exist; sqlite3 *db =3D parser->db; if (db->mallocFailed) goto drop_trigger_cleanup; diff --git a/test/sql-tap/index7.test.lua b/test/sql-tap/index7.test.lua index a8ce37f4b..ffb42403c 100755 --- a/test/sql-tap/index7.test.lua +++ b/test/sql-tap/index7.test.lua @@ -397,6 +397,6 @@ test:do_catchsql_test( "_index"."id" =3D "_space"."id" AND "_space"."name"=3D'TEST8'; ]], - {0, {"pk_TEST8_2",0,"unique_C1_1",1}}) + {0, {"pk_unnamed_TEST8_2",0,"unique_C1_1",1}}) =20 test:finish_test()