Table of Contents
This chapter discusses stored database objects that are defined in terms of SQL code that is stored on the server for later execution.
Stored objects include these object types:
Stored procedure: An object created with
CREATE PROCEDURE
and invoked
using the CALL
statement. A
procedure does not have a return value but can modify its
parameters for later inspection by the caller. It can also
generate result sets to be returned to the client program.
Stored function: An object created with
CREATE FUNCTION
and used much
like a built-in function. You invoke it in an expression and it
returns a value during expression evaluation.
Trigger: An object created with CREATE
TRIGGER
that is associated with a table. A trigger is
activated when a particular event occurs for the table, such as
an insert or update.
Event: An object created with CREATE
EVENT
and invoked by the server according to schedule.
View: An object created with CREATE
VIEW
that when referenced produces a result set. A
view acts as a virtual table.
Terminology used in this document reflects the stored object hierarchy:
Stored routines include stored procedures and functions.
Stored programs include stored routines, triggers, and events.
Stored objects include stored programs and views.
This chapter describes how to use stored objects. The following sections provide additional information about SQL syntax for statements related to these objects, and about object processing:
For each object type, there are CREATE
,
ALTER
, and DROP
statements
that control which objects exist and how they are defined. See
Section 13.1, “Data Definition Statements”.
The CALL
statement is used to
invoke stored procedures. See Section 13.2.1, “CALL Statement”.
Stored program definitions include a body that may use compound statements, loops, conditionals, and declared variables. See Section 13.6, “Compound Statement Syntax”.
Metadata changes to objects referred to by stored programs are detected and cause automatic reparsing of the affected statements when the program is next executed. For more information, see Section 8.10.3, “Caching of Prepared Statements and Stored Programs”.
Each stored program contains a body that consists of an SQL
statement. This statement may be a compound statement made up of
several statements separated by semicolon (;
)
characters. For example, the following stored procedure has a body
made up of a BEGIN ...
END
block that contains a
SET
statement and a REPEAT
loop that
itself contains another
SET
statement:
CREATE PROCEDURE dorepeat(p1 INT) BEGIN SET @x = 0; REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; END;
If you use the mysql client program to define a stored program containing semicolon characters, a problem arises. By default, mysql itself recognizes the semicolon as a statement delimiter, so you must redefine the delimiter temporarily to cause mysql to pass the entire stored program definition to the server.
To redefine the mysql delimiter, use the
delimiter
command. The following example shows
how to do this for the dorepeat()
procedure
just shown. The delimiter is changed to //
to
enable the entire definition to be passed to the server as a
single statement, and then restored to ;
before
invoking the procedure. This enables the ;
delimiter used in the procedure body to be passed through to the
server rather than being interpreted by mysql
itself.
mysql>delimiter //
mysql>CREATE PROCEDURE dorepeat(p1 INT)
->BEGIN
->SET @x = 0;
->REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
->END
->//
Query OK, 0 rows affected (0.00 sec) mysql>delimiter ;
mysql>CALL dorepeat(1000);
Query OK, 0 rows affected (0.00 sec) mysql>SELECT @x;
+------+ | @x | +------+ | 1001 | +------+ 1 row in set (0.00 sec)
You can redefine the delimiter to a string other than
//
, and the delimiter can consist of a single
character or multiple characters. You should avoid the use of the
backslash (\
) character because that is the
escape character for MySQL.
The following is an example of a function that takes a parameter,
performs an operation using an SQL function, and returns the
result. In this case, it is unnecessary to use
delimiter
because the function definition
contains no internal ;
statement delimiters:
mysql>CREATE FUNCTION hello (s CHAR(20))
mysql>RETURNS CHAR(50) DETERMINISTIC
->RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec) mysql>SELECT hello('world');
+----------------+ | hello('world') | +----------------+ | Hello, world! | +----------------+ 1 row in set (0.00 sec)
MySQL supports stored routines (procedures and functions). A stored routine is a set of SQL statements that can be stored in the server. Once this has been done, clients don't need to keep reissuing the individual statements but can refer to the stored routine instead.
Stored routines can be particularly useful in certain situations:
When multiple client applications are written in different languages or work on different platforms, but need to perform the same database operations.
When security is paramount. Banks, for example, use stored procedures and functions for all common operations. This provides a consistent and secure environment, and routines can ensure that each operation is properly logged. In such a setup, applications and users would have no access to the database tables directly, but can only execute specific stored routines.
Stored routines can provide improved performance because less information needs to be sent between the server and the client. The tradeoff is that this does increase the load on the database server because more of the work is done on the server side and less is done on the client (application) side. Consider this if many client machines (such as Web servers) are serviced by only one or a few database servers.
Stored routines also enable you to have libraries of functions in the database server. This is a feature shared by modern application languages that enable such design internally (for example, by using classes). Using these client application language features is beneficial for the programmer even outside the scope of database use.
MySQL follows the SQL:2003 syntax for stored routines, which is also used by IBM's DB2. All syntax described here is supported and any limitations and extensions are documented where appropriate.
You may find the Stored Procedures User Forum of use when working with stored procedures and functions.
For answers to some commonly asked questions regarding stored routines in MySQL, see Section A.4, “MySQL 8.0 FAQ: Stored Procedures and Functions”.
There are some restrictions on the use of stored routines. See Section 25.8, “Restrictions on Stored Programs”.
Binary logging for stored routines takes place as described in Section 25.7, “Stored Program Binary Logging”.
A stored routine is either a procedure or a function. Stored
routines are created with the CREATE
PROCEDURE
and CREATE
FUNCTION
statements (see
Section 13.1.17, “CREATE PROCEDURE and CREATE FUNCTION Statements”). A procedure is invoked using
a CALL
statement (see
Section 13.2.1, “CALL Statement”), and can only pass back values using
output variables. A function can be called from inside a statement
just like any other function (that is, by invoking the function's
name), and can return a scalar value. The body of a stored routine
can use compound statements (see
Section 13.6, “Compound Statement Syntax”).
Stored routines can be dropped with the DROP
PROCEDURE
and DROP
FUNCTION
statements (see
Section 13.1.29, “DROP PROCEDURE and DROP FUNCTION Statements”), and altered with the
ALTER PROCEDURE
and
ALTER FUNCTION
statements (see
Section 13.1.7, “ALTER PROCEDURE Statement”).
A stored procedure or function is associated with a particular database. This has several implications:
When the routine is invoked, an implicit USE
is performed (and
undone when the routine terminates).
db_name
USE
statements within stored
routines are not permitted.
You can qualify routine names with the database name. This can
be used to refer to a routine that is not in the current
database. For example, to invoke a stored procedure
p
or function f
that is
associated with the test
database, you can
say CALL test.p()
or
test.f()
.
When a database is dropped, all stored routines associated with it are dropped as well.
Stored functions cannot be recursive.
Recursion in stored procedures is permitted but disabled by
default. To enable recursion, set the
max_sp_recursion_depth
server
system variable to a value greater than zero. Stored procedure
recursion increases the demand on thread stack space. If you
increase the value of
max_sp_recursion_depth
, it may be
necessary to increase thread stack size by increasing the value of
thread_stack
at server startup.
See Section 5.1.8, “Server System Variables”, for more
information.
MySQL supports a very useful extension that enables the use of
regular SELECT
statements (that is,
without using cursors or local variables) inside a stored
procedure. The result set of such a query is simply sent directly
to the client. Multiple SELECT
statements generate multiple result sets, so the client must use a
MySQL client library that supports multiple result sets. This
means the client must use a client library from a version of MySQL
at least as recent as 4.1. The client should also specify the
CLIENT_MULTI_RESULTS
option when it connects.
For C programs, this can be done with the
mysql_real_connect()
C API
function. See mysql_real_connect(), and
C API Multiple Statement Execution Support.
In MySQL 8.0.22 and later, a user variable referenced by a statement in a stored procedure has its type determined the first time the procedure is invoked, and retains this type each time the procedure is invoked thereafter.
The MySQL grant system takes stored routines into account as follows:
The CREATE ROUTINE
privilege is
needed to create stored routines.
The ALTER ROUTINE
privilege is
needed to alter or drop stored routines. This privilege is
granted automatically to the creator of a routine if
necessary, and dropped from the creator when the routine is
dropped.
The EXECUTE
privilege is
required to execute stored routines. However, this privilege
is granted automatically to the creator of a routine if
necessary (and dropped from the creator when the routine is
dropped). Also, the default SQL SECURITY
characteristic for a routine is DEFINER
,
which enables users who have access to the database with which
the routine is associated to execute the routine.
If the
automatic_sp_privileges
system variable is 0, the
EXECUTE
and
ALTER ROUTINE
privileges are
not automatically granted to and dropped from the routine
creator.
The creator of a routine is the account used to execute the
CREATE
statement for it. This might not be
the same as the account named as the
DEFINER
in the routine definition.
The account named as a routine DEFINER
can
see all routine properties, including its definition. The
account thus has full access to the routine output as produced
by:
The contents of the
INFORMATION_SCHEMA.ROUTINES
table.
The SHOW CREATE FUNCTION
and SHOW CREATE PROCEDURE
statements.
The SHOW FUNCTION CODE
and
SHOW PROCEDURE CODE
statements.
The SHOW FUNCTION STATUS
and SHOW PROCEDURE STATUS
statements.
For an account other than the account named as the routine
DEFINER
, access to routine properties
depends on the privileges granted to the account:
With the SHOW_ROUTINE
privilege or the global
SELECT
privilege, the
account can see all routine properties, including its
definition.
With the CREATE ROUTINE
,
ALTER ROUTINE
or
EXECUTE
privilege granted
at a scope that includes the routine, the account can see
all routine properties except its definition.
To obtain metadata about stored routines:
Query the ROUTINES
table of the
INFORMATION_SCHEMA
database. See
Section 26.30, “The INFORMATION_SCHEMA ROUTINES Table”.
Use the SHOW CREATE PROCEDURE
and SHOW CREATE FUNCTION
statements to see routine definitions. See
Section 13.7.7.9, “SHOW CREATE PROCEDURE Statement”.
Use the SHOW PROCEDURE STATUS
and SHOW FUNCTION STATUS
statements to see routine characteristics. See
Section 13.7.7.28, “SHOW PROCEDURE STATUS Statement”.
Use the SHOW PROCEDURE CODE
and
SHOW FUNCTION CODE
statements
to see a representation of the internal implementation of the
routine. See Section 13.7.7.27, “SHOW PROCEDURE CODE Statement”.
Within the body of a stored routine (procedure or function) or a
trigger, the value of
LAST_INSERT_ID()
changes the same
way as for statements executed outside the body of these kinds of
objects (see Section 12.16, “Information Functions”). The effect
of a stored routine or trigger upon the value of
LAST_INSERT_ID()
that is seen by
following statements depends on the kind of routine:
If a stored procedure executes statements that change the
value of LAST_INSERT_ID()
, the
changed value is seen by statements that follow the procedure
call.
For stored functions and triggers that change the value, the value is restored when the function or trigger ends, so following statements do not see a changed value.
A trigger is a named database object that is associated with a table, and that activates when a particular event occurs for the table. Some uses for triggers are to perform checks of values to be inserted into a table or to perform calculations on values involved in an update.
A trigger is defined to activate when a statement inserts, updates,
or deletes rows in the associated table. These row operations are
trigger events. For example, rows can be inserted by
INSERT
or LOAD
DATA
statements, and an insert trigger activates for each
inserted row. A trigger can be set to activate either before or
after the trigger event. For example, you can have a trigger
activate before each row that is inserted into a table or after each
row that is updated.
MySQL triggers activate only for changes made to tables by SQL
statements. This includes changes to base tables that underlie
updatable views. Triggers do not activate for changes to tables
made by APIs that do not transmit SQL statements to the MySQL
Server. This means that triggers are not activated by updates made
using the NDB
API.
Triggers are not activated by changes in
INFORMATION_SCHEMA
or
performance_schema
tables. Those tables are
actually views and triggers are not permitted on views.
The following sections describe the syntax for creating and dropping triggers, show some examples of how to use them, and indicate how to obtain trigger metadata.
You may find the Triggers User Forum of use when working with triggers.
For answers to commonly asked questions regarding triggers in MySQL, see Section A.5, “MySQL 8.0 FAQ: Triggers”.
There are some restrictions on the use of triggers; see Section 25.8, “Restrictions on Stored Programs”.
Binary logging for triggers takes place as described in Section 25.7, “Stored Program Binary Logging”.
To create a trigger or drop a trigger, use the
CREATE TRIGGER
or
DROP TRIGGER
statement, described
in Section 13.1.22, “CREATE TRIGGER Statement”, and
Section 13.1.34, “DROP TRIGGER Statement”.
Here is a simple example that associates a trigger with a table,
to activate for INSERT
operations.
The trigger acts as an accumulator, summing the values inserted
into one of the columns of the table.
mysql>CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec) mysql>CREATE TRIGGER ins_sum BEFORE INSERT ON account
FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.01 sec)
The CREATE TRIGGER
statement
creates a trigger named ins_sum
that is
associated with the account
table. It also
includes clauses that specify the trigger action time, the
triggering event, and what to do when the trigger activates:
The keyword BEFORE
indicates the trigger
action time. In this case, the trigger activates before each
row inserted into the table. The other permitted keyword here
is AFTER
.
The keyword INSERT
indicates the trigger
event; that is, the type of operation that activates the
trigger. In the example, INSERT
operations cause trigger activation. You can also create
triggers for DELETE
and
UPDATE
operations.
The statement following FOR EACH ROW
defines the trigger body; that is, the statement to execute
each time the trigger activates, which occurs once for each
row affected by the triggering event. In the example, the
trigger body is a simple
SET
that accumulates into a user variable the values inserted into
the amount
column. The statement refers to
the column as NEW.amount
which means
“the value of the amount
column to be
inserted into the new row.”
To use the trigger, set the accumulator variable to zero, execute
an INSERT
statement, and then see
what value the variable has afterward:
mysql>SET @sum = 0;
mysql>INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql>SELECT @sum AS 'Total amount inserted';
+-----------------------+ | Total amount inserted | +-----------------------+ | 1852.48 | +-----------------------+
In this case, the value of @sum
after the
INSERT
statement has executed is
14.98 + 1937.50 - 100
, or
1852.48
.
To destroy the trigger, use a DROP
TRIGGER
statement. You must specify the schema name if
the trigger is not in the default schema:
mysql> DROP TRIGGER test.ins_sum;
If you drop a table, any triggers for the table are also dropped.
Trigger names exist in the schema namespace, meaning that all triggers must have unique names within a schema. Triggers in different schemas can have the same name.
It is possible to define multiple triggers for a given table that
have the same trigger event and action time. For example, you can
have two BEFORE UPDATE
triggers for a table. By
default, triggers that have the same trigger event and action time
activate in the order they were created. To affect trigger order,
specify a clause after FOR EACH ROW
that
indicates FOLLOWS
or
PRECEDES
and the name of an existing trigger
that also has the same trigger event and action time. With
FOLLOWS
, the new trigger activates after the
existing trigger. With PRECEDES
, the new
trigger activates before the existing trigger.
For example, the following trigger definition defines another
BEFORE INSERT
trigger for the
account
table:
mysql>CREATE TRIGGER ins_transaction BEFORE INSERT ON account
FOR EACH ROW PRECEDES ins_sum
SET
@deposits = @deposits + IF(NEW.amount>0,NEW.amount,0),
@withdrawals = @withdrawals + IF(NEW.amount<0,-NEW.amount,0);
Query OK, 0 rows affected (0.01 sec)
This trigger, ins_transaction
, is similar to
ins_sum
but accumulates deposits and
withdrawals separately. It has a PRECEDES
clause that causes it to activate before
ins_sum
; without that clause, it would activate
after ins_sum
because it is created after
ins_sum
.
Within the trigger body, the OLD
and
NEW
keywords enable you to access columns in
the rows affected by a trigger. OLD
and
NEW
are MySQL extensions to triggers; they are
not case-sensitive.
In an INSERT
trigger, only
NEW.
can be
used; there is no old row. In a col_name
DELETE
trigger,
only OLD.
can be used; there is no new row. In an col_name
UPDATE
trigger, you can use
OLD.
to
refer to the columns of a row before it is updated and
col_name
NEW.
to
refer to the columns of the row after it is updated.
col_name
A column named with OLD
is read only. You can
refer to it (if you have the SELECT
privilege), but not modify it. You can refer to a column named
with NEW
if you have the
SELECT
privilege for it. In a
BEFORE
trigger, you can also change its value
with SET NEW.
if you have the
col_name
=
value
UPDATE
privilege for it. This means
you can use a trigger to modify the values to be inserted into a
new row or used to update a row. (Such a SET
statement has no effect in an AFTER
trigger
because the row change has already occurred.)
In a BEFORE
trigger, the NEW
value for an AUTO_INCREMENT
column is 0, not
the sequence number that is generated automatically when the new
row actually is inserted.
By using the BEGIN ...
END
construct, you can define a trigger that executes
multiple statements. Within the BEGIN
block,
you also can use other syntax that is permitted within stored
routines such as conditionals and loops. However, just as for
stored routines, if you use the mysql program
to define a trigger that executes multiple statements, it is
necessary to redefine the mysql statement
delimiter so that you can use the ;
statement
delimiter within the trigger definition. The following example
illustrates these points. It defines an UPDATE
trigger that checks the new value to be used for updating each
row, and modifies the value to be within the range from 0 to 100.
This must be a BEFORE
trigger because the value
must be checked before it is used to update the row:
mysql>delimiter //
mysql>CREATE TRIGGER upd_check BEFORE UPDATE ON account
FOR EACH ROW
BEGIN
IF NEW.amount < 0 THEN
SET NEW.amount = 0;
ELSEIF NEW.amount > 100 THEN
SET NEW.amount = 100;
END IF;
END;//
mysql>delimiter ;
It can be easier to define a stored procedure separately and then
invoke it from the trigger using a simple
CALL
statement. This is also
advantageous if you want to execute the same code from within
several triggers.
There are limitations on what can appear in statements that a trigger executes when activated:
The trigger cannot use the CALL
statement to invoke stored procedures that return data to the
client or that use dynamic SQL. (Stored procedures are
permitted to return data to the trigger through
OUT
or INOUT
parameters.)
The trigger cannot use statements that explicitly or
implicitly begin or end a transaction, such as
START
TRANSACTION
, COMMIT
,
or ROLLBACK
.
(ROLLBACK to
SAVEPOINT
is permitted because it does not end a
transaction.).
See also Section 25.8, “Restrictions on Stored Programs”.
MySQL handles errors during trigger execution as follows:
If a BEFORE
trigger fails, the operation on
the corresponding row is not performed.
A BEFORE
trigger is activated by the
attempt to insert or modify the row,
regardless of whether the attempt subsequently succeeds.
An AFTER
trigger is executed only if any
BEFORE
triggers and the row operation
execute successfully.
An error during either a BEFORE
or
AFTER
trigger results in failure of the
entire statement that caused trigger invocation.
For transactional tables, failure of a statement should cause rollback of all changes performed by the statement. Failure of a trigger causes the statement to fail, so trigger failure also causes rollback. For nontransactional tables, such rollback cannot be done, so although the statement fails, any changes performed prior to the point of the error remain in effect.
Triggers can contain direct references to tables by name, such as
the trigger named testref
shown in this
example:
CREATE TABLE test1(a1 INT); CREATE TABLE test2(a2 INT); CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY); CREATE TABLE test4( a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b4 INT DEFAULT 0 ); delimiter | CREATE TRIGGER testref BEFORE INSERT ON test1 FOR EACH ROW BEGIN INSERT INTO test2 SET a2 = NEW.a1; DELETE FROM test3 WHERE a3 = NEW.a1; UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1; END; | delimiter ; INSERT INTO test3 (a3) VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL), (NULL); INSERT INTO test4 (a4) VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);
Suppose that you insert the following values into table
test1
as shown here:
mysql>INSERT INTO test1 VALUES
(1), (3), (1), (7), (1), (8), (4), (4);
Query OK, 8 rows affected (0.01 sec) Records: 8 Duplicates: 0 Warnings: 0
As a result, the four tables contain the following data:
mysql>SELECT * FROM test1;
+------+ | a1 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec) mysql>SELECT * FROM test2;
+------+ | a2 | +------+ | 1 | | 3 | | 1 | | 7 | | 1 | | 8 | | 4 | | 4 | +------+ 8 rows in set (0.00 sec) mysql>SELECT * FROM test3;
+----+ | a3 | +----+ | 2 | | 5 | | 6 | | 9 | | 10 | +----+ 5 rows in set (0.00 sec) mysql>SELECT * FROM test4;
+----+------+ | a4 | b4 | +----+------+ | 1 | 3 | | 2 | 0 | | 3 | 1 | | 4 | 2 | | 5 | 0 | | 6 | 0 | | 7 | 1 | | 8 | 1 | | 9 | 0 | | 10 | 0 | +----+------+ 10 rows in set (0.00 sec)
To obtain metadata about triggers:
Query the TRIGGERS
table of the
INFORMATION_SCHEMA
database. See
Section 26.45, “The INFORMATION_SCHEMA TRIGGERS Table”.
Use the SHOW CREATE TRIGGER
statement. See Section 13.7.7.11, “SHOW CREATE TRIGGER Statement”.
Use the SHOW TRIGGERS
statement. See Section 13.7.7.40, “SHOW TRIGGERS Statement”.
The MySQL Event Scheduler manages the scheduling and execution of events, that is, tasks that run according to a schedule. The following discussion covers the Event Scheduler and is divided into the following sections:
Section 25.4.1, “Event Scheduler Overview”, provides an introduction to and conceptual overview of MySQL Events.
Section 25.4.3, “Event Syntax”, discusses the SQL statements for creating, altering, and dropping MySQL Events.
Section 25.4.4, “Event Metadata”, shows how to obtain information about events and how this information is stored by the MySQL Server.
Section 25.4.6, “The Event Scheduler and MySQL Privileges”, discusses the privileges required to work with events and the ramifications that events have with regard to privileges when executing.
Stored routines require the events
data
dictionary table in the mysql
system database.
This table is created during the MySQL 8.0 installation
procedure. If you are upgrading to MySQL 8.0 from an
earlier version, be sure to perform the upgrade procedure to make
sure that your system database is up to date. See
Section 2.11, “Upgrading MySQL”.
You may find the MySQL Event Scheduler User Forum of use when working with scheduled events.
There are some restrictions on the use of events; see Section 25.8, “Restrictions on Stored Programs”.
Binary logging for events takes place as described in Section 25.7, “Stored Program Binary Logging”.
MySQL Events are tasks that run according to a schedule.
Therefore, we sometimes refer to them as
scheduled events. When you create an event,
you are creating a named database object containing one or more
SQL statements to be executed at one or more regular intervals,
beginning and ending at a specific date and time. Conceptually,
this is similar to the idea of the Unix crontab
(also known as a “cron job”) or the Windows Task
Scheduler.
Scheduled tasks of this type are also sometimes known as “temporal triggers”, implying that these are objects that are triggered by the passage of time. While this is essentially correct, we prefer to use the term events to avoid confusion with triggers of the type discussed in Section 25.3, “Using Triggers”. Events should more specifically not be confused with “temporary triggers”. Whereas a trigger is a database object whose statements are executed in response to a specific type of event that occurs on a given table, a (scheduled) event is an object whose statements are executed in response to the passage of a specified time interval.
While there is no provision in the SQL Standard for event scheduling, there are precedents in other database systems, and you may notice some similarities between these implementations and that found in the MySQL Server.
MySQL Events have the following major features and properties:
In MySQL, an event is uniquely identified by its name and the schema to which it is assigned.
An event performs a specific action according to a schedule.
This action consists of an SQL statement, which can be a
compound statement in a
BEGIN ...
END
block if desired (see
Section 13.6, “Compound Statement Syntax”). An event's timing
can be either one-time
or recurrent. A one-time
event executes one time only. A recurrent event repeats its
action at a regular interval, and the schedule for a recurring
event can be assigned a specific start day and time, end day
and time, both, or neither. (By default, a recurring event's
schedule begins as soon as it is created, and continues
indefinitely, until it is disabled or dropped.)
If a repeating event does not terminate within its scheduling
interval, the result may be multiple instances of the event
executing simultaneously. If this is undesirable, you should
institute a mechanism to prevent simultaneous instances. For
example, you could use the
GET_LOCK()
function, or row or
table locking.
Users can create, modify, and drop scheduled events using SQL statements intended for these purposes. Syntactically invalid event creation and modification statements fail with an appropriate error message. A user may include statements in an event's action which require privileges that the user does not actually have. The event creation or modification statement succeeds but the event's action fails. See Section 25.4.6, “The Event Scheduler and MySQL Privileges” for details.
Many of the properties of an event can be set or modified using SQL statements. These properties include the event's name, timing, persistence (that is, whether it is preserved following the expiration of its schedule), status (enabled or disabled), action to be performed, and the schema to which it is assigned. See Section 13.1.3, “ALTER EVENT Statement”.
The default definer of an event is the user who created the
event, unless the event has been altered, in which case the
definer is the user who issued the last
ALTER EVENT
statement affecting
that event. An event can be modified by any user having the
EVENT
privilege on the database
for which the event is defined. See
Section 25.4.6, “The Event Scheduler and MySQL Privileges”.
An event's action statement may include most SQL statements permitted within stored routines. For restrictions, see Section 25.8, “Restrictions on Stored Programs”.
Events are executed by a special event
scheduler thread; when we refer to the Event Scheduler,
we actually refer to this thread. When running, the event
scheduler thread and its current state can be seen by users having
the PROCESS
privilege in the output
of SHOW PROCESSLIST
, as shown in
the discussion that follows.
The global event_scheduler
system
variable determines whether the Event Scheduler is enabled and
running on the server. It has one of these 3 values, which affect
event scheduling as described here. The default is
ON
.
ON
: The Event Scheduler is started; the
event scheduler thread runs and executes all scheduled events.
When the Event Scheduler is ON
, the event
scheduler thread is listed in the output of
SHOW PROCESSLIST
as a daemon
process, and its state is represented as shown here:
mysql> SHOW PROCESSLIST\G
*************************** 1. row ***************************
Id: 1
User: root
Host: localhost
db: NULL
Command: Query
Time: 0
State: NULL
Info: show processlist
*************************** 2. row ***************************
Id: 2
User: event_scheduler
Host: localhost
db: NULL
Command: Daemon
Time: 3
State: Waiting for next activation
Info: NULL
2 rows in set (0.00 sec)
Event scheduling can be stopped by setting the value of
event_scheduler
to
OFF
.
OFF
: The Event Scheduler is stopped. The
event scheduler thread does not run, is not shown in the
output of SHOW PROCESSLIST
, and
no scheduled events are executed.
When the Event Scheduler is stopped
(event_scheduler
is
OFF
), it can be started by setting the
value of event_scheduler
to
ON
. (See next item.)
DISABLED
: This value renders the Event
Scheduler nonoperational. When the Event Scheduler is
DISABLED
, the event scheduler thread does
not run (and so does not appear in the output of
SHOW PROCESSLIST
). In addition,
the Event Scheduler state cannot be changed at runtime.
If the Event Scheduler status has not been set to
DISABLED
,
event_scheduler
can be toggled
between ON
and OFF
(using
SET
). It
is also possible to use 0
for
OFF
, and 1
for
ON
when setting this variable. Thus, any of the
following 4 statements can be used in the mysql
client to turn on the Event Scheduler:
SET GLOBAL event_scheduler = ON; SET @@GLOBAL.event_scheduler = ON; SET GLOBAL event_scheduler = 1; SET @@GLOBAL.event_scheduler = 1;
Similarly, any of these 4 statements can be used to turn off the Event Scheduler:
SET GLOBAL event_scheduler = OFF; SET @@GLOBAL.event_scheduler = OFF; SET GLOBAL event_scheduler = 0; SET @@GLOBAL.event_scheduler = 0;
Although ON
and OFF
have
numeric equivalents, the value displayed for
event_scheduler
by
SELECT
or SHOW
VARIABLES
is always one of OFF
,
ON
, or DISABLED
.
DISABLED
has no numeric
equivalent. For this reason, ON
and
OFF
are usually preferred over
1
and 0
when setting this
variable.
Note that attempting to set
event_scheduler
without
specifying it as a global variable causes an error:
mysql< SET @@event_scheduler = OFF;
ERROR 1229 (HY000): Variable 'event_scheduler' is a GLOBAL
variable and should be set with SET GLOBAL
It is possible to set the Event Scheduler to
DISABLED
only at server startup. If
event_scheduler
is
ON
or OFF
, you cannot set
it to DISABLED
at runtime. Also, if the Event
Scheduler is set to DISABLED
at startup, you
cannot change the value of
event_scheduler
at runtime.
To disable the event scheduler, use one of the following two methods:
As a command-line option when starting the server:
--event-scheduler=DISABLED
In the server configuration file (my.cnf
,
or my.ini
on Windows systems), include
the line where it can be read by the server (for example, in a
[mysqld]
section):
event_scheduler=DISABLED
To enable the Event Scheduler, restart the server without the
--event-scheduler=DISABLED
command-line option, or after removing or commenting out the line
containing event-scheduler=DISABLED
in the server configuration file, as appropriate. Alternatively,
you can use ON
(or 1
) or
OFF
(or 0
) in place of the
DISABLED
value when starting the server.
You can issue event-manipulation statements when
event_scheduler
is set to
DISABLED
. No warnings or errors are generated
in such cases (provided that the statements are themselves
valid). However, scheduled events cannot execute until this
variable is set to ON
(or
1
). Once this has been done, the event
scheduler thread executes all events whose scheduling conditions
are satisfied.
Starting the MySQL server with the
--skip-grant-tables
option causes
event_scheduler
to be set to
DISABLED
, overriding any other value set either
on the command line or in the my.cnf
or
my.ini
file (Bug #26807).
For SQL statements used to create, alter, and drop events, see Section 25.4.3, “Event Syntax”.
MySQL provides an EVENTS
table in the
INFORMATION_SCHEMA
database. This table can be
queried to obtain information about scheduled events which have
been defined on the server. See Section 25.4.4, “Event Metadata”,
and Section 26.14, “The INFORMATION_SCHEMA EVENTS Table”, for more
information.
For information regarding event scheduling and the MySQL privilege system, see Section 25.4.6, “The Event Scheduler and MySQL Privileges”.
MySQL provides several SQL statements for working with scheduled events:
New events are defined using the CREATE
EVENT
statement. See Section 13.1.13, “CREATE EVENT Statement”.
The definition of an existing event can be changed by means of
the ALTER EVENT
statement. See
Section 13.1.3, “ALTER EVENT Statement”.
When a scheduled event is no longer wanted or needed, it can
be deleted from the server by its definer using the
DROP EVENT
statement. See
Section 13.1.25, “DROP EVENT Statement”. Whether an event persists past
the end of its schedule also depends on its ON
COMPLETION
clause, if it has one. See
Section 13.1.13, “CREATE EVENT Statement”.
An event can be dropped by any user having the
EVENT
privilege for the
database on which the event is defined. See
Section 25.4.6, “The Event Scheduler and MySQL Privileges”.
To obtain metadata about events:
Query the EVENTS
table of the
INFORMATION_SCHEMA
database. See
Section 26.14, “The INFORMATION_SCHEMA EVENTS Table”.
Use the SHOW CREATE EVENT
statement. See Section 13.7.7.7, “SHOW CREATE EVENT Statement”.
Use the SHOW EVENTS
statement.
See Section 13.7.7.18, “SHOW EVENTS Statement”.
Event Scheduler Time Representation
Each session in MySQL has a session time zone (STZ). This is the
session time_zone
value that is
initialized from the server's global
time_zone
value when the session
begins but may be changed during the session.
The session time zone that is current when a
CREATE EVENT
or
ALTER EVENT
statement executes is
used to interpret times specified in the event definition. This
becomes the event time zone (ETZ); that is, the time zone that is
used for event scheduling and is in effect within the event as it
executes.
For representation of event information in the data dictionary,
the execute_at
, starts
, and
ends
times are converted to UTC and stored
along with the event time zone. This enables event execution to
proceed as defined regardless of any subsequent changes to the
server time zone or daylight saving time effects. The
last_executed
time is also stored in UTC.
Event times can be obtained by selecting from the
INFORMATION_SCHEMA.EVENTS
table or
from SHOW EVENTS
, but they are
reported as ETZ or STZ values. The following table summarizes
representation of event times.
Value | INFORMATION_SCHEMA.EVENTS |
SHOW EVENTS |
---|---|---|
Execute at | ETZ | ETZ |
Starts | ETZ | ETZ |
Ends | ETZ | ETZ |
Last executed | ETZ | n/a |
Created | STZ | n/a |
Last altered | STZ | n/a |
The Event Scheduler writes information about event execution that terminates with an error or warning to the MySQL Server's error log. See Section 25.4.6, “The Event Scheduler and MySQL Privileges” for an example.
To obtain information about the state of the Event Scheduler for debugging and troubleshooting purposes, run mysqladmin debug (see Section 4.5.2, “mysqladmin — A MySQL Server Administration Program”); after running this command, the server's error log contains output relating to the Event Scheduler, similar to what is shown here:
Events status: LLA = Last Locked At LUA = Last Unlocked At WOC = Waiting On Condition DL = Data Locked Event scheduler status: State : INITIALIZED Thread id : 0 LLA : n/a:0 LUA : n/a:0 WOC : NO Workers : 0 Executed : 0 Data locked: NO Event queue status: Element count : 0 Data locked : NO Attempting lock : NO LLA : init_queue:95 LUA : init_queue:103 WOC : NO Next activation : never
In statements that occur as part of events executed by the Event
Scheduler, diagnostics messages (not only errors, but also
warnings) are written to the error log, and, on Windows, to the
application event log. For frequently executed events, it is
possible for this to result in many logged messages. For example,
for SELECT ... INTO
statements, if the
query returns no rows, a warning with error code 1329 occurs
(var_list
No data
), and the variable values remain
unchanged. If the query returns multiple rows, error 1172 occurs
(Result consisted of more than one row
). For
either condition, you can avoid having the warnings be logged by
declaring a condition handler; see
Section 13.6.7.2, “DECLARE ... HANDLER Statement”. For statements that may
retrieve multiple rows, another strategy is to use LIMIT
1
to limit the result set to a single row.
To enable or disable the execution of scheduled events, it is
necessary to set the value of the global
event_scheduler
system variable.
This requires privileges sufficient to set global system
variables. See Section 5.1.9.1, “System Variable Privileges”.
The EVENT
privilege governs the
creation, modification, and deletion of events. This privilege can
be bestowed using GRANT
. For
example, this GRANT
statement
confers the EVENT
privilege for the
schema named myschema
on the user
jon@ghidora
:
GRANT EVENT ON myschema.* TO jon@ghidora;
(We assume that this user account already exists, and that we wish for it to remain unchanged otherwise.)
To grant this same user the EVENT
privilege on all schemas, use the following statement:
GRANT EVENT ON *.* TO jon@ghidora;
The EVENT
privilege has global or
schema-level scope. Therefore, trying to grant it on a single
table results in an error as shown:
mysql> GRANT EVENT ON myschema.mytable TO jon@ghidora;
ERROR 1144 (42000): Illegal GRANT/REVOKE command; please
consult the manual to see which privileges can be used
It is important to understand that an event is executed with the
privileges of its definer, and that it cannot perform any actions
for which its definer does not have the requisite privileges. For
example, suppose that jon@ghidora
has the
EVENT
privilege for
myschema
. Suppose also that this user has the
SELECT
privilege for
myschema
, but no other privileges for this
schema. It is possible for jon@ghidora
to
create a new event such as this one:
CREATE EVENT e_store_ts ON SCHEDULE EVERY 10 SECOND DO INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP());
The user waits for a minute or so, and then performs a
SELECT * FROM mytable;
query, expecting to see
several new rows in the table. Instead, the table is empty. Since
the user does not have the INSERT
privilege for the table in question, the event has no effect.
If you inspect the MySQL error log
(
),
you can see that the event is executing, but the action it is
attempting to perform fails:
hostname
.err
2013-09-24T12:41:31.261992Z 25 [ERROR] Event Scheduler: [jon@ghidora][cookbook.e_store_ts] INSERT command denied to user 'jon'@'ghidora' for table 'mytable' 2013-09-24T12:41:31.262022Z 25 [Note] Event Scheduler: [jon@ghidora].[myschema.e_store_ts] event execution failed. 2013-09-24T12:41:41.271796Z 26 [ERROR] Event Scheduler: [jon@ghidora][cookbook.e_store_ts] INSERT command denied to user 'jon'@'ghidora' for table 'mytable' 2013-09-24T12:41:41.272761Z 26 [Note] Event Scheduler: [jon@ghidora].[myschema.e_store_ts] event execution failed.
Since this user very likely does not have access to the error log, it is possible to verify whether the event's action statement is valid by executing it directly:
mysql> INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP());
ERROR 1142 (42000): INSERT command denied to user
'jon'@'ghidora' for table 'mytable'
Inspection of the
INFORMATION_SCHEMA.EVENTS
table shows
that e_store_ts
exists and is enabled, but its
LAST_EXECUTED
column is
NULL
:
mysql>SELECT * FROM INFORMATION_SCHEMA.EVENTS
>WHERE EVENT_NAME='e_store_ts'
>AND EVENT_SCHEMA='myschema'\G
*************************** 1. row *************************** EVENT_CATALOG: NULL EVENT_SCHEMA: myschema EVENT_NAME: e_store_ts DEFINER: jon@ghidora EVENT_BODY: SQL EVENT_DEFINITION: INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP()) EVENT_TYPE: RECURRING EXECUTE_AT: NULL INTERVAL_VALUE: 5 INTERVAL_FIELD: SECOND SQL_MODE: NULL STARTS: 0000-00-00 00:00:00 ENDS: 0000-00-00 00:00:00 STATUS: ENABLED ON_COMPLETION: NOT PRESERVE CREATED: 2006-02-09 22:36:06 LAST_ALTERED: 2006-02-09 22:36:06 LAST_EXECUTED: NULL EVENT_COMMENT: 1 row in set (0.00 sec)
To rescind the EVENT
privilege, use
the REVOKE
statement. In this
example, the EVENT
privilege on the
schema myschema
is removed from the
jon@ghidora
user account:
REVOKE EVENT ON myschema.* FROM jon@ghidora;
Revoking the EVENT
privilege from
a user does not delete or disable any events that may have been
created by that user.
An event is not migrated or dropped as a result of renaming or dropping the user who created it.
Suppose that the user jon@ghidora
has been
granted the EVENT
and
INSERT
privileges on the
myschema
schema. This user then creates the
following event:
CREATE EVENT e_insert ON SCHEDULE EVERY 7 SECOND DO INSERT INTO myschema.mytable;
After this event has been created, root
revokes
the EVENT
privilege for
jon@ghidora
. However,
e_insert
continues to execute, inserting a new
row into mytable
each seven seconds. The same
would be true if root
had issued either of
these statements:
DROP USER jon@ghidora;
RENAME USER jon@ghidora TO
someotherguy@ghidora;
You can verify that this is true by examining the
INFORMATION_SCHEMA.EVENTS
table (see
Section 26.14, “The INFORMATION_SCHEMA EVENTS Table”) before and
after issuing a DROP USER
or
RENAME USER
statement.
Event definitions are stored in the data dictionary. To drop an
event created by another user account, you must be the MySQL
root
user or another user with the necessary
privileges.
Users' EVENT
privileges are stored
in the Event_priv
columns of the
mysql.user
and mysql.db
tables. In both cases, this column holds one of the values
'Y
' or 'N
'.
'N
' is the default.
mysql.user.Event_priv
is set to
'Y
' for a given user only if that user has the
global EVENT
privilege (that is, if
the privilege was bestowed using GRANT EVENT ON
*.*
). For a schema-level
EVENT
privilege,
GRANT
creates a row in
mysql.db
and sets that row's
Db
column to the name of the schema, the
User
column to the name of the user, and the
Event_priv
column to 'Y
'.
There should never be any need to manipulate these tables
directly, since the GRANT
EVENT
and REVOKE EVENT
statements
perform the required operations on them.
Five status variables provide counts of event-related operations (but not of statements executed by events; see Section 25.8, “Restrictions on Stored Programs”). These are:
Com_create_event
: The number of
CREATE EVENT
statements
executed since the last server restart.
Com_alter_event
: The number of
ALTER EVENT
statements executed
since the last server restart.
Com_drop_event
: The number of
DROP EVENT
statements executed
since the last server restart.
Com_show_create_event
: The number of
SHOW CREATE EVENT
statements
executed since the last server restart.
Com_show_events
: The number of
SHOW EVENTS
statements executed
since the last server restart.
You can view current values for all of these at one time by
running the statement SHOW STATUS LIKE
'%event%';
.
MySQL supports views, including updatable views. Views are stored queries that when invoked produce a result set. A view acts as a virtual table.
The following discussion describes the syntax for creating and dropping views, and shows some examples of how to use them.
You may find the Views User Forum of use when working with views.
For answers to some commonly asked questions regarding views in MySQL, see Section A.6, “MySQL 8.0 FAQ: Views”.
There are some restrictions on the use of views; see Section 25.9, “Restrictions on Views”.
The CREATE VIEW
statement creates a
new view (see Section 13.1.23, “CREATE VIEW Statement”). To alter the
definition of a view or drop a view, use
ALTER VIEW
(see
Section 13.1.11, “ALTER VIEW Statement”), or DROP
VIEW
(see Section 13.1.35, “DROP VIEW Statement”).
A view can be created from many kinds of
SELECT
statements. It can refer to
base tables or other views. It can use joins,
UNION
, and subqueries. The
SELECT
need not even refer to any
tables. The following example defines a view that selects two
columns from another table, as well as an expression calculated
from those columns:
mysql>CREATE TABLE t (qty INT, price INT);
mysql>INSERT INTO t VALUES(3, 50), (5, 60);
mysql>CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql>SELECT * FROM v;
+------+-------+-------+ | qty | price | value | +------+-------+-------+ | 3 | 50 | 150 | | 5 | 60 | 300 | +------+-------+-------+ mysql>SELECT * FROM v WHERE qty = 5;
+------+-------+-------+ | qty | price | value | +------+-------+-------+ | 5 | 60 | 300 | +------+-------+-------+
The optional ALGORITHM
clause for
CREATE VIEW
or
ALTER VIEW
is a MySQL extension to
standard SQL. It affects how MySQL processes the view.
ALGORITHM
takes three values:
MERGE
, TEMPTABLE
, or
UNDEFINED
.
For MERGE
, the text of a statement that
refers to the view and the view definition are merged such
that parts of the view definition replace corresponding parts
of the statement.
For TEMPTABLE
, the results from the view
are retrieved into a temporary table, which then is used to
execute the statement.
For UNDEFINED
, MySQL chooses which
algorithm to use. It prefers MERGE
over
TEMPTABLE
if possible, because
MERGE
is usually more efficient and because
a view cannot be updatable if a temporary table is used.
If no ALGORITHM
clause is present, the
default algorithm is determined by the value of the
derived_merge
flag of the
optimizer_switch
system
variable. For additional discussion, see
Section 8.2.2.4, “Optimizing Derived Tables, View References, and Common Table Expressions
with Merging or Materialization”.
A reason to specify TEMPTABLE
explicitly is
that locks can be released on underlying tables after the
temporary table has been created and before it is used to finish
processing the statement. This might result in quicker lock
release than the MERGE
algorithm so that other
clients that use the view are not blocked as long.
A view algorithm can be UNDEFINED
for three
reasons:
No ALGORITHM
clause is present in the
CREATE VIEW
statement.
The CREATE VIEW
statement has
an explicit ALGORITHM = UNDEFINED
clause.
ALGORITHM = MERGE
is specified for a view
that can be processed only with a temporary table. In this
case, MySQL generates a warning and sets the algorithm to
UNDEFINED
.
As mentioned earlier, MERGE
is handled by
merging corresponding parts of a view definition into the
statement that refers to the view. The following examples briefly
illustrate how the MERGE
algorithm works. The
examples assume that there is a view v_merge
that has this definition:
CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS SELECT c1, c2 FROM t WHERE c3 > 100;
Example 1: Suppose that we issue this statement:
SELECT * FROM v_merge;
MySQL handles the statement as follows:
v_merge
becomes t
*
becomes vc1, vc2
,
which corresponds to c1, c2
The view WHERE
clause is added
The resulting statement to be executed becomes:
SELECT c1, c2 FROM t WHERE c3 > 100;
Example 2: Suppose that we issue this statement:
SELECT * FROM v_merge WHERE vc1 < 100;
This statement is handled similarly to the previous one, except
that vc1 < 100
becomes c1 <
100
and the view WHERE
clause is
added to the statement WHERE
clause using an
AND
connective (and parentheses are
added to make sure the parts of the clause are executed with
correct precedence). The resulting statement to be executed
becomes:
SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);
Effectively, the statement to be executed has a
WHERE
clause of this form:
WHERE (select WHERE) AND (view WHERE)
If the MERGE
algorithm cannot be used, a
temporary table must be used instead. Constructs that prevent
merging are the same as those that prevent merging in derived
tables and common table expressions. Examples are SELECT
DISTINCT
or LIMIT
in the subquery.
For details, see Section 8.2.2.4, “Optimizing Derived Tables, View References, and Common Table Expressions
with Merging or Materialization”.
Some views are updatable and references to them can be used to
specify tables to be updated in data change statements. That is,
you can use them in statements such as
UPDATE
,
DELETE
, or
INSERT
to update the contents of
the underlying table. Derived tables and common table expressions
can also be specified in multiple-table
UPDATE
and
DELETE
statements, but can only be
used for reading data to specify rows to be updated or deleted.
Generally, the view references must be updatable, meaning that
they may be merged and not materialized. Composite views have more
complex rules.
For a view to be updatable, there must be a one-to-one relationship between the rows in the view and the rows in the underlying table. There are also certain other constructs that make a view nonupdatable. To be more specific, a view is not updatable if it contains any of the following:
Aggregate functions or window functions
(SUM()
,
MIN()
,
MAX()
,
COUNT()
, and so forth)
DISTINCT
GROUP BY
HAVING
Subquery in the select list
Nondependent subqueries in the select list fail for
INSERT
, but are okay for
UPDATE
,
DELETE
. For dependent
subqueries in the select list, no data change statements are
permitted.
Certain joins (see additional join discussion later in this section)
Reference to nonupdatable view in the FROM
clause
Subquery in the WHERE
clause that refers to
a table in the FROM
clause
Refers only to literal values (in this case, there is no underlying table to update)
ALGORITHM = TEMPTABLE
(use of a temporary
table always makes a view nonupdatable)
Multiple references to any column of a base table (fails for
INSERT
, okay for
UPDATE
,
DELETE
)
A generated column in a view is considered updatable because it is
possible to assign to it. However, if such a column is updated
explicitly, the only permitted value is
DEFAULT
. For information about generated
columns, see Section 13.1.20.8, “CREATE TABLE and Generated Columns”.
It is sometimes possible for a multiple-table view to be
updatable, assuming that it can be processed with the
MERGE
algorithm. For this to work, the view
must use an inner join (not an outer join or a
UNION
). Also, only a single table
in the view definition can be updated, so the
SET
clause must name only columns from one of
the tables in the view. Views that use
UNION ALL
are not
permitted even though they might be theoretically updatable.
With respect to insertability (being updatable with
INSERT
statements), an updatable
view is insertable if it also satisfies these additional
requirements for the view columns:
There must be no duplicate view column names.
The view must contain all columns in the base table that do not have a default value.
The view columns must be simple column references. They must not be expressions, such as these:
3.14159
col1 + 3
UPPER(col2)
col3 / col4
(subquery
)
MySQL sets a flag, called the view updatability flag, at
CREATE VIEW
time. The flag is set
to YES
(true) if
UPDATE
and
DELETE
(and similar operations) are
legal for the view. Otherwise, the flag is set to
NO
(false). The IS_UPDATABLE
column in the
INFORMATION_SCHEMA.VIEWS
table
displays the status of this flag. It means that the server always
knows whether a view is updatable.
If a view is not updatable, statements such
UPDATE
,
DELETE
, and
INSERT
are illegal and are
rejected. (Even if a view is updatable, it might not be possible
to insert into it, as described elsewhere in this section.)
The updatability of views may be affected by the value of the
updatable_views_with_limit
system
variable. See Section 5.1.8, “Server System Variables”.
For the following discussion, suppose that these tables and views exist:
CREATE TABLE t1 (x INTEGER); CREATE TABLE t2 (c INTEGER); CREATE VIEW vmat AS SELECT SUM(x) AS s FROM t1; CREATE VIEW vup AS SELECT * FROM t2; CREATE VIEW vjoin AS SELECT * FROM vmat JOIN vup ON vmat.s=vup.c;
INSERT
,
UPDATE
, and
DELETE
statements are permitted as
follows:
INSERT
: The insert table of an
INSERT
statement may be a view
reference that is merged. If the view is a join view, all
components of the view must be updatable (not materialized).
For a multiple-table updatable view,
INSERT
can work if it inserts
into a single table.
This statement is invalid because one component of the join view is nonupdatable:
INSERT INTO vjoin (c) VALUES (1);
This statement is valid; the view contains no materialized components:
INSERT INTO vup (c) VALUES (1);
UPDATE
: The table or tables to
be updated in an UPDATE
statement may be view references that are merged. If a view is
a join view, at least one component of the view must be
updatable (this differs from
INSERT
).
In a multiple-table UPDATE
statement, the updated table references of the statement must
be base tables or updatable view references. Nonupdated table
references may be materialized views or derived tables.
This statement is valid; column c
is from
the updatable part of the join view:
UPDATE vjoin SET c=c+1;
This statement is invalid; column x
is from
the nonupdatable part:
UPDATE vjoin SET x=x+1;
This statement is valid; the updated table reference of the
multiple-table UPDATE
is an
updatable view (vup
):
UPDATE vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ... SET c=c+1;
This statement is invalid; it tries to update a materialized derived table:
UPDATE vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ... SET s=s+1;
DELETE
: The table or tables to
be deleted from in a DELETE
statement must be merged views. Join views are not allowed
(this differs from INSERT
and
UPDATE
).
This statement is invalid because the view is a join view:
DELETE vjoin WHERE ...;
This statement is valid because the view is a merged (updatable) view:
DELETE vup WHERE ...;
This statement is valid because it deletes from a merged (updatable) view:
DELETE vup FROM vup JOIN (SELECT SUM(x) AS s FROM t1) AS dt ON ...;
Additional discussion and examples follow.
Earlier discussion in this section pointed out that a view is not insertable if not all columns are simple column references (for example, if it contains columns that are expressions or composite expressions). Although such a view is not insertable, it can be updatable if you update only columns that are not expressions. Consider this view:
CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
This view is not insertable because col2
is an
expression. But it is updatable if the update does not try to
update col2
. This update is permissible:
UPDATE v SET col1 = 0;
This update is not permissible because it attempts to update an expression column:
UPDATE v SET col2 = 0;
If a table contains an AUTO_INCREMENT
column,
inserting into an insertable view on the table that does not
include the AUTO_INCREMENT
column does not
change the value of
LAST_INSERT_ID()
, because the side
effects of inserting default values into columns not part of the
view should not be visible.
The WITH CHECK OPTION
clause can be given for
an updatable view to prevent inserts to rows for which the
WHERE
clause in the
select_statement
is not true. It also
prevents updates to rows for which the WHERE
clause is true but the update would cause it to be not true (in
other words, it prevents visible rows from being updated to
nonvisible rows).
In a WITH CHECK OPTION
clause for an updatable
view, the LOCAL
and CASCADED
keywords determine the scope of check testing when the view is
defined in terms of another view. When neither keyword is given,
the default is CASCADED
.
WITH CHECK OPTION
testing is
standard-compliant:
With LOCAL
, the view
WHERE
clause is checked, then checking
recurses to underlying views and applies the same rules.
With CASCADED
, the view
WHERE
clause is checked, then checking
recurses to underlying views, adds WITH CASCADED
CHECK OPTION
to them (for purposes of the check;
their definitions remain unchanged), and applies the same
rules.
With no check option, the view WHERE
clause
is not checked, then checking recurses to underlying views,
and applies the same rules.
Consider the definitions for the following table and set of views:
CREATE TABLE t1 (a INT); CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2 WITH CHECK OPTION; CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0 WITH LOCAL CHECK OPTION; CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0 WITH CASCADED CHECK OPTION;
Here the v2
and v3
views are
defined in terms of another view, v1
.
Inserts for v2
are checked against its
LOCAL
check option, then the check recurses to
v1
and the rules are applied again. The rules
for v1
cause a check failure. The check for
v3
also fails:
mysql>INSERT INTO v2 VALUES (2);
ERROR 1369 (HY000): CHECK OPTION failed 'test.v2' mysql>INSERT INTO v3 VALUES (2);
ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'
To obtain metadata about views:
Query the VIEWS
table of the
INFORMATION_SCHEMA
database. See
Section 26.48, “The INFORMATION_SCHEMA VIEWS Table”.
Use the SHOW CREATE VIEW
statement. See Section 13.7.7.13, “SHOW CREATE VIEW Statement”.
Stored programs (procedures, functions, triggers, and events) and
views are defined prior to use and, when referenced, execute
within a security context that determines their privileges. The
privileges applicable to execution of a stored object are
controlled by its DEFINER
attribute and
SQL SECURITY
characteristic.
A stored object definition can include a
DEFINER
attribute that names a MySQL account.
If a definition omits the DEFINER
attribute,
the default object definer is the user who creates it.
The following rules determine which accounts you can specify as
the DEFINER
attribute for a stored object:
If you have the SET_USER_ID
privilege (or the deprecated
SUPER
privilege), you can
specify any account as the DEFINER
attribute. If the account does not exist, a warning is
generated. Additionally, to set a stored object
DEFINER
attribute to an account that has
the SYSTEM_USER
privilege,
you must have the SYSTEM_USER
privilege.
Otherwise, the only permitted account is your own, specified
either literally or as
CURRENT_USER
or
CURRENT_USER()
. You cannot
set the definer to any other account.
Creating a stored object with a nonexistent
DEFINER
account creates an orphan object,
which may have negative consequences; see
Orphan Stored Objects.
For stored routines (procedures and functions) and views, the
object definition can include an SQL SECURITY
characteristic with a value of DEFINER
or
INVOKER
to specify whether the object
executes in definer or invoker context. If the definition omits
the SQL SECURITY
characteristic, the default
is definer context.
Triggers and events have no SQL SECURITY
characteristic and always execute in definer context. The server
invokes these objects automatically as necessary, so there is no
invoking user.
Definer and invoker security contexts differ as follows:
A stored object that executes in definer security context
executes with the privileges of the account named by its
DEFINER
attribute. These privileges may
be entirely different from those of the invoking user. The
invoker must have appropriate privileges to reference the
object (for example, EXECUTE
to call a stored procedure or
SELECT
to select from a
view), but during object execution, the invoker's privileges
are ignored and only the DEFINER
account
privileges matter. If the DEFINER
account
has few privileges, the object is correspondingly limited in
the operations it can perform. If the
DEFINER
account is highly privileged
(such as an administrative account), the object can perform
powerful operations no matter who invokes
it.
A stored routine or view that executes in invoker security
context can perform only operations for which the invoker
has privileges. The DEFINER
attribute has
no effect on object execution.
Consider the following stored procedure, which is declared with
SQL SECURITY DEFINER
to execute in definer
security context:
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1() SQL SECURITY DEFINER BEGIN UPDATE t1 SET counter = counter + 1; END;
Any user who has the EXECUTE
privilege for p1
can invoke it with a
CALL
statement. However, when
p1
executes, it does so in definer security
context and thus executes with the privileges of
'admin'@'localhost'
, the account named as its
DEFINER
attribute. This account must have the
EXECUTE
privilege for
p1
as well as the
UPDATE
privilege for the table
t1
referenced within the object body.
Otherwise, the procedure fails.
Now consider this stored procedure, which is identical to
p1
except that its SQL
SECURITY
characteristic is INVOKER
:
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p2() SQL SECURITY INVOKER BEGIN UPDATE t1 SET counter = counter + 1; END;
Unlike p1
, p2
executes in
invoker security context and thus with the privileges of the
invoking user regardless of the DEFINER
attribute value. p2
fails if the invoker
lacks the EXECUTE
privilege for
p2
or the
UPDATE
privilege for the table
t1
.
An orphan stored object is one for which its
DEFINER
attribute names a nonexistent
account:
An orphan stored object can be created by specifying a
nonexistent DEFINER
account at
object-creation time.
An existing stored object can become orphaned through
execution of a DROP USER
statement that drops the object DEFINER
account, or a RENAME USER
statement that renames the object DEFINER
account.
An orphan stored object may be problematic in these ways:
Because the DEFINER
account does not
exist, the object may not work as expected if it executes in
definer security context:
For a stored routine, an error occurs at routine
execution time if the SQL SECURITY
value is DEFINER
but the definer
account does not exist.
For a trigger, it is not a good idea for trigger activation to occur until the account actually does exist. Otherwise, the behavior with respect to privilege checking is undefined.
For an event, an error occurs at event execution time if the account does not exist.
For a view, an error occurs when the view is referenced
if the SQL SECURITY
value is
DEFINER
but the definer account does
not exist.
The object may present a security risk if the nonexistent
DEFINER
account is subsequently
re-created for a purpose unrelated to the object. In this
case, the account “adopts” the object and, with
the appropriate privileges, is able to execute it even if
that is not intended.
As of MySQL 8.0.22, the server imposes additional account-management security checks designed to prevent operations that (perhaps inadvertently) cause stored objects to become orphaned or that cause adoption of stored objects that are currently orphaned:
DROP USER
fails with an error
if any account to be dropped is named as the
DEFINER
attribute for any stored object.
(That is, the statement fails if dropping an account would
cause a stored object to become orphaned.)
RENAME USER
fails with an
error if any account to be renamed is named as the
DEFINER
attribute for any stored object.
(That is, the statement fails if renaming an account would
cause a stored object to become orphaned.)
CREATE USER
fails with an
error if any account to be created is named as the
DEFINER
attribute for any stored object.
(That is, the statement fails if creating an account would
cause the account to adopt a currently orphaned stored
object.)
In certain situations, it may be necessary to deliberately
execute those account-management statements even when they would
otherwise fail. To make this possible, if a user has the
SET_USER_ID
privilege, that
privilege overrides the orphan object security checks and the
statements succeed with a warning rather than failing with an
error.
To obtain information about the accounts used as stored object
definers in a MySQL installation, query the
INFORMATION_SCHEMA
.
This query identifies which
INFORMATION_SCHEMA
tables describe objects
that have a DEFINER
attribute:
mysql>SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'DEFINER';
+--------------------+------------+ | TABLE_SCHEMA | TABLE_NAME | +--------------------+------------+ | information_schema | EVENTS | | information_schema | ROUTINES | | information_schema | TRIGGERS | | information_schema | VIEWS | +--------------------+------------+
The result tells you which tables to query to discover which
stored object DEFINER
values exist and which
objects have a particular DEFINER
value:
To identify which DEFINER
values exist in
each table, use these queries:
SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.EVENTS; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.ROUTINES; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.VIEWS;
The query results are significant for any account displayed as follows:
If the account exists, dropping or renaming it causes stored objects to become orphaned. If you plan to drop or rename the account, consider first dropping its associated stored objects or redefining them to have a different definer.
If the account does not exist, creating it causes it to adopt currently orphaned stored objects. If you plan to create the account, consider whether the orphaned objects should be associated with it. If not, redefine them to have a different definer.
To redefine an object with a different definer, you can use
ALTER EVENT
or
ALTER VIEW
to directly modify
the DEFINER
account of events and views.
For stored procedures and functions and for triggers, you
must drop the object and re-create it to assign a different
DEFINER
account
To identify which objects have a given
DEFINER
account, use these queries,
substituting the account of interest for
:
user_name
@host_name
SELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS WHERE DEFINER = 'user_name
@host_name
'; SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE FROM INFORMATION_SCHEMA.ROUTINES WHERE DEFINER = 'user_name
@host_name
'; SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE DEFINER = 'user_name
@host_name
'; SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE DEFINER = 'user_name
@host_name
';
For the ROUTINES
table, the
query includes the ROUTINE_TYPE
column so
that output rows distinguish whether the
DEFINER
is for a stored procedure or
stored function.
If the account you are searching for does not exist, any objects displayed by those queries are orphan objects.
To minimize the risk potential for stored object creation and use, follow these guidelines:
Do not create orphan stored objects; that is, objects for
which the DEFINER
attribute names a
nonexistent account. Do not cause stored objects to become
orphaned by dropping or renaming an account named by the
DEFINER
attribute of any existing object.
For a stored routine or view, use SQL SECURITY
INVOKER
in the object definition when possible so
that it can be used only by users with permissions
appropriate for the operations performed by the object.
If you create definer-context stored objects while using an
account that has the
SET_USER_ID
privilege (or the
deprecated SUPER
privilege),
specify an explicit DEFINER
attribute
that names an account possessing only the privileges
required for the operations performed by the object. Specify
a highly privileged DEFINER
account only
when absolutely necessary.
Administrators can prevent users from creating stored
objects that specify highly privileged
DEFINER
accounts by not granting them the
SET_USER_ID
privilege (or the
deprecated SUPER
privilege).
Definer-context objects should be written keeping in mind that they may be able to access data for which the invoking user has no privileges. In some cases, you can prevent references to these objects by not granting unauthorized users particular privileges:
However, no such control exists for triggers and events because they always execute in definer context. The server invokes these objects automatically as necessary, and users do not reference them directly:
A trigger is activated by access to the table with which it is associated, even ordinary table accesses by users with no special privileges.
An event is executed by the server on a scheduled basis.
In both cases, if the DEFINER
account is
highly privileged, the object may be able to perform
sensitive or dangerous operations. This remains true if the
privileges needed to create the object are revoked from the
account of the user who created it. Administrators should be
especially careful about granting users object-creation
privileges.
The binary log contains information about SQL statements that modify database contents. This information is stored in the form of “events” that describe the modifications. (Binary log events differ from scheduled event stored objects.) The binary log has two important purposes:
For replication, the binary log is used on source replication servers as a record of the statements to be sent to replica servers. The source sends the events contained in its binary log to its replicas, which execute those events to make the same data changes that were made on the source. See Section 17.2, “Replication Implementation”.
Certain data recovery operations require use of the binary log. After a backup file has been restored, the events in the binary log that were recorded after the backup was made are re-executed. These events bring databases up to date from the point of the backup. See Section 7.3.2, “Using Backups for Recovery”.
However, if logging occurs at the statement level, there are certain binary logging issues with respect to stored programs (stored procedures and functions, triggers, and events):
In some cases, a statement might affect different sets of rows on source and replica.
Replicated statements executed on a replica are processed by the replica SQL thread, which has full privileges. It is possible for a procedure to follow different execution paths on source and replica servers, so a user can write a routine containing a dangerous statement that executes only on the replica where it is processed by a thread that has full privileges.
If a stored program that modifies data is nondeterministic, it is not repeatable. This can result in different data on source and replica, or cause restored data to differ from the original data.
This section describes how MySQL handles binary logging for stored programs. It states the current conditions that the implementation places on the use of stored programs, and what you can do to avoid logging problems. It also provides additional information about the reasons for these conditions.
In general, the issues described here result when binary logging
occurs at the SQL statement level (statement-based binary
logging). If you use row-based binary logging, the log contains
changes made to individual rows as a result of executing SQL
statements. When routines or triggers execute, row changes are
logged, not the statements that make the changes. For stored
procedures, this means that the
CALL
statement is not logged. For
stored functions, row changes made within the function are logged,
not the function invocation. For triggers, row changes made by the
trigger are logged. On the replica side, only the row changes are
seen, not the stored program invocation.
Mixed format binary logging
(binlog_format=MIXED
) uses
statement-based binary logging, except for cases where only
row-based binary logging is guaranteed to lead to proper results.
With mixed format, when a stored function, stored procedure,
trigger, event, or prepared statement contains anything that is
not safe for statement-based binary logging, the entire statement
is marked as unsafe and logged in row format. The statements used
to create and drop procedures, functions, triggers, and events are
always safe, and are logged in statement format. For more
information about row-based, mixed, and statement-based logging,
and how safe and unsafe statements are determined, see
Section 17.2.1, “Replication Formats”.
Unless noted otherwise, the remarks here assume that binary logging is enabled on the server (see Section 5.4.4, “The Binary Log”.) If the binary log is not enabled, replication is not possible, nor is the binary log available for data recovery.
The conditions on the use of stored functions in MySQL can be summarized as follows. These conditions do not apply to stored procedures or Event Scheduler events and they do not apply unless binary logging is enabled.
To create or alter a stored function, you must have the
SET_USER_ID
privilege (or the
deprecated SUPER
privilege), in
addition to the CREATE ROUTINE
or ALTER ROUTINE
privilege that
is normally required. (Depending on the
DEFINER
value in the function definition,
SET_USER_ID
or
SUPER
might be required
regardless of whether binary logging is enabled. See
Section 13.1.17, “CREATE PROCEDURE and CREATE FUNCTION Statements”.)
When you create a stored function, you must declare either that it is deterministic or that it does not modify data. Otherwise, it may be unsafe for data recovery or replication.
By default, for a CREATE
FUNCTION
statement to be accepted, at least one of
DETERMINISTIC
, NO SQL
,
or READS SQL DATA
must be specified
explicitly. Otherwise an error occurs:
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
This function is deterministic (and does not modify data), so it is safe:
CREATE FUNCTION f1(i INT) RETURNS INT DETERMINISTIC READS SQL DATA BEGIN RETURN i; END;
This function uses UUID()
,
which is not deterministic, so the function also is not
deterministic and is not safe:
CREATE FUNCTION f2() RETURNS CHAR(36) CHARACTER SET utf8 BEGIN RETURN UUID(); END;
This function modifies data, so it may not be safe:
CREATE FUNCTION f3(p_id INT) RETURNS INT BEGIN UPDATE t SET modtime = NOW() WHERE id = p_id; RETURN ROW_COUNT(); END;
Assessment of the nature of a function is based on the
“honesty” of the creator. MySQL does not check
that a function declared DETERMINISTIC
is
free of statements that produce nondeterministic results.
When you attempt to execute a stored function, if
binlog_format=STATEMENT
is
set, the DETERMINISTIC
keyword must be
specified in the function definition. If this is not the case,
an error is generated and the function does not run, unless
log_bin_trust_function_creators=1
is specified to override this check (see below). For recursive
function calls, the DETERMINISTIC
keyword
is required on the outermost call only. If row-based or mixed
binary logging is in use, the statement is accepted and
replicated even if the function was defined without the
DETERMINISTIC
keyword.
Because MySQL does not check if a function really is
deterministic at creation time, the invocation of a stored
function with the DETERMINISTIC
keyword
might carry out an action that is unsafe for statement-based
logging, or invoke a function or procedure containing unsafe
statements. If this occurs when
binlog_format=STATEMENT
is
set, a warning message is issued. If row-based or mixed binary
logging is in use, no warning is issued, and the statement is
replicated in row-based format.
To relax the preceding conditions on function creation (that
you must have the SUPER
privilege and that a function must be declared deterministic
or to not modify data), set the global
log_bin_trust_function_creators
system variable to 1. By default, this variable has a value of
0, but you can change it like this:
mysql> SET GLOBAL log_bin_trust_function_creators = 1;
You can also set this variable at server startup.
If binary logging is not enabled,
log_bin_trust_function_creators
does not apply. SUPER
is not
required for function creation unless, as described
previously, the DEFINER
value in the
function definition requires it.
For information about built-in functions that may be unsafe for replication (and thus cause stored functions that use them to be unsafe as well), see Section 17.5.1, “Replication Features and Issues”.
Triggers are similar to stored functions, so the preceding remarks
regarding functions also apply to triggers with the following
exception: CREATE TRIGGER
does not
have an optional DETERMINISTIC
characteristic,
so triggers are assumed to be always deterministic. However, this
assumption might be invalid in some cases. For example, the
UUID()
function is nondeterministic
(and does not replicate). Be careful about using such functions in
triggers.
Triggers can update tables, so error messages similar to those for
stored functions occur with CREATE
TRIGGER
if you do not have the required privileges. On
the replica side, the replica uses the trigger
DEFINER
attribute to determine which user is
considered to be the creator of the trigger.
The rest of this section provides additional detail about the
logging implementation and its implications. You need not read it
unless you are interested in the background on the rationale for
the current logging-related conditions on stored routine use. This
discussion applies only for statement-based logging, and not for
row-based logging, with the exception of the first item:
CREATE
and DROP
statements
are logged as statements regardless of the logging mode.
The server writes CREATE EVENT
,
CREATE PROCEDURE
,
CREATE FUNCTION
,
ALTER EVENT
,
ALTER PROCEDURE
,
ALTER FUNCTION
,
DROP EVENT
,
DROP PROCEDURE
, and
DROP FUNCTION
statements to the
binary log.
A stored function invocation is logged as a
SELECT
statement if the
function changes data and occurs within a statement that would
not otherwise be logged. This prevents nonreplication of data
changes that result from use of stored functions in nonlogged
statements. For example, SELECT
statements are not written to the binary log, but a
SELECT
might invoke a stored
function that makes changes. To handle this, a SELECT
statement is
written to the binary log when the given function makes a
change. Suppose that the following statements are executed on
the source server:
func_name
()
CREATE FUNCTION f1(a INT) RETURNS INT BEGIN IF (a < 3) THEN INSERT INTO t2 VALUES (a); END IF; RETURN 0; END; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); SELECT f1(a) FROM t1;
When the SELECT
statement
executes, the function f1()
is invoked
three times. Two of those invocations insert a row, and MySQL
logs a SELECT
statement for
each of them. That is, MySQL writes the following statements
to the binary log:
SELECT f1(1); SELECT f1(2);
The server also logs a SELECT
statement for a stored function invocation when the function
invokes a stored procedure that causes an error. In this case,
the server writes the SELECT
statement to the log along with the expected error code. On
the replica, if the same error occurs, that is the expected
result and replication continues. Otherwise, replication
stops.
Logging stored function invocations rather than the statements executed by a function has a security implication for replication, which arises from two factors:
It is possible for a function to follow different execution paths on source and replica servers.
Statements executed on a replica are processed by the replica SQL thread which has full privileges.
The implication is that although a user must have the
CREATE ROUTINE
privilege to
create a function, the user can write a function containing a
dangerous statement that executes only on the replica where it
is processed by a thread that has full privileges. For
example, if the source and replica servers have server ID
values of 1 and 2, respectively, a user on the source server
could create and invoke an unsafe function
unsafe_func()
as follows:
mysql>delimiter //
mysql>CREATE FUNCTION unsafe_func () RETURNS INT
->BEGIN
->IF @@server_id=2 THEN
->dangerous_statement
; END IF;RETURN 1;
->END;
->//
mysql>delimiter ;
mysql>INSERT INTO t VALUES(unsafe_func());
The CREATE FUNCTION
and
INSERT
statements are written
to the binary log, so the replica executes them. Because the
replica SQL thread has full privileges, it executes the
dangerous statement. Thus, the function invocation has
different effects on the source and replica and is not
replication-safe.
To guard against this danger for servers that have binary
logging enabled, stored function creators must have the
SUPER
privilege, in addition to
the usual CREATE ROUTINE
privilege that is required. Similarly, to use
ALTER FUNCTION
, you must have
the SUPER
privilege in addition
to the ALTER ROUTINE
privilege.
Without the SUPER
privilege, an
error occurs:
ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
If you do not want to require function creators to have the
SUPER
privilege (for example,
if all users with the CREATE
ROUTINE
privilege on your system are experienced
application developers), set the global
log_bin_trust_function_creators
system variable to 1. You can also set this variable at server
startup. If binary logging is not enabled,
log_bin_trust_function_creators
does not apply. SUPER
is not
required for function creation unless, as described
previously, the DEFINER
value in the
function definition requires it.
If a function that performs updates is nondeterministic, it is not repeatable. This can have two undesirable effects:
It causes a replica to differ from the source.
Restored data does not match the original data.
To deal with these problems, MySQL enforces the following requirement: On a source server, creation and alteration of a function is refused unless you declare the function to be deterministic or to not modify data. Two sets of function characteristics apply here:
The DETERMINISTIC
and NOT
DETERMINISTIC
characteristics indicate whether a
function always produces the same result for given inputs.
The default is NOT DETERMINISTIC
if
neither characteristic is given. To declare that a
function is deterministic, you must specify
DETERMINISTIC
explicitly.
The CONTAINS SQL
, NO
SQL
, READS SQL DATA
, and
MODIFIES SQL DATA
characteristics
provide information about whether the function reads or
writes data. Either NO SQL
or
READS SQL DATA
indicates that a
function does not change data, but you must specify one of
these explicitly because the default is CONTAINS
SQL
if no characteristic is given.
By default, for a CREATE
FUNCTION
statement to be accepted, at least one of
DETERMINISTIC
, NO SQL
,
or READS SQL DATA
must be specified
explicitly. Otherwise an error occurs:
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
If you set
log_bin_trust_function_creators
to 1, the requirement that functions be deterministic or not
modify data is dropped.
Stored procedure calls are logged at the statement level
rather than at the CALL
level.
That is, the server does not log the
CALL
statement, it logs those
statements within the procedure that actually execute. As a
result, the same changes that occur on the source server also
occur on replicas. This prevents problems that could result
from a procedure having different execution paths on different
machines.
In general, statements executed within a stored procedure are written to the binary log using the same rules that would apply were the statements to be executed in standalone fashion. Some special care is taken when logging procedure statements because statement execution within procedures is not quite the same as in nonprocedure context:
A statement to be logged might contain references to local procedure variables. These variables do not exist outside of stored procedure context, so a statement that refers to such a variable cannot be logged literally. Instead, each reference to a local variable is replaced by this construct for logging purposes:
NAME_CONST(var_name
,var_value
)
var_name
is the local variable
name, and var_value
is a
constant indicating the value that the variable has at the
time the statement is logged.
NAME_CONST()
has a value of
var_value
, and a
“name” of
var_name
. Thus, if you invoke
this function directly, you get a result like this:
mysql> SELECT NAME_CONST('myname', 14);
+--------+
| myname |
+--------+
| 14 |
+--------+
NAME_CONST()
enables a
logged standalone statement to be executed on a replica
with the same effect as the original statement that was
executed on the source within a stored procedure.
The use of NAME_CONST()
can
result in a problem for
CREATE TABLE
... SELECT
statements when the source column
expressions refer to local variables. Converting these
references to NAME_CONST()
expressions can result in column names that are different
on the source and replica servers, or names that are too
long to be legal column identifiers. A workaround is to
supply aliases for columns that refer to local variables.
Consider this statement when myvar
has
a value of 1:
CREATE TABLE t1 SELECT myvar;
This is rewritten as follows:
CREATE TABLE t1 SELECT NAME_CONST(myvar, 1);
To ensure that the source and replica tables have the same column names, write the statement like this:
CREATE TABLE t1 SELECT myvar AS myvar;
The rewritten statement becomes:
CREATE TABLE t1 SELECT NAME_CONST(myvar, 1) AS myvar;
A statement to be logged might contain references to
user-defined variables. To handle this, MySQL writes a
SET
statement to the binary log to make sure that the variable
exists on the replica with the same value as on the
source. For example, if a statement refers to a variable
@my_var
, that statement is preceded in
the binary log by the following statement, where
value
is the value of
@my_var
on the source:
SET @my_var = value
;
Procedure calls can occur within a committed or
rolled-back transaction. Transactional context is
accounted for so that the transactional aspects of
procedure execution are replicated correctly. That is, the
server logs those statements within the procedure that
actually execute and modify data, and also logs
BEGIN
,
COMMIT
, and
ROLLBACK
statements as necessary. For example, if a procedure
updates only transactional tables and is executed within a
transaction that is rolled back, those updates are not
logged. If the procedure occurs within a committed
transaction,
BEGIN
and COMMIT
statements are
logged with the updates. For a procedure that executes
within a rolled-back transaction, its statements are
logged using the same rules that would apply if the
statements were executed in standalone fashion:
Updates to transactional tables are not logged.
Updates to nontransactional tables are logged because rollback does not cancel them.
Updates to a mix of transactional and nontransactional
tables are logged surrounded by
BEGIN
and
ROLLBACK
so that replicas make the same changes and rollbacks
as on the source.
A stored procedure call is not written to
the binary log at the statement level if the procedure is
invoked from within a stored function. In that case, the only
thing logged is the statement that invokes the function (if it
occurs within a statement that is logged) or a
DO
statement (if it occurs
within a statement that is not logged). For this reason, care
should be exercised in the use of stored functions that invoke
a procedure, even if the procedure is otherwise safe in
itself.
These restrictions apply to the features described in Chapter 25, Stored Objects.
Some of the restrictions noted here apply to all stored routines; that is, both to stored procedures and stored functions. There are also some restrictions specific to stored functions but not to stored procedures.
The restrictions for stored functions also apply to triggers. There are also some restrictions specific to triggers.
The restrictions for stored procedures also apply to the
DO
clause of Event Scheduler event
definitions. There are also some
restrictions
specific to events.
Stored routines cannot contain arbitrary SQL statements. The following statements are not permitted:
The locking statements LOCK
TABLES
and
UNLOCK
TABLES
.
SQL prepared statements
(PREPARE
,
EXECUTE
,
DEALLOCATE PREPARE
) can be
used in stored procedures, but not stored functions or
triggers. Thus, stored functions and triggers cannot use
dynamic SQL (where you construct statements as strings and
then execute them).
Generally, statements not permitted in SQL prepared
statements are also not permitted in stored programs. For a
list of statements supported as prepared statements, see
Section 13.5, “Prepared Statements”. Exceptions are
SIGNAL
,
RESIGNAL
, and
GET DIAGNOSTICS
, which are
not permissible as prepared statements but are permitted in
stored programs.
Because local variables are in scope only during stored
program execution, references to them are not permitted in
prepared statements created within a stored program.
Prepared statement scope is the current session, not the
stored program, so the statement could be executed after the
program ends, at which point the variables would no longer
be in scope. For example, SELECT ... INTO
cannot be
used as a prepared statement. This restriction also applies
to stored procedure and function parameters. See
Section 13.5.1, “PREPARE Statement”.
local_var
Within all stored programs (stored procedures and functions,
triggers, and events), the parser treats
BEGIN
[WORK]
as the beginning of a
BEGIN ...
END
block. To begin a transaction in this context,
use START
TRANSACTION
instead.
The following additional statements or operations are not
permitted within stored functions. They are permitted within
stored procedures, except stored procedures that are invoked
from within a stored function or trigger. For example, if you
use FLUSH
in a stored procedure,
that stored procedure cannot be called from a stored function or
trigger.
Statements that perform explicit or implicit commit or rollback. Support for these statements is not required by the SQL standard, which states that each DBMS vendor may decide whether to permit them.
Statements that return a result set. This includes
SELECT
statements that do not
have an INTO
clause and
other statements such as
var_list
SHOW
,
EXPLAIN
, and
CHECK TABLE
. A function can
process a result set either with
SELECT ... INTO
or by using a
cursor and var_list
FETCH
statements.
See Section 13.2.10.1, “SELECT ... INTO Statement”, and
Section 13.6.6, “Cursors”.
FLUSH
statements.
Stored functions cannot be used recursively.
A stored function or trigger cannot modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
If you refer to a temporary table multiple times in a stored
function under different aliases, a Can't reopen
table:
'
error occurs, even if the references occur in different
statements within the function.
tbl_name
'
HANDLER ...
READ
statements that invoke stored functions can
cause replication errors and are disallowed.
For triggers, the following additional restrictions apply:
Triggers are not activated by foreign key actions.
When using row-based replication, triggers on the replica are not activated by statements originating on the source. The triggers on the replica are activated when using statement-based replication. For more information, see Section 17.5.1.36, “Replication and Triggers”.
The RETURN
statement is not
permitted in triggers, which cannot return a value. To exit
a trigger immediately, use the
LEAVE
statement.
Triggers are not permitted on tables in the
mysql
database. Nor are they permitted on
INFORMATION_SCHEMA
or
performance_schema
tables. Those tables
are actually views and triggers are not permitted on views.
The trigger cache does not detect when metadata of the underlying objects has changed. If a trigger uses a table and the table has changed since the trigger was loaded into the cache, the trigger operates using the outdated metadata.
The same identifier might be used for a routine parameter, a local variable, and a table column. Also, the same local variable name can be used in nested blocks. For example:
CREATE PROCEDURE p (i INT) BEGIN DECLARE i INT DEFAULT 0; SELECT i FROM t; BEGIN DECLARE i INT DEFAULT 1; SELECT i FROM t; END; END;
In such cases, the identifier is ambiguous and the following precedence rules apply:
A local variable takes precedence over a routine parameter or table column.
A routine parameter takes precedence over a table column.
A local variable in an inner block takes precedence over a local variable in an outer block.
The behavior that variables take precedence over table columns is nonstandard.
Use of stored routines can cause replication problems. This issue is discussed further in Section 25.7, “Stored Program Binary Logging”.
The
--replicate-wild-do-table=
option applies to tables, views, and triggers. It does not apply
to stored procedures and functions, or events. To filter
statements operating on the latter objects, use one or more of
the db_name.tbl_name
--replicate-*-db
options.
The MySQL stored routine syntax is based on the SQL:2003 standard. The following items from that standard are not currently supported:
UNDO
handlers
FOR
loops
To prevent problems of interaction between sessions, when a client issues a statement, the server uses a snapshot of routines and triggers available for execution of the statement. That is, the server calculates a list of procedures, functions, and triggers that may be used during execution of the statement, loads them, and then proceeds to execute the statement. While the statement executes, it does not see changes to routines performed by other sessions.
For maximum concurrency, stored functions should minimize their side-effects; in particular, updating a table within a stored function can reduce concurrent operations on that table. A stored function acquires table locks before executing, to avoid inconsistency in the binary log due to mismatch of the order in which statements execute and when they appear in the log. When statement-based binary logging is used, statements that invoke a function are recorded rather than the statements executed within the function. Consequently, stored functions that update the same underlying tables do not execute in parallel. In contrast, stored procedures do not acquire table-level locks. All statements executed within stored procedures are written to the binary log, even for statement-based binary logging. See Section 25.7, “Stored Program Binary Logging”.
The following limitations are specific to the Event Scheduler:
Event names are handled in case-insensitive fashion. For
example, you cannot have two events in the same database
with the names anEvent
and
AnEvent
.
An event may not be created, altered, or dropped from within a stored program, if the event name is specified by means of a variable. An event also may not create, alter, or drop stored routines or triggers.
DDL statements on events are prohibited while a
LOCK TABLES
statement is in
effect.
Event timings using the intervals YEAR
,
QUARTER
, MONTH
, and
YEAR_MONTH
are resolved in months; those
using any other interval are resolved in seconds. There is
no way to cause events scheduled to occur at the same second
to execute in a given order. In addition—due to
rounding, the nature of threaded applications, and the fact
that a nonzero length of time is required to create events
and to signal their execution—events may be delayed by
as much as 1 or 2 seconds. However, the time shown in the
INFORMATION_SCHEMA.EVENTS
table's LAST_EXECUTED
column is always
accurate to within one second of the actual event execution
time. (See also Bug #16522.)
Each execution of the statements contained in the body of an
event takes place in a new connection; thus, these
statements have no effect in a given user session on the
server's statement counts such as
Com_select
and
Com_insert
that are displayed by
SHOW STATUS
. However, such
counts are updated in the global scope.
(Bug #16422)
Events do not support times later than the end of the Unix Epoch; this is approximately the beginning of the year 2038. Such dates are specifically not permitted by the Event Scheduler. (Bug #16396)
References to stored functions, user-defined functions, and
tables in the ON SCHEDULE
clauses of
CREATE EVENT
and
ALTER EVENT
statements are
not supported. These sorts of references are not permitted.
(See Bug #22830 for more information.)
While stored procedures, stored functions, triggers, and
scheduled events are all supported by tables using the
NDB
storage engine, you must keep
in mind that these do not propagate
automatically between MySQL Servers acting as Cluster SQL nodes.
This is because stored routine and trigger definitions are
stored in tables in the mysql
system database
using InnoDB
tables, which are not copied
between Cluster nodes.
Any stored routine or trigger that interacts with MySQL Cluster
tables must be re-created by running the appropriate
CREATE PROCEDURE
,
CREATE FUNCTION
, or
CREATE TRIGGER
statements on each
MySQL Server that participates in the cluster where you wish to
use the stored routine or trigger. Similarly, any changes to
existing stored routines or triggers must be carried out
explicitly on all Cluster SQL nodes, using the appropriate
ALTER
or DROP
statements
on each MySQL Server accessing the cluster.
Do not attempt to work around the issue
just described by converting any mysql
database tables to use the NDB
storage engine. Altering the system tables in the
mysql
database is not supported
and is very likely to produce undesirable results.
The maximum number of tables that can be referenced in the definition of a view is 61.
View processing is not optimized:
It is not possible to create an index on a view.
Indexes can be used for views processed using the merge algorithm. However, a view that is processed with the temptable algorithm is unable to take advantage of indexes on its underlying tables (although indexes can be used during generation of the temporary tables).
There is a general principle that you cannot modify a table and select from the same table in a subquery. See Section 13.2.11.12, “Restrictions on Subqueries”.
The same principle also applies if you select from a view that selects from the table, if the view selects from the table in a subquery and the view is evaluated using the merge algorithm. Example:
CREATE VIEW v1 AS SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t2.a); UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;
If the view is evaluated using a temporary table, you
can select from the table in the view
subquery and still modify that table in the outer query. In this
case, the view is stored in a temporary table and thus you are not
really selecting from the table in a subquery and modifying it at
the same time. (This is another reason you might wish to force
MySQL to use the temptable algorithm by specifying
ALGORITHM = TEMPTABLE
in the view definition.)
You can use DROP TABLE
or
ALTER TABLE
to drop or alter a
table that is used in a view definition. No warning results from
the DROP
or ALTER
operation,
even though this invalidates the view. Instead, an error occurs
later, when the view is used. CHECK
TABLE
can be used to check for views that have been
invalidated by DROP
or ALTER
operations.
With regard to view updatability, the overall goal for views is that if any view is theoretically updatable, it should be updatable in practice. MySQL as quickly as possible. Many theoretically updatable views can be updated now, but limitations still exist. For details, see Section 25.5.3, “Updatable and Insertable Views”.
There exists a shortcoming with the current implementation of
views. If a user is granted the basic privileges necessary to
create a view (the CREATE VIEW
and
SELECT
privileges), that user
cannot call SHOW CREATE VIEW
on
that object unless the user is also granted the
SHOW VIEW
privilege.
That shortcoming can lead to problems backing up a database with mysqldump, which may fail due to insufficient privileges. This problem is described in Bug #22062.
The workaround to the problem is for the administrator to manually
grant the SHOW VIEW
privilege to
users who are granted CREATE VIEW
,
since MySQL doesn't grant it implicitly when views are created.
Views do not have indexes, so index hints do not apply. Use of index hints when selecting from a view is not permitted.
SHOW CREATE VIEW
displays view
definitions using an AS
clause for each
column. If a column is created from an expression, the default
alias is the expression text, which can be quite long. Aliases for
column names in alias_name
CREATE VIEW
statements are checked against the maximum column length of 64
characters (not the maximum alias length of 256 characters). As a
result, views created from the output of SHOW
CREATE VIEW
fail if any column alias exceeds 64
characters. This can cause problems in the following circumstances
for views with too-long aliases:
View definitions fail to replicate to newer replicas that enforce the column-length restriction.
Dump files created with mysqldump cannot be loaded into servers that enforce the column-length restriction.
A workaround for either problem is to modify each problematic view
definition to use aliases that provide shorter column names. Then
the view replicates properly, and can be dumped and reloaded
without causing an error. To modify the definition, drop and
create the view again with DROP
VIEW
and CREATE VIEW
, or
replace the definition with
CREATE OR REPLACE
VIEW
.
For problems that occur when reloading view definitions in dump
files, another workaround is to edit the dump file to modify its
CREATE VIEW
statements. However,
this does not change the original view definitions, which may
cause problems for subsequent dump operations.