0% found this document useful (0 votes)
5 views56 pages

Chapter 4

The document discusses database views, procedures, and triggers. Views allow saving SELECT statements for reuse and control access to underlying tables. Procedures define reusable blocks of SQL code that can take parameters. Triggers define actions to be automatically performed in response to data changes.

Uploaded by

nonstres095
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views56 pages

Chapter 4

The document discusses database views, procedures, and triggers. Views allow saving SELECT statements for reuse and control access to underlying tables. Procedures define reusable blocks of SQL code that can take parameters. Triggers define actions to be automatically performed in response to data changes.

Uploaded by

nonstres095
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 56

DATABASES

4. Views, procedures and triggers

[email protected]
Chapter 4. Views, procedures and triggers

• Views
• Defining views
• Using views
• Access rights

• Procedures
• Defining procedures
• Using procedures
• Access rights

• Triggers
• Defining triggers
Views

• In relational management systems, the result of each relational


algebra operation is itself a relation
• In database application development, some queries may be
required often (e.g. selecting all products ordered by popularity,
showing all products from an order, compute the shopping cart
total, etc.)
• These queries may be complex, often requiring join operations
between two or more tables
• Relational database management systems allow saving of SELECT
statements
• These saved SELECT statements are known as views
Views

• The syntax to create a view is:


CREATE [OR REPLACE] [DEFINER = { user | CURRENT_USER }]
[SQL SECURITY {DEFINER | INVOKER}]
VIEW view_name [(column_list)] AS select_statement;

• The DEFINER option can be used to specify any valid user account
as the definer of the view
• This option is available only to system administrators which can
create/change new user accounts
• If the user creating a view is not in the system administrators
group, the only option available is its own user account
Views

CREATE [OR REPLACE] [DEFINER = { user | CURRENT_USER }]


[SQL SECURITY {DEFINER | INVOKER}]
VIEW view_name [(column_list)] AS select_statement;

• The SQL SECURITY option specifies the access control for the
tables in the underlying SELECT statement
• INVOKER – the view is queried with the privileges of the user which runs the
query. This means that the user which queries the view must also have
SELECT privileges on the tables/columns which are used in the view
definition
• DEFINER – the view is queried using the privileges of the user which created
the view. This means that the current user may access the view data without
having SELECT privileges on the underlying tables/columns. This is the
default value
Views

CREATE [OR REPLACE] [DEFINER = { user | CURRENT_USER }]


[SQL SECURITY {DEFINER | INVOKER}]
VIEW view_name [(column_list)] AS select_statement;

• By default, the names of the columns of the view are identical to


the names of the columns/aliases used in the SELECT statement
• If the SELECT statement has duplicate column names or if it is
necessary to define new column names for the current view, the
column list may be defined explicitly
• In this case, the number of columns in the list must be the same as
the number of columns/expressions in the SELECT statement
Views
Views
Views

Example: Show the list of artists with their associated genres


CREATE VIEW artists_list (artist, genres) AS
SELECT artists.name,
GROUP_CONCAT(genres.name SEPARATOR ', ')
FROM artists
LEFT JOIN artist_genres
ON artists.id = artist_genres.artist_id
LEFT JOIN genres
ON genres.id = artist_genres.genre_id
GROUP BY artists.id;
Views

genres artist_genres artists


id name artist_id genre_id id name …
1 Rock 1 2 1 Metallica …
2 Heavy metal 1 3 2 Rolling Stones …
3 Thrash metal 2 1 3 Behemoth …
4 Death metal 3 4 4 Iron Maiden …
5 Black metal 3 5
6 Rap 4 2
Views

SELECT * FROM artist_list;


artist genres
Metallica Heavy metal, Thrash metal
Rolling Stones Rock
Behemoth Death metal, Black metal
Iron Maiden Heavy metal
Views

• A view can select data from the tables of the databases and from
other previously defined views
• A view is linked to the tables structure at the moment of creating
the view (even when using the * wildcard for column selection)
• If new columns are added to the underlying table(s), they will not
appear in the view automatically, even if the SELECT statement of
the view uses the * wildcard
• If columns are dropped from the table(s) structure, the views
referencing those columns will no longer be usable
• In both case, if the changes need to be reflected in the view, it must
be recreated
Views

• Example: List the artists details and album count


CREATE OR REPLACE VIEW album_count AS
SELECT artists.*, COUNT(albums.id) AS album_count
FROM artists LEFT JOIN albums
ON artists.id = albums.artist_id
GROUP BY artists.id;

SELECT * FROM album_count;


id name description album_count
1 Metallica NULL 5
2 Rolling Stones NULL 0
3 Behemoth NULL 3
4 Iron Maiden NULL 4
Views

• Adding a new column to the artists table:


ALTER TABLE artists ADD label VARCHAR(255);
SELECT * FROM album_count;
id name description album_count
1 Metallica NULL 5
2 Rolling Stones NULL 0
3 Behemoth NULL 3
4 Iron Maiden NULL 4
• Dropping a column from the artists table:
ALTER TABLE artists DROP description;
SELECT * FROM album_count;
• The previous query will generate an error
Views

Example: List the album names, artist names and albums length
CREATE OR REPLACE VIEW albums_length
(artist, album, length) AS
SELECT art.name, alb.name,
SEC_TO_TIME(SUM(TIME_TO_SEC(s.length)))
FROM albums AS alb
LEFT JOIN artists AS art
ON art.id = alb.artist_id
LEFT JOIN songs AS s
ON alb.id = s.album_id
GROUP BY alb.id;
Views

SELECT * FROM albums_length ORDER BY length ASC;

artist album length


Iron Maiden Iron Maiden 00:37:35
Iron Maiden Killers 00:38:18
Iron Maiden The Number of the Beast 00:39:11
Behemoth Demigod 00:40:47
Behemoth The Satanist 00:44:22
Iron Maiden Piece of Mind 00:45:39
Behemoth I Loved You at Your Darkest 00:46:32
Metallica Ride the Lightning 00:47:20
… … …
SQL variables

• The SQL procedural extensions provide support for creating stored


procedures, user-defined functions, triggers and cursors
• These extensions allow definition of variables, execution blocks and
control flow instructions (conditional statements, loops)
• Variables are used to store values in memory
• Variable declaration differs between various DBMSs:
• MS SQL Server: DECLARE @variable data_type; SELECT @variable = value;
• PostgreSQL: DECLARE variable data_type;
• MySQL: DECLARE variable data_type; SET @variable = value;
SQL variables

• Procedural extensions define additional clauses in SQL statements,


so that they can be used in combination with local variables
• For example, the values returned from SELECT statements can be
stored in local variables
• The SELECT statements must return a single row
• MS SQL Server:
SELECT @v1 = col1, …, @vn = coln FROM tbl_list WHERE condition;
• PostgreSQL:
SELECT c1 INTO v1, …, cn INTO vn FROM tbl_list WHERE condition;
• MySQL:
SELECT c1 INTO v1, …, cn INTO vn FROM tbl_list WHERE condition;
Stored procedures

• A stored procedure is an ordered list of SQL statements, which are


compiled and stored in the database structure
• Stored procedures can implement parts of the application’s
algorithms
• A stored procedure is defined using the following syntax:
CREATE [DEFINER = { user | CURRENT_USER }]
PROCEDURE procedure_name([param1 [, …]])
[SQL SECURITY { DEFINER | INVOKER }] procedure_body;
Stored procedures

• The DEFINER option can be used to specify any valid user account
as the definer of the procedure
• This option is available only to system administrators which can
create/change new user accounts
• If the user creating a view is not in the system administrators
group, the only option available is its own user account
• The SQL SECURITY option specifies the access control for
instructions in the procedure body
• INVOKER – the instructions are executed with the privileges of the user
which calls the procedure
• DEFINER – the instructions are executed using the privileges of the user
which created the procedure
Stored procedures

• The parameters of the procedure can be input (IN), output (OUT)


or input-output (INOUT)
• Advantages:
• Decreased communication between the application and the database server
• Lower execution time for a task (since the stored procedure is already
compiled and stored)

• Disadvantages:
• Server congestion for high number of users
• Changes in the procedure may require special permissions
Stored procedures - example

• Example: Create a procedure which adds a new album


DELIMITER //
CREATE PROCEDURE new_album(
IN artist VARCHAR(255),
IN name VARCHAR(255),
IN rel_date DATE,
OUT album_id INT
)
BEGIN
procedure_body;
END //
DELIMITER ;
Stored procedures

• In the previous example, before creating the procedure, it is


necessary to change the instructions delimiter:
DELIMITER new_delimiter

• This is necessary for the DBMS to treat the procedure definition as


a single instruction and not end the instruction on the first
semicolon (;) in the procedure_body
• At the end of the procedure definition, the delimiter is changed
back to the default semicolon (;), so the following instructions are
not affected:
DELIMITER ;
Stored procedures

• The procedure may define a set of parameters


• In the previous example, the parameters are:
• IN artist VARCHAR(255) – the name of the artist
• IN name VARCHAR(255) – the name of the album
• IN rel_date DATE – the release date of the album
• OUT album_id INT – the auto generated album id for a successful call

• The procedure_body is delimited by BEGIN … END


• The instructions which form the procedure_body are delimited by
the usual semicolon (;)
Stored procedures – example continued

DELIMITER //
CREATE PROCEDURE new_album (IN artist VARCHAR(255), IN name
VARCHAR(255), IN rel_date DATE, OUT album_id INT)
BEGIN
DECLARE artist_id INT;
SELECT id INTO artist_id FROM artists
WHERE artists.name = artist;
IF (artist_id IS NULL) THEN
SELECT 'Artist not found' AS error;
ELSE
INSERT INTO albums VALUES (NULL,artist_id,name,rel_date);
SELECT LAST_INSERT_ID() INTO album_id;
END IF;
END //
DELIMITER ;
Stored procedures

• Once defined, a procedure can be executed using the CALL


statement:
CALL procedure([arguments_list]);

• Example:
CALL new_album('Rolling Stones', 'A Bigger Bang',
'2005-09-05', @album_id);

• When calling a procedure, the number of arguments must match


the number of parameters and the data types of the argument
values must match the data types of the declared parameters in
corresponding order
• The variable @album_id will store the created album id after the
call is completed
Stored procedures
Stored procedures

• In the case when the artist was not found, the procedures displays
an “error” message using a SELECT statement
• This is not always efficient, since the procedure completes the
execution successfully
• Applications built on top of the database may not (and should not
be required to) test the actual message displayed at the end of the
procedure call
• A more efficient way to alert the user that something went wrong is
to raise an actual error in the database system
• This can be achieved using the SIGNAL statement
Signals

• A signal is the SQL method to raise an error. The syntax is:


SIGNAL SQLSTATE sqlstate_value
[SET signal_information_1 [, signal_information_2] …];

• An SQLSTATE is a return code for any SQL instruction. Each


SQLSTATE consists in 5 literal characters, corresponding to the
result of each operation
• Each DBMS implements its own errors based on SQLSTATES.
While error codes are specific to each DBMS, SQLSTATES are
common for all DBMSs, although each DBMS can define its own
SQLSTATES for non-standard extensions
SQL states

• The first two letters of any SQLSTATE indicate the result of the
operation:
• 00 – success
• 01 – warning
• 02 – no data
• XX – any other value denotes an exception

• When manually raising errors using the SIGNAL statement, the


SQLSTATE must be appropriately chosen, since an incorrect
SQLSTATE may cause other unexpected errors in the DBMS
• A generic SQLSTATE for user defined errors is '45000' - Unhandled
user-defined exception
Signals

Example: Redefine the new_album procedure to raise an error when


the artist is not found (full code in the annex)
DROP PROCEDURE IF EXISTS new_album;
DELIMITER //
CREATE PROCEDURE new_album (…)
BEGIN

IF (artist_id IS NULL) THEN
SIGNAL SQLSTATE '45000';
ELSE

END IF;
END //
DELIMITER ;
Signals

⚫ In the previous example, when calling the procedure with an


unknown artist, the following error will be displayed:
Error Code: 1644. Unhandled user-defined
exception condition
⚫ While this behavior is closer to the desired output, it does not
show the actual error which caused the exception
⚫ The SIGNAL statement allows setting some signal information,
which include the error text:
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Artist not found';
⚫ The new error message will be: Error Code: 1644. Artist
not found
Error handlers

• SQL procedures allow the use of error handlers when an exception


occurs
• The error handlers are code blocks which are executed whenever
an error condition is met
• They allow proper error management inside stored procedures
• The syntax for an error handler is:
DECLARE handler_action HANDLER
FOR condition_value [, condition_value] [, …]
handler_block
Error handlers

DECLARE handler_action HANDLER


FOR condition_value [, condition_value] [, …]
handler_block
• The handler action specifies what happens after the handler_block
is executed. It can take the following values:
• CONTINUE – The execution of the current procedure continues after the
handler_block is executed
• EXIT – The execution of the current procedure will not resume after the
handler_block is executed

• The handler_block must be delimited by BEGIN … END if it


contains more than one instruction
Error handlers

DECLARE handler_action HANDLER


FOR condition_value [, condition_value] [, …]
handler_block
• The condition_value specifies the specific condition/class of
conditions that activates the handler:
• mysql_error_code (Example: 1051 – corresponding to “Unknown table”)
• SQLSTATE sqlstate_value (Example: '42S01' – “Unknown table”)
• SQLWARNING – Shorthand for any SQLSTATE that begins with '01'
• NOT FOUND – Shorthand for any SQLSTATE that begins with '02'
• SQLEXCEPTION – Shorthand for any SQLSTATE that does not begin with
'00', '01' or '02'
Stored procedures – example continued

Example: Change the procedure to add the artist if it doesn’t exist


CREATE PROCEDURE new_album (…)
BEGIN
DECLARE artist_id INT;
DECLARE CONTINUE HANDLER FOR SQLSTATE '45000'
BEGIN
INSERT INTO artists (name) VALUES (artist);
SELECT LAST_INSERT_ID() INTO artist_id;
INSERT INTO albums VALUES (…);
SELECT LAST_INSERT_ID() INTO album_id;
END;

END //
Triggers

• A trigger is a named database object that is associated with a table


and that activates when a statement inserts, updates, or deletes
rows in the associated table
• These row operations are trigger events
• A trigger can be set to activate either before or after the trigger
event
• Some uses for triggers are to perform checks or calculations of
values to be inserted/changed into a table or to make backups
when deleting rows from a table
Triggers

• The syntax to define a trigger is:


CREATE [DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name
{ BEFORE | AFTER } { INSERT | UPDATE | DELETE }
ON table_name FOR EACH ROW
[{ FOLLOWS | PRECEDES } other_trigger]
trigger_body;

• The DEFINER option allows the association of the trigger with a


specified user account
• If the option is not set, the definer will be the CURRENT_USER by
default
• To use this option, the user which creates the trigger must have
administrative privileges
Triggers

• Since the trigger is not explicitly called (like stored procedures), but
activated automatically when the trigger operation occurs
(INSERT, UPDATE, DELETE), there is not use for the SQL
SECURITY option, like in the case of stored procedures and views
• A table can have multiple triggers for the same operation and the
same time (BEFORE/AFTER). In this case, the triggers are activated
in the order in which they were created.
• It is possible to control the trigger order using the FOLLOWS /
PRECEDES other_trigger clause.
Triggers

• The trigger_body will be executed FOR EACH ROW that is


changed when the trigger operation is executed
• If the trigger_body contains more than one instruction, it must be
delimited by a BEGIN … END block, and for the definition of the
trigger, the instruction DELIMITER must be changed, similar to the
definition of the stored procedures
• One very important aspect of triggers is that they are only activated
for changes made by SQL statements. This implies that a trigger
associated to an operation will not activate if the operation is
executed as a result of a foreign key CASCADE/SET NULL action
• Triggers cannot be associated with views or temporary tables
Triggers

• Example: Add the column website to the artists table and create a
trigger to check if the website begins with http:// or https://
ALTER TABLE artists ADD website VARCHAR(255) AFTER label;
DELIMITER //
CREATE TRIGGER check_insert_website BEFORE INSERT
ON artists FOR EACH ROW
BEGIN
DECLARE has_protocol BOOLEAN;
SELECT new.website REGEXP '^https?://.+$' INTO has_protocol;
IF (has_protocol = 0) THEN
SET new.website = CONCAT('http://', new.website);
END IF;
END //
DELIMITER ;
Triggers

• The format is checked using a regular expression (REGEXP)


https://dev.mysql.com/doc/refman/8.0/en/regexp.html
INSERT INTO artists VALUES (NULL, 'Muse', NULL,
NULL);
INSERT INTO artists VALUES (NULL, 'Rammstein',
NULL, 'rammstein.com');
INSERT INTO artists VALUES (NULL, 'Apocalyptica',
NULL, 'https://www.apocalyptica.com');
id name label website
5 Muse NULL NULL
6 Rammstein NULL http://rammstein.com
7 Behemoth NULL https://www.apocalyptica.com
Triggers

• To access the values of the table columns which are used in the
statements that activate the triggers, the new and old objects are
available
• The INSERT operation has access only to the new object, since it
only creates new records in the database
• The UPDATE operation can access both the new and old objects,
because it changes the old values with the new values
• The DELETE operation can access only the old object, because it is
used only to remove records from the tables
• Example: new.website, old.name, etc.
Triggers

• To demonstrate that the trigger is not activated for foreign keys


cascaded actions, consider the following example:
• Tables artists and artist_genres have AFTER DELETE
triggers which log the action into a separate logs table
CREATE TABLE logs (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
operation VARCHAR(255),
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Triggers

• Full code in annex


DELIMITER //
CREATE TRIGGER log_artist_delete AFTER DELETE
ON artists FOR EACH ROW
BEGIN
INSERT INTO logs (operation) VALUES
('Artist deleted');
END//
DELIMITER ;
Triggers

DELIMITER //
CREATE TRIGGER log_artist_genre_delete
AFTER DELETE ON artist_genres FOR EACH ROW
BEGIN
DECLARE artist_name VARCHAR(255);
SELECT name INTO artist_name FROM artists
WHERE id = old.artist_id;
IF (artist_name IS NOT NULL) THEN
INSERT INTO logs (operation) VALUES
('Artist genres deleted');
END IF;
END//
DELIMITER ;
Triggers

DELETE FROM artists WHERE id = 5;


DELETE FROM artists WHERE id = 1;
DELETE FROM artist_genres WHERE artist_id = 2;

logs
id operation timestamp
1 Artist Muse deleted 2018-11-20 16:14:10
2 Artist Metallica deleted 2018-11-20 16:15:19
3 Artist genres for Rolling Stones deleted 2018-11-20 16:15:39
Definer and SQL Security options

• The DEFINER option in stored routines, triggers and views allows


the association of the routine definition with a use account
• By default, if the option is not specified, the routine’s definer is the
current user
• Considering the following scenario:
CREATE USER 'user'@'%' IDENTIFIED BY 'abcd';
GRANT SELECT ON music.album_count TO 'user'@'%';
GRANT SELECT ON music.artists_list TO 'user'@'%';
GRANT EXECUTE ON music.* TO 'user'@'%';
GRANT INSERT ON music.artists TO 'user'@'%';

• https://dev.mysql.com/doc/refman/8.0/en/grant.html
Definer and SQL Security options

• In the previous case, the new user can:


• SELECT from the two previously defined views: album_count and artists_list
• INSERT into the table artists
• CALL (EXACUTE) all procedures from the music database

• The user cannot:


• UPDATE or DELETE from any table
• INSERT into all other tables except the artists table
• SELECT data directly from the tables in the music database
Definer and SQL Security options

• The two views album_count and artists_list were defined by a user


with full access to the music database (in this case, the root user)
• The DEFINER and SQL SECURITY options were not explicitly set
• By default, the DEFINER of the views is the user which created the
view (root) and the SQL SECURITY option is set to DEFINER
• The following statements performed by the user will work:
SELECT * FROM album_count;
SELECT * FROM artists_list;
Definer and SQL Security options

• The following statement will generate an error:


SELECT * FROM artists;
Error Code: 1142. SELECT command denied to user
'user'@'localhost' for table 'artists’

• Although the SELECT statement saved in the form of a view


references the table artists (and others), the user can view the
results because the saved SELECT statement is executed with the
DEFINER privileges (root in this case)
• When trying to SELECT directly from the tables, the access is
denied
Definer and SQL Security options

• The album_count view is recreated with the DEFINER set to user


and the SQL SECURITY set to DEFINER:
CREATE OR REPLACE DEFINER='user'@'%' SQL SECURITY DEFINER
VIEW album_count AS
SELECT artists.*, COUNT(albums.id) AS album_count
FROM artists
LEFT JOIN albums ON artists.id = albums.artist_id
GROUP BY artists.id;
• In this case, any user which uses the view will get an error:
Error Code: 1143. SELECT command denied to user 'user'@'%'
for column 'id' in table 'artists’
Definer and SQL Security options

• The previous view is redefined with the INVOKER SQL SECURITY


option:
CREATE OR REPLACE DEFINER='user'@'%' SQL SECURITY INVOKER
VIEW album_count AS
SELECT artists.*, COUNT(albums.id) AS album_count
FROM artists
LEFT JOIN albums ON artists.id = albums.artist_id
GROUP BY artists.id;
• In this case, the regular user will get an error:
Error Code: 1143. SELECT command denied to user
'user'@'localhost' for column 'id' in table 'artists’

• If the view is executed by another user with privileges for the


underlying tables, it will return the expected results
Definer and SQL Security options

• The same is true for stored procedures


• The procedure new_album is created by the root user with the
default options (DEFINER – current user, SQL SECURITY
DEFINER)
• The regular user can INSERT into the artists table, but he can’t
INSERT directly into the albums table
• However, when calling the procedure, the instructions will be
executed with the privileges of the definer (root)
CALL new_album('Metallica', 'Load', '1996-06-04', @id);
Definer and SQL Security options

• The new_album procedure is redefined with the SQL SECURITY


option set to INVOKER (full code in annex):
DROP PROCEDURE IF EXISTS new_album;
DELIMITER //
CREATE PROCEDURE new_album (…) SQL SECURITY INVOKER
BEGIN

END//
DELIMITER ;
CALL new_album('Metallica', 'Reload', '1997-11-18', @id);
Error Code: 1142. SELECT command denied to user
'user'@'localhost' for table 'artists'
Definer and SQL Security options

• The previous error is generated because of the artist check in the


procedure body
• If the user receives the SELECT privilege on the artists table, then
the result will be:
GRANT SELECT ON music.artists TO 'user'@'%';
CALL new_album('Metallica', 'Reload', '1997-11-18', @id);
Error Code: 1142. INSERT command denied to user
'user'@'localhost' for table 'albums’

• If the procedure is called with an artist which does not exists, the
same error will be returned but the artist will be added, because the
user can INSERT into the artists table
CALL new_album('Therion', 'Lemuria', '2004-05-24', @id);

You might also like