50. User Defined
Functions
• Was introduced in MariaDB 10.1
• Functions are written in C or C++, and to make use of them, the operating
system must support dynamic loading
51. What are user defined functions?
Some functions needed to be defined for UDFs
• x(): Required for all UDF's, this is where the results are calculated
• x_init(): Initialization function for x()
• x_deinit(): De-initialization function for x(). Used to deallocate memory
that was allocated in x_init()
52. What are user defined functions?
In addition to the functions mentioned earlier we need these extra functions for
aggregate UDF
• x_clear(): Used to reset the current aggregate, but without inserting the
argument as the initial aggregate value for the new group.
• x_add():Used to add the argument to the current aggregate
59. What are custom aggregate functions?
● Aggregate functions
○ Computed over a sequence of rows
○ Return one result for the sequence of rows
● Identified by:
○ AGGREGATE keyword
○ FETCH GROUP NEXT ROW instruction
60. Syntax for custom aggregate functions
CREATE AGGREGATE FUNCTION function_name (parameters)
RETURNS return_type
BEGIN
All types of declarations
DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN
return_val;
LOOP
FETCH GROUP NEXT ROW; // fetches next row from table
other instructions
END LOOP;
END|
61. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
62. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
63. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=0
x=1
64. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=0
x=1
65. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=1
x=1
66. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=1
x=2
67. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=2
x=2
68. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=2
x=3
69. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=3
x=3
70. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=3
x=3
71. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=3
x=4
72. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
count_students=4
x=4
73. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
A signal stating NO MORE ROWS is sent
count_students=4
x=4
74. Let’s start with an example
SELECT
aggregate_count(Stud_Id) from MARKS;
+----------+---------+
|Stud_Id | GradeCnt|
+----------+---------+
| 1 | 6 |
| 2 | 4 |
| 3 | 7 |
| 4 | 5 |
+----------+---------+
CREATE AGGREGATE FUNCTION
aggregate_count(x INT) RETURNS INT
BEGIN
DECLARE count_students INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN count_students;
LOOP
FETCH GROUP NEXT ROW;
IF x THEN
SET count_students = count_students+1;
END IF;
END LOOP;
END|
Handler handles the signal and
executes the return statement
Return Value
4
75. Example: Median
CREATE AGGREGATE FUNCTION function_name (parameters) RETURNS return_type
BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
DECLARE res DOUBLE;
DECLARE cnt INT DEFAULT (select count(*) from tt);
DECLARE lim INT DEFAULT (cnt-1) DIV 2;
IF cnt % 2 == 0 THEN
SET res= (select AVG(a) FROM (select a FROM tt ORDER BY a LIMIT lim,2) ttt);
ELSE
SET res= (select a FROM tt ORDER BY a LIMIT lim,1);
END IF;
DROP TEMPORARY TABLE tt;
RETURN res;
END;
CREATE TEMPORARY TABLE tt (a INT);
LOOP
FETCH GROUP NEXT ROW;
INSERT INTO tt VALUES(x);
END LOOP;
END|
76. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=1
x= 5
77. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=1
x= 5
78. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=5
x= 5
79. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=5
x= 4
80. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=20
x= 4
81. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=20
x= 5
82. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
mean=100
x= 5
83. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1| |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
A signal stating NO MORE ROWS is sent
mean=100
x= 5
84. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1|4.641588833 |
| 1 | 4 | | 2| |
| 1 | 5 | | 3| |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
Handler handles the signal and
executes the return statement
mean=100
x= 5
85. Example: Custom Aggregate with GROUP BY clause
SELECT Stud_Id, geometric_mean(Grade) from GRADES
GROUP BY Stud_Id;
+----------+---------+ +--------+--------------+
| Stud_Id |Grade | |Stud_Id |geometric_mean|
+----------+---------+ +--------+--------------+
| 1 | 5 | | 1|4.641588833 |
| 1 | 4 | | 2|2.884499140 |
| 1 | 5 | | 3|6 |
| 2 | 2 | +--------+--------------+
| 2 | 4 |
| 2 | 3 |
| 3 | 6 |
+----------+---------+
CREATE AGGREGATE FUNCTION geometric_mean(x DOUBLE)
RETURNS DOUBLE
BEGIN
DECLARE mean DOUBLE DEFAULT 1;
DECLARE num_rows DOUBLE DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND
RETURN Power(mean, 1/num_rows);
LOOP
FETCH GROUP NEXT ROW;
IF x is NOT NULL THEN
SET mean = mean * x;
SET num_rows = num_rows+1;
END IF
END LOOP;
END|
After repeating the same for other
groups the final result is
86. Summary
● Custom Aggregate Functions allows us to write aggregate functions
in SQL while the UDF functions make us to do it in C or C++.
● FETCH GROUP NEXT ROW instruction fetches the next row and then the
values are set to the parameters of the function.
● DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN -> this tells the
function what to do when the computation is done (NO MORE ROWS).
● The GROUP BY, ORDER BY and HAVING clauses work with aggregate
functions.
● In Future we would like to make Custom Aggregate Functions to work
as Window Functions also.