[Tarantool-patches] [PATCH v1 7/9] sql: wrap all ASTs in sql_trigger_expr structure
Kirill Shcherbatov
kshcherbatov at tarantool.org
Mon Oct 14 19:03:22 MSK 2019
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 <column-list> trigger,
+ * the <column-list> 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 <column-list> trigger,
- * the <column-list> 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
More information about the Tarantool-patches
mailing list