mirror of
https://github.com/MariaDB/server.git
synced 2025-02-21 21:03:09 +01:00

This patch adds support for SYS_REFCURSOR (a weakly typed cursor) for both sql_mode=ORACLE and sql_mode=DEFAULT. Works as a regular stored routine variable, parameter and return value: - can be passed as an IN parameter to stored functions and procedures - can be passed as an OUT parameter to stored procedures - can be returned from a stored function Note, strongly typed REF CURSOR will be added separately. The implementation consists of the following parts: - A new class sp_cursor_array deriving from Dynamic_array - A new member THD::m_session_cursors of the sp_cursor_array data type. - A new data type handler Type_handler_sys_refcursor. It is designed to store an uint16 index - the position of the cursor in THD::m_session_cursors. - Type_handler_sys_refcursor suppresses some derived numeric features. When a SYS_REFCURSOR variable is used as an integer an error is raised. - A new abstract class sp_instr_fetch_cursor. It's needed to share the common code between "OPEN cur" (for static cursors) and "OPER cur FOR stmt" (for SYS_REFCURSORs). - New sp_instr classes: * sp_instr_copen_by_ref - OPEN sys_ref_curor FOR stmt; * sp_instr_cfetch_by_ref - FETCH sys_ref_cursor INTO targets; * sp_instr_cclose_by_ref - CLOSE sys_ref_cursor; - New methods in LEX: * sp_open_cursor_for_stmt - handles "OPER sys_ref_cursor FOR stmt". * sp_add_instr_fetch_cursor - "FETCH cur INTO targets" for both static cursors and SYS_REFCURSORs. * sp_close - handles "CLOSE cur" both for static cursors and SYS_REFCURSORs. - Changes in cursor functions to handle both static cursors and SYS_REFCURSORs: * Item_func_cursor_isopen * Item_func_cursor_found * Item_func_cursor_notfound * Item_func_cursor_rowcount - A new system variable @@max_open_cursors - to limit the number of cursors (static and SYS_REFCURSORs) opened at the same time. Its allowed range is [0-65536], with 50 by default. - A new virtual method Type_handler::can_return_bool() telling if Item::val_bool() can be used. - New methods in Sp_rcontext_handlers: * get_cursor() * get_cursor_by_ref() - A new class Sp_rcontext_handler_session to handle session-wide cursors
98 lines
3 KiB
C++
98 lines
3 KiB
C++
/*
|
|
Copyright (c) 2025, MariaDB Corporation.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
|
|
#ifdef MYSQL_SERVER
|
|
#include "mariadb.h"
|
|
#include "sql_class.h"
|
|
|
|
|
|
/*
|
|
Find a cursor available for open.
|
|
@param thd - the current THD
|
|
@param ref - the field behind a SYS_REFCURSOR SP variable
|
|
*/
|
|
sp_cursor *sp_cursor_array::get_cursor_by_ref(THD *thd,
|
|
Field *ref,
|
|
bool for_open)
|
|
{
|
|
uint pos;
|
|
if (!Sp_rcontext_handler::dereference(ref, &pos, (uint) elements()))
|
|
{
|
|
/*
|
|
"ref" points to an initialized sp_cursor. It can be closed or open.
|
|
Two consequent OPEN (without a CLOSE in between) are allowed
|
|
for SYS_REFCURSORs (unlike for static CURSORs).
|
|
Close the first cursor automatically if it's open, e.g.:
|
|
OPEN c FOR SELECT 1;
|
|
OPEN c FOR SELECT 2;
|
|
Let's also reuse the same sp_cursor instance
|
|
to guarantee cursor aliasing works as expected:
|
|
OPEN c0 FOR SELECT 1;
|
|
SET c1= c0; -- Creating an alias
|
|
OPEN c0 FOR SELECT 2; -- Reopening affects both c0 and c1
|
|
FETCH c1 INTO a; -- Fetches "2", from the second "OPEN c0"
|
|
*/
|
|
return &at(pos);
|
|
}
|
|
|
|
if (!for_open)
|
|
return nullptr;
|
|
|
|
/*
|
|
We are here when:
|
|
- The reference ref->is_null() returned true, meaning that
|
|
ref's SP variable is not linked to any curors in this array:
|
|
* this is the very first "OPEN .. FOR STMT" command for "ref"
|
|
* or the ref's SP variable was set to NULL explicitly.
|
|
- Or dereference() for some reasons returned a value greater than
|
|
elements().
|
|
Search for an unused sp_cursor instance inside sp_cursor_array.
|
|
*/
|
|
if (!find_unused(&pos))
|
|
{
|
|
/*
|
|
An unused sp_cursor instance has been found at the offset "pos".
|
|
Store the position of the found sp_cursor into the reference Field
|
|
and reset the sp_cursor.
|
|
*/
|
|
ref->set_notnull();
|
|
ref->store(pos);
|
|
at(pos).reset(thd);
|
|
return &at(pos);
|
|
}
|
|
|
|
// No unused cursors were found. Append a new one.
|
|
return append(thd, ref);
|
|
}
|
|
|
|
|
|
/*
|
|
Append a new cursor into the array.
|
|
*/
|
|
sp_cursor *sp_cursor_array::append(THD *thd, Field *ref)
|
|
{
|
|
if (Dynamic_array::append(sp_cursor()))
|
|
return nullptr; // The EOM error should already be in DA
|
|
|
|
uint pos= (uint) size() - 1;
|
|
ref->set_notnull();
|
|
ref->store(pos);
|
|
at(pos).reset(thd);
|
|
return &at(pos);
|
|
}
|
|
|
|
#endif
|