You are on page 1of 25

Stored Routines Workshop

for MySQL and MariaDB

by FromDual

contact@fromdual.com
http://www.fromdual.com

www.fromdual.com 1
Programming Languages
● Set – oriented
● SQL
● Procedural [][][][][][][]
[][]
[][][][][][][][]
[][][]
● C, PHP [][][][][][

● Object Oriented
● C++, Java, PHP
● Functional
● Erlang, Scheme

www.fromdual.com 2
Stored routines

mysqld Client / application

[][][][][][][]
[][]
[][][][][][][][]
Network – [][][]
[][][][][][][] round trips [][][][][][
[][]
[][][][][][][][]
[][][]
[][][][][][

www.fromdual.com 3
Stored routines
● Some logic cannot be solved with SQL!
● Location of business logic?
● Stored routines are proprietary!
● MySQL stored routines like DB2 (ANSI
conform)
● MySQL SR: Poor developer support for
debugging, programming and functional
● MySQL stored routines non optimal for big
an complex tasks
www.fromdual.com 4
ETL (Extract-Transform-Load)
● Extract (how to unload data)
● Transform (conversion, transformation, aggregation,
calculation)
● Load (how to load data)
● Tools:
● SELECT INTO OUTFILE / LOAD DATA INFILE
● CSV Tables
● Kettle
● MySQL Migration Toolkit
● JDBC/ODBC
● other
www.fromdual.com 5
MySQL Stored Routines
● Stored Procedures
● Logic with IN and OUT parameters
● Stored Functions
● Logic with IN parameters OUT in SELECTS
● Triggers
● Logic executed based on events (BEFORE or AFTER
INSERT, UPDATE or DELETE)
● Events
● Logic executed based on time events
www.fromdual.com 6
PROCEDURE

delimiter //

CREATE PROCEDURE hello (OUT str VARCHAR(64))
BEGIN
  SELECT 'Hello world!' INTO str;
END;
//

delimiter ;

CALL hello(@s);
SELECT @s;

www.fromdual.com 7
FUNCTION

delimiter //

CREATE FUNCTION hello (str VARCHAR(20))
RETURNS CHAR(64) DETERMINISTIC
BEGIN
  RETURN CONCAT('Hello ', str, '!');
END;
//

delimiter ;

SELECT hello('world');

www.fromdual.com 8
TRIGGER
delimiter //

CREATE TRIGGER hello
AFTER INSERT ON user
FOR EACH ROW BEGIN
  INSERT INTO test
  VALUES (NULL, CONCAT('Hello ', NEW.data, '!'), NULL);
END;
//

delimiter ;

INSERT INTO user VALUES (NULL, 'world', NULL);

SELECT * FROM user;
SELECT * FROM test;

www.fromdual.com 9
EVENT

delimiter //

CREATE EVENT hello
ON SCHEDULE AT '2010­12­20 09:05:00' + INTERVAL 1 DAY DO
BEGIN
  INSERT INTO test VALUES (NULL, 'Hello world!', NULL);
END;
//

delimiter ;

www.fromdual.com 10
When to use Stored Routines
● Stored Procedure
● Pass back values using output variables
● Stored Function
● Can be called from inside a statement, returns scalar value
● Trigger
● Based on UPDATE, INSERT or DELETE on a table (BEFORE or AFTER)
● Event
● Time based action

● Alternatives
● SP/SF: External languages (PHP, Java, Perl, C, ...)
● Triggers: Explicitly code in wrapping interface (more difficult)
● Crontab, at, Windows scheduler, etc.
www.fromdual.com 11
Compound Statements

BEGIN .. END Block

[label:] BEGIN
  ...
END [label]

DELIMITER //
...
honorar: BEGIN
  ...;
END honorar;
//

www.fromdual.com 12
Conditions

CASE n
IF n > 0 THEN
WHEN 0 THEN
  ...
  ...
ELSEIF n = 0 THEN
WHEN 1 THEN
  ...
  ...
ELSE
ELSE
  ...
  ...
END IF;
END CASE;

www.fromdual.com 13
Infinit Loop

[label:] LOOP
    ...;
    LEAVE label;   ­­ break
    ITERATE label; ­­ continue
END LOOP [label];

● Often used with cursors

www.fromdual.com 14
Conditional Loops

­­ at least once
[label:] REPEAT ­­ as long as true
  ...; [label:] WHILE v > 42 DO
­­ repeat until true   ...;
UNTIL v > 42 END WHILE [label];
END REPEAT [label];

www.fromdual.com 15
Variables
● System variables (DB variables)
● User-defined variables (SQL)
● Local variables declared inside a stored routine (SR)

BEGIN
  SET p_var = 42;
  SET @u_var = 42;
  SET @@sort_buffer_size = 42;
END;

● Declare order:
● VARIABLES & CONDITIONS
● CURSORS
● HANDLERS
www.fromdual.com 16
User and system variables

­­ User variables
SET @var_name = 42;
SELECT @var_name;

­­ System variables
SET sort_buffer_size           = 2*1024*1024;
SET @@sort_buffer_size         = 2*1024*1024;
SET @@local.sort_buffer_size   = 2*1024*1024;
SET @@session.sort_buffer_size = 2*1024*1024;

SET SESSION sort_buffer_size   = 2*1024*1024;
SET LOCAL sort_buffer_size     = 2*1024*1024;

SET @@global.sort_buffer_size  = 2*1024*1024;
SET GLOBAL sort_buffer_size    = 2*1024*1024;

www.fromdual.com 17
Stored Routines Local Variables

BEGIN

  DECLARE i VARCHAR(10) DEFAULT NULL;
  SELECT 'test' INTO i [FROM dual];

  BEGIN

    DECLARE i VARCHAR(10) DEFAULT NULL;
    SELECT 'overwrite' INTO i;
  END;
END;

● Any valid MySQL data type


● http://dev.mysql.com/doc/refman/5.1/en/data-types.html

www.fromdual.com 18
Error Conditions and Handlers
BEGIN
  DECLARE test_cond CONDITION FOR SQLSTATE '42S02';

  DECLARE EXIT     HANDLER FOR test_cond BEGIN ... END;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' BEGIN ... END;
  DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN ... END;
  DECLARE CONTINUE HANDLER FOR NOT FOUND BEGIN ... END;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN ... END;
  DECLARE CONTINUE HANDLER FOR 1146 BEGIN ... END;

  ...
END;

● CONTINUE handler: Execution of the current program continues after execution of the handler
statement.
● EXIT handler: Execution terminates the BEGIN ... END compound statement in which the handler is
declared.
● A numeric MySQL error code (1146)
● A five-character SQLSTATE value ('42S02'): ANSI SQL (and ODBC)
● http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html

www.fromdual.com 19
Cursors
● Are made to traverse a set of rows
● Not updateable
● Can be traversed only in one direction and cannot skip rows

BEGIN
  DECLARE no_more_rows INT DEFAULT 0;
  DECLARE c_test CURSOR FOR SELECT id, data FROM test.t1;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_more_rows = 1;

  OPEN c_test;
  test_loop: LOOP

    FETCH c_test INTO a, b;
    IF no_more_rows THEN
      LEAVE test_loop;
    END IF;
  END LOOP test_loop;
  CLOSE c_test;
END;

● http://rpbouman.blogspot.com/2005/09/why-repeat-and-while-are-usually-not.html
● http://rpbouman.blogspot.com/2005/10/nesting-mysql-cursor-loops.html

www.fromdual.com 20
Logging / Error handling
CREATE PROCEDURE log_error(IN severity VARCHAR(8), IN message VARCHAR(128))
BEGIN
  INSERT INTO log_table VALUES (NULL, NULL, severity, message);
END;

CREATE PROCEDURE my_procedure(IN test_case INT, OUT result INT)
BEGIN

  IF test_case = 1 THEN
    CALL log_error('INFO', 'Not error, just info message');
    SET result = 0;
  ELSEIF test_case = 2 THEN
    CALL log_error('ERROR', 'My error message');
    SET result = 1;
  ELSE
    CALL log_error('ERROR', CONCAT('Unknown error code: ', test_case));
    SET result = 1;
  END IF;
END;

www.fromdual.com 21
SIGNAL (v5.5)

CREATE PROCEDURE my_procedure (divisor INT)
BEGIN

  DECLARE division_by_zero CONDITION FOR SQLSTATE '22012';

  IF divisor = 0 THEN
    SIGNAL division_by_zero
    SET MESSAGE_TEXT = 'Division by ZERO is not allowed!';
  END IF;
END;

● http://dev.mysql.com/doc/refman/5.5/en/sign
al-resignal.html
www.fromdual.com 22
RESIGNAL (v5.5)

CREATE PROCEDURE my_procedure (IN test_case INT)
BEGIN

  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    IF test_case = 0 THEN
      RESIGNAL SQLSTATE '45000'
      SET MYSQL_ERRNO = 5,
      MESSAGE_TEXT = "Table 'xx' does not exist";
    ELSE
      SET test_case = test_case;
    END IF;
  END;

  DROP TABLE xx;
END;

www.fromdual.com 23
Prepared Statements
● Server Side and Client Side Prepared Statements
● Special binary protocol C-API, Connector/J, Connector/NET.
● SQL syntax for prepared statements is intended to be used for:
● You want to test how prepared statements work in your application before coding it.
● An application has problems executing prepared statements and you want to determine
interactively what the problem is.
● You want to create a test case that describes a problem you are having with prepared
statements, so that you can file a bug report.
● You need to use prepared statements but do not have access to a programming API that
supports them.
● How does it work:
● PREPARE
● EXECUTE x n
● DEALLOCATE PREPARE
● http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-prepared-statements.html

www.fromdual.com 24
Prepared Statements

CREATE TABLE a
(a INT NOT NULL);
PREPARE stmt1
   FROM 'SELECT ? AS  SET @table = 'a';
   value FROM dual'; SET @v1 = 42;
SET @a = 42; SET @v2 = 43;
EXECUTE stmt1 USING @a; SET @s = CONCAT('INSERT INTO '
SET @a = 43;   , @table
EXECUTE stmt1 USING @a;   , ' VALUES (?)
DEALLOCATE PREPARE stmt1;   , (?+1)');
EXECUTE stmt1 USING @a; PREPARE stmt1 FROM @s;
EXECUTE stmt1 USING @v1, @v2;
SELECT * FROM a;
DEALLOCATE PREPARE stmt1;

www.fromdual.com 25

You might also like