From: Nikita Pettik <korablev@tarantool.org> To: tarantool-patches@freelists.org Cc: v.shpilevoy@tarantool.org, kostja@tarantool.org, Nikita Pettik <korablev@tarantool.org> Subject: [tarantool-patches] [PATCH v2 1/5] sql: introduce structs assembling DDL arguments during parsing Date: Wed, 23 Jan 2019 20:56:14 +0300 [thread overview] Message-ID: <0fcc585532a1f1200a7dfd4a8e911ecf9f2c94aa.1548265148.git.korablev@tarantool.org> (raw) In-Reply-To: <cover.1548265148.git.korablev@tarantool.org> In-Reply-To: <cover.1548265148.git.korablev@tarantool.org> 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. Note that grammar for CREATE TABLE statement is not trivial and consists of wide range of sub-clauses (e.g. to parse foreign key or check constraints). Therefore, parts of space definition are assembled as soon as parser processes sub-rules. For this reason, current patch doesn't affect CREATE TABLE handling. Patch itself is made up of refactoring; no functional changes are provided. Needed for #3097 --- src/box/sql/CMakeLists.txt | 1 + src/box/sql/alter.c | 10 ++- src/box/sql/build.c | 146 ++++++++++++++++++------------ src/box/sql/parse.y | 209 ++++++++++++++++++++++++++++++++++++------- src/box/sql/parse_def.c | 158 ++++++++++++++++++++++++++++++++ src/box/sql/parse_def.h | 170 +++++++++++++++++++++++++++++++++++ src/box/sql/sqliteInt.h | 70 +++------------ src/box/sql/trigger.c | 57 ++++++------ test/sql-tap/index7.test.lua | 2 +- 9 files changed, 647 insertions(+), 176 deletions(-) create mode 100644 src/box/sql/parse_def.c create mode 100644 src/box/sql/parse_def.h diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt index 7f7b60e22..0ff311173 100644 --- a/src/box/sql/CMakeLists.txt +++ b/src/box/sql/CMakeLists.txt @@ -45,6 +45,7 @@ add_library(sql STATIC malloc.c os.c os_unix.c + parse_def.c pragma.c prepare.c printf.c diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c index d0ce9d893..cf1164ab9 100644 --- a/src/box/sql/alter.c +++ b/src/box/sql/alter.c @@ -33,17 +33,19 @@ * This file contains C code routines that used to generate VDBE code * that implements the ALTER TABLE command. */ -#include "sqliteInt.h" +#include "parse_def.h" #include "box/box.h" #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 = + (struct rename_entity_def *) parse->alter_entity_def; + struct SrcList *src_tab = rename_def->base->entity_name; 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 49b90b5d0..d0e19407a 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -46,6 +46,7 @@ #include "sqliteInt.h" #include "vdbeInt.h" #include "tarantoolInt.h" +#include "parse_def.h" #include "box/box.h" #include "box/fkey.h" #include "box/sequence.h" @@ -566,7 +567,6 @@ 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 @@ -713,6 +713,16 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ } } } + struct alter_entity_def alter_def = {}; + struct create_entity_def create_def = {}; + struct create_constraint_def constr_def = {}; + struct create_index_def idx_def = {}; + create_def.base = &alter_def; + constr_def.base = &create_def; + idx_def.base = &constr_def; + idx_def.idx_type = SQL_INDEX_TYPE_CONSTRAINT_PK; + idx_def.sort_order = sortOrder; + pParse->alter_entity_def = (void *) &idx_def; if (nTerm == 1 && iCol != -1 && pTab->def->fields[iCol].type == FIELD_TYPE_INTEGER && sortOrder != SORT_ORDER_DESC) { @@ -727,8 +737,8 @@ 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); + idx_def.cols = list; + sql_create_index(pParse); if (db->mallocFailed) goto primary_key_exit; } else if (autoInc) { @@ -736,8 +746,8 @@ sqlite3AddPrimaryKey(Parse * pParse, /* Parsing context */ "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); + idx_def.cols = pList; + sql_create_index(pParse); pList = 0; if (pParse->nErr > 0) goto primary_key_exit; @@ -774,9 +784,12 @@ 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_constraint_def *constr_def = + (struct create_constraint_def *) parser->alter_entity_def; + struct create_entity_def *entity_def = constr_def->base; + if (entity_def->name.n > 0) { sqlite3ExprListSetName(parser, table->def->opts.checks, - &parser->constraintName, 1); + &entity_def->name, 1); } } else { release_expr: @@ -1695,14 +1708,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->alter_entity_def; + struct alter_entity_def *alter_def = drop_def->base; + struct SrcList *table_name_list = alter_def->entity_name; struct Vdbe *v = sqlite3GetVdbe(parse_context); struct sqlite3 *db = parse_context->db; if (v == NULL || db->mallocFailed) { @@ -1714,10 +1727,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; @@ -1800,12 +1813,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 = + (struct create_fk_def *) parse_context->alter_entity_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; /* * When this function is called second time during * <CREATE TABLE ...> statement (i.e. at VDBE runtime), @@ -1828,16 +1843,17 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child, /* 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); @@ -1854,6 +1870,7 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child, memset(fk, 0, sizeof(*fk)); rlist_add_entry(&parse_context->new_fkey, fk, link); } + struct Token *parent = create_fk_def->parent_name; assert(parent != NULL); parent_name = sqlite3NameFromToken(db, parent); if (parent_name == NULL) @@ -1865,6 +1882,7 @@ 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) { @@ -1884,18 +1902,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, 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; @@ -1928,10 +1947,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); @@ -2016,11 +2036,13 @@ fkey_change_defer_mode(struct Parse *parse_context, bool 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 = + (struct drop_entity_def *) parse_context->alter_entity_def; + struct alter_entity_def *alter_def = drop_def->base; + const char *table_name = alter_def->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); @@ -2029,7 +2051,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); @@ -2223,19 +2245,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 = + (struct create_index_def *) parse->alter_entity_def; + struct create_constraint_def *create_constr_def = create_idx_def->base; + struct create_entity_def *create_entity_def = create_constr_def->base; + struct alter_entity_def *alter_entity_def = create_entity_def->base; + /* + * 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); @@ -2250,12 +2282,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++; @@ -2266,8 +2299,6 @@ sql_create_index(struct Parse *parse, struct Token *token, } else { if (parse->pNewTable == NULL) goto exit_create_index; - assert(token == NULL); - assert(start == NULL); space = parse->pNewTable->space; def = parse->pNewTable->def; } @@ -2296,13 +2327,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->pNewTable == 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); @@ -2311,11 +2342,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 @@ -2373,7 +2403,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"); } @@ -2521,8 +2552,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, @@ -2546,30 +2575,33 @@ 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 = + (struct drop_entity_def *) parse_context->alter_entity_def; + struct alter_entity_def *alter_def = drop_def->base; 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 = alter_def->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) { @@ -2595,8 +2627,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 50bb2ba01..b0327c27a 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -52,6 +52,7 @@ %include { #include "sqliteInt.h" #include "box/fkey.h" +#include "parse_def.h" /* ** Disable all error recovery processing in the parser push-down @@ -237,8 +238,36 @@ 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 ::= . { + struct alter_entity_def *alter_def = + alter_entity_def_new(pParse, NULL); + if (alter_def == NULL) + break; + struct create_entity_def *create_def = + create_entity_def_new(pParse, alter_def, (struct Token){}, false); + if (create_def == NULL) + break; + pParse->alter_entity_def = (void *) create_def; +} +cconsname_parse ::= CONSTRAINT nm(X). { + struct create_entity_def *create_def = pParse->alter_entity_def; + create_def->name = X; + struct create_constraint_def *constr_def = + create_constraint_def_new(pParse, create_def, false); + if (constr_def == NULL) + break; + constr_def->base = create_def; + pParse->alter_entity_def = constr_def; +} +cconsname_parse ::= . { + struct create_entity_def *create_def = pParse->alter_entity_def; + struct create_constraint_def *constr_def = + create_constraint_def_new(pParse, create_def, false); + if (constr_def == NULL) + break; + pParse->alter_entity_def = constr_def; +} ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);} ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);} ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);} @@ -262,12 +291,26 @@ ccons ::= NULL onconf(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 ::= UNIQUE. { + struct create_constraint_def *constr_def = pParse->alter_entity_def; + struct create_index_def *idx_def = + create_index_def_new(pParse, constr_def, NULL, + SQL_INDEX_TYPE_CONSTRAINT_UNIQUE, SORT_ORDER_ASC); + if (idx_def == NULL) + break; + pParse->alter_entity_def = (void *) idx_def; + sql_create_index(pParse); +} 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 ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). { + struct create_constraint_def *constr_def = pParse->alter_entity_def; + struct create_fk_def *fk_def = + create_fk_def_new(pParse, constr_def, NULL, &T, TA, R); + if (fk_def == NULL) + break; + pParse->alter_entity_def = (void *) fk_def; + sql_create_foreign_key(pParse); +} ccons ::= defer_subclause(D). {fkey_change_defer_mode(pParse, D);} ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, &C);} @@ -307,20 +350,31 @@ 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;} +tconsdef ::= cconsname tcons. 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 ::= UNIQUE LP sortlist(X) RP. { + struct create_constraint_def *constr_def = pParse->alter_entity_def; + struct create_index_def *idx_def = + create_index_def_new(pParse, constr_def, X, + SQL_INDEX_TYPE_CONSTRAINT_UNIQUE, SORT_ORDER_ASC); + if (idx_def == NULL) + break; + pParse->alter_entity_def = (void *) idx_def; + sql_create_index(pParse); +} tcons ::= CHECK LP expr(E) RP onconf. {sql_add_check_constraint(pParse,&E);} 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); + struct create_constraint_def *constr_def = pParse->alter_entity_def; + constr_def->is_deferred = D; + struct create_fk_def *fk_def = + create_fk_def_new(pParse, constr_def, FA, &T, TA, R); + if (fk_def == NULL) + break; + pParse->alter_entity_def = (void *) fk_def; + sql_create_foreign_key(pParse); } %type defer_subclause_opt {int} defer_subclause_opt(A) ::= . {A = 0;} @@ -343,9 +397,27 @@ 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) . { + struct alter_entity_def *alter_def = + alter_entity_def_new(pParse, X); + if (alter_def == NULL) + break; + struct drop_entity_def *drop_def = + drop_entity_def_new(pParse, alter_def, (struct Token){}, E); + if (drop_def == NULL) + break; + pParse->alter_entity_def = (void *) drop_def; +} + +%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;} @@ -359,9 +431,6 @@ cmd ::= createkw(X) VIEW ifnotexists(E) nm(Y) eidlist_opt(C) else sql_store_select(pParse, S); } -cmd ::= DROP VIEW ifexists(E) fullname(X). { - sql_drop_table(pParse, X, 1, E); -} //////////////////////// The SELECT statement ///////////////////////////////// // @@ -1209,10 +1278,22 @@ 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); + struct alter_entity_def alter_def = {}; + struct create_entity_def create_def = {}; + struct create_constraint_def constr_def = {}; + struct create_index_def idx_def = {}; + alter_def.entity_name = sqlite3SrcListAppend(pParse->db,0,&Y); + create_def.base = &alter_def; + create_def.name = X; + create_def.if_not_exist = NE; + constr_def.base = &create_def; + idx_def.base = &constr_def; + idx_def.cols = Z; + idx_def.idx_type = U; + pParse->alter_entity_def = (void *) &idx_def; + sql_create_index(pParse); } %type uniqueflag {int} @@ -1274,8 +1355,15 @@ 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). { + struct alter_entity_def alter_def = {}; + struct drop_entity_def drop_def = {}; + alter_def.entity_name = Y; + drop_def.base = &alter_def; + drop_def.if_exist = E; + drop_def.name = X; + pParse->alter_entity_def = (void *) &drop_def; + sql_drop_index(pParse); } ///////////////////////////// The PRAGMA command ///////////////////////////// @@ -1326,7 +1414,20 @@ 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 alter_entity_def alter_def = {}; + struct create_entity_def create_def = {}; + struct create_trigger_def trigger_def = {}; + alter_def.entity_name = E; + create_def.base = &alter_def; + create_def.name = B; + create_def.if_not_exist = NOERR; + trigger_def.base = &create_def; + trigger_def.tr_tm = C; + trigger_def.op = D.a; + trigger_def.cols = D.b; + trigger_def.when = G; + pParse->alter_entity_def = (void *) &trigger_def; + sql_trigger_begin(pParse); A = B; /*A-overwrites-T*/ } @@ -1436,7 +1537,13 @@ raisetype(A) ::= FAIL. {A = ON_CONFLICT_ACTION_FAIL;} //////////////////////// DROP TRIGGER statement ////////////////////////////// cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). { - sql_drop_trigger(pParse,X,NOERR); + struct alter_entity_def alter_def = {}; + struct drop_entity_def drop_def = {}; + alter_def.entity_name = X; + drop_def.base = &alter_def; + drop_def.if_exist = NOERR; + pParse->alter_entity_def = (void *) &drop_def; + sql_drop_trigger(pParse); } /////////////////////////////////// ANALYZE /////////////////////////////////// @@ -1445,17 +1552,59 @@ 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); + struct alter_entity_def *alter_def = + alter_entity_def_new(pParse, X); + /* + * After code preprocessing, this code snippet will get to + * one of "switch" cases. Hence, break is enough to gently + * terminate it. No clean-ups are required since all structs + * are allocated on region. OOM error is set inside def + * constructors. + */ + if (alter_def == NULL) + break; + struct rename_entity_def *rename_def = + rename_entity_def_new(pParse, alter_def, Z); + if (rename_def == NULL) + break; + pParse->alter_entity_def = (void *) rename_def; + 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); + struct alter_entity_def *alter_def = + alter_entity_def_new(pParse, X); + if (alter_def == NULL) + break; + struct create_entity_def *create_def = + create_entity_def_new(pParse, alter_def, Z, false); + if (create_def == NULL) + break; + struct create_constraint_def *constraint_def = + create_constraint_def_new(pParse, create_def, D); + if (constraint_def == NULL) + break; + struct create_fk_def *fk_def = + create_fk_def_new(pParse, constraint_def, FA, &T, TA, R); + if (fk_def == NULL) + break; + pParse->alter_entity_def = (void *) fk_def; + sql_create_foreign_key(pParse); } cmd ::= ALTER TABLE fullname(X) DROP CONSTRAINT nm(Z). { - sql_drop_foreign_key(pParse, X, &Z); + struct alter_entity_def *alter_def = + alter_entity_def_new(pParse, X); + if (alter_def == NULL) + break; + struct drop_entity_def *drop_def = + drop_entity_def_new(pParse, alter_def, Z, false); + if (drop_def == NULL) + break; + pParse->alter_entity_def = (void *) drop_def; + sql_drop_foreign_key(pParse); } //////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// diff --git a/src/box/sql/parse_def.c b/src/box/sql/parse_def.c new file mode 100644 index 000000000..7f241636a --- /dev/null +++ b/src/box/sql/parse_def.c @@ -0,0 +1,158 @@ +/* + * 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 "parse_def.h" + +struct alter_entity_def * +alter_entity_def_new(struct Parse *parse, struct SrcList *name) +{ + size_t sz = sizeof(struct alter_entity_def); + struct alter_entity_def *alter_def = region_alloc(&parse->region, sz); + if (alter_def == NULL) { + diag_set(OutOfMemory, sz, "region", "alter_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + alter_def->entity_name = name; + return alter_def; +} + +struct rename_entity_def * +rename_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token new_name) +{ + size_t sz = sizeof(struct rename_entity_def); + struct rename_entity_def *rename_def = region_alloc(&parse->region, sz); + if (rename_def == NULL) { + diag_set(OutOfMemory, sz, "region", "rename_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + rename_def->base = base; + rename_def->new_name = new_name; + return rename_def; +} + +struct create_entity_def * +create_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token name, bool if_not_exists) +{ + size_t sz = sizeof(struct create_entity_def); + struct create_entity_def *create_def = region_alloc(&parse->region, sz); + if (create_def == NULL) { + diag_set(OutOfMemory, sz, "region", "create_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + create_def->base = base; + create_def->name = name; + create_def->if_not_exist = if_not_exists; + return create_def; +} + +struct drop_entity_def * +drop_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token entity_name, bool if_exist) +{ + size_t sz = sizeof(struct drop_entity_def); + struct drop_entity_def *drop_def = region_alloc(&parse->region, sz); + if (drop_def == NULL) { + diag_set(OutOfMemory, sz, "region", "drop_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + drop_def->base = base; + drop_def->name = entity_name; + drop_def->if_exist = if_exist; + return drop_def; +} + +struct create_constraint_def * +create_constraint_def_new(struct Parse *parse, struct create_entity_def *base, + bool is_deferred) +{ + size_t sz = sizeof(struct create_constraint_def); + struct create_constraint_def *constr_def = + region_alloc(&parse->region, sz); + if (constr_def == NULL) { + diag_set(OutOfMemory, sz, "region", "constr_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + constr_def->base = base; + constr_def->is_deferred = is_deferred; + return constr_def; +} + +struct create_fk_def * +create_fk_def_new(struct Parse *parse, struct create_constraint_def *base, + struct ExprList *child_cols, struct Token *parent_name, + struct ExprList *parent_cols, int actions) +{ + size_t sz = sizeof(struct create_fk_def); + struct create_fk_def *fk_def = region_alloc(&parse->region, sz); + if (fk_def == NULL) { + diag_set(OutOfMemory, sz, "region", "fk_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + fk_def->base = base; + fk_def->child_cols = child_cols; + fk_def->parent_name = parent_name; + fk_def->parent_cols = parent_cols; + fk_def->actions = actions; + return fk_def; +} + +struct create_index_def * +create_index_def_new(struct Parse *parse, struct create_constraint_def *base, + struct ExprList *cols, enum sql_index_type idx_type, + enum sort_order sort_order) +{ + size_t sz = sizeof(struct create_index_def); + struct create_index_def *idx_def = region_alloc(&parse->region, sz); + if (idx_def == NULL) { + diag_set(OutOfMemory, sz, "region", "idx_def"); + parse->rc = SQL_TARANTOOL_ERROR; + parse->nErr++; + return NULL; + } + idx_def->base = base; + idx_def->cols = cols; + idx_def->idx_type = idx_type; + idx_def->sort_order = sort_order; + return idx_def; +} diff --git a/src/box/sql/parse_def.h b/src/box/sql/parse_def.h new file mode 100644 index 000000000..2f6d3d047 --- /dev/null +++ b/src/box/sql/parse_def.h @@ -0,0 +1,170 @@ +/* + * 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 "sqliteInt.h" +#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 + */ +struct alter_entity_def { + /** 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 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_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; +}; + + +/** + * Below is a list of *_def constructors. All of them allocate + * memory for new object using parser's region: it simplifies + * things since their lifetime is restricted by parser. + * + * In case of OOM, they return NULL and set appropriate + * error code in parser's structure and re-raise error + * via diag_set(). + */ +struct alter_entity_def * +alter_entity_def_new(struct Parse *parse, struct SrcList *name); + +struct rename_entity_def * +rename_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token new_name); + +struct create_entity_def * +create_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token name, bool if_not_exists); + +struct drop_entity_def * +drop_entity_def_new(struct Parse *parse, struct alter_entity_def *base, + struct Token name, bool if_exist); + +struct create_constraint_def * +create_constraint_def_new(struct Parse *parse, struct create_entity_def *base, + bool is_deferred); + +struct create_fk_def * +create_fk_def_new(struct Parse *parse, struct create_constraint_def *base, + struct ExprList *child_cols, struct Token *parent_name, + struct ExprList *parent_cols, int actions); + +struct create_index_def * +create_index_def_new(struct Parse *parse, struct create_constraint_def *base, + struct ExprList *cols, enum sql_index_type idx_type, + enum sort_order sort_order); diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 4110a5991..73d8a6a7c 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -2728,7 +2728,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 */ @@ -2781,6 +2780,12 @@ struct Parse { 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 */ + /** + * One of parse_def structures which are used to + * assemble and carry arguments of DDL routines + * from parse.y + */ + void *alter_entity_def; /** * Number of FK constraints declared within * CREATE TABLE statement. @@ -3459,7 +3464,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); @@ -3488,36 +3493,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 *, @@ -3919,20 +3907,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 @@ -3952,11 +3929,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. @@ -4136,14 +4111,6 @@ 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. @@ -4152,22 +4119,16 @@ fkey_change_defer_mode(struct Parse *parse_context, bool is_deferred); * 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); @@ -4385,12 +4346,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/trigger.c b/src/box/sql/trigger.c index 7d5dc9e23..685343ce9 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -34,7 +34,7 @@ */ #include "box/schema.h" -#include "sqliteInt.h" +#include "parse_def.h" #include "tarantoolInt.h" #include "vdbeInt.h" #include "box/session.h" @@ -62,34 +62,29 @@ 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->alter_entity_def; + struct create_entity_def *create_def = trigger_def->base; + struct alter_entity_def *alter_def = create_def->base; - 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 +107,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 +125,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 +140,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 +421,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 = + (struct drop_entity_def *) parser->alter_entity_def; + struct alter_entity_def *alter_def = drop_def->base; + 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() -- 2.15.1
next prev parent reply other threads:[~2019-01-23 17:56 UTC|newest] Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-01-23 17:56 [tarantool-patches] [PATCH v2 0/5] Introduce ALTER TABLE ADD CONSTRAINT UNIQUE/PK Nikita Pettik 2019-01-23 17:56 ` Nikita Pettik [this message] 2019-01-24 8:36 ` [tarantool-patches] Re: [PATCH v2 1/5] sql: introduce structs assembling DDL arguments during parsing Konstantin Osipov 2019-01-24 10:47 ` n.pettik 2019-01-24 12:30 ` Konstantin Osipov 2019-01-29 19:03 ` n.pettik 2019-01-29 19:29 ` Vladislav Shpilevoy 2019-01-29 20:04 ` n.pettik 2019-01-29 20:20 ` Vladislav Shpilevoy 2019-01-29 21:25 ` n.pettik 2019-01-31 19:32 ` n.pettik 2019-02-04 15:25 ` Vladislav Shpilevoy 2019-02-08 14:25 ` n.pettik 2019-02-15 20:13 ` Vladislav Shpilevoy 2019-02-27 22:56 ` n.pettik 2019-03-12 12:50 ` Vladislav Shpilevoy 2019-03-14 18:13 ` n.pettik 2019-03-25 11:25 ` Vladislav Shpilevoy 2019-03-26 18:01 ` n.pettik 2019-03-26 18:06 ` Vladislav Shpilevoy 2019-03-27 13:00 ` n.pettik 2019-03-27 13:29 ` Vladislav Shpilevoy 2019-03-27 13:44 ` n.pettik 2019-03-27 14:03 ` Vladislav Shpilevoy 2019-03-27 14:11 ` n.pettik 2019-01-23 17:56 ` [tarantool-patches] [PATCH v2 2/5] sql: rework ALTER TABLE grammar Nikita Pettik 2019-01-23 17:56 ` [tarantool-patches] [PATCH v2 3/5] sql: refactor getNewIid() function Nikita Pettik 2019-01-23 17:56 ` [tarantool-patches] [PATCH v2 4/5] sql: fix error message for improperly created index Nikita Pettik 2019-02-08 17:14 ` [tarantool-patches] " Konstantin Osipov 2019-01-23 17:56 ` [tarantool-patches] [PATCH v2 5/5] sql: introduce ALTER TABLE ADD CONSTRAINT UNIQUE/PRIMARY KEY Nikita Pettik 2019-01-24 8:31 ` [tarantool-patches] " Konstantin Osipov 2019-01-29 19:29 ` Vladislav Shpilevoy 2019-02-08 17:16 ` Konstantin Osipov 2019-02-08 17:36 ` n.pettik
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=0fcc585532a1f1200a7dfd4a8e911ecf9f2c94aa.1548265148.git.korablev@tarantool.org \ --to=korablev@tarantool.org \ --cc=kostja@tarantool.org \ --cc=tarantool-patches@freelists.org \ --cc=v.shpilevoy@tarantool.org \ --subject='Re: [tarantool-patches] [PATCH v2 1/5] sql: introduce structs assembling DDL arguments during parsing' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox