mariadb/sql/sp_cursor.cc
Alexander Barkov d14a185748 MDEV-20034 Add support for the pre-defined weak SYS_REFCURSOR
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
2025-02-21 12:43:36 +04:00

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