1
0
mirror of https://github.com/MariaDB/server.git synced 2025-04-18 21:44:20 +03:00

MDEV-10862: Stored procedures: default values for parameters (optional parameters)

Implement default values for parameters of stored routines
in both default and oracle mode.

- Default values for cursor parameters are *NOT* supported yet.
- An IN parameter with DEFAULT followed by an OUT param is not supported yet.
  This combination will be enabled together with the arrow syntax:
    sp1(v=>p2)

The default values can be either literals or expressions.
When it is an expression, it is only evaluated if the parameter
has not been supplied by the caller
(important if the expression has side effects).
This commit is contained in:
Iqbal Hassan 2024-11-21 14:55:51 +08:00 committed by Alexander Barkov
parent 5a8e6230d7
commit dfdbec1636
18 changed files with 1038 additions and 21 deletions

View File

@ -1701,3 +1701,20 @@ DROP PROCEDURE p1;
#
# End of 10.5 tests
#
# Start of 11.8 tests
#
# MDEV-10862 Stored procedures: default values for parameters (optional parameters)
#
CREATE OR REPLACE PROCEDURE p1(par1 INT, par2 INT DEFAULT 1)
BEGIN
DECLARE var1 INT DEFAULT 5;
SELECT par1, par2 FROM DUAL;
END;
$$
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set default param par2@1 1
1 set var1@2 5
2 stmt 0 "SELECT par1, par2 FROM DUAL"
DROP PROCEDURE p1;
# End of 11.8 tests

View File

@ -1219,3 +1219,22 @@ DROP PROCEDURE p1;
--echo #
--echo # End of 10.5 tests
--echo #
--echo # Start of 11.8 tests
--echo #
--echo # MDEV-10862 Stored procedures: default values for parameters (optional parameters)
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(par1 INT, par2 INT DEFAULT 1)
BEGIN
DECLARE var1 INT DEFAULT 5;
SELECT par1, par2 FROM DUAL;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo # End of 11.8 tests

View File

@ -0,0 +1,133 @@
# Start of 11.8 tests
#
# MDEV-10862 Stored procedures: default values for parameters (optional parameters)
#
#
# Basic default parameter test for procedures
#
CREATE OR REPLACE PROCEDURE p1(par1 INT, par2 INT DEFAULT 1)
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
CALL p1(2,3);
par1 par2
2 3
CALL p1(2);
par1 par2
2 1
CALL p1(2,3,4);
ERROR 42000: Incorrect number of arguments for PROCEDURE test.p1; expected 2, got 3
CALL p1();
ERROR 42000: Incorrect number of arguments for PROCEDURE test.p1; expected 2, got 0
DROP PROCEDURE p1;
#
# Basic default parameter test for functions
#
CREATE OR REPLACE FUNCTION f1(par1 INT, par2 INT DEFAULT 1) RETURNS INT
RETURN par1 + par2;
$$
SELECT f1(2,3) FROM DUAL;
f1(2,3)
5
SELECT f1(2) FROM DUAL;
f1(2)
3
SELECT f1(2,3,4) FROM DUAL;
ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 2, got 3
SELECT f1() FROM DUAL;
ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 2, got 0
DROP FUNCTION f1;
#
# Test various data types
#
CREATE TABLE t1 (a INT, b VARCHAR(10));
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (a INT, b VARCHAR(10));
USE test;
CREATE OR REPLACE PROCEDURE p1(par1 INT DEFAULT 1,
par2 VARCHAR(10) DEFAULT 'abc',
par3 DATE DEFAULT '2010-01-01',
par4 DECIMAL(10,2) DEFAULT 1.23,
par5 DOUBLE DEFAULT 1.23,
par6 FLOAT DEFAULT 1.23,
par7 CHAR DEFAULT 'a',
par8 BINARY DEFAULT 'a',
par9 BLOB DEFAULT 'a',
par10 TEXT DEFAULT 'a',
par11 ENUM('a','b') DEFAULT 'a',
par12 SET('a','b') DEFAULT 'a',
par13 TIMESTAMP DEFAULT '2010-01-01 00:00:00',
par14 DATETIME DEFAULT '2010-01-01 00:00:00',
par15 TIME DEFAULT '00:00:00',
par16 YEAR DEFAULT 2010,
par17 BOOLEAN DEFAULT TRUE,
par18 TYPE OF t1.a DEFAULT 10,
par19 TYPE OF d1.t1.a DEFAULT 10,
par20 ROW TYPE OF t1 DEFAULT ROW(1, 'cde'),
par21 ROW TYPE OF d1.t1 DEFAULT ROW(1, 'cde'))
BEGIN
SELECT par1, par2, par3, par4, par5, par6, par7, par8, par9,
par10, par11, par12, par13, par14, par15, par16, par17, par18,
par19, par20.b, par21.b
FROM DUAL;
END;
$$
CALL p1();
par1 par2 par3 par4 par5 par6 par7 par8 par9 par10 par11 par12 par13 par14 par15 par16 par17 par18 par19 par20.b par21.b
1 abc 2010-01-01 1.23 1.23 1.23 a a a a a a 2010-01-01 00:00:00 2010-01-01 00:00:00 00:00:00 2010 1 10 10 cde cde
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE d1;
#
# Default parameters in package's routines
#
CREATE OR REPLACE PACKAGE p1
PROCEDURE p1(par1 INT,
par2 INT DEFAULT 2);
FUNCTION f1(par1 INT,
par2 INT DEFAULT 2) RETURNS INT;
END;
$$
CREATE OR REPLACE PACKAGE BODY p1
PROCEDURE p1(par1 INT,
par2 INT DEFAULT 2)
BEGIN
SELECT par1, par2 FROM DUAL;
END;
FUNCTION f1(par1 INT,
par2 INT DEFAULT 2) RETURNS INT
BEGIN
RETURN par1 + par2;
END;
END;
$$
CALL p1.p1(1,4);
par1 par2
1 4
CALL p1.p1(1);
par1 par2
1 2
SELECT p1.f1(1,4) FROM DUAL;
p1.f1(1,4)
5
SELECT p1.f1(1) FROM DUAL;
p1.f1(1)
3
DROP PACKAGE p1;
#
# MDEV-35925 OUT and INOUT parameters shouldn't expect a default value
#
CREATE PROCEDURE sp1(IN p1 INT DEFAULT 0, OUT p2 INT)
BEGIN
SET p2 = p2 + 1;
END;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(IN p1 INT DEFAULT 0, IN OUT p2 INT)
BEGIN
SET p2 = p2 + 1;
END;
DELIMITER ;$$
ERROR 42000: This version of MariaDB doesn't yet support 'IN sparam1 <type> DEFAULT <expr>, OUT spparam2 <type>'
# End of 11.8 tests

View File

@ -0,0 +1,142 @@
--echo # Start of 11.8 tests
--echo #
--echo # MDEV-10862 Stored procedures: default values for parameters (optional parameters)
--echo #
--echo #
--echo # Basic default parameter test for procedures
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(par1 INT, par2 INT DEFAULT 1)
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1(2,3);
CALL p1(2);
--error ER_SP_WRONG_NO_OF_ARGS
CALL p1(2,3,4);
--error ER_SP_WRONG_NO_OF_ARGS
CALL p1();
DROP PROCEDURE p1;
--echo #
--echo # Basic default parameter test for functions
--echo #
DELIMITER $$;
CREATE OR REPLACE FUNCTION f1(par1 INT, par2 INT DEFAULT 1) RETURNS INT
RETURN par1 + par2;
$$
DELIMITER ;$$
SELECT f1(2,3) FROM DUAL;
SELECT f1(2) FROM DUAL;
--error ER_SP_WRONG_NO_OF_ARGS
SELECT f1(2,3,4) FROM DUAL;
--error ER_SP_WRONG_NO_OF_ARGS
SELECT f1() FROM DUAL;
DROP FUNCTION f1;
--echo #
--echo # Test various data types
--echo #
CREATE TABLE t1 (a INT, b VARCHAR(10));
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (a INT, b VARCHAR(10));
USE test;
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(par1 INT DEFAULT 1,
par2 VARCHAR(10) DEFAULT 'abc',
par3 DATE DEFAULT '2010-01-01',
par4 DECIMAL(10,2) DEFAULT 1.23,
par5 DOUBLE DEFAULT 1.23,
par6 FLOAT DEFAULT 1.23,
par7 CHAR DEFAULT 'a',
par8 BINARY DEFAULT 'a',
par9 BLOB DEFAULT 'a',
par10 TEXT DEFAULT 'a',
par11 ENUM('a','b') DEFAULT 'a',
par12 SET('a','b') DEFAULT 'a',
par13 TIMESTAMP DEFAULT '2010-01-01 00:00:00',
par14 DATETIME DEFAULT '2010-01-01 00:00:00',
par15 TIME DEFAULT '00:00:00',
par16 YEAR DEFAULT 2010,
par17 BOOLEAN DEFAULT TRUE,
par18 TYPE OF t1.a DEFAULT 10,
par19 TYPE OF d1.t1.a DEFAULT 10,
par20 ROW TYPE OF t1 DEFAULT ROW(1, 'cde'),
par21 ROW TYPE OF d1.t1 DEFAULT ROW(1, 'cde'))
BEGIN
SELECT par1, par2, par3, par4, par5, par6, par7, par8, par9,
par10, par11, par12, par13, par14, par15, par16, par17, par18,
par19, par20.b, par21.b
FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE d1;
--echo #
--echo # Default parameters in package's routines
--echo #
DELIMITER $$;
CREATE OR REPLACE PACKAGE p1
PROCEDURE p1(par1 INT,
par2 INT DEFAULT 2);
FUNCTION f1(par1 INT,
par2 INT DEFAULT 2) RETURNS INT;
END;
$$
CREATE OR REPLACE PACKAGE BODY p1
PROCEDURE p1(par1 INT,
par2 INT DEFAULT 2)
BEGIN
SELECT par1, par2 FROM DUAL;
END;
FUNCTION f1(par1 INT,
par2 INT DEFAULT 2) RETURNS INT
BEGIN
RETURN par1 + par2;
END;
END;
$$
DELIMITER ;$$
CALL p1.p1(1,4);
CALL p1.p1(1);
SELECT p1.f1(1,4) FROM DUAL;
SELECT p1.f1(1) FROM DUAL;
DROP PACKAGE p1;
--echo #
--echo # MDEV-35925 OUT and INOUT parameters shouldn't expect a default value
--echo #
# An IN param with default followed by an OUT param
DELIMITER $$;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(IN p1 INT DEFAULT 0, OUT p2 INT)
BEGIN
SET p2 = p2 + 1;
END;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(IN p1 INT DEFAULT 0, IN OUT p2 INT)
BEGIN
SET p2 = p2 + 1;
END;
DELIMITER ;$$
--echo # End of 11.8 tests

View File

@ -1514,3 +1514,22 @@ SHOW PROCEDURE CODE p1;
Pos Instruction
0 stmt 31 "max_error_count:=10"
DROP PROCEDURE p1;
# End of 10.5 tests
# Start of 11.8 tests
#
# MDEV-10862 Stored procedures: default values for parameters (optional parameters)
#
CREATE OR REPLACE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
var1 INT DEFAULT 5;
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
SHOW PROCEDURE CODE p1;
Pos Instruction
0 set default param par2@1 1
1 set var1@2 5
2 stmt 0 "SELECT par1, par2 FROM DUAL"
DROP PROCEDURE p1;
# End of 11.8 tests

View File

@ -0,0 +1,225 @@
# Start of 11.8 tests
#
# MDEV-10862 Stored procedures: default values for parameters (optional parameters)
#
SET sql_mode=oracle;
#
# Basic default parameter test for procedures
#
CREATE OR REPLACE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
CALL p1(2,3);
par1 par2
2 3
CALL p1(2);
par1 par2
2 1
CALL p1(2,3,4);
ERROR 42000: Incorrect number of arguments for PROCEDURE test.p1; expected 2, got 3
CALL p1();
ERROR 42000: Incorrect number of arguments for PROCEDURE test.p1; expected 2, got 0
DROP PROCEDURE p1;
#
# Basic default parameter test for functions
#
CREATE OR REPLACE FUNCTION f1(par1 INT, par2 INT DEFAULT 1) RETURN INT
AS
BEGIN
RETURN par1 + par2;
END;
$$
SELECT f1(2,3) FROM DUAL;
f1(2,3)
5
SELECT f1(2) FROM DUAL;
f1(2)
3
SELECT f1(2,3,4) FROM DUAL;
ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 2, got 3
SELECT f1() FROM DUAL;
ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 2, got 0
DROP FUNCTION f1;
#
# OUT parameters cannot have default values
#
CREATE OR REPLACE PROCEDURE p1(par1 IN INT DEFAULT 1, par2 OUT INT DEFAULT 2)
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
ERROR HY000: Default/ignore value is not supported for such parameter usage
#
# INOUT parameters cannot have default values
#
CREATE OR REPLACE PROCEDURE p1(par1 INOUT INT DEFAULT 1, par2 OUT INT DEFAULT 2)
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
ERROR HY000: Default/ignore value is not supported for such parameter usage
#
# Test various data types
#
CREATE TABLE t1 (a INT, b VARCHAR(10));
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (a INT, b VARCHAR(10));
USE test;
CREATE OR REPLACE PROCEDURE p1(
par1 IN INT DEFAULT 1,
par2 IN VARCHAR(10) DEFAULT 'abc',
par3 IN DATETIME DEFAULT '2010-01-01 12:34:56',
par4 IN DECIMAL(10,2) DEFAULT 123.45,
par5 IN FLOAT DEFAULT 123.45,
par6 IN DOUBLE DEFAULT 123.45,
par7 IN CHAR DEFAULT 'a',
par8 IN BOOLEAN DEFAULT TRUE,
par9 IN ROW(a INT, b VARCHAR(10)) DEFAULT ROW(1, 'abc'),
par10 IN t1.a%TYPE DEFAULT 10,
par11 IN d1.t1.a%TYPE DEFAULT 10,
par12 IN t1%ROWTYPE DEFAULT (1, 'cde'),
par13 IN d1.t1%ROWTYPE DEFAULT (1, 'cde')
)
AS
BEGIN
SELECT par1, par2, par3, par4, par5, par6, par7, par8, par9.b, par10, par11, par12.b, par13.b FROM DUAL;
END;
$$
CALL p1();
par1 par2 par3 par4 par5 par6 par7 par8 par9.b par10 par11 par12.b par13.b
1 abc 2010-01-01 12:34:56 123.45 123.45 123.45 a 1 abc 10 10 cde cde
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE d1;
#
# Expression as default value is not evaluated if value is provided
#
CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY);
CREATE FUNCTION f1() RETURN INT
AS
BEGIN
INSERT INTO t1 VALUES (NULL);
RETURN LAST_INSERT_ID();
END;
$$
CREATE PROCEDURE p1(par1 IN INT DEFAULT f1())
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
CALL p1();
par1
1
CALL p1(10);
par1
10
CALL p1();
par1
2
DROP PROCEDURE p1;
DROP FUNCTION f1;
DROP TABLE t1;
#
# Subquery as default value
# NOTE: Oracle does not allow this
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
CREATE PROCEDURE p1(par1 IN INT DEFAULT (SELECT a FROM t1))
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
CALL p1();
par1
1
CALL p1(10);
par1
10
DROP PROCEDURE p1;
DROP TABLE t1;
#
# Default value from another parameter
# NOTE: Oracle does not allow this
#
CREATE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT par1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
CALL p1(10);
par1 par2
10 10
CALL p1(10,20);
par1 par2
10 20
DROP PROCEDURE p1;
#
# Default value referencing self
# NOTE: Oracle does not allow this
#
CREATE PROCEDURE p1(par1 IN INT DEFAULT par1)
AS
BEGIN
NULL;
END;
$$
ERROR 42000: Undeclared variable: par1
#
# Default parameters in package's routines
#
CREATE PACKAGE p1 AS
PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1);
FUNCTION f1(par1 IN INT, par2 IN INT DEFAULT 1) RETURN INT;
END p1;
$$
CREATE PACKAGE BODY p1 AS
PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
FUNCTION f1(par1 IN INT, par2 IN INT DEFAULT 1) RETURN INT
AS
BEGIN
RETURN par1 + par2;
END;
END p1;
$$
CALL p1.p1(5);
par1 par2
5 1
CALL p1.p1(5, 10);
par1 par2
5 10
SELECT p1.f1(5) FROM DUAL;
p1.f1(5)
6
SELECT p1.f1(5, 10) FROM DUAL;
p1.f1(5, 10)
15
DROP PACKAGE p1;
#
# MDEV-35925 OUT and INOUT parameters shouldn't expect a default value
#
CREATE PROCEDURE sp1(p1 IN INT DEFAULT 0, p2 OUT INT)
BEGIN
SET p2 = p2 + 1;
END;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(p1 IN INT DEFAULT 0, p2 INOUT INT)
BEGIN
SET p2 = p2 + 1;
END;
DELIMITER ;$$
ERROR 42000: This version of MariaDB doesn't yet support 'sparam1 IN <type> DEFAULT <expr>, spparam2 OUT <type>'
# End of 11.8 tests

View File

@ -1085,4 +1085,24 @@ DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo # End of 10.5 tests
--echo # Start of 11.8 tests
--echo #
--echo # MDEV-10862 Stored procedures: default values for parameters (optional parameters)
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
var1 INT DEFAULT 5;
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
DELIMITER ;$$
SHOW PROCEDURE CODE p1;
DROP PROCEDURE p1;
--echo # End of 11.8 tests

View File

@ -0,0 +1,247 @@
--echo # Start of 11.8 tests
--echo #
--echo # MDEV-10862 Stored procedures: default values for parameters (optional parameters)
--echo #
SET sql_mode=oracle;
--echo #
--echo # Basic default parameter test for procedures
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1(2,3);
CALL p1(2);
--error ER_SP_WRONG_NO_OF_ARGS
CALL p1(2,3,4);
--error ER_SP_WRONG_NO_OF_ARGS
CALL p1();
DROP PROCEDURE p1;
--echo #
--echo # Basic default parameter test for functions
--echo #
DELIMITER $$;
CREATE OR REPLACE FUNCTION f1(par1 INT, par2 INT DEFAULT 1) RETURN INT
AS
BEGIN
RETURN par1 + par2;
END;
$$
DELIMITER ;$$
SELECT f1(2,3) FROM DUAL;
SELECT f1(2) FROM DUAL;
--error ER_SP_WRONG_NO_OF_ARGS
SELECT f1(2,3,4) FROM DUAL;
--error ER_SP_WRONG_NO_OF_ARGS
SELECT f1() FROM DUAL;
DROP FUNCTION f1;
--echo #
--echo # OUT parameters cannot have default values
--echo #
DELIMITER $$;
--error ER_INVALID_DEFAULT_PARAM
CREATE OR REPLACE PROCEDURE p1(par1 IN INT DEFAULT 1, par2 OUT INT DEFAULT 2)
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
DELIMITER ;$$
--echo #
--echo # INOUT parameters cannot have default values
--echo #
DELIMITER $$;
--error ER_INVALID_DEFAULT_PARAM
CREATE OR REPLACE PROCEDURE p1(par1 INOUT INT DEFAULT 1, par2 OUT INT DEFAULT 2)
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
DELIMITER ;$$
--echo #
--echo # Test various data types
--echo #
CREATE TABLE t1 (a INT, b VARCHAR(10));
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (a INT, b VARCHAR(10));
USE test;
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1(
par1 IN INT DEFAULT 1,
par2 IN VARCHAR(10) DEFAULT 'abc',
par3 IN DATETIME DEFAULT '2010-01-01 12:34:56',
par4 IN DECIMAL(10,2) DEFAULT 123.45,
par5 IN FLOAT DEFAULT 123.45,
par6 IN DOUBLE DEFAULT 123.45,
par7 IN CHAR DEFAULT 'a',
par8 IN BOOLEAN DEFAULT TRUE,
par9 IN ROW(a INT, b VARCHAR(10)) DEFAULT ROW(1, 'abc'),
par10 IN t1.a%TYPE DEFAULT 10,
par11 IN d1.t1.a%TYPE DEFAULT 10,
par12 IN t1%ROWTYPE DEFAULT (1, 'cde'),
par13 IN d1.t1%ROWTYPE DEFAULT (1, 'cde')
)
AS
BEGIN
SELECT par1, par2, par3, par4, par5, par6, par7, par8, par9.b, par10, par11, par12.b, par13.b FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1();
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE d1;
--echo #
--echo # Expression as default value is not evaluated if value is provided
--echo #
CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY);
DELIMITER $$;
CREATE FUNCTION f1() RETURN INT
AS
BEGIN
INSERT INTO t1 VALUES (NULL);
RETURN LAST_INSERT_ID();
END;
$$
CREATE PROCEDURE p1(par1 IN INT DEFAULT f1())
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
DELIMITER ;$$
--disable_ps_protocol
CALL p1();
CALL p1(10);
CALL p1();
--enable_ps_protocol
DROP PROCEDURE p1;
DROP FUNCTION f1;
DROP TABLE t1;
--echo #
--echo # Subquery as default value
--echo # NOTE: Oracle does not allow this
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1);
DELIMITER $$;
CREATE PROCEDURE p1(par1 IN INT DEFAULT (SELECT a FROM t1))
AS
BEGIN
SELECT par1 FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1();
CALL p1(10);
DROP PROCEDURE p1;
DROP TABLE t1;
--echo #
--echo # Default value from another parameter
--echo # NOTE: Oracle does not allow this
--echo #
DELIMITER $$;
CREATE PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT par1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
$$
DELIMITER ;$$
CALL p1(10);
CALL p1(10,20);
DROP PROCEDURE p1;
--echo #
--echo # Default value referencing self
--echo # NOTE: Oracle does not allow this
--echo #
DELIMITER $$;
--error ER_SP_UNDECLARED_VAR
CREATE PROCEDURE p1(par1 IN INT DEFAULT par1)
AS
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--echo #
--echo # Default parameters in package's routines
--echo #
DELIMITER $$;
CREATE PACKAGE p1 AS
PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1);
FUNCTION f1(par1 IN INT, par2 IN INT DEFAULT 1) RETURN INT;
END p1;
$$
CREATE PACKAGE BODY p1 AS
PROCEDURE p1(par1 IN INT, par2 IN INT DEFAULT 1)
AS
BEGIN
SELECT par1, par2 FROM DUAL;
END;
FUNCTION f1(par1 IN INT, par2 IN INT DEFAULT 1) RETURN INT
AS
BEGIN
RETURN par1 + par2;
END;
END p1;
$$
DELIMITER ;$$
CALL p1.p1(5);
CALL p1.p1(5, 10);
SELECT p1.f1(5) FROM DUAL;
SELECT p1.f1(5, 10) FROM DUAL;
DROP PACKAGE p1;
--echo #
--echo # MDEV-35925 OUT and INOUT parameters shouldn't expect a default value
--echo #
# An IN param with default followed by an OUT param
DELIMITER $$;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(p1 IN INT DEFAULT 0, p2 OUT INT)
BEGIN
SET p2 = p2 + 1;
END;
--error ER_NOT_SUPPORTED_YET
CREATE PROCEDURE sp1(p1 IN INT DEFAULT 0, p2 INOUT INT)
BEGIN
SET p2 = p2 + 1;
END;
DELIMITER ;$$
--echo # End of 11.8 tests

View File

@ -1894,6 +1894,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
{
ulonglong UNINIT_VAR(binlog_save_options);
bool need_binlog_call= FALSE;
uint params= m_pcont->context_var_count();
uint default_params= m_pcont->default_context_var_count();
uint arg_no;
sp_rcontext *octx = thd->spcont;
char buf[STRING_BUFFER_USUAL_SIZE];
@ -1912,7 +1914,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
If it is not, use my_error() to report an error, or it will not terminate
the invoking query properly.
*/
if (argcount != m_pcont->context_var_count())
if (argcount < (params - default_params) ||
argcount > params)
{
/*
Need to use my_error here, or it will not terminate the
@ -1964,6 +1967,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (err_status)
goto err_with_cleanup;
}
(*func_ctx)->set_inited_param_count(arg_no);
/*
If row-based binlogging, we don't need to binlog the function's call, let
@ -2142,6 +2146,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
{
bool err_status= FALSE;
uint params = m_pcont->context_var_count();
uint default_params= m_pcont->default_context_var_count();
/* Query start time may be reset in a multi-stmt SP; keep this for later. */
ulonglong utime_before_sp_exec= thd->utime_after_lock;
sp_rcontext *save_spcont, *octx;
@ -2155,7 +2160,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (m_parent && m_parent->instantiate_if_needed(thd))
DBUG_RETURN(true);
if (args->elements != params)
if (args->elements < (params - default_params) ||
args->elements > params)
{
my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE",
ErrConvDQName(this).ptr(), params, args->elements);
@ -2223,6 +2229,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (err_status)
break;
}
nctx->set_inited_param_count(args->elements);
/*
Okay, got values for all arguments. Close tables that might be used by

View File

@ -1131,6 +1131,50 @@ sp_instr_set::print(String *str)
}
int sp_instr_set_default_param::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_set_default_param::execute");
DBUG_PRINT("info", ("offset: %u", m_offset));
auto rctx= get_rcontext(thd);
if (m_offset < rctx->get_inited_param_count())
{
// NOP
*nextp= m_ip + 1;
DBUG_RETURN(0);
}
DBUG_RETURN(m_lex_keeper.validate_lex_and_exec_core(thd, nextp, true, this));
}
void
sp_instr_set_default_param::print(String *str)
{
/* set name@offset ... */
size_t rsrv = SP_INSTR_UINT_MAXLEN+20;
sp_variable *var = m_ctx->find_variable(m_offset);
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
/* 'var' should always be non-null, but just in case... */
if (var)
rsrv+= var->name.length + prefix->length;
if (str->reserve(rsrv))
return;
str->qs_append(STRING_WITH_LEN("set default param "));
str->qs_append(prefix->str, prefix->length);
if (var)
{
str->qs_append(&var->name);
str->qs_append('@');
}
str->qs_append(m_offset);
str->qs_append(' ');
m_value->print(str, enum_query_type(QT_ORDINARY |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
}
/*
sp_instr_set_field class functions
*/

View File

@ -663,6 +663,31 @@ public:
}; // class sp_instr_set : public sp_lex_instr
/*
This instr initializes parameters with default values
if it's parameter's spvar was not set by caller.
*/
class sp_instr_set_default_param : public sp_instr_set
{
/**< Prevent use of these */
sp_instr_set_default_param(const sp_instr_set_default_param &);
void operator=(sp_instr_set_default_param &);
public:
sp_instr_set_default_param(uint ip, sp_pcontext *ctx,
const Sp_rcontext_handler *rh,
uint offset, Item *val,
LEX *lex, bool lex_resp,
const LEX_CSTRING &expr_str)
: sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp, expr_str)
{}
virtual ~sp_instr_set_default_param() = default;
int execute(THD *thd, uint *nextp) override;
void print(String *str) override;
};
/*
This class handles assignments of a ROW fields:
DECLARE rec ROW (a INT,b INT);

View File

@ -269,6 +269,23 @@ sp_variable *sp_pcontext::find_variable(uint offset) const
}
uint sp_pcontext::default_context_var_count() const
{
uint default_params= 0;
for (uint i= 0; i< context_var_count(); i++)
{
sp_variable *spvar= get_context_variable(i);
if (!spvar)
break;
if (spvar->default_value)
default_params++;
}
return default_params;
}
sp_variable *sp_pcontext::add_variable(THD *thd, const LEX_CSTRING *name)
{
sp_variable *p=

View File

@ -481,6 +481,9 @@ public:
return m_vars.at(i);
}
/// @return the number of variables with default values in this context.
uint default_context_var_count() const;
/*
Return the i-th last context variable.
If i is 0, then return the very last variable in m_vars.

View File

@ -72,7 +72,8 @@ sp_rcontext::sp_rcontext(sp_head *owner,
m_return_value_set(false),
m_in_sub_stmt(in_sub_stmt),
m_handlers(PSI_INSTRUMENT_MEM), m_handler_call_stack(PSI_INSTRUMENT_MEM),
m_ccount(0)
m_ccount(0),
m_inited_params_count(0)
{
}

View File

@ -210,6 +210,14 @@ public:
bool is_return_value_set() const
{ return m_return_value_set; }
/////////////////////////////////////////////////////////////////////////
// Parameters.
/////////////////////////////////////////////////////////////////////////
uint get_inited_param_count() const
{ return m_inited_params_count; }
void set_inited_param_count(uint count)
{ m_inited_params_count= count; }
/////////////////////////////////////////////////////////////////////////
// SQL-handlers.
/////////////////////////////////////////////////////////////////////////
@ -401,6 +409,10 @@ private:
/// Array of CASE expression holders.
Bounds_checked_array<Item_cache *> m_case_expr_holders;
/// Number of parameters initialized by the callee. This is used to
/// determine which parameters should be initialized with the default value.
uint m_inited_params_count;
}; // class sp_rcontext : public Sql_alloc
#endif /* _SP_RCONTEXT_H_ */

View File

@ -6550,6 +6550,58 @@ bool LEX::sp_param_fill_definition(sp_variable *spvar,
}
bool LEX::sp_param_set_default_and_finalize(sp_variable *spvar,
Item *default_value,
const LEX_CSTRING &expr_str)
{
DBUG_ASSERT(spvar);
if (default_value)
{
if (spvar->mode != sp_variable::MODE_IN)
{
// PLS-00230: OUT and IN OUT formal parameters may not have default expressions
my_error(ER_INVALID_DEFAULT_PARAM, MYF(0));
return true;
}
spvar->default_value= default_value;
sp_instr_set_default_param *is= new (thd->mem_root)
sp_instr_set_default_param(sphead->instructions(),
spcont, &sp_rcontext_handler_local,
spvar->offset, default_value,
this, true, expr_str);
if (unlikely(is == NULL || sphead->add_instr(is)))
return true;
}
else if (spcont->context_var_count() > 1)
{
if (unlikely(spcont->get_last_context_variable(1)->default_value))
{
/*
Previous formal parameter has a default value, but this one doesn't.
*/
if (spvar->mode == sp_variable::MODE_IN)
my_error(ER_NO_DEFAULT, MYF(0), spvar->name.str);
else if (thd->variables.sql_mode & MODE_ORACLE)
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"sparam1 IN <type> DEFAULT <expr>, spparam2 OUT <type>");
else
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"IN sparam1 <type> DEFAULT <expr>, OUT spparam2 <type>");
return true;
}
}
spcont->declare_var_boundary(0);
if (sphead->restore_lex(thd))
return true;
return false;
}
bool LEX::sf_return_fill_definition(const Lex_field_type_st &def)
{
return

View File

@ -3789,6 +3789,9 @@ public:
sp_variable *sp_param_init(LEX_CSTRING *name);
bool sp_param_fill_definition(sp_variable *spvar,
const Lex_field_type_st &def);
bool sp_param_set_default_and_finalize(sp_variable *spvar,
Item *default_value,
const LEX_CSTRING &expr_str);
bool sf_return_fill_definition(const Lex_field_type_st &def);
bool sf_return_fill_definition_row(Row_definition_list *def);
bool sf_return_fill_definition_rowtype_of(const Qualified_column_ident &col);

View File

@ -1874,6 +1874,8 @@ rule:
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
%type <spname> sp_name
%type <spvar> sp_param_name sp_param_name_and_mode sp_param
%type <spvar> sp_param_init_vars sp_param_default
%type <spvar> sp_param_name_and_mode_init_vars
%type <spvar> sp_param_anchored
%type <for_loop> sp_for_loop_index_and_bounds
%type <for_loop_bounds> sp_for_loop_bounds
@ -3379,7 +3381,12 @@ sp_fdparam_list:
;
sp_fdparams:
sp_fdparams ',' sp_param
sp_fdparams ',' sp_param_default
| sp_param_default
;
sp_fdparams_no_default:
sp_fdparams_no_default ',' sp_param
| sp_param
;
@ -3391,6 +3398,14 @@ sp_param_name:
}
;
sp_param_name_and_mode_init_vars:
sp_param_name_and_mode
{
Lex->sp_variable_declarations_init(thd, 1);
$$= $1;
}
;
/* Stored PROCEDURE parameter declaration list */
sp_pdparam_list:
/* Empty */
@ -3398,8 +3413,8 @@ sp_pdparam_list:
;
sp_pdparams:
sp_pdparams ',' sp_param
| sp_param
sp_pdparams ',' sp_param_default
| sp_param_default
;
sp_parameter_type:
@ -3420,6 +3435,22 @@ sp_parenthesized_pdparam_list:
}
;
sp_param_default:
sp_param_init_vars sp_opt_default
{
if (unlikely(Lex->sp_param_set_default_and_finalize(($$= $1), $2.expr, $2.expr_str)))
MYSQL_YYABORT;
}
;
sp_param:
sp_param_init_vars
{
if (unlikely(Lex->sp_param_set_default_and_finalize(($$= $1), nullptr, empty_clex_str)))
MYSQL_YYABORT;
}
;
sp_parenthesized_fdparam_list:
'(' sp_fdparam_list ')'
;
@ -3580,7 +3611,7 @@ sp_decl_handler:
opt_parenthesized_cursor_formal_parameters:
/* Empty */
| '(' sp_fdparams ')'
| '(' sp_fdparams_no_default ')'
;
@ -18983,13 +19014,13 @@ sp_param_name_and_mode:
| sp_param_name
;
sp_param:
sp_param_name_and_mode field_type
sp_param_init_vars:
sp_param_name_and_mode_init_vars field_type
{
if (unlikely(Lex->sp_param_fill_definition($$= $1, $2)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode ROW_SYM row_type_body
| sp_param_name_and_mode_init_vars ROW_SYM row_type_body
{
if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3)))
MYSQL_YYABORT;
@ -18998,25 +19029,25 @@ sp_param:
;
sp_param_anchored:
sp_param_name_and_mode TYPE_SYM OF_SYM ident '.' ident
sp_param_name_and_mode_init_vars TYPE_SYM OF_SYM ident '.' ident
{
if (unlikely(Lex->sphead->spvar_fill_type_reference(thd,
$$= $1, $4,
$6)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode TYPE_SYM OF_SYM ident '.' ident '.' ident
| sp_param_name_and_mode_init_vars TYPE_SYM OF_SYM ident '.' ident '.' ident
{
if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1,
$4, $6, $8)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode ROW_SYM TYPE_SYM OF_SYM ident
| sp_param_name_and_mode_init_vars ROW_SYM TYPE_SYM OF_SYM ident
{
if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode ROW_SYM TYPE_SYM OF_SYM ident '.' ident
| sp_param_name_and_mode_init_vars ROW_SYM TYPE_SYM OF_SYM ident '.' ident
{
if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5, $7)))
MYSQL_YYABORT;
@ -19861,13 +19892,13 @@ sp_param_name_and_mode:
}
;
sp_param:
sp_param_name_and_mode field_type
sp_param_init_vars:
sp_param_name_and_mode_init_vars field_type
{
if (unlikely(Lex->sp_param_fill_definition($$= $1, $2)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode ROW_SYM row_type_body
| sp_param_name_and_mode_init_vars ROW_SYM row_type_body
{
if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3)))
MYSQL_YYABORT;
@ -19876,22 +19907,22 @@ sp_param:
;
sp_param_anchored:
sp_param_name_and_mode sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
sp_param_name_and_mode_init_vars sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
{
if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
| sp_param_name_and_mode_init_vars sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
{
if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4, $6)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
| sp_param_name_and_mode_init_vars sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
{
if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2)))
MYSQL_YYABORT;
}
| sp_param_name_and_mode sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
| sp_param_name_and_mode_init_vars sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
{
if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2, $4)))
MYSQL_YYABORT;