Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/mysql/plugin_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,20 @@

#include <mysql/plugin.h>

class Create_func;

/*
API for function plugins. (MariaDB_FUNCTION_PLUGIN)

An aggregate function's Create_func must create an Item_sum_plugin descendant.
Aggregate implementations use the normal Item_sum lifecycle and
aggregation_arg() to read values, including values replayed by DISTINCT. They
can implement supports_removal() and remove() for moving window frames, and
val_native() to preserve a pluggable result type.

The server keeps the function plugin and data type plugins referenced by an
Item_sum_plugin loaded for the lifetime of the prepared Item tree and its
execution copies.
*/
#define MariaDB_FUNCTION_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)

Expand Down
1 change: 1 addition & 0 deletions include/mysql/plugin_function.h.pp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@
const void *ha_data);
void thd_wakeup_subsequent_commits(THD* thd, int wakeup_error);
}
class Create_func;
class Plugin_function
{
int m_interface_version;
Expand Down
203 changes: 203 additions & 0 deletions plugin/func_test/mysql-test/func_test/function_plugin.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1, 1), (2, 1), (NULL, 1), (3, 2);
SELECT test_plugin_count(a) FROM t1;
test_plugin_count(a)
3
SELECT b, test_plugin_count(a) FROM t1 GROUP BY b ORDER BY b;
b test_plugin_count(a)
1 2
2 1
SELECT test_plugin_count(DISTINCT a) FROM
(SELECT 1 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT NULL) dt;
test_plugin_count(DISTINCT a)
2
SELECT test_plugin_count(a) FROM t1 WHERE FALSE;
test_plugin_count(a)
0
SELECT test_plugin_count(a) FROM t1 WHERE a IS NULL;
test_plugin_count(a)
0
SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'derived_merge=off';
SELECT b, test_plugin_count(a)
FROM (SELECT a, b FROM t1) AS dt
GROUP BY b ORDER BY b;
b test_plugin_count(a)
1 2
2 1
SET optimizer_switch= @save_optimizer_switch;
PREPARE stmt FROM
'SELECT test_plugin_count(a) FROM t1 WHERE b = ?';
SET @b= 1;
EXECUTE stmt USING @b;
test_plugin_count(a)
2
SET @b= 2;
EXECUTE stmt USING @b;
test_plugin_count(a)
1
SET @b= 3;
EXECUTE stmt USING @b;
test_plugin_count(a)
0
DEALLOCATE PREPARE stmt;
SELECT a, test_plugin_count(a) OVER (ORDER BY a) FROM t1 ORDER BY a;
a test_plugin_count(a) OVER (ORDER BY a)
NULL 0
1 1
2 2
3 3
CREATE TABLE t_window (id INT, part INT, value INT);
INSERT INTO t_window VALUES
(1, 1, 10), (2, 1, NULL), (3, 1, 30), (4, 1, 40),
(5, 2, NULL), (6, 2, 60);
SELECT id, part, value,
test_plugin_count(value) OVER (
PARTITION BY part ORDER BY id
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS cnt
FROM t_window ORDER BY id;
id part value cnt
1 1 10 1
2 1 NULL 2
3 1 30 2
4 1 40 2
5 2 NULL 1
6 2 60 1
SELECT test_plugin_count(DISTINCT a) OVER () FROM t1;
ERROR 42000: This version of MariaDB doesn't yet support 'plugin aggregate with DISTINCT as window function'
SELECT sysconst_test() OVER ();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'OVER ()' at line 1
SELECT strnxfrm(DISTINCT 'a', 1, 1, 0);
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
CREATE TABLE t_uuid (id INT, grp INT, value UUID);
INSERT INTO t_uuid VALUES
(1, 1, NULL),
(2, 1, '00000000-0000-0000-0000-000000000001'),
(3, 2, '00000000-0000-0000-0000-000000000002'),
(4, 2, NULL),
(5, 3, NULL);
SELECT test_plugin_first(value) FROM t_uuid WHERE grp = 1;
test_plugin_first(value)
00000000-0000-0000-0000-000000000001
SELECT grp, test_plugin_first(value) FROM t_uuid GROUP BY grp ORDER BY grp;
grp test_plugin_first(value)
1 00000000-0000-0000-0000-000000000001
2 00000000-0000-0000-0000-000000000002
3 NULL
SELECT id, grp, test_plugin_first(value) OVER (
PARTITION BY grp ORDER BY id
ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS value
FROM t_uuid ORDER BY id;
id grp value
1 1 00000000-0000-0000-0000-000000000001
2 1 00000000-0000-0000-0000-000000000001
3 2 00000000-0000-0000-0000-000000000002
4 2 NULL
5 3 NULL
SELECT test_plugin_count(DISTINCT value) FROM t_uuid;
test_plugin_count(DISTINCT value)
2
SELECT test_plugin_first(DISTINCT value) FROM
(SELECT value FROM t_uuid WHERE id = 2
UNION ALL
SELECT value FROM t_uuid WHERE id = 2) AS dt;
test_plugin_first(DISTINCT value)
00000000-0000-0000-0000-000000000001
SELECT test_plugin_first(DISTINCT value) =
(SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid WHERE grp = 1;
test_plugin_first(DISTINCT value) =
(SELECT value FROM t_uuid WHERE id = 2)
1
SELECT test_plugin_first(value) IS NULL FROM t_uuid WHERE FALSE;
test_plugin_first(value) IS NULL
1
SELECT test_plugin_first(value) IS NULL FROM t_uuid WHERE grp = 3;
test_plugin_first(value) IS NULL
1
SELECT test_plugin_first(value) =
(SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid WHERE grp = 1;
test_plugin_first(value) =
(SELECT value FROM t_uuid WHERE id = 2)
1
SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'derived_merge=off';
SELECT value, value = (SELECT value FROM t_uuid WHERE id = 3)
FROM
(SELECT test_plugin_first(value) AS value
FROM t_uuid WHERE grp = 2) AS dt;
value value = (SELECT value FROM t_uuid WHERE id = 3)
00000000-0000-0000-0000-000000000002 1
SET optimizer_switch= @save_optimizer_switch;
CREATE TABLE t_uuid_aggregate AS
SELECT grp, test_plugin_first(value) AS value
FROM t_uuid GROUP BY grp;
SHOW CREATE TABLE t_uuid_aggregate;
Table Create Table
t_uuid_aggregate CREATE TABLE `t_uuid_aggregate` (
`grp` int(11) DEFAULT NULL,
`value` uuid DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
SELECT * FROM t_uuid_aggregate ORDER BY grp;
grp value
1 00000000-0000-0000-0000-000000000001
2 00000000-0000-0000-0000-000000000002
3 NULL
CREATE TABLE t_uuid_result (value UUID);
INSERT INTO t_uuid_result
SELECT test_plugin_first(value) FROM t_uuid WHERE grp = 1;
SELECT value, value = (SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid_result;
value value = (SELECT value FROM t_uuid WHERE id = 2)
00000000-0000-0000-0000-000000000001 1
CREATE TABLE t_blob (value TEXT);
INSERT INTO t_blob VALUES ('a'), ('a'), ('b'), (NULL);
SELECT test_plugin_count(DISTINCT value) FROM t_blob;
test_plugin_count(DISTINCT value)
2
SELECT test_plugin_first(DISTINCT value) IS NOT NULL FROM t_blob;
test_plugin_first(DISTINCT value) IS NOT NULL
1
INSTALL SONAME 'type_test';
PREPARE type_stmt FROM
'SELECT test_plugin_first(CAST(1 AS test_int8))';
UNINSTALL PLUGIN test_double;
UNINSTALL PLUGIN test_int8;
EXECUTE type_stmt;
test_plugin_first(CAST(1 AS test_int8))
1
DEALLOCATE PREPARE type_stmt;
INSTALL SONAME 'type_test';
UNINSTALL SONAME 'type_test';
DROP TABLE t_blob, t_uuid_result, t_uuid_aggregate, t_uuid, t_window;
SELECT GET_LOCK('function_plugin_lock', 10);
GET_LOCK('function_plugin_lock', 10)
1
connect con1,localhost,root,,;
connection con1;
SELECT test_plugin_count(IF(GET_LOCK('function_plugin_lock', 10), a, a)) FROM t1;
connection default;
UNINSTALL SONAME 'func_test';
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
SELECT RELEASE_LOCK('function_plugin_lock');
RELEASE_LOCK('function_plugin_lock')
1
connection con1;
test_plugin_count(IF(GET_LOCK('function_plugin_lock', 10), a, a))
3
disconnect con1;
connection default;
INSTALL SONAME 'func_test';
PREPARE function_stmt FROM
'SELECT test_plugin_count(a) FROM t1';
UNINSTALL SONAME 'func_test';
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
EXECUTE function_stmt;
test_plugin_count(a)
3
DEALLOCATE PREPARE function_stmt;
INSTALL SONAME 'func_test';
DROP TABLE t1;
151 changes: 151 additions & 0 deletions plugin/func_test/mysql-test/func_test/function_plugin.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
--source include/have_udf.inc

--disable_query_log
if (`SELECT COUNT(*) FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME='test_plugin_count'`)
{
UNINSTALL SONAME 'func_test';
}
INSTALL SONAME 'func_test';
--enable_query_log

CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1, 1), (2, 1), (NULL, 1), (3, 2);

SELECT test_plugin_count(a) FROM t1;
SELECT b, test_plugin_count(a) FROM t1 GROUP BY b ORDER BY b;
SELECT test_plugin_count(DISTINCT a) FROM
(SELECT 1 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT NULL) dt;
SELECT test_plugin_count(a) FROM t1 WHERE FALSE;
SELECT test_plugin_count(a) FROM t1 WHERE a IS NULL;

SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'derived_merge=off';
SELECT b, test_plugin_count(a)
FROM (SELECT a, b FROM t1) AS dt
GROUP BY b ORDER BY b;
SET optimizer_switch= @save_optimizer_switch;

PREPARE stmt FROM
'SELECT test_plugin_count(a) FROM t1 WHERE b = ?';
SET @b= 1;
EXECUTE stmt USING @b;
SET @b= 2;
EXECUTE stmt USING @b;
SET @b= 3;
EXECUTE stmt USING @b;
DEALLOCATE PREPARE stmt;

SELECT a, test_plugin_count(a) OVER (ORDER BY a) FROM t1 ORDER BY a;

CREATE TABLE t_window (id INT, part INT, value INT);
INSERT INTO t_window VALUES
(1, 1, 10), (2, 1, NULL), (3, 1, 30), (4, 1, 40),
(5, 2, NULL), (6, 2, 60);
SELECT id, part, value,
test_plugin_count(value) OVER (
PARTITION BY part ORDER BY id
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS cnt
FROM t_window ORDER BY id;

--error ER_NOT_SUPPORTED_YET
SELECT test_plugin_count(DISTINCT a) OVER () FROM t1;

--error ER_PARSE_ERROR
SELECT sysconst_test() OVER ();
--error ER_PARSE_ERROR
SELECT strnxfrm(DISTINCT 'a', 1, 1, 0);

CREATE TABLE t_uuid (id INT, grp INT, value UUID);
INSERT INTO t_uuid VALUES
(1, 1, NULL),
(2, 1, '00000000-0000-0000-0000-000000000001'),
(3, 2, '00000000-0000-0000-0000-000000000002'),
(4, 2, NULL),
(5, 3, NULL);

SELECT test_plugin_first(value) FROM t_uuid WHERE grp = 1;
SELECT grp, test_plugin_first(value) FROM t_uuid GROUP BY grp ORDER BY grp;
SELECT id, grp, test_plugin_first(value) OVER (
PARTITION BY grp ORDER BY id
ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS value
FROM t_uuid ORDER BY id;
SELECT test_plugin_count(DISTINCT value) FROM t_uuid;
SELECT test_plugin_first(DISTINCT value) FROM
(SELECT value FROM t_uuid WHERE id = 2
UNION ALL
SELECT value FROM t_uuid WHERE id = 2) AS dt;
SELECT test_plugin_first(DISTINCT value) =
(SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid WHERE grp = 1;
SELECT test_plugin_first(value) IS NULL FROM t_uuid WHERE FALSE;
SELECT test_plugin_first(value) IS NULL FROM t_uuid WHERE grp = 3;
SELECT test_plugin_first(value) =
(SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid WHERE grp = 1;

SET @save_optimizer_switch= @@optimizer_switch;
SET optimizer_switch= 'derived_merge=off';
SELECT value, value = (SELECT value FROM t_uuid WHERE id = 3)
FROM
(SELECT test_plugin_first(value) AS value
FROM t_uuid WHERE grp = 2) AS dt;
SET optimizer_switch= @save_optimizer_switch;

CREATE TABLE t_uuid_aggregate AS
SELECT grp, test_plugin_first(value) AS value
FROM t_uuid GROUP BY grp;
SHOW CREATE TABLE t_uuid_aggregate;
SELECT * FROM t_uuid_aggregate ORDER BY grp;

CREATE TABLE t_uuid_result (value UUID);
INSERT INTO t_uuid_result
SELECT test_plugin_first(value) FROM t_uuid WHERE grp = 1;
SELECT value, value = (SELECT value FROM t_uuid WHERE id = 2)
FROM t_uuid_result;

CREATE TABLE t_blob (value TEXT);
INSERT INTO t_blob VALUES ('a'), ('a'), ('b'), (NULL);
SELECT test_plugin_count(DISTINCT value) FROM t_blob;
SELECT test_plugin_first(DISTINCT value) IS NOT NULL FROM t_blob;

INSTALL SONAME 'type_test';
PREPARE type_stmt FROM
'SELECT test_plugin_first(CAST(1 AS test_int8))';
UNINSTALL PLUGIN test_double;
UNINSTALL PLUGIN test_int8;
EXECUTE type_stmt;
DEALLOCATE PREPARE type_stmt;
INSTALL SONAME 'type_test';
UNINSTALL SONAME 'type_test';

DROP TABLE t_blob, t_uuid_result, t_uuid_aggregate, t_uuid, t_window;
SELECT GET_LOCK('function_plugin_lock', 10);
--connect (con1,localhost,root,,)
--connection con1
--send SELECT test_plugin_count(IF(GET_LOCK('function_plugin_lock', 10), a, a)) FROM t1
--connection default
let $wait_condition=
SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE STATE = 'User lock' AND INFO LIKE 'SELECT test_plugin_count%';
--source include/wait_condition.inc
UNINSTALL SONAME 'func_test';
SELECT RELEASE_LOCK('function_plugin_lock');
--connection con1
--reap
--disconnect con1
--connection default
INSTALL SONAME 'func_test';

PREPARE function_stmt FROM
'SELECT test_plugin_count(a) FROM t1';
UNINSTALL SONAME 'func_test';
EXECUTE function_stmt;
DEALLOCATE PREPARE function_stmt;
INSTALL SONAME 'func_test';
DROP TABLE t1;
--disable_query_log
UNINSTALL SONAME 'func_test';
INSTALL SONAME 'func_test';
DELETE FROM mysql.plugin WHERE dl='func_test.so';
--enable_query_log
Loading
Loading