MDEV-27666 User variable not parsed as geometry variable in geometry function

Adding GEOMETRY type user variables.
This commit is contained in:
Alexander Barkov 2023-12-27 18:57:49 +04:00
parent caad34df54
commit fa3171df08
23 changed files with 510 additions and 119 deletions

View File

@ -5328,5 +5328,112 @@ SELECT BIT_XOR(a) FROM t1;
ERROR HY000: Illegal parameter data type geometry for operation 'bit_xor(' ERROR HY000: Illegal parameter data type geometry for operation 'bit_xor('
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-27666 User variable not parsed as geometry variable in geometry function.
#
set @g= point(1, 1);
select ST_AsWKT(GeometryCollection(Point(44, 6), @g));
ST_AsWKT(GeometryCollection(Point(44, 6), @g))
GEOMETRYCOLLECTION(POINT(44 6),POINT(1 1))
set @g= "just a string";
select ST_AsWKT(GeometryCollection(Point(44, 6), @g));
ERROR HY000: Illegal parameter data type longblob for operation 'geometrycollection'
SET @g= LineString(Point(0,0), Point(0,1));
SELECT AsText(PointN(@g, 1));
AsText(PointN(@g, 1))
POINT(0 0)
SELECT AsText(PointN(@g, 2));
AsText(PointN(@g, 2))
POINT(0 1)
SET @g= Point(1, 1);
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` point DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
POINT(1 1)
DROP TABLE t1;
SET @g= MultiPoint(Point(1, 1), Point(-1,-1));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` multipoint DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
MULTIPOINT(1 1,-1 -1)
DROP TABLE t1;
SET @g= LineString(Point(1, 1), Point(2,2));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` linestring DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
LINESTRING(1 1,2 2)
DROP TABLE t1;
SET @g= MultiLineString(LineString(Point(1, 1), Point(2,2)),
LineString(Point(-1, -1), Point(-2,-2)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` multilinestring DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
MULTILINESTRING((1 1,2 2),(-1 -1,-2 -2))
DROP TABLE t1;
SET @g= Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` polygon DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
POLYGON((0 0,30 0,30 30,0 0))
DROP TABLE t1;
SET @g= MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3),
Point(3, 0), Point(0, 3))));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` multipolygon DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
DROP TABLE t1;
SET @g= GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` geometrycollection DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
DROP TABLE t1;
SET @g= GeometryFromText('POINT(1 1)');
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`g` geometry DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT AsText(g) FROM t1;
AsText(g)
POINT(1 1)
DROP TABLE t1;
#
# End of 10.5 tests # End of 10.5 tests
# #

View File

@ -3374,6 +3374,69 @@ SELECT BIT_OR(a) FROM t1;
SELECT BIT_XOR(a) FROM t1; SELECT BIT_XOR(a) FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-27666 User variable not parsed as geometry variable in geometry function.
--echo #
set @g= point(1, 1);
select ST_AsWKT(GeometryCollection(Point(44, 6), @g));
set @g= "just a string";
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
select ST_AsWKT(GeometryCollection(Point(44, 6), @g));
SET @g= LineString(Point(0,0), Point(0,1));
SELECT AsText(PointN(@g, 1));
SELECT AsText(PointN(@g, 2));
SET @g= Point(1, 1);
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= MultiPoint(Point(1, 1), Point(-1,-1));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= LineString(Point(1, 1), Point(2,2));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= MultiLineString(LineString(Point(1, 1), Point(2,2)),
LineString(Point(-1, -1), Point(-2,-2)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3),
Point(3, 0), Point(0, 3))));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)));
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
SET @g= GeometryFromText('POINT(1 1)');
CREATE TABLE t1 AS SELECT @g AS g;
SHOW CREATE TABLE t1;
SELECT AsText(g) FROM t1;
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.5 tests --echo # End of 10.5 tests

View File

@ -0,0 +1,12 @@
SET @g0= POINT(1,1);
SET @g1= Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)));
CREATE TABLE t1 AS SELECT @g0 AS g0, @g1 AS g1;
DROP TABLE t1;
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # User var # # @`g0`=/*point*/_binary X'000000000101000000000000000000F03F000000000000F03F' COLLATE binary
master-bin.000001 # User var # # @`g1`=/*polygon*/_binary X'0000000001030000000100000004000000000000000000000000000000000000000000000000003E4000000000000000000000000000003E400000000000003E4000000000000000000000000000000000' COLLATE binary
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 AS SELECT @g0 AS g0, @g1 AS g1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */

View File

@ -0,0 +1,15 @@
--source include/not_embedded.inc
--source include/have_binlog_format_statement.inc
--source include/have_geometry.inc
--disable_query_log
reset master; # get rid of previous tests binlog
--enable_query_log
SET @g0= POINT(1,1);
SET @g1= Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0)));
CREATE TABLE t1 AS SELECT @g0 AS g0, @g1 AS g1;
DROP TABLE t1;
--let $binlog_file = LAST
source include/show_binlog_events.inc;

View File

@ -0,0 +1,21 @@
include/master-slave.inc
[connection master]
#
#
#
connection master;
SET @p=POINT(1,1);
CREATE TABLE t1 AS SELECT @p AS p;
connection slave;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`p` point DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT ST_AsWKT(p) FROM t1;
ST_AsWKT(p)
POINT(1 1)
connection master;
DROP TABLE t1;
connection slave;
include/rpl_end.inc

View File

@ -0,0 +1,18 @@
--source include/have_geometry.inc
--source include/master-slave.inc
--echo #
--echo #
--echo #
connection master;
SET @p=POINT(1,1);
CREATE TABLE t1 AS SELECT @p AS p;
sync_slave_with_master;
SHOW CREATE TABLE t1;
SELECT ST_AsWKT(p) FROM t1;
connection master;
DROP TABLE t1;
sync_slave_with_master;
--source include/rpl_end.inc

View File

@ -79,9 +79,9 @@ static int user_variables_fill(THD *thd, TABLE_LIST *tables, COND *cond)
else else
return 1; return 1;
const LEX_CSTRING *tmp= var->unsigned_flag ? const LEX_CSTRING *tmp= var->type_handler()->is_unsigned() ?
&unsigned_result_types[var->type] : &unsigned_result_types[var->type_handler()->result_type()] :
&result_types[var->type]; &result_types[var->type_handler()->result_type()];
field[2]->store(tmp->str, tmp->length, system_charset_info); field[2]->store(tmp->str, tmp->length, system_charset_info);
if (var->charset()) if (var->charset())

View File

@ -4658,7 +4658,6 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name,
entry->length=0; entry->length=0;
entry->update_query_id=0; entry->update_query_id=0;
entry->set_charset(NULL); entry->set_charset(NULL);
entry->unsigned_flag= 0;
/* /*
If we are here, we were called from a SET or a query which sets a If we are here, we were called from a SET or a query which sets a
variable. Imagine it is this: variable. Imagine it is this:
@ -4670,7 +4669,7 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name,
by Item_func_get_user_var (because that's not necessary). by Item_func_get_user_var (because that's not necessary).
*/ */
entry->used_query_id=current_thd->query_id; entry->used_query_id=current_thd->query_id;
entry->type=STRING_RESULT; entry->set_handler(&type_handler_long_blob);
memcpy((char*) entry->name.str, name->str, name->length+1); memcpy((char*) entry->name.str, name->str, name->length+1);
if (my_hash_insert(hash,(uchar*) entry)) if (my_hash_insert(hash,(uchar*) entry))
{ {
@ -4746,6 +4745,9 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
switch (args[0]->result_type()) { switch (args[0]->result_type()) {
case STRING_RESULT: case STRING_RESULT:
case TIME_RESULT: case TIME_RESULT:
if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY)
set_handler(args[0]->type_handler());
else
set_handler(type_handler_long_blob. set_handler(type_handler_long_blob.
type_handler_adjusted_to_max_octet_length(max_length, type_handler_adjusted_to_max_octet_length(max_length,
collation.collation)); collation.collation));
@ -4873,9 +4875,9 @@ bool Item_func_set_user_var::register_field_in_bitmap(void *arg)
bool bool
update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
Item_result type, CHARSET_INFO *cs, const Type_handler *th, CHARSET_INFO *cs)
bool unsigned_arg)
{ {
entry->set_handler(th);
if (set_null) if (set_null)
{ {
char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry));
@ -4886,7 +4888,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
} }
else else
{ {
if (type == STRING_RESULT) if (th->result_type() == STRING_RESULT)
length++; // Store strings with end \0 length++; // Store strings with end \0
if (length <= extra_size) if (length <= extra_size)
{ {
@ -4915,20 +4917,18 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
return 1; return 1;
} }
} }
if (type == STRING_RESULT) if (th->result_type() == STRING_RESULT)
{ {
length--; // Fix length change above length--; // Fix length change above
entry->value[length]= 0; // Store end \0 entry->value[length]= 0; // Store end \0
} }
if (length) if (length)
memmove(entry->value, ptr, length); memmove(entry->value, ptr, length);
if (type == DECIMAL_RESULT) if (th->result_type() == DECIMAL_RESULT)
((my_decimal*)entry->value)->fix_buffer_pointer(); ((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length; entry->length= length;
entry->set_charset(cs); entry->set_charset(cs);
entry->unsigned_flag= unsigned_arg;
} }
entry->type=type;
#ifdef USER_VAR_TRACKING #ifdef USER_VAR_TRACKING
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
THD *thd= current_thd; THD *thd= current_thd;
@ -4941,9 +4941,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
bool bool
Item_func_set_user_var::update_hash(void *ptr, size_t length, Item_func_set_user_var::update_hash(void *ptr, size_t length,
Item_result res_type, const Type_handler *th,
CHARSET_INFO *cs, CHARSET_INFO *cs)
bool unsigned_arg)
{ {
/* /*
If we set a variable explicitly to NULL then keep the old If we set a variable explicitly to NULL then keep the old
@ -4957,9 +4956,8 @@ Item_func_set_user_var::update_hash(void *ptr, size_t length,
else else
null_value= args[0]->null_value; null_value= args[0]->null_value;
if (null_value && null_item) if (null_value && null_item)
res_type= m_var_entry->type; // Don't change type of item th= m_var_entry->type_handler(); // Don't change type of item
if (::update_hash(m_var_entry, null_value, if (::update_hash(m_var_entry, null_value, ptr, length, th, cs))
ptr, length, res_type, cs, unsigned_arg))
{ {
null_value= 1; null_value= 1;
return 1; return 1;
@ -4975,7 +4973,7 @@ double user_var_entry::val_real(bool *null_value)
if ((*null_value= (value == 0))) if ((*null_value= (value == 0)))
return 0.0; return 0.0;
switch (type) { switch (type_handler()->result_type()) {
case REAL_RESULT: case REAL_RESULT:
return *(double*) value; return *(double*) value;
case INT_RESULT: case INT_RESULT:
@ -5000,7 +4998,7 @@ longlong user_var_entry::val_int(bool *null_value) const
if ((*null_value= (value == 0))) if ((*null_value= (value == 0)))
return 0; return 0;
switch (type) { switch (type_handler()->result_type()) {
case REAL_RESULT: case REAL_RESULT:
return (longlong) *(double*) value; return (longlong) *(double*) value;
case INT_RESULT: case INT_RESULT:
@ -5029,12 +5027,12 @@ String *user_var_entry::val_str(bool *null_value, String *str,
if ((*null_value= (value == 0))) if ((*null_value= (value == 0)))
return (String*) 0; return (String*) 0;
switch (type) { switch (type_handler()->result_type()) {
case REAL_RESULT: case REAL_RESULT:
str->set_real(*(double*) value, decimals, charset()); str->set_real(*(double*) value, decimals, charset());
break; break;
case INT_RESULT: case INT_RESULT:
if (!unsigned_flag) if (!type_handler()->is_unsigned())
str->set(*(longlong*) value, charset()); str->set(*(longlong*) value, charset());
else else
str->set(*(ulonglong*) value, charset()); str->set(*(ulonglong*) value, charset());
@ -5061,7 +5059,7 @@ my_decimal *user_var_entry::val_decimal(bool *null_value, my_decimal *val)
if ((*null_value= (value == 0))) if ((*null_value= (value == 0)))
return 0; return 0;
switch (type) { switch (type_handler()->result_type()) {
case REAL_RESULT: case REAL_RESULT:
double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val); double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val);
break; break;
@ -5200,33 +5198,37 @@ Item_func_set_user_var::update()
case REAL_RESULT: case REAL_RESULT:
{ {
res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal), res= update_hash((void*) &save_result.vreal,sizeof(save_result.vreal),
REAL_RESULT, &my_charset_numeric, 0); &type_handler_double, &my_charset_numeric);
break; break;
} }
case INT_RESULT: case INT_RESULT:
{ {
res= update_hash((void*) &save_result.vint, sizeof(save_result.vint), res= update_hash((void*) &save_result.vint, sizeof(save_result.vint),
INT_RESULT, &my_charset_numeric, unsigned_flag); unsigned_flag ? (Type_handler *) &type_handler_ulonglong :
(Type_handler *) &type_handler_slonglong,
&my_charset_numeric);
break; break;
} }
case STRING_RESULT: case STRING_RESULT:
{ {
if (!save_result.vstr) // Null value if (!save_result.vstr) // Null value
res= update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin, 0); res= update_hash((void*) 0, 0, &type_handler_long_blob, &my_charset_bin);
else else
res= update_hash((void*) save_result.vstr->ptr(), res= update_hash((void*) save_result.vstr->ptr(),
save_result.vstr->length(), STRING_RESULT, save_result.vstr->length(),
save_result.vstr->charset(), 0); field_type() == MYSQL_TYPE_GEOMETRY ?
type_handler() : &type_handler_long_blob,
save_result.vstr->charset());
break; break;
} }
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
if (!save_result.vdec) // Null value if (!save_result.vdec) // Null value
res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin, 0); res= update_hash((void*) 0, 0, &type_handler_newdecimal, &my_charset_bin);
else else
res= update_hash((void*) save_result.vdec, res= update_hash((void*) save_result.vdec,
sizeof(my_decimal), DECIMAL_RESULT, sizeof(my_decimal), &type_handler_newdecimal,
&my_charset_numeric, 0); &my_charset_numeric);
break; break;
} }
case ROW_RESULT: case ROW_RESULT:
@ -5618,9 +5620,8 @@ get_var_with_binlog(THD *thd, enum_sql_command sql_command,
user_var_event->value= (char*) user_var_event + user_var_event->value= (char*) user_var_event +
ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)); ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
user_var_event->user_var_event= var_entry; user_var_event->user_var_event= var_entry;
user_var_event->type= var_entry->type; user_var_event->th= var_entry->type_handler();
user_var_event->charset_number= var_entry->charset()->number; user_var_event->charset_number= var_entry->charset()->number;
user_var_event->unsigned_flag= var_entry->unsigned_flag;
if (!var_entry->value) if (!var_entry->value)
{ {
/* NULL value*/ /* NULL value*/
@ -5663,9 +5664,9 @@ bool Item_func_get_user_var::fix_length_and_dec()
*/ */
if (likely(!error && m_var_entry)) if (likely(!error && m_var_entry))
{ {
unsigned_flag= m_var_entry->unsigned_flag; unsigned_flag= m_var_entry->type_handler()->is_unsigned();
max_length= (uint32)m_var_entry->length; max_length= (uint32)m_var_entry->length;
switch (m_var_entry->type) { switch (m_var_entry->type_handler()->result_type()) {
case REAL_RESULT: case REAL_RESULT:
collation.set(&my_charset_numeric, DERIVATION_NUMERIC); collation.set(&my_charset_numeric, DERIVATION_NUMERIC);
fix_char_length(DBL_DIG + 8); fix_char_length(DBL_DIG + 8);
@ -5684,6 +5685,8 @@ bool Item_func_get_user_var::fix_length_and_dec()
collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT); collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT);
max_length= MAX_BLOB_WIDTH - 1; max_length= MAX_BLOB_WIDTH - 1;
set_handler(&type_handler_long_blob); set_handler(&type_handler_long_blob);
if (m_var_entry->type_handler()->field_type() == MYSQL_TYPE_GEOMETRY)
set_handler(m_var_entry->type_handler());
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
collation.set(&my_charset_numeric, DERIVATION_NUMERIC); collation.set(&my_charset_numeric, DERIVATION_NUMERIC);
@ -5756,7 +5759,7 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
DBUG_ASSERT(thd->lex->exchange); DBUG_ASSERT(thd->lex->exchange);
if (!(entry= get_variable(&thd->user_vars, &org_name, 1))) if (!(entry= get_variable(&thd->user_vars, &org_name, 1)))
return TRUE; return TRUE;
entry->type= STRING_RESULT; entry->set_handler(&type_handler_long_blob);
/* /*
Let us set the same collation which is used for loading Let us set the same collation which is used for loading
of fields in LOAD DATA INFILE. of fields in LOAD DATA INFILE.
@ -5772,15 +5775,14 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs) void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs)
{ {
::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */); ::update_hash(entry, TRUE, 0, 0, &type_handler_long_blob, cs);
} }
void Item_user_var_as_out_param::set_value(const char *str, uint length, void Item_user_var_as_out_param::set_value(const char *str, uint length,
CHARSET_INFO* cs) CHARSET_INFO* cs)
{ {
::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, ::update_hash(entry, FALSE, (void*)str, length, &type_handler_long_blob, cs);
0 /* unsigned_arg */);
} }

View File

@ -3066,8 +3066,8 @@ public:
String *str_result(String *str); String *str_result(String *str);
my_decimal *val_decimal_result(my_decimal *); my_decimal *val_decimal_result(my_decimal *);
bool is_null_result(); bool is_null_result();
bool update_hash(void *ptr, size_t length, enum Item_result type, bool update_hash(void *ptr, size_t length, const Type_handler *th,
CHARSET_INFO *cs, bool unsigned_arg); CHARSET_INFO *cs);
bool send(Protocol *protocol, st_value *buffer); bool send(Protocol *protocol, st_value *buffer);
void make_send_field(THD *thd, Send_field *tmp_field); void make_send_field(THD *thd, Send_field *tmp_field);
bool check(bool use_result_field); bool check(bool use_result_field);
@ -3825,7 +3825,6 @@ double my_double_round(double value, longlong dec, bool dec_unsigned,
extern bool volatile mqh_used; extern bool volatile mqh_used;
bool update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length, bool update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
Item_result type, CHARSET_INFO *cs, const Type_handler *th, CHARSET_INFO *cs);
bool unsigned_arg);
#endif /* ITEM_FUNC_INCLUDED */ #endif /* ITEM_FUNC_INCLUDED */

View File

@ -6794,18 +6794,12 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
BINLOG_USER_VAR_EVENT *user_var_event; BINLOG_USER_VAR_EVENT *user_var_event;
get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i); get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
/* setting flags for user var log event */
uchar flags= User_var_log_event::UNDEF_F;
if (user_var_event->unsigned_flag)
flags|= User_var_log_event::UNSIGNED_F;
User_var_log_event e(thd, user_var_event->user_var_event->name.str, User_var_log_event e(thd, user_var_event->user_var_event->name.str,
user_var_event->user_var_event->name.length, user_var_event->user_var_event->name.length,
user_var_event->value, user_var_event->value,
user_var_event->length, user_var_event->length,
user_var_event->type, user_var_event->th->user_var_log_event_data_type(
user_var_event->charset_number, user_var_event->charset_number),
flags,
using_trans, using_trans,
direct); direct);
if (write_event(&e, cache_data, file)) if (write_event(&e, cache_data, file))

View File

@ -2880,6 +2880,41 @@ XA_prepare_log_event(const char* buf,
User_var_log_event methods User_var_log_event methods
**************************************************************************/ **************************************************************************/
bool Log_event_data_type::unpack_optional_attributes(const char *pos,
const char *end)
{
for ( ; pos < end; )
{
switch (*pos) {
case CHUNK_SIGNED:
m_is_unsigned= false;
pos++;
continue;
case CHUNK_UNSIGNED:
m_is_unsigned= true;
pos++;
continue;
case CHUNK_DATA_TYPE_NAME:
{
pos++;
if (pos >= end)
return true;
uint length= (uchar) *pos++;
if (pos + length > end)
return true;
m_data_type_name= {pos, length};
pos+= length;
continue;
}
default:
break; // Unknown chunk
}
}
return false;
}
User_var_log_event:: User_var_log_event::
User_var_log_event(const char* buf, uint event_len, User_var_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event) const Format_description_log_event* description_event)
@ -2917,11 +2952,8 @@ User_var_log_event(const char* buf, uint event_len,
buf+= UV_NAME_LEN_SIZE + name_len; buf+= UV_NAME_LEN_SIZE + name_len;
is_null= (bool) *buf; is_null= (bool) *buf;
flags= User_var_log_event::UNDEF_F; // defaults to UNDEF_F
if (is_null) if (is_null)
{ {
type= STRING_RESULT;
charset_number= my_charset_bin.number;
val_len= 0; val_len= 0;
val= 0; val= 0;
} }
@ -2936,8 +2968,8 @@ User_var_log_event(const char* buf, uint event_len,
goto err; goto err;
} }
type= (Item_result) buf[UV_VAL_IS_NULL]; m_type= (Item_result) buf[UV_VAL_IS_NULL];
charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE); m_charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE); UV_CHARSET_NUMBER_SIZE);
@ -2950,20 +2982,14 @@ User_var_log_event(const char* buf, uint event_len,
the flags value. the flags value.
Old events will not have this extra byte, thence, Old events will not have this extra byte, thence,
we keep the flags set to UNDEF_F. we keep m_is_unsigned==false.
*/ */
size_t bytes_read= (val + val_len) - buf_start; const char *pos= val + val_len;
if (bytes_read > event_len) if (pos > buf_end || unpack_optional_attributes(pos, buf_end))
{ {
error= true; error= true;
goto err; goto err;
} }
if ((data_written - bytes_read) > 0)
{
flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE +
val_len);
}
} }
err: err:

View File

@ -57,6 +57,8 @@
#include "rpl_gtid.h" #include "rpl_gtid.h"
#include "log_event_data_type.h"
/* Forward declarations */ /* Forward declarations */
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
class String; class String;
@ -3269,32 +3271,27 @@ private:
@section User_var_log_event_binary_format Binary Format @section User_var_log_event_binary_format Binary Format
*/ */
class User_var_log_event: public Log_event
class User_var_log_event: public Log_event, public Log_event_data_type
{ {
public: public:
enum {
UNDEF_F= 0,
UNSIGNED_F= 1
};
const char *name; const char *name;
size_t name_len; size_t name_len;
const char *val; const char *val;
size_t val_len; size_t val_len;
Item_result type;
uint charset_number;
bool is_null; bool is_null;
uchar flags;
#ifdef MYSQL_SERVER #ifdef MYSQL_SERVER
bool deferred; bool deferred;
query_id_t query_id; query_id_t query_id;
User_var_log_event(THD* thd_arg, const char *name_arg, size_t name_len_arg, User_var_log_event(THD* thd_arg, const char *name_arg, size_t name_len_arg,
const char *val_arg, size_t val_len_arg, Item_result type_arg, const char *val_arg, size_t val_len_arg,
uint charset_number_arg, uchar flags_arg, const Log_event_data_type &data_type,
bool using_trans, bool direct) bool using_trans, bool direct)
:Log_event(thd_arg, 0, using_trans), :Log_event(thd_arg, 0, using_trans),
Log_event_data_type(data_type),
name(name_arg), name_len(name_len_arg), val(val_arg), name(name_arg), name_len(name_len_arg), val(val_arg),
val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg), val_len(val_len_arg),
flags(flags_arg), deferred(false) deferred(false)
{ {
is_null= !val; is_null= !val;
if (direct) if (direct)

View File

@ -2435,7 +2435,7 @@ bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
} }
else else
{ {
switch (type) { switch (m_type) {
case REAL_RESULT: case REAL_RESULT:
double real_val; double real_val;
char real_buf[FMT_G_BUFSIZE(14)]; char real_buf[FMT_G_BUFSIZE(14)];
@ -2447,8 +2447,7 @@ bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
break; break;
case INT_RESULT: case INT_RESULT:
char int_buf[22]; char int_buf[22];
longlong10_to_str(uint8korr(val), int_buf, longlong10_to_str(uint8korr(val), int_buf, is_unsigned() ? 10 : -10);
((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
if (my_b_printf(&cache, ":=%s%s\n", int_buf, if (my_b_printf(&cache, ":=%s%s\n", int_buf,
print_event_info->delimiter)) print_event_info->delimiter))
goto err; goto err;
@ -2503,7 +2502,7 @@ bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
people want to mysqlbinlog|mysql into another server not supporting the people want to mysqlbinlog|mysql into another server not supporting the
character set. But there's not much to do about this and it's unlikely. character set. But there's not much to do about this and it's unlikely.
*/ */
if (!(cs= get_charset(charset_number, MYF(0)))) if (!(cs= get_charset(m_charset_number, MYF(0))))
{ /* { /*
Generate an unusable command (=> syntax error) is probably the best Generate an unusable command (=> syntax error) is probably the best
thing we can do here. thing we can do here.

74
sql/log_event_data_type.h Normal file
View File

@ -0,0 +1,74 @@
/* Copyright (c) 2024, 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 St, Fifth Floor, Boston, MA 02110-1335 USA */
#ifndef LOG_EVENT_DATA_TYPE_H
#define LOG_EVENT_DATA_TYPE_H
class Log_event_data_type
{
public:
enum {
CHUNK_SIGNED= 0,
CHUNK_UNSIGNED= 1,
CHUNK_DATA_TYPE_NAME= 2
};
protected:
LEX_CSTRING m_data_type_name;
Item_result m_type;
uint m_charset_number;
bool m_is_unsigned;
public:
Log_event_data_type()
:m_data_type_name({NULL,0}),
m_type(STRING_RESULT),
m_charset_number(my_charset_bin.number),
m_is_unsigned(false)
{ }
Log_event_data_type(const LEX_CSTRING &data_type_name_arg,
Item_result type_arg,
uint charset_number_arg,
bool is_unsigned_arg)
:m_data_type_name(data_type_name_arg),
m_type(type_arg),
m_charset_number(charset_number_arg),
m_is_unsigned(is_unsigned_arg)
{ }
const LEX_CSTRING & data_type_name() const
{
return m_data_type_name;
}
Item_result type() const
{
return m_type;
}
uint charset_number() const
{
return m_charset_number;
}
bool is_unsigned() const
{
return m_is_unsigned;
}
bool unpack_optional_attributes(const char *str, const char *end);
};
#endif // LOG_EVENT_DATA_TYPE_H

View File

@ -4170,11 +4170,16 @@ bool XA_prepare_log_event::write()
#if defined(HAVE_REPLICATION) #if defined(HAVE_REPLICATION)
static bool static bool
user_var_append_name_part(THD *thd, String *buf, user_var_append_name_part(THD *thd, String *buf,
const char *name, size_t name_len) const char *name, size_t name_len,
const LEX_CSTRING &data_type_name)
{ {
return buf->append("@") || return buf->append("@") ||
append_identifier(thd, buf, name, name_len) || append_identifier(thd, buf, name, name_len) ||
buf->append("="); buf->append("=") ||
(data_type_name.length &&
(buf->append("/*") ||
buf->append(data_type_name.str, data_type_name.length) ||
buf->append("*/")));
} }
void User_var_log_event::pack_info(Protocol* protocol) void User_var_log_event::pack_info(Protocol* protocol)
@ -4184,14 +4189,15 @@ void User_var_log_event::pack_info(Protocol* protocol)
char buf_mem[FN_REFLEN+7]; char buf_mem[FN_REFLEN+7];
String buf(buf_mem, sizeof(buf_mem), system_charset_info); String buf(buf_mem, sizeof(buf_mem), system_charset_info);
buf.length(0); buf.length(0);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || if (user_var_append_name_part(protocol->thd, &buf, name, name_len,
m_data_type_name) ||
buf.append("NULL")) buf.append("NULL"))
return; return;
protocol->store(buf.ptr(), buf.length(), &my_charset_bin); protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
} }
else else
{ {
switch (type) { switch (m_type) {
case REAL_RESULT: case REAL_RESULT:
{ {
double real_val; double real_val;
@ -4200,7 +4206,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
String buf(buf_mem, sizeof(buf_mem), system_charset_info); String buf(buf_mem, sizeof(buf_mem), system_charset_info);
float8get(real_val, val); float8get(real_val, val);
buf.length(0); buf.length(0);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || if (user_var_append_name_part(protocol->thd, &buf, name, name_len,
m_data_type_name) ||
buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE, buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL))) MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
return; return;
@ -4213,10 +4220,11 @@ void User_var_log_event::pack_info(Protocol* protocol)
char buf_mem[FN_REFLEN + 22]; char buf_mem[FN_REFLEN + 22];
String buf(buf_mem, sizeof(buf_mem), system_charset_info); String buf(buf_mem, sizeof(buf_mem), system_charset_info);
buf.length(0); buf.length(0);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || if (user_var_append_name_part(protocol->thd, &buf, name, name_len,
m_data_type_name) ||
buf.append(buf2, buf.append(buf2,
longlong10_to_str(uint8korr(val), buf2, longlong10_to_str(uint8korr(val), buf2,
((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2)) (is_unsigned() ? 10 : -10))-buf2))
return; return;
protocol->store(buf.ptr(), buf.length(), &my_charset_bin); protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
break; break;
@ -4229,7 +4237,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
String str(buf2, sizeof(buf2), &my_charset_bin); String str(buf2, sizeof(buf2), &my_charset_bin);
buf.length(0); buf.length(0);
my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str); my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || if (user_var_append_name_part(protocol->thd, &buf, name, name_len,
m_data_type_name) ||
buf.append(buf2)) buf.append(buf2))
return; return;
protocol->store(buf.ptr(), buf.length(), &my_charset_bin); protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
@ -4242,7 +4251,7 @@ void User_var_log_event::pack_info(Protocol* protocol)
String buf(buf_mem, sizeof(buf_mem), system_charset_info); String buf(buf_mem, sizeof(buf_mem), system_charset_info);
CHARSET_INFO *cs; CHARSET_INFO *cs;
buf.length(0); buf.length(0);
if (!(cs= get_charset(charset_number, MYF(0)))) if (!(cs= get_charset(m_charset_number, MYF(0))))
{ {
if (buf.append("???")) if (buf.append("???"))
return; return;
@ -4251,7 +4260,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
{ {
size_t old_len; size_t old_len;
char *beg, *end; char *beg, *end;
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) || if (user_var_append_name_part(protocol->thd, &buf, name, name_len,
m_data_type_name) ||
buf.append("_") || buf.append("_") ||
buf.append(cs->csname) || buf.append(cs->csname) ||
buf.append(" ")) buf.append(" "))
@ -4299,10 +4309,10 @@ bool User_var_log_event::write()
} }
else else
{ {
buf1[1]= type; buf1[1]= m_type;
int4store(buf1 + 2, charset_number); int4store(buf1 + 2, m_charset_number);
switch (type) { switch (m_type) {
case REAL_RESULT: case REAL_RESULT:
float8store(buf2, *(double*) val); float8store(buf2, *(double*) val);
break; break;
@ -4332,15 +4342,28 @@ bool User_var_log_event::write()
buf1_length= 10; buf1_length= 10;
} }
/* Length of the whole event */ uchar data_type_name_chunk_signature= (uchar) CHUNK_DATA_TYPE_NAME;
event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len; uint data_type_name_chunk_signature_length= m_data_type_name.length ? 1 : 0;
uchar data_type_name_length_length= m_data_type_name.length ? 1 : 0;
/* Length of the whole event */
event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len +
data_type_name_chunk_signature_length +
data_type_name_length_length +
(uint) m_data_type_name.length;
uchar unsig= m_is_unsigned ? CHUNK_UNSIGNED : CHUNK_SIGNED;
uchar data_type_name_length= (uchar) m_data_type_name.length;
return write_header(event_length) || return write_header(event_length) ||
write_data(buf, sizeof(buf)) || write_data(buf, sizeof(buf)) ||
write_data(name, name_len) || write_data(name, name_len) ||
write_data(buf1, buf1_length) || write_data(buf1, buf1_length) ||
write_data(pos, val_len) || write_data(pos, val_len) ||
write_data(&flags, unsigned_len) || write_data(&unsig, unsigned_len) ||
write_data(&data_type_name_chunk_signature,
data_type_name_chunk_signature_length) ||
write_data(&data_type_name_length, data_type_name_length_length) ||
write_data(m_data_type_name.str, (uint) m_data_type_name.length) ||
write_footer(); write_footer();
} }
@ -4364,7 +4387,7 @@ int User_var_log_event::do_apply_event(rpl_group_info *rgi)
current_thd->query_id= query_id; /* recreating original time context */ current_thd->query_id= query_id; /* recreating original time context */
} }
if (!(charset= get_charset(charset_number, MYF(MY_WME)))) if (!(charset= get_charset(m_charset_number, MYF(MY_WME))))
{ {
rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
ER_THD(thd, ER_SLAVE_FATAL_ERROR), ER_THD(thd, ER_SLAVE_FATAL_ERROR),
@ -4383,7 +4406,7 @@ int User_var_log_event::do_apply_event(rpl_group_info *rgi)
} }
else else
{ {
switch (type) { switch (m_type) {
case REAL_RESULT: case REAL_RESULT:
if (val_len != 8) if (val_len != 8)
{ {
@ -4447,13 +4470,10 @@ int User_var_log_event::do_apply_event(rpl_group_info *rgi)
if (e->fix_fields(thd, 0)) if (e->fix_fields(thd, 0))
DBUG_RETURN(1); DBUG_RETURN(1);
/* const Type_handler *th= Type_handler::handler_by_log_event_data_type(thd,
A variable can just be considered as a table with *this);
a single record and with a single column. Thus, like e->update_hash((void*) val, val_len, th, charset);
a column value, it could always have IMPLICIT derivation.
*/
e->update_hash((void*) val, val_len, type, charset,
(flags & User_var_log_event::UNSIGNED_F));
if (!is_deferred()) if (!is_deferred())
free_root(thd->mem_root, 0); free_root(thd->mem_root, 0);
else else

View File

@ -134,7 +134,7 @@ int binlog_defragment(THD *thd)
entry[k]= entry[k]=
(user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name[k].str, (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name[k].str,
name[k].length); name[k].length);
if (!entry[k] || entry[k]->type != STRING_RESULT) if (!entry[k] || entry[k]->type_handler()->result_type() != STRING_RESULT)
{ {
my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), name[k].str); my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), name[k].str);
return -1; return -1;
@ -159,7 +159,8 @@ int binlog_defragment(THD *thd)
gathered_length += entry[k]->length; gathered_length += entry[k]->length;
} }
for (uint k=0; k < 2; k++) for (uint k=0; k < 2; k++)
update_hash(entry[k], true, NULL, 0, STRING_RESULT, &my_charset_bin, 0); update_hash(entry[k], true, NULL, 0,
&type_handler_long_blob, &my_charset_bin);
DBUG_ASSERT(gathered_length == thd->lex->comment.length); DBUG_ASSERT(gathered_length == thd->lex->comment.length);

View File

@ -275,9 +275,8 @@ typedef struct st_user_var_events
user_var_entry *user_var_event; user_var_entry *user_var_event;
char *value; char *value;
size_t length; size_t length;
Item_result type; const Type_handler *th;
uint charset_number; uint charset_number;
bool unsigned_flag;
} BINLOG_USER_VAR_EVENT; } BINLOG_USER_VAR_EVENT;
/* /*
@ -6808,7 +6807,7 @@ public:
// this is needed for user_vars hash // this is needed for user_vars hash
class user_var_entry class user_var_entry: public Type_handler_hybrid_field_type
{ {
CHARSET_INFO *m_charset; CHARSET_INFO *m_charset;
public: public:
@ -6817,8 +6816,6 @@ class user_var_entry
char *value; char *value;
size_t length; size_t length;
query_id_t update_query_id, used_query_id; query_id_t update_query_id, used_query_id;
Item_result type;
bool unsigned_flag;
double val_real(bool *null_value); double val_real(bool *null_value);
longlong val_int(bool *null_value) const; longlong val_int(bool *null_value) const;

View File

@ -510,7 +510,7 @@ static enum enum_binlog_checksum_alg get_binlog_checksum_value_at_connect(THD *
} }
else else
{ {
DBUG_ASSERT(entry->type == STRING_RESULT); DBUG_ASSERT(entry->type_handler()->result_type() == STRING_RESULT);
String str; String str;
uint dummy_errors; uint dummy_errors;
str.copy(entry->value, entry->length, &my_charset_bin, &my_charset_bin, str.copy(entry->value, entry->length, &my_charset_bin, &my_charset_bin,

View File

@ -2248,6 +2248,34 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
} }
const Type_handler *
Type_handler::handler_by_log_event_data_type(THD *thd,
const Log_event_data_type &type)
{
if (type.data_type_name().length)
{
const Type_handler *th= handler_by_name(thd, type.data_type_name());
if (th)
return th;
}
switch (type.type()) {
case STRING_RESULT:
case ROW_RESULT:
case TIME_RESULT:
break;
case REAL_RESULT:
return &type_handler_double;
case INT_RESULT:
if (type.is_unsigned())
return &type_handler_ulonglong;
return &type_handler_slonglong;
case DECIMAL_RESULT:
return &type_handler_newdecimal;
}
return &type_handler_long_blob;
}
/** /**
Create a DOUBLE field by default. Create a DOUBLE field by default.
*/ */

View File

@ -30,6 +30,8 @@
#include "sql_type_string.h" #include "sql_type_string.h"
#include "sql_type_real.h" #include "sql_type_real.h"
#include "compat56.h" #include "compat56.h"
#include "log_event_data_type.h"
C_MODE_START C_MODE_START
#include <ma_dyncol.h> #include <ma_dyncol.h>
C_MODE_END C_MODE_END
@ -3652,6 +3654,9 @@ public:
static const Type_handler *handler_by_name(THD *thd, const LEX_CSTRING &name); static const Type_handler *handler_by_name(THD *thd, const LEX_CSTRING &name);
static const Type_handler *handler_by_name_or_error(THD *thd, static const Type_handler *handler_by_name_or_error(THD *thd,
const LEX_CSTRING &name); const LEX_CSTRING &name);
static const Type_handler *handler_by_log_event_data_type(
THD *thd,
const Log_event_data_type &type);
static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str); static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str);
static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *blob_type_handler(uint max_octet_length);
static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length);
@ -3936,6 +3941,12 @@ public:
{ {
return false; return false;
} }
virtual Log_event_data_type user_var_log_event_data_type(uint charset_nr) const
{
return Log_event_data_type({NULL,0}/*data type name*/, result_type(),
charset_nr, is_unsigned());
}
virtual uint Column_definition_gis_options_image(uchar *buff, virtual uint Column_definition_gis_options_image(uchar *buff,
const Column_definition &def) const Column_definition &def)
const const

View File

@ -81,6 +81,13 @@ public:
Field *make_conversion_table_field(MEM_ROOT *root, Field *make_conversion_table_field(MEM_ROOT *root,
TABLE *table, uint metadata, TABLE *table, uint metadata,
const Field *target) const override; const Field *target) const override;
Log_event_data_type user_var_log_event_data_type(uint charset_nr)
const override
{
return Log_event_data_type(name().lex_cstring(), result_type(),
charset_nr, false/*unsigned*/);
}
uint Column_definition_gis_options_image(uchar *buff, uint Column_definition_gis_options_image(uchar *buff,
const Column_definition &def) const Column_definition &def)
const override; const override;

View File

@ -1886,7 +1886,7 @@ int spider_conn_queue_loop_check(
loop_check_buf[lex_str.length] = '\0'; loop_check_buf[lex_str.length] = '\0';
DBUG_PRINT("info", ("spider param name=%s", lex_str.str)); DBUG_PRINT("info", ("spider param name=%s", lex_str.str));
loop_check = get_variable(&thd->user_vars, &lex_str, FALSE); loop_check = get_variable(&thd->user_vars, &lex_str, FALSE);
if (!loop_check || loop_check->type != STRING_RESULT) if (!loop_check || loop_check->type_handler()->result_type() != STRING_RESULT)
{ {
DBUG_PRINT("info", ("spider client is not Spider")); DBUG_PRINT("info", ("spider client is not Spider"));
lex_str.str = ""; lex_str.str = "";

View File

@ -4742,7 +4742,7 @@ SPIDER_SHARE *spider_get_share(
((char *) lex_str.str)[lex_str.length] = '\0'; ((char *) lex_str.str)[lex_str.length] = '\0';
DBUG_PRINT("info",("spider loop check param name=%s", lex_str.str)); DBUG_PRINT("info",("spider loop check param name=%s", lex_str.str));
loop_check = get_variable(&thd->user_vars, &lex_str, FALSE); loop_check = get_variable(&thd->user_vars, &lex_str, FALSE);
if (loop_check && loop_check->type == STRING_RESULT) if (loop_check && loop_check->type_handler()->result_type() == STRING_RESULT)
{ {
lex_str.length = top_share->path.length + spider_unique_id.length + 1; lex_str.length = top_share->path.length + spider_unique_id.length + 1;
lex_str.str = loop_check_buf + buf_sz - top_share->path.length - lex_str.str = loop_check_buf + buf_sz - top_share->path.length -