Bug#18761: constant expression as UDF parameters not passed in as constant

The code that set up data to be passed to user-defined functions was very
old and analyzed the "Type" of the data that was passed into the UDF, when
it really should analyze the "return_type", which is hard-coded for simple
Items and works correctly for complex ones like functions.
---
Added test at Sergei's behest.
parent e8c7f191
...@@ -15,3 +15,11 @@ ...@@ -15,3 +15,11 @@
45214442pBGT9KuZEGixBH71jTzbOA 45214442pBGT9KuZEGixBH71jTzbOA
45214a07hVsIGwvwa-WrO-jpeaSwVw 45214a07hVsIGwvwa-WrO-jpeaSwVw
452a92d0-31-8wSzSfZi165fcGcXPA 452a92d0-31-8wSzSfZi165fcGcXPA
454bb488ijVLOUK_GFjcoISE0GxPUA
454bb9a8AwlGRC_wWLS2sNMoRBMRGw
454c946ciQoR4dfTBZ0RTBmGJKp6lw
454f6e7eAnfLD9OCbGr5X9KiKvfKcQ
454f704bJiJy0_Nx2drY9P5kK3uOzg
454fa71cxshxszXJQYa9jbo0-_hAHw
4550b0ceIcozdgQhWFUTAtWkN196lA
4558b3d73Cxjlb7Wv1oytdSTthxDfw
...@@ -115,3 +115,38 @@ DROP FUNCTION sequence; ...@@ -115,3 +115,38 @@ DROP FUNCTION sequence;
DROP FUNCTION lookup; DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup; DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost; DROP FUNCTION avgcost;
CREATE FUNCTION is_const RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
select
is_const(3) as const,
is_const(3.14) as const,
is_const('fnord') as const,
is_const(2+3) as const,
is_const(rand()) as 'nc rand()',
is_const(sin(3.14)) as const,
is_const(upper('test')) as const;
const const const const nc rand() const const
const const const const not const const const
create table bug18761 (n int);
insert into bug18761 values (null),(2);
select
is_const(3) as const,
is_const(3.14) as const,
is_const('fnord') as const,
is_const(2+3) as const,
is_const(2+n) as 'nc 2+n ',
is_const(sin(n)) as 'nc sin(n)',
is_const(sin(3.14)) as const,
is_const(upper('test')) as const,
is_const(rand()) as 'nc rand()',
is_const(n) as 'nc n ',
is_const(is_const(n)) as 'nc ic?(n)',
is_const(is_const('c')) as const
from
bug18761;
const const const const nc 2+n nc sin(n) const const nc rand() nc n nc ic?(n) const
const const const const not const not const const const not const not const not const const
const const const const not const not const const const not const not const not const const
drop table bug18761;
select is_const((1,2,3));
ERROR 21000: Operand should contain 1 column(s)
drop function if exists is_const;
...@@ -143,4 +143,41 @@ DROP FUNCTION lookup; ...@@ -143,4 +143,41 @@ DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup; DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost; DROP FUNCTION avgcost;
#
# Bug#18761: constant expression as UDF parameters not passed in as constant
#
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
eval CREATE FUNCTION is_const RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
select
is_const(3) as const,
is_const(3.14) as const,
is_const('fnord') as const,
is_const(2+3) as const,
is_const(rand()) as 'nc rand()',
is_const(sin(3.14)) as const,
is_const(upper('test')) as const;
create table bug18761 (n int);
insert into bug18761 values (null),(2);
select
is_const(3) as const,
is_const(3.14) as const,
is_const('fnord') as const,
is_const(2+3) as const,
is_const(2+n) as 'nc 2+n ',
is_const(sin(n)) as 'nc sin(n)',
is_const(sin(3.14)) as const,
is_const(upper('test')) as const,
is_const(rand()) as 'nc rand()',
is_const(n) as 'nc n ',
is_const(is_const(n)) as 'nc ic?(n)',
is_const(is_const('c')) as const
from
bug18761;
drop table bug18761;
--error 1241
select is_const((1,2,3));
drop function if exists is_const;
...@@ -2683,41 +2683,49 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, ...@@ -2683,41 +2683,49 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
char *to=num_buffer; char *to=num_buffer;
for (uint i=0; i < arg_count; i++) for (uint i=0; i < arg_count; i++)
{ {
f_args.args[i]=0; /*
For a constant argument i, args->args[i] points to the argument value.
For non-constant, args->args[i] is NULL.
*/
f_args.args[i]= NULL; /* Non-const unless updated below. */
f_args.lengths[i]= arguments[i]->max_length; f_args.lengths[i]= arguments[i]->max_length;
f_args.maybe_null[i]= (char) arguments[i]->maybe_null; f_args.maybe_null[i]= (char) arguments[i]->maybe_null;
f_args.attributes[i]= arguments[i]->name; f_args.attributes[i]= arguments[i]->name;
f_args.attribute_lengths[i]= arguments[i]->name_length; f_args.attribute_lengths[i]= arguments[i]->name_length;
switch(arguments[i]->type()) { if (arguments[i]->const_item())
case Item::STRING_ITEM: // Constant string !
{ {
String *res=arguments[i]->val_str(&buffers[i]);
if (arguments[i]->null_value) if (arguments[i]->null_value)
continue; continue;
switch (arguments[i]->result_type())
{
case STRING_RESULT:
case DECIMAL_RESULT:
{
String *res= arguments[i]->val_str(&buffers[i]);
f_args.args[i]= (char*) res->ptr(); f_args.args[i]= (char*) res->ptr();
break; break;
} }
case Item::INT_ITEM: case INT_RESULT:
*((longlong*) to) = arguments[i]->val_int(); *((longlong*) to)= arguments[i]->val_int();
if (!arguments[i]->null_value) f_args.args[i]= to;
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(longlong)); to+= ALIGN_SIZE(sizeof(longlong));
}
break; break;
case Item::REAL_ITEM: case REAL_RESULT:
*((double*) to)= arguments[i]->val_real(); *((double*) to)= arguments[i]->val_real();
if (!arguments[i]->null_value) f_args.args[i]= to;
{
f_args.args[i]=to;
to+= ALIGN_SIZE(sizeof(double)); to+= ALIGN_SIZE(sizeof(double));
}
break; break;
default: // Skip these case ROW_RESULT:
default:
// This case should never be chosen
DBUG_ASSERT(0);
break; break;
} }
} }
}
thd->net.last_error[0]=0; thd->net.last_error[0]=0;
Udf_func_init init= u_d->func_init; Udf_func_init init= u_d->func_init;
if ((error=(uchar) init(&initid, &f_args, thd->net.last_error))) if ((error=(uchar) init(&initid, &f_args, thd->net.last_error)))
......
...@@ -165,6 +165,9 @@ void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ...@@ -165,6 +165,9 @@ void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error
void avgcost_clear( UDF_INIT* initid, char* is_null, char *error ); void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long
*length, char *is_null, char *error);
/************************************************************************* /*************************************************************************
...@@ -1075,4 +1078,31 @@ char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)), ...@@ -1075,4 +1078,31 @@ char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)),
return result; return result;
} }
my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
if (args->arg_count != 1)
{
strmov(message, "IS_CONST accepts only one argument");
return 1;
}
initid->ptr= (args->args[0] != NULL) ? 1 : 0;
return 0;
}
char * is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long
*length, char *is_null, char *error)
{
if (initid->ptr != 0) {
sprintf(result, "const");
} else {
sprintf(result, "not const");
}
*is_null= 0;
*length= strlen(result);
return result;
}
#endif /* HAVE_DLOPEN */ #endif /* HAVE_DLOPEN */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment