mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
SET sql_mode=ORACLE;
DELIMITER $$
CREATE OR REPLACE PACKAGE pkg AS
-- Declare a package public data type
TYPE varchar_array IS TABLE OF VARCHAR(2000) INDEX BY INTEGER;
END;
$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE PROCEDURE p1 AS
v pkg.varchar_array; -- Use the package public data type
BEGIN
v(0):='test';
SELECT v(0);
END;
$$
DELIMITER ;
Note, the change is done only for sql_mode=ORACLE, because the TYPE
declaration is not available for the default mode.
Where package-wide types are available
--------------------------------------
- Variabe list type:
DECLARE var pkg1.type1;
- RETURN type for a package routine:
CREATE FUNCTION .. RETURN pkg1.type1 ...
- Parameter type for a package routine:
PROCEDURE p1(param1 pkg1.type1);
- Assoc array element type:
TYPE assoc1_t IS TABLE OF pkg1.type1 ...
- REF CURSOR RETURN type:
TYPE cur1_t IS REF CURSOR RETURN pkg1.type1;
Change details
--------------
- Adding a member Lex_length_and_dec_st::m_foreign_module_type
It's set to true when the data type was initialized from a TYPE
in foreign routine (e.g. in PACKAGE spec).
It's needed to prevent use of qualified identifiers in public contexts,
i.e. in schema public routine parameter types and schema publuc function
RETURN types.
Adding a helper method sp_head::check_applicability() which prevents
use of qualified types in public context.
- Adding a helper method sp_head::raise_unknown_data_type().
- Adding methods LEX::set_field_type_typedef_package_spec() for
2-step and 3-step qualified indentifiers.
It's used in field_type_all_with_typedefs which covers cases:
- Variabe list type : DECLARE var pkg1.type1;
- RETURN type : CREATE FUNCTION .. RETURN pkg1.type1 ...
- Parameter type : PROCEDURE p1(param1 pkg1.type1);
- Assoc array element type : TYPE assoc1_t IS TABLE OF pkg1.type1 ...
- Adding a method LEX::declare_type_ref_cursor_return_typedef().
It handles cases when a new TYPE REF CURSOR RETURN is declared,
for both for qualified RETURN types and non-qualified RETURN types:
- TYPE cur0_t IS REF CURSOR RETURN rec1_t;
- TYPE cur0_t IS REF CURSOR RETURN pkg1.rec1_t;
- TYPE cur0_t IS REF CURSOR RETURN db1.pkg1.rec1_t;
The code was moved from LEX::declare_type_ref_cursor() into
LEX::declare_type_ref_cursor_return_typedef() and extended
to cover qualified RETURN types.
- Adding a method Sql_path::find_package_spec_type().
It iterates through all schemas specified in @@path and searches
for the given type in the given package.
- Adding a helper method sp_pcontext::type_defs_add_ref_cursor()
to reuse the code.
- Adding a new method sp_package::get_typedef() to search
for TYPE definitions in PACKAGE specifications.
- Adding a new method sp_head::get_typedef_package_spec()
to search for TYPE definitions used by a PROCEDURE or FUNCTION.
- Adding a helper method
Sp_handler::sp_cache_routine_reentrant_suppress_errors
Adding a method Sp_handler::find_package_spec().
190 lines
5.3 KiB
C++
190 lines
5.3 KiB
C++
#ifndef CHAR_BUFFER_INCLUDED
|
|
#define CHAR_BUFFER_INCLUDED
|
|
/*
|
|
Copyright (c) 2023, MariaDB
|
|
|
|
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 St, Fifth Floor, Boston, MA 02110-1335 USA
|
|
*/
|
|
|
|
|
|
/*
|
|
A string buffer with length.
|
|
This template class is useful to store things like database, table names,
|
|
whose maximum length a small fixed known value. Mainly to be used as
|
|
stack variables to store temporary values.
|
|
|
|
Can store exact string copies or casefolded string copies.
|
|
The stored value is returned as a LEX_CSTRING.
|
|
*/
|
|
template<size_t buff_sz>
|
|
class CharBuffer
|
|
{
|
|
protected:
|
|
char m_buff[buff_sz + 1 /* one extra byte for '\0' */];
|
|
size_t m_length;
|
|
bool is_sane() const
|
|
{
|
|
return m_length <= buff_sz; // One byte is still left for '\0'
|
|
}
|
|
bool buffer_overlaps(const LEX_CSTRING &str) const
|
|
{
|
|
return str.str + str.length >= m_buff && str.str <= m_buff + sizeof(m_buff);
|
|
}
|
|
public:
|
|
constexpr size_t max_data_size() const
|
|
{
|
|
return buff_sz; // The maximum data size, without the trailing '\0' byte.
|
|
}
|
|
size_t available_size() const
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
return buff_sz - m_length;
|
|
}
|
|
CharBuffer()
|
|
:m_length(0)
|
|
{
|
|
m_buff[0]= '\0';
|
|
}
|
|
CharBuffer<buff_sz> & copy(const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
m_length= MY_MIN(buff_sz, str.length);
|
|
memcpy(m_buff, str.str, m_length);
|
|
m_buff[m_length]= '\0';
|
|
return *this;
|
|
}
|
|
CharBuffer<buff_sz> & copy_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
m_length= cs->cset->casedn(cs, str.str, str.length, m_buff, buff_sz);
|
|
/*
|
|
casedn() never writes outsize of buff_sz (unless a bug in casedn()),
|
|
so it's safe to write '\0' at the position m_length:
|
|
*/
|
|
DBUG_ASSERT(is_sane());
|
|
m_buff[m_length]= '\0';
|
|
return *this;
|
|
}
|
|
CharBuffer<buff_sz> & copy_caseup(CHARSET_INFO *cs, const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
m_length= cs->cset->caseup(cs, str.str, str.length, m_buff, buff_sz);
|
|
DBUG_ASSERT(is_sane());
|
|
m_buff[m_length]= '\0'; // See comments in copy_casedn()
|
|
return *this;
|
|
}
|
|
CharBuffer<buff_sz> & copy_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str,
|
|
bool casedn)
|
|
{
|
|
casedn ? copy_casedn(cs, str) : copy(str);
|
|
return *this;
|
|
}
|
|
|
|
// Append an unsigned number
|
|
CharBuffer<buff_sz> & append_ulonglong(ulonglong nr)
|
|
{
|
|
if (available_size() >= MAX_BIGINT_WIDTH)
|
|
{
|
|
char *end= (char*) longlong10_to_str(nr, &m_buff[m_length], 10);
|
|
m_length= (end - m_buff);
|
|
}
|
|
DBUG_ASSERT(is_sane());
|
|
return *this;
|
|
}
|
|
|
|
// Append one character
|
|
CharBuffer<buff_sz> & append_char(char ch)
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
if (available_size())
|
|
{
|
|
m_buff[m_length++]= ch;
|
|
m_buff[m_length]= '\0';
|
|
}
|
|
DBUG_ASSERT(is_sane());
|
|
return *this;
|
|
}
|
|
|
|
// Append a string
|
|
CharBuffer<buff_sz> & append(const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
size_t len= MY_MIN(available_size(), str.length);
|
|
memcpy(m_buff + m_length, str.str, len);
|
|
m_length+= len;
|
|
DBUG_ASSERT(is_sane());
|
|
m_buff[m_length]= '\0';
|
|
return *this;
|
|
}
|
|
|
|
// Append a string with casedn conversion
|
|
CharBuffer<buff_sz> & append_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
size_t casedn_length= cs->casedn(str.str, str.length,
|
|
m_buff + m_length, available_size());
|
|
m_length+= casedn_length;
|
|
DBUG_ASSERT(is_sane());
|
|
m_buff[m_length]= '\0';
|
|
return *this;
|
|
}
|
|
|
|
CharBuffer<buff_sz> & append_opt_casedn(CHARSET_INFO *cs,
|
|
const LEX_CSTRING &str,
|
|
bool casedn)
|
|
{
|
|
return casedn ? append_casedn(cs, str) : append(str);
|
|
}
|
|
|
|
// Append a string with caseup conversion
|
|
CharBuffer<buff_sz> & append_caseup(CHARSET_INFO *cs, const LEX_CSTRING &str)
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
DBUG_ASSERT(!buffer_overlaps(str));
|
|
size_t casedn_length= cs->caseup(str.str, str.length,
|
|
m_buff + m_length, available_size());
|
|
m_length+= casedn_length;
|
|
DBUG_ASSERT(is_sane());
|
|
m_buff[m_length]= '\0';
|
|
return *this;
|
|
}
|
|
|
|
CharBuffer<buff_sz> & truncate(size_t length)
|
|
{
|
|
DBUG_ASSERT(is_sane());
|
|
if (m_length > length)
|
|
{
|
|
m_length= length;
|
|
m_buff[m_length]= '\0';
|
|
DBUG_ASSERT(is_sane());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
LEX_CSTRING to_lex_cstring() const
|
|
{
|
|
return LEX_CSTRING{m_buff, m_length};
|
|
}
|
|
|
|
const char *ptr() const { return m_buff; }
|
|
size_t length() const { return m_length; }
|
|
const char *end() const { return m_buff + m_length; }
|
|
|
|
};
|
|
|
|
#endif // CHAR_BUFFER_INCLUDED
|