mysql-server/sql/server_component/mysql_stored_program_imp.cc
2025-03-05 14:31:37 +07:00

1326 lines
51 KiB
C++

/* Copyright (c) 2022, 2024, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is designed to work with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have either included with
the program or referenced in the documentation.
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, version 2.0, 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-1301 USA */
#include "mysql_stored_program_imp.h"
#include <cstring> // strcmp
#include "my_time.h" // check_datetime_range
#include "mysql/components/services/bits/stored_program_bits.h" // stored_program_argument_type
#include "mysql_time.h"
#include "sql/current_thd.h"
#include "sql/item_timefunc.h" // Item_time_literal
#include "sql/sp_cache.h" // sp_cache
#include "sql/sp_head.h" // sp_head
#include "sql/sp_pcontext.h" // sp_runtime_ctx
#include "sql/sp_rcontext.h"
#include "sql/tztime.h" // Time_zone
constexpr auto MYSQL_SUCCESS = 0;
constexpr auto MYSQL_FAILURE = 1;
/**
Implementation of the mysql_stored_program services
*/
/**
Get stored program data
Accepted keys and corresponding data type
"sp_name" -> mysql_cstring_with_length *
"database_name" -> mysql_cstring_with_length *
"qualified_name" -> mysql_cstring_with_length *
"sp_language" -> mysql_cstring_with_length *
"sp_body" -> mysql_cstring_with_length *
"sp_type" -> uint16_t
"argument_count" -> uint32_t
@note Have the key at least 7 characters long, with unique first 8 characters.
@param [in] sp_handle Handle to stored procedure structure
@param [in] key Metadata name
@param [out] value Metadata value
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_metadata_query_imp::get,
(stored_program_handle sp_handle, const char *key,
void *value)) {
auto sp = reinterpret_cast<sp_head *>(sp_handle);
if (strcmp("sp_name", key) == 0)
*reinterpret_cast<MYSQL_LEX_STRING *>(value) = sp->m_name;
else if (strcmp("database_name", key) == 0)
*reinterpret_cast<MYSQL_LEX_STRING *>(value) = sp->m_db;
else if (strcmp("qualified_name", key) == 0)
*reinterpret_cast<MYSQL_LEX_STRING *>(value) = sp->m_qname;
else if (strcmp("sp_language", key) == 0)
*reinterpret_cast<MYSQL_LEX_CSTRING *>(value) = sp->m_chistics->language;
else if (strcmp("sp_body", key) == 0)
*reinterpret_cast<MYSQL_LEX_CSTRING *>(value) = sp->m_body;
else if (strcmp("sp_type", key) == 0)
switch (sp->m_type) {
case enum_sp_type::FUNCTION:
*reinterpret_cast<uint16_t *>(value) =
MYSQL_STORED_PROGRAM_DATA_QUERY_TYPE_FUNCTION;
break;
case enum_sp_type::PROCEDURE:
*reinterpret_cast<uint16_t *>(value) =
MYSQL_STORED_PROGRAM_DATA_QUERY_TYPE_PROCEDURE;
break;
default:
return MYSQL_FAILURE; // unknown type
}
else if (strcmp("argument_count", key) == 0)
*reinterpret_cast<uint32_t *>(value) =
sp->get_root_parsing_context()->context_var_count();
else
return MYSQL_FAILURE;
return MYSQL_SUCCESS;
}
/*
* Argument-related services:
*/
/**
Get stored program argument metadata
"argument_name" -> const char *
"sql_type" -> uint64_t
"in_variable" -> boolean
"out_variable" -> boolean
"is_signed" -> boolean (Applicable to numeric data types)
"is_nullable" -> boolean
"byte_length" -> uint64_t
"char_length" -> uint64_t (Applicable to string data types)
"charset" -> char const *
@note Have the key at least 7 characters long, with unique first 8 characters.
@returns status of get operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
static int get_field_metadata_internal(Create_field &field, bool input,
bool output, const char *key,
void *value) {
if (strcmp("argument_name", key) == 0)
*reinterpret_cast<char const **>(value) = field.field_name;
else if (strcmp("in_variable", key) == 0)
*reinterpret_cast<bool *>(value) = input;
else if (strcmp("out_variable", key) == 0)
*reinterpret_cast<bool *>(value) = output;
else if (strcmp("is_signed", key) == 0)
*reinterpret_cast<bool *>(value) = !field.is_unsigned;
else if (strcmp("is_nullable", key) == 0)
*reinterpret_cast<bool *>(value) = field.is_nullable;
else if (strcmp("sql_type", key) == 0)
switch (field.sql_type) {
case MYSQL_TYPE_DECIMAL:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_DECIMAL;
break;
case MYSQL_TYPE_TINY:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TINY;
break;
case MYSQL_TYPE_SHORT:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_SHORT;
break;
case MYSQL_TYPE_LONG:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_LONG;
break;
case MYSQL_TYPE_FLOAT:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_FLOAT;
break;
case MYSQL_TYPE_DOUBLE:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_DOUBLE;
break;
case MYSQL_TYPE_NULL:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_NULL;
break;
case MYSQL_TYPE_TIMESTAMP:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TIMESTAMP;
break;
case MYSQL_TYPE_LONGLONG:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_LONGLONG;
break;
case MYSQL_TYPE_INT24:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_INT24;
break;
case MYSQL_TYPE_DATE:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_DATE;
break;
case MYSQL_TYPE_TIME:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TIME;
break;
case MYSQL_TYPE_DATETIME:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_DATETIME;
break;
case MYSQL_TYPE_YEAR:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_YEAR;
break;
case MYSQL_TYPE_NEWDATE:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_NEWDATE;
break;
case MYSQL_TYPE_VARCHAR:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_VARCHAR;
break;
case MYSQL_TYPE_BIT:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_BIT;
break;
case MYSQL_TYPE_TIMESTAMP2:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TIMESTAMP2;
break;
case MYSQL_TYPE_DATETIME2:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_DATETIME2;
break;
case MYSQL_TYPE_TIME2:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TIME2;
break;
case MYSQL_TYPE_TYPED_ARRAY:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TYPED_ARRAY;
break;
case MYSQL_TYPE_INVALID:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_INVALID;
break;
case MYSQL_TYPE_BOOL:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_BOOL;
break;
case MYSQL_TYPE_JSON:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_JSON;
break;
case MYSQL_TYPE_NEWDECIMAL:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_NEWDECIMAL;
break;
case MYSQL_TYPE_ENUM:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_ENUM;
break;
case MYSQL_TYPE_SET:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_SET;
break;
case MYSQL_TYPE_TINY_BLOB:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_TINY_BLOB;
break;
case MYSQL_TYPE_MEDIUM_BLOB:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_MEDIUM_BLOB;
break;
case MYSQL_TYPE_LONG_BLOB:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_LONG_BLOB;
break;
case MYSQL_TYPE_BLOB:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_BLOB;
break;
case MYSQL_TYPE_VAR_STRING:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_VAR_STRING;
break;
case MYSQL_TYPE_STRING:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_STRING;
break;
case MYSQL_TYPE_GEOMETRY:
*reinterpret_cast<uint64_t *>(value) = MYSQL_SP_ARG_TYPE_GEOMETRY;
break;
default:
return MYSQL_FAILURE;
}
else if (strcmp("byte_length", key) == 0)
*reinterpret_cast<size_t *>(value) = field.pack_length();
else if (strcmp("char_length", key) == 0)
*reinterpret_cast<size_t *>(value) = field.key_length();
else if (strcmp("charset", key) == 0)
*reinterpret_cast<char const **>(value) = field.charset->csname;
else if (strcmp("decimals", key) == 0)
*reinterpret_cast<uint32_t *>(value) = field.decimals;
else
return MYSQL_FAILURE;
return MYSQL_SUCCESS;
}
/**
Get stored program argument metadata
"argument_name" -> const char *
"sql_type" -> uint64_t
"in_variable" -> boolean
"out_variable" -> boolean
"is_signed" -> boolean (Applicable to numeric data types)
"is_nullable" -> boolean
"byte_length" -> uint64_t
"char_length" -> uint64_t (Applicable to string data types)
"charset" -> char const *
@note Have the key at least 7 characters long, with unique first 8 characters.
@param [in] sp_handle Handle to stored procedure structure
@param [in] index Argument index
@param [in] key Metadata name
@param [out] value Metadata value
@returns status of get operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_argument_metadata_query_imp::get,
(stored_program_handle sp_handle, uint16_t index,
const char *key, void *value)) {
auto sp = reinterpret_cast<sp_head *>(sp_handle);
auto context = sp->get_root_parsing_context();
auto variable = context->find_variable(index);
auto input = variable->mode == sp_variable::enum_mode::MODE_IN ||
variable->mode == sp_variable::enum_mode::MODE_INOUT;
auto output = variable->mode == sp_variable::enum_mode::MODE_OUT ||
variable->mode == sp_variable::enum_mode::MODE_INOUT;
return get_field_metadata_internal(variable->field_def, input, output, key,
value);
}
/**
Get stored program return metadata
"argument_name" -> const char *
"sql_type" -> uint64_t
"in_variable" -> boolean
"out_variable" -> boolean
"is_signed" -> boolean (Applicable to numeric data types)
"is_nullable" -> boolean
"byte_length" -> uint64_t
"char_length" -> uint64_t (Applicable to string data types)
"charset" -> char const *
@note Have the key at least 7 characters long, with unique first 8 characters.
@param [in] sp_handle Handle to stored procedure structure
@param [in] key Metadata name
@param [out] value Metadata value
@returns status of get operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_metadata_query_imp::get,
(stored_program_handle sp_handle, const char *key,
void *value)) {
auto sp = reinterpret_cast<sp_head *>(sp_handle);
return get_field_metadata_internal(sp->m_return_field_def, false, true, key,
value);
}
auto static set_variable(stored_program_runtime_context sp_runtime_context,
Item *item, int index) -> int {
assert(index >= 0);
if (index < 0) return MYSQL_FAILURE;
auto runtime_context = reinterpret_cast<sp_rcontext *>(sp_runtime_context);
if (runtime_context == nullptr) runtime_context = current_thd->sp_runtime_ctx;
return runtime_context->set_variable(current_thd, false, index, &item);
}
auto static set_return_value(stored_program_runtime_context sp_runtime_context,
Item *item) -> int {
auto runtime_context = reinterpret_cast<sp_rcontext *>(sp_runtime_context);
if (runtime_context == nullptr) runtime_context = current_thd->sp_runtime_ctx;
return runtime_context->set_return_value(current_thd, false, &item);
}
auto static get_item(stored_program_runtime_context sp_runtime_context,
int index) -> Item * {
assert(index >= 0);
if (index < 0) return nullptr;
auto runtime_context = reinterpret_cast<sp_rcontext *>(sp_runtime_context);
if (runtime_context == nullptr) runtime_context = current_thd->sp_runtime_ctx;
return runtime_context->get_item(index);
}
auto static get_return_field(stored_program_runtime_context sp_runtime_context)
-> Field * {
auto runtime_context = reinterpret_cast<sp_rcontext *>(sp_runtime_context);
if (runtime_context == nullptr) runtime_context = current_thd->sp_runtime_ctx;
return runtime_context->get_return_field();
}
/**
Returns the field name of the return value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context
will be used.
@param [out] value Metadata value
@returns status of get operation
@retval false Success
@retval true Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_field_name_imp::get_name,
(stored_program_runtime_context sp_runtime_context,
char const **value)) {
auto field = get_return_field(sp_runtime_context);
if (field == nullptr) return MYSQL_FAILURE;
*value = field->field_name;
return MYSQL_SUCCESS;
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] year Year
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_year_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t *year, bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (!*is_null) *year = item->val_int();
return MYSQL_SUCCESS;
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] hour Hour of the day
@param [out] minute Minute of the hour
@param [out] second Second of the minute
@param [out] micro Micro second of the second
@param [out] negative Is negative
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_time_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t *hour, uint32_t *minute,
uint32_t *second, uint64_t *micro, bool *negative,
bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (*is_null) return MYSQL_SUCCESS;
auto date = MYSQL_TIME{};
item->get_time(&date);
*hour = date.hour;
*minute = date.minute;
*second = date.second;
*micro = date.second_part;
*negative = date.neg;
return MYSQL_SUCCESS;
}
/**
Helper function that retrieves runtime argument value for DATETIME
and TIMESTAMP types.
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] year Year part
@param [out] month Month of the year
@param [out] day Day of the month
@param [out] hour Hour of the day
@param [out] minute Minute of the hour
@param [out] second Second of the minute
@param [out] micro Micro second of the second
@param [out] negative Is negative
@param [out] time_zone_offset Time zone offset in seconds
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
static int runtime_argument_datetime_get(
stored_program_runtime_context sp_runtime_context, uint16_t index,
uint32_t *year, uint32_t *month, uint32_t *day, uint32_t *hour,
uint32_t *minute, uint32_t *second, uint64_t *micro, bool *negative,
int32_t *time_zone_offset, bool *is_null) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (*is_null) return MYSQL_SUCCESS;
auto date = MYSQL_TIME{};
item->get_time(&date);
*year = date.year;
*month = date.month;
*day = date.day;
*hour = date.hour;
*minute = date.minute;
*second = date.second;
*micro = date.second_part;
*negative = date.neg;
*time_zone_offset = date.time_zone_displacement;
assert(date.time_type == enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME);
return MYSQL_SUCCESS;
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] year Year part
@param [out] month Month of the year
@param [out] day Day of the month
@param [out] hour Hour of the day
@param [out] minute Minute of the hour
@param [out] second Second of the minute
@param [out] micro Micro second of the second
@param [out] negative Is negative
@param [out] time_zone_offset Time zone offset in seconds
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_datetime_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t *year, uint32_t *month,
uint32_t *day, uint32_t *hour, uint32_t *minute,
uint32_t *second, uint64_t *micro, bool *negative,
int32_t *time_zone_offset, bool *is_null)) {
return runtime_argument_datetime_get(sp_runtime_context, index, year, month,
day, hour, minute, second, micro,
negative, time_zone_offset, is_null);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] year Year part
@param [out] month Month of the year
@param [out] day Day of the month
@param [out] hour Hour of the day
@param [out] minute Minute of the hour
@param [out] second Second of the minute
@param [out] micro Micro second of the second
@param [out] negative Is negative
@param [out] time_zone_offset Time zone offset in seconds
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_timestamp_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t *year, uint32_t *month,
uint32_t *day, uint32_t *hour, uint32_t *minute,
uint32_t *second, uint64_t *micro, bool *negative,
int32_t *time_zone_offset, bool *is_null)) {
return runtime_argument_datetime_get(sp_runtime_context, index, year, month,
day, hour, minute, second, micro,
negative, time_zone_offset, is_null);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] year Year
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_year_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t year)) {
Item *item = new Item_int(static_cast<long long>(year));
return set_variable(sp_runtime_context, item, index);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_time_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t hour, uint32_t minute,
uint32_t second, uint64_t micro, bool negative,
uint8_t decimals)) {
auto time = MYSQL_TIME{static_cast<unsigned int>(0),
static_cast<unsigned int>(0),
static_cast<unsigned int>(0),
static_cast<unsigned int>(hour),
static_cast<unsigned int>(minute),
static_cast<unsigned int>(second),
static_cast<unsigned long>(micro),
negative,
MYSQL_TIMESTAMP_TIME,
{}};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto item = new Item_time_literal(&time, decimals);
return set_variable(sp_runtime_context, item, index);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [out] year Year information
@param [out] month Month of the year
@param [out] day Day of the month
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_date_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t *year, uint32_t *month,
uint32_t *day, bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (*is_null) return MYSQL_SUCCESS;
auto date = MYSQL_TIME{};
item->get_date(&date, TIME_FUZZY_DATE);
*year = date.year;
*month = date.month;
*day = date.day;
return MYSQL_SUCCESS;
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] year Year information
@param [in] month Month of the year
@param [in] day Day of the month
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_date_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t year, uint32_t month,
uint32_t day)) {
auto time = MYSQL_TIME{
year, month, day, {}, {}, {}, {}, {}, MYSQL_TIMESTAMP_DATE, {}};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto item = new Item_date_literal(&time);
return set_variable(sp_runtime_context, item, index);
}
/**
Helper function that sets runtime argument value for DATETIME
and TIMESTAMP types.
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
static int runtime_argument_datetime_set(
stored_program_runtime_context sp_runtime_context, uint16_t index,
uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute,
uint32_t second, uint64_t micro, bool negative, uint32_t decimals,
int32_t time_zone_offset, bool time_zone_aware) {
enum_mysql_timestamp_type ts_type{};
if (time_zone_aware) {
ts_type = enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME_TZ;
} else {
ts_type = enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME;
}
auto time = MYSQL_TIME{static_cast<unsigned int>(year),
static_cast<unsigned int>(month),
static_cast<unsigned int>(day),
static_cast<unsigned int>(hour),
static_cast<unsigned int>(minute),
static_cast<unsigned int>(second),
static_cast<unsigned long>(micro),
negative,
ts_type,
static_cast<int>(time_zone_offset)};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto item =
new Item_datetime_literal(&time, decimals, current_thd->time_zone());
return set_variable(sp_runtime_context, item, index);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_datetime_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second,
uint64_t micro, bool negative, uint32_t decimals,
int32_t time_zone_offset, bool time_zone_aware)) {
return runtime_argument_datetime_set(
sp_runtime_context, index, year, month, day, hour, minute, second, micro,
negative, decimals, time_zone_offset, time_zone_aware);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_timestamp_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint32_t year, uint32_t month, uint32_t day,
uint32_t hour, uint32_t minute, uint32_t second,
uint64_t micro, bool negative, uint32_t decimals,
int32_t time_zone_offset, bool time_zone_aware)) {
return runtime_argument_datetime_set(
sp_runtime_context, index, year, month, day, hour, minute, second, micro,
negative, decimals, time_zone_offset, time_zone_aware);
}
/**
Set null value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_null_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index)) {
auto item = new Item_null{};
return set_variable(sp_runtime_context, item, index);
}
/**
Get value of a string argument
@note: A pointer to the original data is returned. No guarantee is provided
that the original data will not be consecutively modified.
If the data is to be stored, it needs to be copied locally.
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will
be used.
@param [in] index Argument location
@param [out] value A pointer to the original string
@param [out] length Length of the original string
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_string_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, char const **value, size_t *length,
bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (*is_null) return MYSQL_SUCCESS;
auto temp = String{};
auto string = item->val_str(&temp);
// HCS-8941: fix the bug when service called for non-string types: in case
// this string owns the buffer, the buffer will be freed when this function
// exits
if (string->is_alloced()) {
*value = nullptr;
return MYSQL_FAILURE;
}
*value = string->c_ptr();
*length = string->length();
return MYSQL_SUCCESS;
}
/**
Set value of a string argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] string Value of the argument
@param [in] length Length of the string
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_string_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, char const *string, size_t length)) {
auto item = new Item_string(string, length, &my_charset_bin);
return set_variable(sp_runtime_context, item, index);
}
/**
Get value of an int argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [out] result Value of the argument
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_int_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, int64_t *result, bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (!*is_null) *result = item->val_int();
return MYSQL_SUCCESS;
}
/**
Set value of an int argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] value Value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_int_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, int64_t value)) {
Item *item = new Item_int(static_cast<long long>(value));
return set_variable(sp_runtime_context, item, index);
}
/**
Get value of an unsigned int argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [out] result Value of the argument
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_unsigned_int_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint64_t *result, bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (!*is_null) *result = item->val_uint();
return MYSQL_SUCCESS;
}
/**
Set value of an unsigned int argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] value Value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_unsigned_int_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, uint64_t value)) {
Item *item = new Item_int(static_cast<unsigned long long>(value));
return set_variable(sp_runtime_context, item, index);
}
/**
Get a float time value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [out] result Value of the argument
@param [out] is_null Flag to indicate if value is null
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_float_imp::get,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, double *result, bool *is_null)) {
auto item = get_item(sp_runtime_context, index);
if (item == nullptr) return MYSQL_FAILURE;
*is_null = item->is_null();
if (!*is_null) *result = item->val_real();
return MYSQL_SUCCESS;
}
/**
Set value of a float argument
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] index Argument location
@param [in] value value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_runtime_argument_float_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint16_t index, double value)) {
Item *item = new Item_float(value, DECIMAL_NOT_SPECIFIED);
return set_variable(sp_runtime_context, item, index);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] year Year
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_year_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint32_t year)) {
Item *item = new Item_int(static_cast<long long>(year));
return set_return_value(sp_runtime_context, item);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_time_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint32_t hour, uint32_t minute, uint32_t second,
uint64_t micro, bool negative, uint8_t decimals)) {
auto time = MYSQL_TIME{static_cast<unsigned int>(0),
static_cast<unsigned int>(0),
static_cast<unsigned int>(0),
static_cast<unsigned int>(hour),
static_cast<unsigned int>(minute),
static_cast<unsigned int>(second),
static_cast<unsigned long>(micro),
negative,
MYSQL_TIMESTAMP_TIME,
{}};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto item = new Item_time_literal(&time, decimals);
return set_return_value(sp_runtime_context, item);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] year Year information
@param [in] month Month of the year
@param [in] day Day of the month
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_date_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint32_t year, uint32_t month, uint32_t day)) {
auto time = MYSQL_TIME{
year, month, day, {}, {}, {}, {}, {}, MYSQL_TIMESTAMP_DATE, {}};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto item = new Item_date_literal(&time);
return set_return_value(sp_runtime_context, item);
}
/**
Helper function that sets return value for DATETIME
and TIMESTAMP types.
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
static int return_value_datetime_set(
stored_program_runtime_context sp_runtime_context, uint32_t year,
uint32_t month, uint32_t day, uint32_t hour, uint32_t minute,
uint32_t second, uint64_t micro, bool negative, uint32_t decimals,
int32_t time_zone_offset, bool time_zone_aware) {
enum_mysql_timestamp_type ts_type{};
if (time_zone_aware) {
ts_type = enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME_TZ;
} else {
ts_type = enum_mysql_timestamp_type::MYSQL_TIMESTAMP_DATETIME;
}
auto time = MYSQL_TIME{year,
month,
day,
hour,
minute,
second,
static_cast<unsigned long>(micro),
negative,
ts_type,
time_zone_offset};
if (check_datetime_range(time)) return MYSQL_FAILURE;
auto *item =
new Item_datetime_literal(&time, decimals, current_thd->time_zone());
return set_return_value(sp_runtime_context, item);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_datetime_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint32_t year, uint32_t month, uint32_t day, uint32_t hour,
uint32_t minute, uint32_t second, uint64_t micro,
bool negative, uint32_t decimals, int32_t time_zone_offset,
bool time_zone_aware)) {
return return_value_datetime_set(sp_runtime_context, year, month, day, hour,
minute, second, micro, negative, decimals,
time_zone_offset, time_zone_aware);
}
/**
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] year Year part
@param [in] month Month of the year
@param [in] day Day of the month
@param [in] hour Hour of the day
@param [in] minute Minute of the hour
@param [in] second Second of the minute
@param [in] micro Micro second of the second
@param [in] negative Is negative
@param [in] decimals Precision information
@param [in] time_zone_offset Time zone offset in seconds
@param [in] time_zone_aware Is time zone aware
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_timestamp_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint32_t year, uint32_t month, uint32_t day, uint32_t hour,
uint32_t minute, uint32_t second, uint64_t micro,
bool negative, uint32_t decimals, int32_t time_zone_offset,
bool time_zone_aware)) {
return return_value_datetime_set(sp_runtime_context, year, month, day, hour,
minute, second, micro, negative, decimals,
time_zone_offset, time_zone_aware);
}
/**
Set null value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_null_imp::set,
(stored_program_runtime_context sp_runtime_context)) {
auto item = new Item_null{};
return set_return_value(sp_runtime_context, item);
}
/**
Set value of a string return value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] string Value of the argument
@param [in] length Length of the string
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_string_imp::set,
(stored_program_runtime_context sp_runtime_context,
char const *string, size_t length)) {
auto item = new Item_string(string, length, &my_charset_bin);
return set_return_value(sp_runtime_context, item);
}
/**
Set value of an int return value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] value Value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_int_imp::set,
(stored_program_runtime_context sp_runtime_context,
int64_t value)) {
Item *item = new Item_int(static_cast<long long>(value));
return set_return_value(sp_runtime_context, item);
}
/**
Set value of an unsigned int return value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] value Value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_unsigned_int_imp::set,
(stored_program_runtime_context sp_runtime_context,
uint64_t value)) {
Item *item = new Item_int(static_cast<unsigned long long>(value));
return set_return_value(sp_runtime_context, item);
}
/**
Set value of a float return value
@param [in] sp_runtime_context stored program runtime context.
If null, current runtime context will be
used.
@param [in] value value to be set
@returns Status of operation
@retval MYSQL_SUCCESS Success
@retval MYSQL_FAILURE Failure
*/
DEFINE_BOOL_METHOD(mysql_stored_program_return_value_float_imp::set,
(stored_program_runtime_context sp_runtime_context,
double value)) {
Item *item = new Item_float(value, DECIMAL_NOT_SPECIFIED);
return set_return_value(sp_runtime_context, item);
}
/**
* @brief Ensure the sp_head is part of the current THD.
*
* @param sp - sp_head pointer.
* @return true if the sp_head is part of the current THD.
* @return false if not.
*/
static auto is_sp_in_current_thd(sp_head *sp) -> bool {
assert(sp);
if (!sp) return false;
if (sp_cache_has(current_thd->sp_func_cache, sp)) return true;
if (sp_cache_has(current_thd->sp_proc_cache, sp)) return true;
assert(false);
return false;
}
DEFINE_BOOL_METHOD(mysql_stored_program_external_program_handle_imp::get,
(stored_program_handle sp_handle,
external_program_handle *value)) {
assert(value);
if (!value) return MYSQL_FAILURE;
auto sp = reinterpret_cast<sp_head *>(sp_handle);
if (!is_sp_in_current_thd(sp)) return MYSQL_FAILURE;
*value = sp->get_external_program_handle();
return MYSQL_SUCCESS;
}
DEFINE_BOOL_METHOD(mysql_stored_program_external_program_handle_imp::set,
(stored_program_handle sp_handle,
external_program_handle value)) {
auto sp = reinterpret_cast<sp_head *>(sp_handle);
if (!is_sp_in_current_thd(sp)) return MYSQL_FAILURE;
return sp->set_external_program_handle(value);
}