mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Updated/added copyright headers
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -21,6 +21,7 @@
|
||||
#include "sp_head.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "parse_file.h"
|
||||
#include <mysys_err.h>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
@ -294,6 +295,52 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
An error handler that catches all non-OOM errors which can occur during
|
||||
parsing of trigger body. Such errors are ignored and corresponding error
|
||||
message is used to construct a more verbose error message which contains
|
||||
name of problematic trigger. This error message is later emitted when
|
||||
one tries to perform DML or some of DDL on this table.
|
||||
Also, if possible, grabs name of the trigger being parsed so it can be
|
||||
used to correctly drop problematic trigger.
|
||||
*/
|
||||
class Deprecated_trigger_syntax_handler : public Internal_error_handler
|
||||
{
|
||||
private:
|
||||
|
||||
char m_message[MYSQL_ERRMSG_SIZE];
|
||||
LEX_STRING *m_trigger_name;
|
||||
|
||||
public:
|
||||
|
||||
Deprecated_trigger_syntax_handler() : m_trigger_name(NULL) {}
|
||||
|
||||
virtual bool handle_error(uint sql_errno, const char *message,
|
||||
MYSQL_ERROR::enum_warning_level level, THD *thd)
|
||||
{
|
||||
if (sql_errno != EE_OUTOFMEMORY &&
|
||||
sql_errno != ER_OUT_OF_RESOURCES)
|
||||
{
|
||||
if(thd->lex->spname)
|
||||
m_trigger_name= &thd->lex->spname->m_name;
|
||||
if (m_trigger_name)
|
||||
my_snprintf(m_message, sizeof(m_message),
|
||||
"Trigger '%s' has an error in its body: '%s'",
|
||||
m_trigger_name->str, message);
|
||||
else
|
||||
my_snprintf(m_message, sizeof(m_message),
|
||||
"Unknown trigger has an error in its body: '%s'",
|
||||
message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LEX_STRING *get_trigger_name() { return m_trigger_name; }
|
||||
char *get_error_message() { return m_message; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Create or drop trigger for table.
|
||||
|
||||
@ -577,6 +624,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
|
||||
LEX_STRING *trg_connection_cl_name;
|
||||
LEX_STRING *trg_db_cl_name;
|
||||
|
||||
if (check_for_broken_triggers())
|
||||
return true;
|
||||
|
||||
/* Trigger must be in the same schema as target table. */
|
||||
if (my_strcasecmp(table_alias_charset, table->s->db.str,
|
||||
@ -850,7 +899,7 @@ static bool rm_trigger_file(char *path, const char *db,
|
||||
@param path char buffer of size FN_REFLEN to be used
|
||||
for constructing path to .TRN file.
|
||||
@param db trigger's database name
|
||||
@param table_name trigger's name
|
||||
@param trigger_name trigger's name
|
||||
|
||||
@retval
|
||||
False success
|
||||
@ -1314,12 +1363,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
lex_start(thd);
|
||||
thd->spcont= NULL;
|
||||
|
||||
if (parse_sql(thd, & parser_state, creation_ctx))
|
||||
{
|
||||
/* Currently sphead is always deleted in case of a parse error */
|
||||
DBUG_ASSERT(lex.sphead == 0);
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
Deprecated_trigger_syntax_handler error_handler;
|
||||
thd->push_internal_handler(&error_handler);
|
||||
bool parse_error= parse_sql(thd, & parser_state, creation_ctx);
|
||||
thd->pop_internal_handler();
|
||||
|
||||
/*
|
||||
Not strictly necessary to invoke this method here, since we know
|
||||
that we've parsed CREATE TRIGGER and not an
|
||||
@ -1330,6 +1378,52 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
*/
|
||||
lex.set_trg_event_type_for_tables();
|
||||
|
||||
if (parse_error)
|
||||
{
|
||||
if (!triggers->m_has_unparseable_trigger)
|
||||
triggers->set_parse_error_message(error_handler.get_error_message());
|
||||
/* Currently sphead is always set to NULL in case of a parse error */
|
||||
DBUG_ASSERT(lex.sphead == 0);
|
||||
if (error_handler.get_trigger_name())
|
||||
{
|
||||
LEX_STRING *trigger_name;
|
||||
const LEX_STRING *orig_trigger_name= error_handler.get_trigger_name();
|
||||
|
||||
if (!(trigger_name= alloc_lex_string(&table->mem_root)) ||
|
||||
!(trigger_name->str= strmake_root(&table->mem_root,
|
||||
orig_trigger_name->str,
|
||||
orig_trigger_name->length)))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
trigger_name->length= orig_trigger_name->length;
|
||||
|
||||
if (triggers->names_list.push_back(trigger_name,
|
||||
&table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
The Table_triggers_list is not constructed as a list of
|
||||
trigger objects as one would expect, but rather of lists of
|
||||
properties of equal length. Thus, even if we don't get the
|
||||
trigger name, we still fill all in all the lists with
|
||||
placeholders as we might otherwise create a skew in the
|
||||
lists. Obviously, this has to be refactored.
|
||||
*/
|
||||
LEX_STRING *empty= alloc_lex_string(&table->mem_root);
|
||||
if (!empty)
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
empty->str= const_cast<char*>("");
|
||||
empty->length= 0;
|
||||
if (triggers->names_list.push_back(empty, &table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
lex_end(&lex);
|
||||
continue;
|
||||
}
|
||||
|
||||
lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode);
|
||||
|
||||
int event= lex.trg_chistics.event;
|
||||
@ -1370,8 +1464,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
|
||||
if (triggers->names_list.push_back(&lex.sphead->m_name,
|
||||
&table->mem_root))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
if (!(on_table_name= alloc_lex_string(&table->mem_root)))
|
||||
goto err_with_lex_cleanup;
|
||||
|
||||
@ -1396,9 +1490,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
char fname[NAME_LEN + 1];
|
||||
DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->db, db) ||
|
||||
(check_n_cut_mysql50_prefix(db, fname, sizeof(fname)) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->db, fname))) &&
|
||||
(!my_strcasecmp(table_alias_charset, lex.query_tables->table_name,
|
||||
table_name) ||
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->db, fname))));
|
||||
DBUG_ASSERT((!my_strcasecmp(table_alias_charset, lex.query_tables->table_name, table_name) ||
|
||||
(check_n_cut_mysql50_prefix(table_name, fname, sizeof(fname)) &&
|
||||
!my_strcasecmp(table_alias_charset, lex.query_tables->table_name, fname))));
|
||||
#endif
|
||||
@ -1682,6 +1775,13 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name)
|
||||
|
||||
while ((trigger= it_name++))
|
||||
{
|
||||
/*
|
||||
Trigger, which body we failed to parse during call
|
||||
Table_triggers_list::check_n_load(), might be missing name.
|
||||
Such triggers have zero-length name and are skipped here.
|
||||
*/
|
||||
if (trigger->length == 0)
|
||||
continue;
|
||||
if (rm_trigname_file(path, db, trigger->str))
|
||||
{
|
||||
/*
|
||||
@ -1905,6 +2005,11 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
}
|
||||
if (table.triggers)
|
||||
{
|
||||
if (table.triggers->check_for_broken_triggers())
|
||||
{
|
||||
result= 1;
|
||||
goto end;
|
||||
}
|
||||
LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
|
||||
LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
|
||||
/*
|
||||
@ -1993,6 +2098,9 @@ bool Table_triggers_list::process_triggers(THD *thd,
|
||||
sp_head *sp_trigger= bodies[event][time_type];
|
||||
SELECT_LEX *save_current_select;
|
||||
|
||||
if (check_for_broken_triggers())
|
||||
return true;
|
||||
|
||||
if (sp_trigger == NULL)
|
||||
return FALSE;
|
||||
|
||||
@ -2071,6 +2179,22 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signals to the Table_triggers_list that a parse error has occured when
|
||||
reading a trigger from file. This makes the Table_triggers_list enter an
|
||||
error state flagged by m_has_unparseable_trigger == true. The error message
|
||||
will be used whenever a statement invoking or manipulating triggers is
|
||||
issued against the Table_triggers_list's table.
|
||||
|
||||
@param error_message The error message thrown by the parser.
|
||||
*/
|
||||
void Table_triggers_list::set_parse_error_message(char *error_message)
|
||||
{
|
||||
m_has_unparseable_trigger= true;
|
||||
strcpy(m_parse_error_message, error_message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Trigger BUG#14090 compatibility hook.
|
||||
|
||||
|
Reference in New Issue
Block a user