mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
new UDF arguments interface (WL#1017) (SCRUM)
This commit is contained in:
@ -278,6 +278,8 @@ typedef struct st_udf_args
|
|||||||
char **args; /* Pointer to argument */
|
char **args; /* Pointer to argument */
|
||||||
unsigned long *lengths; /* Length of string arguments */
|
unsigned long *lengths; /* Length of string arguments */
|
||||||
char *maybe_null; /* Set to 1 for all maybe_null args */
|
char *maybe_null; /* Set to 1 for all maybe_null args */
|
||||||
|
char **attributes; /* Pointer to attribute name */
|
||||||
|
unsigned long *attribute_lengths; /* Length of attribute arguments */
|
||||||
} UDF_ARGS;
|
} UDF_ARGS;
|
||||||
|
|
||||||
/* This holds information about the result */
|
/* This holds information about the result */
|
||||||
|
@ -39,7 +39,7 @@ void item_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Item::Item():
|
Item::Item():
|
||||||
fixed(0)
|
name_length(0), fixed(0)
|
||||||
{
|
{
|
||||||
marker= 0;
|
marker= 0;
|
||||||
maybe_null=null_value=with_sum_func=unsigned_flag=0;
|
maybe_null=null_value=with_sum_func=unsigned_flag=0;
|
||||||
@ -121,6 +121,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
|
|||||||
{
|
{
|
||||||
/* Empty string, used by AS or internal function like last_insert_id() */
|
/* Empty string, used by AS or internal function like last_insert_id() */
|
||||||
name= (char*) str;
|
name= (char*) str;
|
||||||
|
name_length= 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (length && !my_isgraph(cs,*str))
|
while (length && !my_isgraph(cs,*str))
|
||||||
@ -131,12 +132,12 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
|
|||||||
if (!my_charset_same(cs, system_charset_info))
|
if (!my_charset_same(cs, system_charset_info))
|
||||||
{
|
{
|
||||||
uint32 res_length;
|
uint32 res_length;
|
||||||
name= sql_strmake_with_convert(str, length, cs,
|
name= sql_strmake_with_convert(str, name_length= length, cs,
|
||||||
MAX_ALIAS_NAME, system_charset_info,
|
MAX_ALIAS_NAME, system_charset_info,
|
||||||
&res_length);
|
&res_length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
name=sql_strmake(str, min(length,MAX_ALIAS_NAME));
|
name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ public:
|
|||||||
my_string name; /* Name from select */
|
my_string name; /* Name from select */
|
||||||
Item *next;
|
Item *next;
|
||||||
uint32 max_length;
|
uint32 max_length;
|
||||||
|
uint name_length; /* Length of name */
|
||||||
uint8 marker,decimals;
|
uint8 marker,decimals;
|
||||||
my_bool maybe_null; /* If item may be null */
|
my_bool maybe_null; /* If item may be null */
|
||||||
my_bool null_value; /* if item is null */
|
my_bool null_value; /* if item is null */
|
||||||
|
@ -1498,11 +1498,16 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
|
|||||||
const_item_cache&=item->const_item();
|
const_item_cache&=item->const_item();
|
||||||
f_args.arg_type[i]=item->result_type();
|
f_args.arg_type[i]=item->result_type();
|
||||||
}
|
}
|
||||||
|
//TODO: why all folowing memory is not allocated with 1 call of sql_alloc?
|
||||||
if (!(buffers=new String[arg_count]) ||
|
if (!(buffers=new String[arg_count]) ||
|
||||||
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
|
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
|
||||||
!(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) ||
|
!(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) ||
|
||||||
!(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) ||
|
!(f_args.maybe_null= (char*) sql_alloc(arg_count * sizeof(char))) ||
|
||||||
!(num_buffer= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
|
!(num_buffer= (char*) sql_alloc(arg_count *
|
||||||
|
ALIGN_SIZE(sizeof(double)))) ||
|
||||||
|
!(f_args.attributes= (char**) sql_alloc(arg_count * sizeof(char *))) ||
|
||||||
|
!(f_args.attribute_lengths= (ulong*) sql_alloc(arg_count *
|
||||||
|
sizeof(long))))
|
||||||
{
|
{
|
||||||
free_udf(u_d);
|
free_udf(u_d);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -1521,8 +1526,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
|
|||||||
for (uint i=0; i < arg_count; i++)
|
for (uint i=0; i < arg_count; i++)
|
||||||
{
|
{
|
||||||
f_args.args[i]=0;
|
f_args.args[i]=0;
|
||||||
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.attribute_lengths[i]= arguments[i]->name_length;
|
||||||
|
|
||||||
switch(arguments[i]->type()) {
|
switch(arguments[i]->type()) {
|
||||||
case Item::STRING_ITEM: // Constant string !
|
case Item::STRING_ITEM: // Constant string !
|
||||||
|
@ -2986,6 +2986,8 @@ mysql_execute_command(THD *thd)
|
|||||||
break;
|
break;
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
sp_head *sph= sp_find_function(thd, &lex->udf.name);
|
sp_head *sph= sp_find_function(thd, &lex->udf.name);
|
||||||
|
// close & unlock table opened by sp_find_function
|
||||||
|
close_thread_tables(thd);
|
||||||
if (sph)
|
if (sph)
|
||||||
{
|
{
|
||||||
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
|
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
|
||||||
|
@ -630,13 +630,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
%type <item>
|
%type <item>
|
||||||
literal text_literal insert_ident order_ident
|
literal text_literal insert_ident order_ident
|
||||||
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
|
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
|
||||||
table_wild no_in_expr expr_expr simple_expr no_and_expr
|
table_wild no_in_expr expr_expr simple_expr no_and_expr udf_expr
|
||||||
using_list expr_or_default set_expr_or_default interval_expr
|
using_list expr_or_default set_expr_or_default interval_expr
|
||||||
param_marker singlerow_subselect singlerow_subselect_init
|
param_marker singlerow_subselect singlerow_subselect_init
|
||||||
exists_subselect exists_subselect_init sp_opt_default
|
exists_subselect exists_subselect_init sp_opt_default
|
||||||
|
|
||||||
%type <item_list>
|
%type <item_list>
|
||||||
expr_list udf_expr_list when_list ident_list ident_list_arg
|
expr_list sp_expr_list udf_expr_list udf_expr_list2 when_list
|
||||||
|
ident_list ident_list_arg
|
||||||
|
|
||||||
%type <key_type>
|
%type <key_type>
|
||||||
key_type opt_unique_or_fulltext
|
key_type opt_unique_or_fulltext
|
||||||
@ -702,7 +703,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
select_item_list select_item values_list no_braces
|
select_item_list select_item values_list no_braces
|
||||||
opt_limit_clause delete_limit_clause fields opt_values values
|
opt_limit_clause delete_limit_clause fields opt_values values
|
||||||
procedure_list procedure_list2 procedure_item
|
procedure_list procedure_list2 procedure_item
|
||||||
when_list2 expr_list2 handler
|
when_list2 expr_list2 udf_expr_list3 handler
|
||||||
opt_precision opt_ignore opt_column opt_restrict
|
opt_precision opt_ignore opt_column opt_restrict
|
||||||
grant revoke set lock unlock string_list field_options field_option
|
grant revoke set lock unlock string_list field_options field_option
|
||||||
field_opt_list opt_binary table_lock_list table_lock
|
field_opt_list opt_binary table_lock_list table_lock
|
||||||
@ -3246,7 +3247,7 @@ simple_expr:
|
|||||||
{ $$= new Item_func_round($3,$5,1); }
|
{ $$= new Item_func_round($3,$5,1); }
|
||||||
| TRUE_SYM
|
| TRUE_SYM
|
||||||
{ $$= new Item_int((char*) "TRUE",1,1); }
|
{ $$= new Item_int((char*) "TRUE",1,1); }
|
||||||
| SP_FUNC '(' udf_expr_list ')'
|
| SP_FUNC '(' sp_expr_list ')'
|
||||||
{
|
{
|
||||||
sp_add_fun_to_lex(Lex, $1);
|
sp_add_fun_to_lex(Lex, $1);
|
||||||
if ($3)
|
if ($3)
|
||||||
@ -3336,10 +3337,43 @@ simple_expr:
|
|||||||
| EXTRACT_SYM '(' interval FROM expr ')'
|
| EXTRACT_SYM '(' interval FROM expr ')'
|
||||||
{ $$=new Item_extract( $3, $5); };
|
{ $$=new Item_extract( $3, $5); };
|
||||||
|
|
||||||
udf_expr_list:
|
sp_expr_list:
|
||||||
/* empty */ { $$= NULL; }
|
/* empty */ { $$= NULL; }
|
||||||
| expr_list { $$= $1;};
|
| expr_list { $$= $1;};
|
||||||
|
|
||||||
|
udf_expr_list:
|
||||||
|
/* empty */ { $$= NULL; }
|
||||||
|
| udf_expr_list2 { $$= $1;}
|
||||||
|
;
|
||||||
|
|
||||||
|
udf_expr_list2:
|
||||||
|
{ Select->expr_list.push_front(new List<Item>); }
|
||||||
|
udf_expr_list3
|
||||||
|
{ $$= Select->expr_list.pop(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
udf_expr_list3:
|
||||||
|
udf_expr
|
||||||
|
{
|
||||||
|
Select->expr_list.head()->push_back($1);
|
||||||
|
}
|
||||||
|
| udf_expr_list3 ',' udf_expr
|
||||||
|
{
|
||||||
|
Select->expr_list.head()->push_back($3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
udf_expr:
|
||||||
|
remember_name expr remember_end select_alias
|
||||||
|
{
|
||||||
|
if ($4.str)
|
||||||
|
$2->set_name($4.str,$4.length,system_charset_info);
|
||||||
|
else
|
||||||
|
$2->set_name($1,(uint) ($3 - $1), YYTHD->charset());
|
||||||
|
$$= $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
sum_expr:
|
sum_expr:
|
||||||
AVG_SYM '(' in_sum_expr ')'
|
AVG_SYM '(' in_sum_expr ')'
|
||||||
{ $$=new Item_sum_avg($3); }
|
{ $$=new Item_sum_avg($3); }
|
||||||
|
@ -56,7 +56,9 @@
|
|||||||
**
|
**
|
||||||
** Function 'myfunc_int' returns summary length of all its arguments.
|
** Function 'myfunc_int' returns summary length of all its arguments.
|
||||||
**
|
**
|
||||||
** Function 'sequence' returns an sequence starting from a certain number
|
** Function 'sequence' returns an sequence starting from a certain number.
|
||||||
|
**
|
||||||
|
** Function 'myfunc_argument_name' returns name of argument.
|
||||||
**
|
**
|
||||||
** On the end is a couple of functions that converts hostnames to ip and
|
** On the end is a couple of functions that converts hostnames to ip and
|
||||||
** vice versa.
|
** vice versa.
|
||||||
@ -82,6 +84,7 @@
|
|||||||
** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
|
** CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
|
||||||
** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
|
** CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
|
||||||
** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
|
** CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
|
||||||
|
** CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
|
||||||
**
|
**
|
||||||
** After this the functions will work exactly like native MySQL functions.
|
** After this the functions will work exactly like native MySQL functions.
|
||||||
** Functions should be created only once.
|
** Functions should be created only once.
|
||||||
@ -94,6 +97,7 @@
|
|||||||
** DROP FUNCTION lookup;
|
** DROP FUNCTION lookup;
|
||||||
** DROP FUNCTION reverse_lookup;
|
** DROP FUNCTION reverse_lookup;
|
||||||
** DROP FUNCTION avgcost;
|
** DROP FUNCTION avgcost;
|
||||||
|
** DROP FUNCTION myfunc_argument_name;
|
||||||
**
|
**
|
||||||
** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
|
** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
|
||||||
** Active function will be reloaded on every restart of server
|
** Active function will be reloaded on every restart of server
|
||||||
@ -975,4 +979,46 @@ avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
|
|||||||
return data->totalprice/double(data->totalquantity);
|
return data->totalprice/double(data->totalquantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
|
||||||
|
char *message);
|
||||||
|
void myfunc_argument_name_deinit(UDF_INIT *initid);
|
||||||
|
char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
||||||
|
unsigned long *length, char *null_value,
|
||||||
|
char *error);
|
||||||
|
}
|
||||||
|
|
||||||
|
my_bool myfunc_argument_name_init(UDF_INIT *initid, UDF_ARGS *args,
|
||||||
|
char *message)
|
||||||
|
{
|
||||||
|
if (args->arg_count != 1)
|
||||||
|
{
|
||||||
|
strmov(message,"myfunc_argument_name_init accepts only one argument");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
initid->max_length= args->attribute_lengths[0];
|
||||||
|
initid->maybe_null= 1;
|
||||||
|
initid->const_item= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void myfunc_argument_name_deinit(UDF_INIT *initid) {}
|
||||||
|
|
||||||
|
char *myfunc_argument_name(UDF_INIT *initid, UDF_ARGS *args, char *result,
|
||||||
|
unsigned long *length, char *null_value,
|
||||||
|
char *error)
|
||||||
|
{
|
||||||
|
if (!args->attributes[0])
|
||||||
|
{
|
||||||
|
null_value= 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
(*length)--; // space for ending \0 (for debugging purposes)
|
||||||
|
if (*length > args->attribute_lengths[0])
|
||||||
|
*length= args->attribute_lengths[0];
|
||||||
|
memcpy(result, args->attributes[0], *length);
|
||||||
|
result[*length]= 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_DLOPEN */
|
#endif /* HAVE_DLOPEN */
|
||||||
|
@ -9,6 +9,7 @@ CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
|
|||||||
CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
|
CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
|
||||||
CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
|
CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
|
||||||
CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
|
CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
|
||||||
|
CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
|
||||||
|
|
||||||
select metaphon("hello");
|
select metaphon("hello");
|
||||||
select myfunc_double("hello","world");
|
select myfunc_double("hello","world");
|
||||||
@ -20,6 +21,7 @@ create temporary table t1 (a int,b double);
|
|||||||
insert into t1 values (1,5),(1,4),(2,8),(3,9),(4,11);
|
insert into t1 values (1,5),(1,4),(2,8),(3,9),(4,11);
|
||||||
select avgcost(a,b) from t1;
|
select avgcost(a,b) from t1;
|
||||||
select avgcost(a,b) from t1 group by a;
|
select avgcost(a,b) from t1 group by a;
|
||||||
|
select a, myfunc_argument_name(a) from t1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
DROP FUNCTION metaphon;
|
DROP FUNCTION metaphon;
|
||||||
@ -28,3 +30,4 @@ DROP FUNCTION myfunc_int;
|
|||||||
DROP FUNCTION lookup;
|
DROP FUNCTION lookup;
|
||||||
DROP FUNCTION reverse_lookup;
|
DROP FUNCTION reverse_lookup;
|
||||||
DROP FUNCTION avgcost;
|
DROP FUNCTION avgcost;
|
||||||
|
DROP FUNCTION myfunc_argument_name;
|
||||||
|
@ -34,6 +34,12 @@ CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so"
|
|||||||
|
|
||||||
Query OK, 0 rows affected
|
Query OK, 0 rows affected
|
||||||
|
|
||||||
|
--------------
|
||||||
|
CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so"
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Query OK, 0 rows affected
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
select metaphon("hello")
|
select metaphon("hello")
|
||||||
--------------
|
--------------
|
||||||
@ -106,6 +112,18 @@ avgcost(a,b)
|
|||||||
11.0000
|
11.0000
|
||||||
4 rows in set
|
4 rows in set
|
||||||
|
|
||||||
|
--------------
|
||||||
|
select a, myfunc_argument_name(a) from t1;
|
||||||
|
--------------
|
||||||
|
|
||||||
|
a myfunc_argument_name(a)
|
||||||
|
1 a
|
||||||
|
1 a
|
||||||
|
2 a
|
||||||
|
3 a
|
||||||
|
4 a
|
||||||
|
5 rows in set
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
drop table t1
|
drop table t1
|
||||||
--------------
|
--------------
|
||||||
@ -148,4 +166,10 @@ DROP FUNCTION avgcost
|
|||||||
|
|
||||||
Query OK, 0 rows affected
|
Query OK, 0 rows affected
|
||||||
|
|
||||||
|
--------------
|
||||||
|
DROP FUNCTION myfunc_argument_name;
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Query OK, 0 rows affected
|
||||||
|
|
||||||
Bye
|
Bye
|
||||||
|
Reference in New Issue
Block a user