Skip to content

Commit

Permalink
sql: move Triggers to server
Browse files Browse the repository at this point in the history
Introduced sql_triggers field in space structure.
Changed parser logic to do not insert built triggers, just only
to do parsing. All triggers insertions and deletions are operated
via on_replace_dd_trigger now.

Resolves #3273.
  • Loading branch information
kshcherbatov committed Jun 1, 2018
1 parent 1f0cb06 commit 068cdf9
Show file tree
Hide file tree
Showing 18 changed files with 417 additions and 275 deletions.
37 changes: 36 additions & 1 deletion src/box/alter.cc
Expand Up @@ -551,6 +551,9 @@ space_swap_triggers(struct space *new_space, struct space *old_space)
rlist_swap(&new_space->before_replace, &old_space->before_replace);
rlist_swap(&new_space->on_replace, &old_space->on_replace);
rlist_swap(&new_space->on_stmt_begin, &old_space->on_stmt_begin);
/** Copy SQL Triggers pointer. */
new_space->sql_triggers = old_space->sql_triggers;
old_space->sql_triggers = NULL;
}

/**
Expand Down Expand Up @@ -732,7 +735,6 @@ alter_space_commit(struct trigger *trigger, void *event)
}

trigger_run_xc(&on_alter_space, alter->new_space);

alter->new_space = NULL; /* for alter_space_delete(). */
/*
* Delete the old version of the space, we are not
Expand Down Expand Up @@ -3100,6 +3102,39 @@ on_replace_dd_trigger(struct trigger * /* trigger */, void *event)
{
struct txn *txn = (struct txn *) event;
txn_check_singlestatement_xc(txn, "Space _trigger");

struct txn_stmt *stmt = txn_current_stmt(txn);
if (stmt->old_tuple != NULL) {
uint32_t trigger_name_len;
const char *trigger_name_src =
tuple_field_str_xc(stmt->old_tuple, 0,
&trigger_name_len);
if (sql_trigger_delete_by_name(sql_get(), trigger_name_src,
trigger_name_len) != 0)
diag_raise();
}
if (stmt->new_tuple != NULL) {
uint32_t trigger_name_len;
const char *trigger_name_src =
tuple_field_str_xc(stmt->new_tuple, 0,
&trigger_name_len);
const char *space_opts =
tuple_field_with_type_xc(stmt->new_tuple, 1, MP_MAP);
struct space_opts opts;
struct region *region = &fiber()->gc;
space_opts_decode(&opts, space_opts, region);
struct Trigger *trigger =
sql_trigger_compile(sql_get(), opts.sql);
if (trigger == NULL)
diag_raise();
auto trigger_guard = make_scoped_guard([=] {
sql_trigger_delete(sql_get(), trigger);
});
if (sql_trigger_insert(trigger, trigger_name_src,
trigger_name_len) != 0)
diag_raise();
trigger_guard.is_active = false;
}
}

struct trigger alter_space_on_replace_space = {
Expand Down
2 changes: 1 addition & 1 deletion src/box/errcode.h
Expand Up @@ -107,7 +107,7 @@ struct errcode_record {
/* 52 */_(ER_FUNCTION_EXISTS, "Function '%s' already exists") \
/* 53 */_(ER_BEFORE_REPLACE_RET, "Invalid return value of space:before_replace trigger: expected tuple or nil, got %s") \
/* 54 */_(ER_FUNCTION_MAX, "A limit on the total number of functions has been reached: %u") \
/* 55 */_(ER_UNUSED4, "") \
/* 55 */_(ER_TRIGGER_EXISTS, "Trigger '%s' already exists") \
/* 56 */_(ER_USER_MAX, "A limit on the total number of users has been reached: %u") \
/* 57 */_(ER_NO_SUCH_ENGINE, "Space engine '%s' does not exist") \
/* 58 */_(ER_RELOAD_CFG, "Can't set option '%s' dynamically") \
Expand Down
2 changes: 2 additions & 0 deletions src/box/space.h
Expand Up @@ -146,6 +146,8 @@ struct space {
struct rlist on_replace;
/** Triggers fired before space statement */
struct rlist on_stmt_begin;
/** SQL Trigger list. */
struct Trigger *sql_triggers;
/**
* The number of *enabled* indexes in the space.
*
Expand Down
48 changes: 9 additions & 39 deletions src/box/sql.c
Expand Up @@ -1223,9 +1223,6 @@ space_foreach_put_cb(struct space *space, void *udata)
/* Load database schema from Tarantool. */
void tarantoolSqlite3LoadSchema(InitData *init)
{
box_iterator_t *it;
box_tuple_t *tuple;

sql_schema_put(
init, TARANTOOL_SYS_SCHEMA_NAME,
BOX_SCHEMA_ID, 0,
Expand Down Expand Up @@ -1294,42 +1291,6 @@ void tarantoolSqlite3LoadSchema(InitData *init)
init->rc = SQL_TARANTOOL_ERROR;
return;
}

/* Read _trigger */
it = box_index_iterator(BOX_TRIGGER_ID, 0, ITER_GE,
nil_key, nil_key + sizeof(nil_key));

if (it == NULL) {
init->rc = SQL_TARANTOOL_ITERATOR_FAIL;
return;
}

while (box_iterator_next(it, &tuple) == 0 && tuple != NULL) {
const char *field, *ptr;
char *name, *sql;
unsigned len;
assert(tuple_field_count(tuple) == 2);

field = tuple_field(tuple, 0);
assert (field != NULL);
ptr = mp_decode_str(&field, &len);
name = strndup(ptr, len);

field = tuple_field(tuple, 1);
assert (field != NULL);
mp_decode_array(&field);
ptr = mp_decode_str(&field, &len);
assert (strncmp(ptr, "sql", 3) == 0);

ptr = mp_decode_str(&field, &len);
sql = strndup(ptr, len);

sql_schema_put(init, name, 0, 0, sql);

free(name);
free(sql);
}
box_iterator_free(it);
}

/*********************************************************************
Expand Down Expand Up @@ -1737,6 +1698,15 @@ space_column_default_expr(uint32_t space_id, uint32_t fieldno)
return space->def->fields[fieldno].default_value_expr;
}

struct Trigger *
space_trigger_list(uint32_t space_id)
{
struct space *space = space_cache_find(space_id);
assert(space != NULL);
assert(space->def != NULL);
return space->sql_triggers;
}

struct space_def *
sql_ephemeral_space_def_new(Parse *parser, const char *name)
{
Expand Down
44 changes: 44 additions & 0 deletions src/box/sql.h
Expand Up @@ -83,6 +83,17 @@ struct Trigger;
struct Expr *
sql_expr_compile(struct sqlite3 *db, const char *expr, int expr_len);

/**
* Perform parsing of provided SQL request and construct trigger AST.
* @param db SQL context handle.
* @param sql request to parse.
*
* @retval NULL on error
* @retval not NULL Trigger AST pointer on success.
*/
struct Trigger *
sql_trigger_compile(struct sqlite3 *db, const char *sql);

/**
* Free AST pointed by trigger.
* @param db SQL handle.
Expand All @@ -91,6 +102,39 @@ sql_expr_compile(struct sqlite3 *db, const char *expr, int expr_len);
void
sql_trigger_delete(struct sqlite3 *db, struct Trigger *trigger);

/**
* Remove a trigger from the hash tables of the sqlite* pointer.
* @param db SQL handle.
* @param name a name of trigger object to delete.
* @param name_len length of the name.
*
* @retval 0 on success.
* @retval -1 on error.
*/
int
sql_trigger_delete_by_name(struct sqlite3 *db, const char *name, int name_len);

/**
* Get server triggers list by space_id.
* @param space_id Space ID.
*
* @retval trigger AST list.
*/
struct Trigger *
space_trigger_list(uint32_t space_id);

/**
* Perform insert trigger in appropriate space.
* @param trigger object to append.
* @param name a name of trigger object to insert.
* @param name_len length of the name.
*
* @retval 0 on success.
* @retval -1 on error.
*/
int
sql_trigger_insert(struct Trigger *trigger, const char *name, int name_len);

/**
* Store duplicate of a parsed expression into @a parser.
* @param parser Parser context.
Expand Down
8 changes: 3 additions & 5 deletions src/box/sql/build.c
Expand Up @@ -2289,16 +2289,14 @@ sql_code_drop_table(struct Parse *parse_context, struct space *space,
/*
* Drop all triggers associated with the table being
* dropped. Code is generated to remove entries from
* _trigger. OP_DropTrigger will remove it from internal
* SQL structures.
* _trigger. on_replace_dd_trigger will remove it from
* internal SQL structures.
*
* Do not account triggers deletion - they will be
* accounted in DELETE from _space below.
*/
parse_context->nested++;
Table *table = sqlite3HashFind(&parse_context->db->pSchema->tblHash,
space->def->name);
struct Trigger *trigger = table->pTrigger;
struct Trigger *trigger = space->sql_triggers;
while (trigger != NULL) {
sqlite3DropTriggerPtr(parse_context, trigger);
trigger = trigger->pNext;
Expand Down
1 change: 0 additions & 1 deletion src/box/sql/fkey.c
Expand Up @@ -1440,7 +1440,6 @@ fkActionTrigger(Parse * pParse, /* Parse context */
}
pStep->pTrig = pTrigger;
pTrigger->pSchema = pTab->pSchema;
pTrigger->pTabSchema = pTab->pSchema;
pFKey->apTrigger[iAction] = pTrigger;
pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE);
}
Expand Down
6 changes: 3 additions & 3 deletions src/box/sql/insert.c
Expand Up @@ -1766,9 +1766,9 @@ xferOptimization(Parse * pParse, /* Parser context */
*/
return 0;
}
if (pDest->pTrigger) {
return 0; /* tab1 must not have triggers */
}
/* The pDest must not have triggers. */
if (space_trigger_list(pDest->def->id) != NULL)
return 0;
if (onError == ON_CONFLICT_ACTION_DEFAULT) {
if (pDest->iPKey >= 0)
onError = pDest->keyConf;
Expand Down
6 changes: 2 additions & 4 deletions src/box/sql/sqliteInt.h
Expand Up @@ -1935,7 +1935,6 @@ struct Table {
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
#endif
Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */
Table *pNextZombie; /* Next on the Parse.pZombieTab list */
/** Space definition with Tarantool metadata. */
Expand Down Expand Up @@ -3032,14 +3031,14 @@ struct Parse {
*/
struct Trigger {
char *zName; /* The name of the trigger */
char *table; /* The table or view to which the trigger applies */
/** The ID of space the triggers is refer to. */
uint32_t space_id;
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
the <column-list> is stored here */
Schema *pSchema; /* Schema containing the trigger */
Schema *pTabSchema; /* Schema containing the table */
TriggerStep *step_list; /* Link list of trigger program steps */
Trigger *pNext; /* Next trigger associated with the table */
};
Expand Down Expand Up @@ -4027,7 +4026,6 @@ TriggerStep *sqlite3TriggerInsertStep(sqlite3 *, Token *, IdList *,
TriggerStep *sqlite3TriggerUpdateStep(sqlite3 *, Token *, ExprList *, Expr *,
u8);
TriggerStep *sqlite3TriggerDeleteStep(sqlite3 *, Token *, Expr *);
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *, const char *);
u32 sqlite3TriggerColmask(Parse *, Trigger *, ExprList *, int, int, Table *,
int);
#define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
Expand Down
38 changes: 35 additions & 3 deletions src/box/sql/tokenize.c
Expand Up @@ -39,6 +39,7 @@
#include <stdlib.h>
#include <unicode/utf8.h>
#include <unicode/uchar.h>
#include "box/schema.h"

#include "say.h"
#include "sqliteInt.h"
Expand Down Expand Up @@ -122,6 +123,7 @@ static const char sql_ascii_class[] = {
* the #include below.
*/
#include "keywordhash.h"
#include "tarantoolInt.h"

#define maybe_utf8(c) ((sqlite3CtypeMap[c] & 0x40) != 0)

Expand Down Expand Up @@ -510,8 +512,13 @@ sqlite3RunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
}
if (pParse->rc != SQLITE_OK && pParse->rc != SQLITE_DONE
&& pParse->zErrMsg == 0) {
pParse->zErrMsg =
sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
const char *error;
if (is_tarantool_error(pParse->rc) && tarantoolErrorMessage()) {
error = tarantoolErrorMessage();
} else {
error = sqlite3ErrStr(pParse->rc);
}
pParse->zErrMsg = sqlite3MPrintf(db, "%s", error);
}
assert(pzErrMsg != 0);
if (pParse->zErrMsg) {
Expand All @@ -528,7 +535,12 @@ sqlite3RunParser(Parse * pParse, const char *zSql, char **pzErrMsg)

if (pParse->pWithToFree)
sqlite3WithDelete(db, pParse->pWithToFree);
sql_trigger_delete(db, pParse->pNewTrigger);
/*
* Trigger is exporting with pNewTrigger field when
* parse_only flag is set.
*/
if (!pParse->parse_only)
sql_trigger_delete(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->pVList);
while (pParse->pZombieTab) {
Table *p = pParse->pZombieTab;
Expand Down Expand Up @@ -569,3 +581,23 @@ sql_expr_compile(sqlite3 *db, const char *expr, int expr_len)
sql_parser_destroy(&parser);
return expression;
}

struct Trigger *
sql_trigger_compile(struct sqlite3 *db, const char *sql)
{
struct Parse parser;
sql_parser_create(&parser, db);
parser.parse_only = true;
char *sql_error;
struct Trigger *trigger = NULL;
if (sqlite3RunParser(&parser, sql, &sql_error) != SQLITE_OK) {
char *error = tt_static_buf();
snprintf(error, TT_STATIC_BUF_LEN, "%s", sql_error);
diag_set(ClientError, ER_SQL_EXECUTE, sql);
goto cleanup;
}
trigger = parser.pNewTrigger;
cleanup:
sql_parser_destroy(&parser);
return trigger;
}

0 comments on commit 068cdf9

Please sign in to comment.