mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge branch '10.4' into 10.5
This commit is contained in:
@ -124,6 +124,9 @@ When one supplies long data for a placeholder:
|
||||
#include "mysql/psi/mysql_ps.h" // MYSQL_EXECUTE_PS
|
||||
#include "wsrep_mysqld.h"
|
||||
|
||||
/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
|
||||
static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8;
|
||||
|
||||
/**
|
||||
A result class used to send cursor rows using the binary protocol.
|
||||
*/
|
||||
@ -897,11 +900,73 @@ static bool insert_bulk_params(Prepared_statement *stmt,
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
static bool set_conversion_functions(Prepared_statement *stmt,
|
||||
uchar **data, uchar *data_end)
|
||||
|
||||
/**
|
||||
Checking if parameter type and flags are valid
|
||||
|
||||
@param typecode ushort value with type in low byte, and flags in high byte
|
||||
|
||||
@retval true this parameter is wrong
|
||||
@retval false this parameter is OK
|
||||
*/
|
||||
|
||||
static bool
|
||||
parameter_type_sanity_check(ushort typecode)
|
||||
{
|
||||
/* Checking if type in lower byte is valid */
|
||||
switch (typecode & 0xff) {
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
case MYSQL_TYPE_YEAR:
|
||||
case MYSQL_TYPE_BIT:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
case MYSQL_TYPE_NULL:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_SET:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
break;
|
||||
/*
|
||||
This types normally cannot be sent by client, so maybe it'd be
|
||||
better to treat them like an error here.
|
||||
*/
|
||||
case MYSQL_TYPE_TIMESTAMP2:
|
||||
case MYSQL_TYPE_TIME2:
|
||||
case MYSQL_TYPE_DATETIME2:
|
||||
default:
|
||||
return true;
|
||||
};
|
||||
|
||||
// In Flags in high byte only unsigned bit may be set
|
||||
if (typecode & ((~PARAMETER_FLAG_UNSIGNED) & 0x0000ff00))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_conversion_functions(Prepared_statement *stmt, uchar **data)
|
||||
{
|
||||
uchar *read_pos= *data;
|
||||
const uint signed_bit= 1 << 15;
|
||||
|
||||
DBUG_ENTER("set_conversion_functions");
|
||||
/*
|
||||
First execute or types altered by the client, setup the
|
||||
@ -914,12 +979,17 @@ static bool set_conversion_functions(Prepared_statement *stmt,
|
||||
{
|
||||
ushort typecode;
|
||||
|
||||
if (read_pos >= data_end)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/*
|
||||
stmt_execute_packet_sanity_check has already verified, that there
|
||||
are enough data in the packet for data types
|
||||
*/
|
||||
typecode= sint2korr(read_pos);
|
||||
read_pos+= 2;
|
||||
(**it).unsigned_flag= MY_TEST(typecode & signed_bit);
|
||||
if (parameter_type_sanity_check(typecode))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
(**it).unsigned_flag= MY_TEST(typecode & PARAMETER_FLAG_UNSIGNED);
|
||||
(*it)->setup_conversion(thd, (uchar) (typecode & 0xff));
|
||||
(*it)->sync_clones();
|
||||
}
|
||||
@ -929,7 +999,7 @@ static bool set_conversion_functions(Prepared_statement *stmt,
|
||||
|
||||
|
||||
static bool setup_conversion_functions(Prepared_statement *stmt,
|
||||
uchar **data, uchar *data_end,
|
||||
uchar **data,
|
||||
bool bulk_protocol= 0)
|
||||
{
|
||||
/* skip null bits */
|
||||
@ -942,7 +1012,7 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
|
||||
if (*read_pos++) //types supplied / first execute
|
||||
{
|
||||
*data= read_pos;
|
||||
bool res= set_conversion_functions(stmt, data, data_end);
|
||||
bool res= set_conversion_functions(stmt, data);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
*data= read_pos;
|
||||
@ -3137,11 +3207,19 @@ static void mysql_stmt_execute_common(THD *thd,
|
||||
|
||||
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
||||
{
|
||||
const uint packet_min_lenght= 9;
|
||||
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
|
||||
|
||||
DBUG_ENTER("mysqld_stmt_execute");
|
||||
|
||||
if (packet_length < packet_min_lenght)
|
||||
{
|
||||
my_error(ER_MALFORMED_PACKET, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
ulong stmt_id= uint4korr(packet);
|
||||
ulong flags= (ulong) packet[4];
|
||||
uchar *packet_end= packet + packet_length;
|
||||
DBUG_ENTER("mysqld_stmt_execute");
|
||||
|
||||
packet+= 9; /* stmt_id + 5 bytes of flags */
|
||||
|
||||
@ -3197,6 +3275,84 @@ void mysqld_stmt_bulk_execute(THD *thd, char *packet_arg, uint packet_length)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/**
|
||||
Additional packet checks for direct execution
|
||||
|
||||
@param thd THD handle
|
||||
@param stmt prepared statement being directly executed
|
||||
@param paket packet with parameters to bind
|
||||
@param packet_end pointer to the byte after parameters end
|
||||
@param bulk_op is it bulk operation
|
||||
@param direct_exec is it direct execution
|
||||
@param read_bytes need to read types (only with bulk_op)
|
||||
|
||||
@retval true this parameter is wrong
|
||||
@retval false this parameter is OK
|
||||
*/
|
||||
|
||||
static bool
|
||||
stmt_execute_packet_sanity_check(Prepared_statement *stmt,
|
||||
uchar *packet, uchar *packet_end,
|
||||
bool bulk_op, bool direct_exec,
|
||||
bool read_types)
|
||||
{
|
||||
|
||||
DBUG_ASSERT((!read_types) || (read_types && bulk_op));
|
||||
if (stmt->param_count > 0)
|
||||
{
|
||||
uint packet_length= static_cast<uint>(packet_end - packet);
|
||||
uint null_bitmap_bytes= (bulk_op ? 0 : (stmt->param_count + 7)/8);
|
||||
uint min_len_for_param_count = null_bitmap_bytes
|
||||
+ (bulk_op ? 0 : 1); /* sent types byte */
|
||||
|
||||
if (!bulk_op && packet_length >= min_len_for_param_count)
|
||||
{
|
||||
if ((read_types= packet[null_bitmap_bytes]))
|
||||
{
|
||||
/*
|
||||
Should be 0 or 1. If the byte is not 1, that could mean,
|
||||
e.g. that we read incorrect byte due to incorrect number
|
||||
of sent parameters for direct execution (i.e. null bitmap
|
||||
is shorter or longer, than it should be)
|
||||
*/
|
||||
if (packet[null_bitmap_bytes] != '\1')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (read_types)
|
||||
{
|
||||
/* 2 bytes per parameter of the type and flags */
|
||||
min_len_for_param_count+= 2*stmt->param_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If types are not sent, there is nothing to do here.
|
||||
But for direct execution types should always be sent
|
||||
*/
|
||||
return direct_exec;
|
||||
}
|
||||
|
||||
/*
|
||||
If true, the packet is guaranteed too short for the number of
|
||||
parameters in the PS
|
||||
*/
|
||||
return (packet_length < min_len_for_param_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If there is no parameters, this should be normally already end
|
||||
of the packet. If it's not - then error
|
||||
*/
|
||||
return (packet_end > packet);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Common part of prepared statement execution
|
||||
@ -3243,6 +3399,22 @@ static void mysql_stmt_execute_common(THD *thd,
|
||||
llstr(stmt_id, llbuf), "mysqld_stmt_execute");
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
In case of direct execution application decides how many parameters
|
||||
to send.
|
||||
|
||||
Thus extra checks are required to prevent crashes caused by incorrect
|
||||
interpretation of the packet data. Plus there can be always a broken
|
||||
evil client.
|
||||
*/
|
||||
if (stmt_execute_packet_sanity_check(stmt, packet, packet_end, bulk_op,
|
||||
stmt_id == LAST_STMT_ID, read_types))
|
||||
{
|
||||
my_error(ER_MALFORMED_PACKET, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
stmt->read_types= read_types;
|
||||
|
||||
#if defined(ENABLED_PROFILING)
|
||||
@ -4178,7 +4350,7 @@ Prepared_statement::set_parameters(String *expanded_query,
|
||||
{
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
uchar *null_array= packet;
|
||||
res= (setup_conversion_functions(this, &packet, packet_end) ||
|
||||
res= (setup_conversion_functions(this, &packet) ||
|
||||
set_params(this, null_array, packet, packet_end, expanded_query));
|
||||
#else
|
||||
/*
|
||||
@ -4378,7 +4550,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (read_types &&
|
||||
set_conversion_functions(this, &packet, packet_end))
|
||||
set_conversion_functions(this, &packet))
|
||||
#else
|
||||
// bulk parameters are not supported for embedded, so it will an error
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user