[tarantool-patches] Re: [PATCH v2 1/5] sql: introduce structs assembling DDL arguments during parsing

n.pettik korablev at tarantool.org
Thu Jan 31 22:32:57 MSK 2019


I’ve 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 <korablev at tarantool.org>
Date:   Wed Jan 9 12:28:09 2019 +0200

    sql: introduce structs assembling DDL arguments during parsing
    
    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.
    
    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.
    
    Patch itself is made up of refactoring; no functional changes are
    provided.
    
    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"
 
 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 = parse->rename_entity_def;
+	struct SrcList *src_tab = rename_def.base.entity_name;
+	assert(rename_def.base.entity_type == ENTITY_TYPE_TABLE);
 	assert(src_tab->nSrc == 1);
 	struct sqlite3 *db = parse->db;
-	char *new_name = sqlite3NameFromToken(db, new_name_tk);
+	char *new_name = sqlite3NameFromToken(db, &rename_def.new_name);
 	if (new_name == 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 = 0;	/* The name of the new table */
@@ -403,8 +401,9 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 	if (v == NULL)
 		goto cleanup;
 	sqlite3VdbeCountChanges(v);
-
-	zName = sqlite3NameFromToken(db, pName);
+	struct Token name =
+		((struct create_entity_def *) &pParse->create_table_def)->name;
+	zName = sqlite3NameFromToken(db, &name);
 
 	if (zName == 0)
 		return;
@@ -413,7 +412,7 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 
 	struct space *space = space_by_name(zName);
 	if (space != 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 == NULL)
 		goto cleanup;
 
-	assert(pParse->pNewTable == 0);
-	pParse->pNewTable = pTable;
+	pParse->create_table_def.new_table = pTable;
 
 	if (!db->init.busy && (v = sqlite3GetVdbe(pParse)) != 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 = pParse->db;
-	if ((p = pParse->pNewTable) == 0)
+	if ((p = pParse->create_table_def.new_table) == 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 = type_def->type;
 	column_def->type = sql_affinity_to_field_type(column_def->affinity);
 	p->def->field_count++;
-	pParse->constraintName.n = 0;
 }
 
 void
 sql_column_add_nullable_action(struct Parse *parser,
 			       enum on_conflict_action nullable_action)
 {
-	struct Table *p = parser->pNewTable;
+	struct Table *p = parser->create_table_def.new_table;
 	if (p == NULL || NEVER(p->def->field_count < 1))
 		return;
 	struct field_def *field = &p->def->fields[p->def->field_count - 1];
@@ -609,7 +606,7 @@ sqlite3AddDefaultValue(Parse * pParse, ExprSpan * pSpan)
 {
 	Table *p;
 	sqlite3 *db = pParse->db;
-	p = pParse->pNewTable;
+	p = pParse->create_table_def.new_table;
 	assert(p->def->opts.is_temporary);
 	if (p != 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 = pParse->pNewTable;
+	Table *pTab = pParse->create_table_def.new_table;
 	int iCol = -1, i;
 	int nTerm;
 	if (pTab == 0)
@@ -712,11 +708,12 @@ sqlite3AddPrimaryKey(Parse * pParse,	/* Parsing context */
 			}
 		}
 	}
+	pParse->create_index_def.idx_type = SQL_INDEX_TYPE_CONSTRAINT_PK;
+	pParse->create_index_def.sort_order = sortOrder;
+	entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX);
 	if (nTerm == 1 && iCol != -1 &&
 	    pTab->def->fields[iCol].type == FIELD_TYPE_INTEGER &&
 	    sortOrder != SORT_ORDER_DESC) {
-		assert(autoInc == 0 || autoInc == 1);
-		pParse->is_new_table_autoinc = autoInc;
 		struct sqlite3 *db = pParse->db;
 		struct ExprList *list;
 		struct Token token;
@@ -726,17 +723,17 @@ sqlite3AddPrimaryKey(Parse * pParse,	/* Parsing context */
 							     &token, 0));
 		if (list == 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 = 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 = pList;
+		sql_create_index(pParse);
 		pList = 0;
 		if (pParse->nErr > 0)
 			goto primary_key_exit;
@@ -756,14 +753,21 @@ primary_key_exit:
 }
 
 void
-sql_add_check_constraint(struct Parse *parser, struct ExprSpan *span)
-{
-	struct Expr *expr = span->pExpr;
-	struct Table *table = parser->pNewTable;
+sql_add_check_constraint(struct Parse *parser)
+{
+	struct create_ck_def *ck_def = &parser->create_ck_def;
+	struct alter_entity_def *alter_def =
+		(struct alter_entity_def *) &parser->create_ck_def;
+	assert(alter_def->entity_type == ENTITY_TYPE_CK);
+	(void) alter_def;
+	struct Expr *expr = ck_def->expr->pExpr;
+	struct Table *table = parser->create_table_def.new_table;
 	if (table != NULL) {
 		expr->u.zToken =
-			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 == NULL)
 			goto release_expr;
 		table->def->opts.checks =
@@ -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 =
+			(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 = pParse->pNewTable;
+	Table *p = pParse->create_table_def.new_table;
 	if (p == NULL)
 		return;
 	uint32_t i = 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 = raw;
 
-	if (parse->pNewTable != NULL) {
+	if (parse->create_table_def.new_table != 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 = pParse->pNewTable;
+	struct Table *table = pParse->create_table_def.new_table;
 	Vdbe *v = sqlite3GetVdbe(pParse);
 	int iFirstCol = ++pParse->nMem;
 	int iRecord = (pParse->nMem += 7);
@@ -1113,14 +1119,15 @@ vdbe_emit_fkey_create(struct Parse *parse_context, const struct fkey_def *fk)
 	 * of <CREATE TABLE ...> statement, we don't have child
 	 * id, but we know register where it will be stored.
 	 */
-	if (parse_context->pNewTable != NULL) {
+	if (parse_context->create_table_def.new_table != 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 != NULL && fkey_is_self_referenced(fk)) {
+	if (parse_context->create_table_def.new_table != 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 == NULL)
+	if (parse_context->create_table_def.new_table == 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 = pParse->pNewTable;
+	p = pParse->create_table_def.new_table;
 	if (p == 0)
 		return;
 
@@ -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 != 0);
 		/* Do an insertion into _sequence. */
 		int reg_seq_id = ++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 = fk_parse->fkey;
 		if (fk_parse->selfref_cols != NULL) {
 			struct ExprList *cols = fk_parse->selfref_cols;
@@ -1369,8 +1377,7 @@ cleanup:
 
 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 = parse_context->db;
 	struct Table *sel_tab = 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 = parse_context->pNewTable;
+	sqlite3StartTable(parse_context);
+	struct Table *p = parse_context->create_table_def.new_table;
 	if (p == NULL || parse_context->nErr != 0)
 		goto create_view_fail;
 	sel_tab = 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 = parse_context->drop_entity_def;
+	assert(drop_def.base.entity_type == ENTITY_TYPE_TABLE);
+	struct SrcList *table_name_list = drop_def.base.entity_name;
 	struct Vdbe *v = sqlite3GetVdbe(parse_context);
 	struct sqlite3 *db = parse_context->db;
 	if (v == NULL || db->mallocFailed) {
@@ -1702,10 +1709,10 @@ sql_drop_table(struct Parse *parse_context, struct SrcList *table_name_list,
 	const char *space_name = table_name_list->a[0].zName;
 	struct space *space = space_by_name(space_name);
 	if (space == 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,
 }
 
 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 = parse_context->db;
+	struct create_fk_def create_fk_def = parse_context->create_fk_def;
+	struct create_constraint_def create_constr_def = create_fk_def.base;
+	struct create_entity_def create_def = create_constr_def.base;
+	struct alter_entity_def alter_def = create_def.base;
+	assert(alter_def.entity_type == ENTITY_TYPE_FK);
 	/*
 	 * When this function is called second time during
 	 * <CREATE TABLE ...> 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 = parse_context->pNewTable;
+	struct create_table_def *table_def = &parse_context->create_table_def;
+	struct Table *new_tab = table_def->new_table;
 	/* Whether we are processing ALTER TABLE or CREATE TABLE. */
 	bool is_alter = new_tab == NULL;
 	uint32_t child_cols_count;
+	struct ExprList *child_cols = create_fk_def.child_cols;
 	if (child_cols == NULL) {
 		assert(!is_alter);
 		child_cols_count = 1;
 	} else {
 		child_cols_count = child_cols->nExpr;
 	}
-	assert(!is_alter || (child != NULL && child->nSrc == 1));
 	struct space *child_space = NULL;
 	if (is_alter) {
-		const char *child_name = child->a[0].zName;
+		const char *child_name = alter_def.entity_name->a[0].zName;
 		child_space = space_by_name(child_name);
 		if (child_space == 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 = create_fk_def.parent_name;
 	assert(parent != NULL);
 	parent_name = sqlite3NameFromToken(db, parent);
 	if (parent_name == NULL)
@@ -1853,11 +1864,12 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child,
 	 */
 	is_self_referenced = !is_alter &&
 			     strcmp(parent_name, new_tab->def->name) == 0;
+	struct ExprList *parent_cols = create_fk_def.parent_cols;
 	struct space *parent_space = space_by_name(parent_name);
 	if (parent_space == NULL) {
 		if (is_self_referenced) {
 			struct fkey_parse *fk =
-				rlist_first_entry(&parse_context->new_fkey,
+				rlist_first_entry(&table_def->new_fkey,
 						  struct fkey_parse, link);
 			fk->selfref_cols = parent_cols;
 			fk->is_self_referenced = true;
@@ -1872,18 +1884,19 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child,
 			goto exit_create_fk;
 		}
 	}
-	if (constraint == NULL && !is_alter) {
-		if (parse_context->constraintName.n == 0) {
+	if (!is_alter) {
+		if (create_def.name.n == 0) {
 			constraint_name =
 				sqlite3MPrintf(db, "FK_CONSTRAINT_%d_%s",
-					       ++parse_context->fkey_count,
+					       ++table_def->fkey_count,
 					       new_tab->def->name);
 		} else {
-			struct Token *cnstr_nm = &parse_context->constraintName;
-			constraint_name = sqlite3NameFromToken(db, cnstr_nm);
+			constraint_name =
+				sqlite3NameFromToken(db, &create_def.name);
 		}
 	} else {
-		constraint_name = sqlite3NameFromToken(db, constraint);
+		constraint_name =
+			sqlite3NameFromToken(db, &create_def.name);
 	}
 	if (constraint_name == 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 = create_fk_def.actions;
 	fk->field_count = child_cols_count;
 	fk->child_id = child_space != NULL ? child_space->def->id : 0;
 	fk->parent_id = parent_space != NULL ? parent_space->def->id : 0;
-	fk->is_deferred = is_deferred;
+	fk->is_deferred = create_constr_def.is_deferred;
 	fk->match = (enum fkey_match) ((actions >> 16) & 0xff);
 	fk->on_update = (enum fkey_action) ((actions >> 8) & 0xff);
 	fk->on_delete = (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 =
-			rlist_first_entry(&parse_context->new_fkey,
+			rlist_first_entry(&table_def->new_fkey,
 					  struct fkey_parse, link);
 		parse_fk->fkey = 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 = is_deferred;
+	rlist_first_entry(&parse_context->create_table_def.new_fkey,
+			  struct fkey_parse, link)->fkey->is_deferred =
+		is_deferred;
 }
 
 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 != NULL && table->nSrc == 1);
-	const char *table_name = table->a[0].zName;
+	struct drop_entity_def drop_def = parse_context->drop_entity_def;
+	assert(drop_def.base.entity_type == ENTITY_TYPE_FK);
+	const char *table_name = drop_def.base.entity_name->a[0].zName;
+	assert(table_name != NULL);
 	struct space *child = space_by_name(table_name);
 	if (child == 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 = sqlite3NameFromToken(parse_context->db,
-						     constraint);
+						     &drop_def.name);
 	if (constraint_name != NULL)
 		vdbe_emit_fkey_drop(parse_context, constraint_name,
 				    child->def->id);
@@ -2211,19 +2227,29 @@ constraint_is_named(const char *name)
 }
 
 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 = NULL;
 	/* Name of the index. */
 	char *name = NULL;
 	struct sqlite3 *db = parse->db;
 	assert(!db->init.busy);
+	struct create_index_def create_idx_def = parse->create_index_def;
+	struct create_entity_def *create_entity_def =
+		(struct create_entity_def *) &create_idx_def;
+	struct alter_entity_def alter_entity_def = create_entity_def->base;
+	assert(alter_entity_def.entity_type == 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 = create_idx_def.cols;
+	struct SrcList *tbl_name = alter_entity_def.entity_name;
 
 	if (db->mallocFailed || parse->nErr > 0)
 		goto exit_create_index;
+	enum sql_index_type idx_type = create_idx_def.idx_type;
 	if (idx_type == SQL_INDEX_TYPE_UNIQUE ||
 	    idx_type == SQL_INDEX_TYPE_NON_UNIQUE) {
 		Vdbe *v = sqlite3GetVdbe(parse);
@@ -2238,12 +2264,13 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	 */
 	struct space *space = NULL;
 	struct space_def *def = NULL;
+	struct Token token = create_entity_def->name;
 	if (tbl_name != NULL) {
-		assert(token != NULL && token->z != NULL);
+		assert(token.n > 0 && token.z != NULL);
 		const char *name = tbl_name->a[0].zName;
 		space = space_by_name(name);
 		if (space == NULL) {
-			if (! if_not_exist) {
+			if (! create_entity_def->if_not_exist) {
 				diag_set(ClientError, ER_NO_SUCH_SPACE, name);
 				parse->rc = SQL_TARANTOOL_ERROR;
 				parse->nErr++;
@@ -2252,12 +2279,10 @@ sql_create_index(struct Parse *parse, struct Token *token,
 		}
 		def = space->def;
 	} else {
-		if (parse->pNewTable == NULL)
+		if (parse->create_table_def.new_table == NULL)
 			goto exit_create_index;
-		assert(token == NULL);
-		assert(start == NULL);
-		space = parse->pNewTable->space;
-		def = parse->pNewTable->def;
+		space = parse->create_table_def.new_table->space;
+		def = parse->create_table_def.new_table->def;
 	}
 
 	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 != NULL) {
-		assert(token->z != NULL);
-		name = sqlite3NameFromToken(db, token);
+	if (parse->create_table_def.new_table == NULL) {
+		assert(token.z != NULL);
+		name = sqlite3NameFromToken(db, &token);
 		if (name == NULL)
 			goto exit_create_index;
 		if (sql_space_index_by_name(space, name) != 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 = NULL;
-		if (parse->constraintName.z != NULL)
+		if (create_entity_def->name.n > 0)
 			constraint_name =
 				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 == NULL)
 			goto exit_create_index;
 		assert(col_list->nExpr == 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 != NULL) {
+	if (parse->create_table_def.new_table != NULL) {
 		for (uint32_t i = 0; i < space->index_count; ++i) {
 			struct index *existing_idx = space->index[i];
 			uint32_t iid = 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 != NULL);
 		int index_id = 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,
 }
 
 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 = parse_context->drop_entity_def;
+	assert(drop_def.base.entity_type == ENTITY_TYPE_INDEX);
 	struct Vdbe *v = sqlite3GetVdbe(parse_context);
 	assert(v != NULL);
 	struct sqlite3 *db = parse_context->db;
 	/* Never called with prior errors. */
 	assert(parse_context->nErr == 0);
-	assert(table_token != NULL);
-	const char *table_name = sqlite3NameFromToken(db, table_token);
+	struct SrcList *table_list = drop_def.base.entity_name;
+	assert(table_list->nSrc == 1);
+	char *table_name = table_list->a[0].zName;
+	const char *index_name = NULL;
 	if (db->mallocFailed) {
 		goto exit_drop_index;
 	}
 	sqlite3VdbeCountChanges(v);
-	assert(index_name_list->nSrc == 1);
-	assert(table_token->n > 0);
 	struct space *space = space_by_name(table_name);
+	bool if_exists = drop_def.if_exist;
 	if (space == NULL) {
 		if (!if_exists)
 			sqlite3ErrorMsg(parse_context, "no such space: %s",
 					table_name);
 		goto exit_drop_index;
 	}
-	const char *index_name = index_name_list->a[0].zName;
+	index_name = sqlite3NameFromToken(db, &drop_def.name);
 	uint32_t index_id = box_index_id_by_name(space->def->id, index_name,
 						 strlen(index_name));
 	if (index_id == 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);
 }
 
 /*
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 ::= ROLLBACK TO savepoint_opt nm(X). {
 //
 cmd ::= create_table create_table_args.
 create_table ::= 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) ::= CREATE(A).  {disableLookaside(pParse);}
 
@@ -237,8 +239,15 @@ nm(A) ::= id(A). {
 carglist ::= carglist cconsdef.
 carglist ::= .
 cconsdef ::= cconsname ccons.
-cconsname ::= CONSTRAINT nm(X).           {pParse->constraintName = X;}
-cconsname ::= .                           {pParse->constraintName.n = 0;}
+cconsname ::= cconsname_start cconsname_parse .
+cconsname_start ::= . {
+  /* Prepare base members for re-usage. */
+  memset(&pParse->create_index_def, 0, sizeof(struct create_index_def));
+}
+cconsname_parse ::= CONSTRAINT nm(X). {
+  create_entity_def_init(&pParse->create_index_def, X, false);
+}
+cconsname_parse ::= .
 ccons ::= DEFAULT term(X).            {sqlite3AddDefaultValue(pParse,&X);}
 ccons ::= DEFAULT LP expr(X) RP.      {sqlite3AddDefaultValue(pParse,&X);}
 ccons ::= DEFAULT PLUS term(X).       {sqlite3AddDefaultValue(pParse,&X);}
@@ -260,14 +269,29 @@ ccons ::= NULL onconf(R).        {
         sql_column_add_nullable_action(pParse, R);
 }
 ccons ::= NOT NULL onconf(R).    {sql_column_add_nullable_action(pParse, R);}
-ccons ::= PRIMARY KEY sortorder(Z) autoinc(I).
-                                 {sqlite3AddPrimaryKey(pParse,0,I,Z);}
-ccons ::= UNIQUE.                {sql_create_index(pParse,0,0,0,0,
-                                                   SORT_ORDER_ASC, false,
-                                                   SQL_INDEX_TYPE_CONSTRAINT_UNIQUE);}
-ccons ::= CHECK LP expr(X) RP.   {sql_add_check_constraint(pParse,&X);}
-ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
-                                 {sql_create_foreign_key(pParse, NULL, NULL, NULL, &T, TA, false, R);}
+ccons ::= PRIMARY KEY sortorder(Z) autoinc(I). {
+  pParse->create_table_def.has_autoinc = I;
+  sqlite3AddPrimaryKey(pParse,0,Z);
+}
+ccons ::= UNIQUE. {
+  pParse->create_index_def.idx_type = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE;
+  entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX);
+  sql_create_index(pParse);
+}
+
+ccons ::= check_constraint_def .
+
+check_constraint_def ::= CHECK LP expr(X) RP. {
+  pParse->create_ck_def.expr = &X;
+  entity_set_type(&pParse->create_index_def, ENTITY_TYPE_CK);
+  sql_add_check_constraint(pParse);
+}
+
+ccons ::= 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 ::= defer_subclause(D).    {fkey_change_defer_mode(pParse, D);}
 ccons ::= COLLATE id(C).        {sqlite3AddCollateType(pParse, &C);}
 
@@ -307,20 +331,24 @@ init_deferred_pred_opt(A) ::= .                       {A = 0;}
 init_deferred_pred_opt(A) ::= INITIALLY DEFERRED.     {A = 1;}
 init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE.    {A = 0;}
 
-tconsdef ::= tconsname tcons.
-tconsname ::= CONSTRAINT nm(X).      {pParse->constraintName = X;}
-tconsname ::= .                      {pParse->constraintName.n = 0;}
-tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP.
-                                 {sqlite3AddPrimaryKey(pParse,X,I,0);}
-tcons ::= UNIQUE LP sortlist(X) RP.
-                                 {sql_create_index(pParse,0,0,X,0,
-                                                   SORT_ORDER_ASC,false,
-                                                   SQL_INDEX_TYPE_CONSTRAINT_UNIQUE);}
-tcons ::= CHECK LP expr(E) RP onconf.
-                                 {sql_add_check_constraint(pParse,&E);}
+tconsdef ::= cconsname tcons.
+tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP. {
+  pParse->create_table_def.has_autoinc = I;
+  sqlite3AddPrimaryKey(pParse, X, 0);
+}
+tcons ::= UNIQUE LP sortlist(X) RP. {
+  pParse->create_index_def.cols = X;
+  pParse->create_index_def.idx_type = SQL_INDEX_TYPE_CONSTRAINT_UNIQUE;
+  entity_set_type(&pParse->create_index_def, ENTITY_TYPE_INDEX);
+  sql_create_index(pParse);
+}
+tcons ::= check_constraint_def .
 tcons ::= 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) ::= .                    {A = 0;}
@@ -343,9 +371,20 @@ resolvetype(A) ::= REPLACE.                  {A = ON_CONFLICT_ACTION_REPLACE;}
 
 ////////////////////////// The DROP TABLE /////////////////////////////////////
 //
-cmd ::= DROP TABLE ifexists(E) fullname(X). {
-  sql_drop_table(pParse, X, 0, E);
+
+cmd ::= drop_start(X) drop_table . {
+  sql_drop_table(pParse, X);
 }
+
+drop_table ::= ifexists(E) fullname(X) . {
+  alter_entity_def_init(&pParse->drop_entity_def, X, ENTITY_TYPE_TABLE);
+  pParse->drop_entity_def.if_exist = E;
+}
+
+%type drop_start {bool}
+drop_start(X) ::= DROP VIEW . { X = true; }
+drop_start(X) ::= DROP TABLE . { X = false; }
+
 %type ifexists {int}
 ifexists(A) ::= IF EXISTS.   {A = 1;}
 ifexists(A) ::= .            {A = 0;}
@@ -354,13 +393,13 @@ ifexists(A) ::= .            {A = 0;}
 //
 cmd ::= 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 ::= DROP VIEW ifexists(E) fullname(X). {
-  sql_drop_table(pParse, X, 1, E);
+  }
 }
 
 //////////////////////// The SELECT statement /////////////////////////////////
@@ -1198,10 +1237,15 @@ paren_exprlist(A) ::= LP exprlist(X) RP.  {A = X;}
 
 ///////////////////////////// The CREATE INDEX command ///////////////////////
 //
-cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X)
+cmd ::= 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 = U;
+  pParse->create_index_def.cols = Z;
+  sql_create_index(pParse);
 }
 
 %type uniqueflag {int}
@@ -1263,8 +1307,10 @@ collate(C) ::= COLLATE id.   {C = 1;}
 
 ///////////////////////////// The DROP INDEX command /////////////////////////
 //
-cmd ::= DROP INDEX ifexists(E) fullname(X) ON nm(Y).   {
-    sql_drop_index(pParse, X, &Y, E);
+cmd ::= 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);
 }
 
 ///////////////////////////// The PRAGMA command /////////////////////////////
@@ -1315,7 +1361,14 @@ cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
 trigger_decl(A) ::= 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 = &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 = C;
+  trigger_def->op = D.a;
+  trigger_def->cols = D.b;
+  trigger_def->when = G;
+  sql_trigger_begin(pParse);
   A = B; /*A-overwrites-T*/
 }
 
@@ -1425,7 +1478,9 @@ raisetype(A) ::= FAIL.      {A = ON_CONFLICT_ACTION_FAIL;}
 
 ////////////////////////  DROP TRIGGER statement //////////////////////////////
 cmd ::= 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);
 }
 
 /////////////////////////////////// ANALYZE ///////////////////////////////////
@@ -1434,17 +1489,25 @@ cmd ::= ANALYZE nm(X).          {sqlite3Analyze(pParse, &X);}
 
 //////////////////////// ALTER TABLE table ... ////////////////////////////////
 cmd ::= 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 = Z;
+  sql_alter_table_rename(pParse);
 }
 
 cmd ::= 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);
 }
 
 cmd ::= 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);
 }
 
 //////////////////////// 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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 = 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 = 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 =
+		(struct alter_entity_def *) entity_def;
+	alter_def->entity_type = type;
+}
+
+static inline void
+entity_set_defer_mode(void *entity_def, bool is_deferred)
+{
+	struct create_constraint_def *constr_def =
+		(struct create_constraint_def *) entity_def;
+	constr_def->is_deferred = 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 =
+		(struct alter_entity_def *) entity_def;
+	alter_def->entity_name = entity_name;
+	alter_def->entity_type = type;
+}
+
+static inline void
+create_entity_def_init(void *entity_def, struct Token name, bool if_not_exist)
+{
+	struct create_entity_def *create_def =
+		(struct create_entity_def *) entity_def;
+	create_def->name = name;
+	create_def->if_not_exist = 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 = name;
+	drop_def->if_exist = 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 != NULL);
+	fk_def->child_cols = child_cols;
+	fk_def->parent_name = parent_name;
+	fk_def->parent_cols = parent_cols;
+	fk_def->actions = 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 = 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 != NULL) {
 		assert(db->lookaside.bDisable >=
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;
 
 	assert(type == NC_IsCheck || type == 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 @@
 
 #include <stdbool.h>
 
+#include "parse_def.h"
 #include "box/field_def.h"
 #include "box/sql.h"
 #include "box/txn.h"
@@ -1915,19 +1916,6 @@ struct UnpackedRecord {
 				 */
 };
 
-/*
- * 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 = 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)] == 200 */
 #define DEFAULT_TUPLE_LOG_COUNT 200
 
-/*
- * 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==0 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==0.
- */
-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);
 
-void sqlite3StartTable(Parse *, Token *, int);
+void sqlite3StartTable(Parse *);
 void sqlite3AddColumn(Parse *, Token *, struct type_def *);
 
 /**
@@ -3375,16 +3350,15 @@ void
 sql_column_add_nullable_action(struct Parse *parser,
 			       enum on_conflict_action nullable_action);
 
-void sqlite3AddPrimaryKey(Parse *, ExprList *, int, enum sort_order);
+void sqlite3AddPrimaryKey(Parse *, ExprList *, enum sort_order);
 
 /**
  * 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);
 
 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);
 
 /**
  * Helper to convert SQLite affinity to corresponding
@@ -3472,7 +3443,7 @@ void
 sql_store_select(struct Parse *parse_context, struct Select *select);
 
 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==NULL.
- * @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);
 
 /**
  * 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);
 
 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);
 
 /**
  * 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);
 
 /**
  * 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 <CREATE TABLE ...>
  *
  * @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);
 
 /**
  * Function called from parser to handle
  * <ALTER TABLE table DROP CONSTRAINT constraint> 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);
 
 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);
 
 /**
  * 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 == 0);
+	assert(pParse->create_table_def.new_table == NULL);
 	assert(pParse->parsed_ast.trigger == NULL);
 	assert(pParse->nVar == 0);
 	assert(pParse->pVList == 0);
@@ -529,7 +529,7 @@ sqlite3RunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
 		sqlite3VdbeDelete(pParse->pVdbe);
 		pParse->pVdbe = 0;
 	}
-	sqlite3DeleteTable(db, pParse->pNewTable);
+	sqlite3DeleteTable(db, pParse->create_table_def.new_table);
 
 	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)
 }
 
 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 = NULL;
 	/* The database connection. */
 	struct sqlite3 *db = parse->db;
-	/* The name of the Trigger. */
-	char *trigger_name = NULL;
-
-	/* pName->z might be NULL, but not pName itself. */
-	assert(name != NULL);
-	assert(op == TK_INSERT || op == TK_UPDATE || op == TK_DELETE);
-	assert(op > 0 && op < 0xff);
+	struct create_trigger_def trigger_def = parse->create_trigger_def;
+	struct create_entity_def create_def = trigger_def.base;
+	struct alter_entity_def alter_def = create_def.base;
+	assert(alter_def.entity_type == ENTITY_TYPE_TRIGGER);
 
-	if (table == NULL || db->mallocFailed)
+	char *trigger_name = NULL;
+	if (alter_def.entity_name == NULL || db->mallocFailed)
 		goto trigger_cleanup;
-	assert(table->nSrc == 1);
-
-	trigger_name = sqlite3NameFromToken(db, name);
+	assert(alter_def.entity_name->nSrc == 1);
+	assert(create_def.name.n > 0);
+	trigger_name = sqlite3NameFromToken(db, &create_def.name);
 	if (trigger_name == NULL)
 		goto trigger_cleanup;
 
 	if (sqlite3CheckIdentifierName(parse, trigger_name) != SQLITE_OK)
 		goto trigger_cleanup;
 
-	const char *table_name = table->a[0].zName;
+	const char *table_name = 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) != 0)
@@ -112,6 +108,7 @@ sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm,
 		int name_reg = ++parse->nMem;
 		sqlite3VdbeAddOp4(parse->pVdbe, OP_String8, 0, name_reg, 0,
 				  name_copy, P4_DYNAMIC);
+		bool no_err = 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 = space_id;
 	trigger->zName = trigger_name;
 	trigger_name = NULL;
-
-	trigger->op = (u8) op;
-	trigger->tr_tm = tr_tm;
-	trigger->pWhen = sqlite3ExprDup(db, when, EXPRDUP_REDUCE);
-	trigger->pColumns = sqlite3IdListDup(db, columns);
-	if ((when != NULL && trigger->pWhen == NULL) ||
-	    (columns != NULL && trigger->pColumns == NULL))
+	assert(trigger_def.op == TK_INSERT || trigger_def.op == TK_UPDATE ||
+	       trigger_def.op== TK_DELETE);
+	trigger->op = (u8) trigger_def.op;
+	trigger->tr_tm = trigger_def.tr_tm;
+	trigger->pWhen = sqlite3ExprDup(db, trigger_def.when, EXPRDUP_REDUCE);
+	trigger->pColumns = sqlite3IdListDup(db, trigger_def.cols);
+	if ((trigger->pWhen != NULL && trigger->pWhen == NULL) ||
+	    (trigger->pColumns != NULL && trigger->pColumns == NULL))
 		goto trigger_cleanup;
 	assert(parse->parsed_ast.trigger == NULL);
 	parse->parsed_ast.trigger = trigger;
@@ -143,9 +141,9 @@ sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm,
 
  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 == NULL)
 		sql_trigger_delete(db, trigger);
 	else
@@ -424,9 +422,13 @@ vdbe_code_drop_trigger(struct Parse *parser, const char *trigger_name,
 }
 
 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 = parser->drop_entity_def;
+	struct alter_entity_def alter_def = drop_def.base;
+	assert(alter_def.entity_type == ENTITY_TYPE_TRIGGER);
+	struct SrcList *name = alter_def.entity_name;
+	bool no_err = drop_def.if_exist;
 	sqlite3 *db = 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" = "_space"."id" AND
                 "_space"."name"='TEST8';
         ]],
-        {0, {"pk_TEST8_2",0,"unique_C1_1",1}})
+        {0, {"pk_unnamed_TEST8_2",0,"unique_C1_1",1}})
 
 test:finish_test()





More information about the Tarantool-patches mailing list