[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