From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id EE8A242F044 for ; Mon, 14 Oct 2019 19:03:30 +0300 (MSK) From: Kirill Shcherbatov Date: Mon, 14 Oct 2019 19:03:22 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH v1 7/9] sql: wrap all ASTs in sql_trigger_expr structure List-Id: Tarantool development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@freelists.org, tarantool-patches@dev.tarantool.org, kostja.osipov@gmail.com, korablev@tarantool.org Introduced a new sql_trigger_expr to aggregate all sql_triger-related ASTs. This allows to rework sql_trigger_compile function in further patches to return sql_trigger_expr object instead of the complete trigger object. It is an important step of refactoring, because we are going to construct trigger and trigger_def objects universally by information that will be defined in the _trigger space. Needed for #4343 --- src/box/sql.h | 37 +++++++++++++++----- src/box/sql/fk_constraint.c | 15 +++++--- src/box/sql/trigger.c | 69 +++++++++++++++++++++++++++++-------- 3 files changed, 92 insertions(+), 29 deletions(-) diff --git a/src/box/sql.h b/src/box/sql.h index 09d2b7d7c..d0c18b6ff 100644 --- a/src/box/sql.h +++ b/src/box/sql.h @@ -99,6 +99,32 @@ sql_expr_compile(struct sql *db, const char *expr, int expr_len); struct Select * sql_view_compile(struct sql *db, const char *view_stmt); +/** The SQL Trigger AST runtime representation. */ +struct sql_trigger_expr { + /** The WHEN clause of the expression (may be NULL). */ + struct Expr *when; + /** + * If this is an UPDATE OF trigger, + * the is stored here + */ + struct IdList *cols; + /** Link list of trigger program steps. */ + struct TriggerStep *step_list; +}; + +/** + * Allocate a new SQL Trigger AST runtime object. + * In case of successfull construction, the constructed object + * start manipulate given arguments lifecycle. + */ +struct sql_trigger_expr * +sql_trigger_expr_new(struct sql *db, struct IdList *cols, struct Expr *when, + struct TriggerStep *step_list); + +/** Free SQL Trigger AST object. */ +void +sql_trigger_expr_delete(struct sql *db, struct sql_trigger_expr *trigger_expr); + /** * Perform parsing of provided SQL request and construct trigger AST. * @param db SQL context handle. @@ -452,15 +478,8 @@ struct sql_trigger { * triggering event. The value is `BEFORE` or `AFTER`. */ enum trigger_action_timing action_timing; - /** The WHEN clause of the expression (may be NULL). */ - struct Expr *pWhen; - /** - * If this is an UPDATE OF trigger, - * the is stored here - */ - struct IdList *pColumns; - /** Link list of trigger program steps. */ - struct TriggerStep *step_list; + /** The SQL trigger AST. */ + struct sql_trigger_expr *expr; /** * Organize sql_trigger structs into linked list * with space::trigger_list. diff --git a/src/box/sql/fk_constraint.c b/src/box/sql/fk_constraint.c index 539a16560..454ed311f 100644 --- a/src/box/sql/fk_constraint.c +++ b/src/box/sql/fk_constraint.c @@ -856,22 +856,27 @@ fk_constraint_action_trigger(struct Parse *pParse, struct space_def *def, sizeof(*trigger)); if (trigger != NULL) { size_t step_size = sizeof(TriggerStep) + name_len + 1; - trigger->step_list = sqlDbMallocZero(db, step_size); + step = sqlDbMallocZero(db, step_size); rlist_create(&trigger->link); - step = trigger->step_list; + if (step == NULL) + goto end; step->zTarget = (char *) &step[1]; memcpy((char *) step->zTarget, space_name, name_len); - step->pWhere = sqlExprDup(db, where, EXPRDUP_REDUCE); step->pExprList = sql_expr_list_dup(db, list, EXPRDUP_REDUCE); step->pSelect = sqlSelectDup(db, select, EXPRDUP_REDUCE); if (when != NULL) { when = sqlPExpr(pParse, TK_NOT, when, 0); - trigger->pWhen = - sqlExprDup(db, when, EXPRDUP_REDUCE); + if (when == NULL) + goto end; } + trigger->expr = sql_trigger_expr_new(db, NULL, when, step); + if (trigger->expr == NULL) + goto end; + when = NULL; } +end: sql_expr_delete(db, where, false); sql_expr_delete(db, when, false); sql_expr_list_delete(db, list); diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 3a0ee6b7d..71a78d7ed 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -106,14 +106,15 @@ sql_store_trigger(struct Parse *parse) trigger_name = NULL; trigger->event_manipulation = trigger_def->event_manipulation; trigger->action_timing = trigger_def->action_timing; - trigger->pWhen = sqlExprDup(db, trigger_def->when, EXPRDUP_REDUCE); - trigger->pColumns = sqlIdListDup(db, trigger_def->cols); rlist_create(&trigger->link); - if ((trigger_def->when != NULL && trigger->pWhen == NULL) || - (trigger_def->cols != NULL && trigger->pColumns == NULL)) + trigger->expr = sql_trigger_expr_new(db, trigger_def->cols, + trigger_def->when, + trigger_def->step_list); + if (trigger->expr == NULL) goto trigger_cleanup; - trigger->step_list = parse->create_trigger_def.step_list; - parse->create_trigger_def.step_list = NULL; + trigger_def->cols = NULL; + trigger_def->when = NULL; + trigger_def->step_list = NULL; assert(parse->parsed_ast.trigger == NULL); parse->parsed_ast.trigger = trigger; @@ -247,15 +248,53 @@ sql_trigger_delete_step(struct sql *db, struct Token *table_name, return trigger_step; } +struct sql_trigger_expr * +sql_trigger_expr_new(struct sql *db, struct IdList *cols, struct Expr *when, + struct TriggerStep *step_list) +{ + struct sql_trigger_expr *trigger_expr = + (struct sql_trigger_expr *)malloc(sizeof(*trigger_expr)); + if (trigger_expr == NULL) { + diag_set(OutOfMemory, sizeof(*trigger_expr), + "malloc", "trigger_expr"); + return NULL; + } + if (when != NULL) { + trigger_expr->when = sqlExprDup(db, when, EXPRDUP_REDUCE); + if (trigger_expr->when == NULL) { + diag_set(OutOfMemory, + sql_expr_sizeof(when, EXPRDUP_REDUCE), + "sqlExprDup", "trigger_expr->when"); + free(trigger_expr); + return NULL; + } + } else { + trigger_expr->when = NULL; + } + /* Object refers to reduced copy of when expression. */ + sql_expr_delete(db, when, false); + trigger_expr->cols = cols; + trigger_expr->step_list = step_list; + return trigger_expr; +} + +void +sql_trigger_expr_delete(struct sql *db, struct sql_trigger_expr *trigger_expr) +{ + sqlDeleteTriggerStep(db, trigger_expr->step_list); + sql_expr_delete(db, trigger_expr->when, false); + sqlIdListDelete(db, trigger_expr->cols); + free(trigger_expr); +} + void sql_trigger_delete(struct sql *db, struct sql_trigger *trigger) { if (trigger == NULL) return; - sqlDeleteTriggerStep(db, trigger->step_list); + if (trigger->expr != NULL) + sql_trigger_expr_delete(db, trigger->expr); sqlDbFree(db, trigger->zName); - sql_expr_delete(db, trigger->pWhen, false); - sqlIdListDelete(db, trigger->pColumns); sqlDbFree(db, trigger); } @@ -427,7 +466,7 @@ sql_triggers_exist(struct space *space, struct sql_trigger *p; rlist_foreach_entry(p, trigger_list, link) { if (p->event_manipulation == event_manipulation && - checkColumnOverlap(p->pColumns, changes_list) != 0) + checkColumnOverlap(p->expr->cols, changes_list) != 0) mask |= (1 << p->action_timing); } if (mask_ptr != NULL) @@ -665,8 +704,8 @@ sql_row_trigger_program(struct Parse *parser, struct sql_trigger *trigger, * immediately halted by jumping to the OP_Halt * inserted at the end of the program. */ - if (trigger->pWhen != NULL) { - pWhen = sqlExprDup(db, trigger->pWhen, 0); + if (trigger->expr->when != NULL) { + pWhen = sqlExprDup(db, trigger->expr->when, 0); if (0 == sqlResolveExprNames(&sNC, pWhen) && db->mallocFailed == 0) { iEndTrigger = sqlVdbeMakeLabel(v); @@ -678,7 +717,7 @@ sql_row_trigger_program(struct Parse *parser, struct sql_trigger *trigger, } /* Code the trigger program into the sub-vdbe. */ - codeTriggerProgram(pSubParse, trigger->step_list, orconf); + codeTriggerProgram(pSubParse, trigger->expr->step_list, orconf); /* Insert an OP_Halt at the end of the sub-program. */ if (iEndTrigger) @@ -814,7 +853,7 @@ vdbe_code_row_trigger(struct Parse *parser, struct rlist *trigger_list, /* Determine whether we should code trigger. */ if (p->event_manipulation == event_manipulation && p->action_timing == action_timing && - checkColumnOverlap(p->pColumns, changes_list)) { + checkColumnOverlap(p->expr->cols, changes_list)) { vdbe_code_row_trigger_direct(parser, p, space, reg, orconf, ignore_jump); } @@ -838,7 +877,7 @@ sql_trigger_colmask(Parse *parser, struct rlist *trigger_list, rlist_foreach_entry(p, trigger_list, link) { if (p->event_manipulation == event_manipulation && ((action_timing_mask & (1 << p->action_timing)) != 0) && - checkColumnOverlap(p->pColumns, changes_list)) { + checkColumnOverlap(p->expr->cols, changes_list)) { TriggerPrg *prg = sql_row_trigger(parser, p, space, orconf); if (prg != NULL) -- 2.23.0