summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bell@laptop.sanja.is.com.ua>2003-09-28 12:00:30 +0300
committerunknown <bell@laptop.sanja.is.com.ua>2003-09-28 12:00:30 +0300
commitbb9a92cc53aaf805750c03b77bb742b3c7f2d80e (patch)
tree28781e89211161574909d489abd41ade4e7e3373
parent03042c7db4be039b0088de24bd5b7b50f76c91b5 (diff)
parent07e372cd6b3a89d301fc44b5359fac01e285aa76 (diff)
downloadmariadb-git-bb9a92cc53aaf805750c03b77bb742b3c7f2d80e.tar.gz
Merge laptop.sanja.is.com.ua:/home/bell/mysql/bk/mysql-5.0
into laptop.sanja.is.com.ua:/home/bell/mysql/bk/work-udf-5.0 include/mysql_com.h: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_func.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/udf_example.cc: Auto merged
-rw-r--r--include/mysql_com.h2
-rw-r--r--sql/item.cc7
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_func.cc17
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_yacc.yy44
-rw-r--r--sql/udf_example.cc48
-rw-r--r--tests/udf_test3
-rw-r--r--tests/udf_test.res24
9 files changed, 134 insertions, 14 deletions
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 31da8cfe6b2..317cf4f7079 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -285,6 +285,8 @@ typedef struct st_udf_args
char **args; /* Pointer to argument */
unsigned long *lengths; /* Length of string arguments */
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;
/* This holds information about the result */
diff --git a/sql/item.cc b/sql/item.cc
index 775dbd95ca0..f07afe79ef1 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -40,7 +40,7 @@ void item_init(void)
}
Item::Item():
- fixed(0)
+ name_length(0), fixed(0)
{
marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
@@ -122,6 +122,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() */
name= (char*) str;
+ name_length= 0;
return;
}
while (length && !my_isgraph(cs,*str))
@@ -132,12 +133,12 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
if (!my_charset_same(cs, system_charset_info))
{
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,
&res_length);
}
else
- name=sql_strmake(str, min(length,MAX_ALIAS_NAME));
+ name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME)));
}
diff --git a/sql/item.h b/sql/item.h
index 46e9e49cb25..9cd68e91273 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -106,6 +106,7 @@ public:
my_string name; /* Name from select */
Item *next;
uint32 max_length;
+ uint name_length; /* Length of name */
uint8 marker,decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 164b895fb01..b59ef185837 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1459,11 +1459,16 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
const_item_cache&=item->const_item();
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]) ||
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
- !(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) ||
- !(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) ||
- !(num_buffer= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count)))
+ !(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) ||
+ !(f_args.maybe_null= (char*) sql_alloc(arg_count * sizeof(char))) ||
+ !(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);
DBUG_RETURN(1);
@@ -1482,8 +1487,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
for (uint i=0; i < arg_count; i++)
{
f_args.args[i]=0;
- f_args.lengths[i]=arguments[i]->max_length;
- f_args.maybe_null[i]=(char) arguments[i]->maybe_null;
+ f_args.lengths[i]= arguments[i]->max_length;
+ 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()) {
case Item::STRING_ITEM: // Constant string !
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 93f5bf99ebe..103dde10814 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2939,6 +2939,8 @@ mysql_execute_command(THD *thd)
break;
#ifdef HAVE_DLOPEN
sp_head *sph= sp_find_function(thd, &lex->udf.name);
+ // close & unlock table opened by sp_find_function
+ close_thread_tables(thd);
if (sph)
{
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index dc896e36dc0..ebf3ebf6b35 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -650,13 +650,14 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <item>
literal text_literal insert_ident order_ident
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
param_marker singlerow_subselect singlerow_subselect_init
exists_subselect exists_subselect_init sp_opt_default
%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>
key_type opt_unique_or_fulltext
@@ -722,7 +723,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
select_item_list select_item values_list no_braces
opt_limit_clause delete_limit_clause fields opt_values values
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
grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary table_lock_list table_lock
@@ -3503,7 +3504,7 @@ simple_expr:
{ $$= new Item_func_round($3,$5,1); }
| TRUE_SYM
{ $$= new Item_int((char*) "TRUE",1,1); }
- | SP_FUNC '(' udf_expr_list ')'
+ | SP_FUNC '(' sp_expr_list ')'
{
sp_add_fun_to_lex(Lex, $1);
if ($3)
@@ -3593,10 +3594,43 @@ simple_expr:
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); };
-udf_expr_list:
+sp_expr_list:
/* empty */ { $$= NULL; }
| 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:
AVG_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_avg($3); }
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index ba056a9d2fd..397a5051aa2 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -56,7 +56,9 @@
**
** 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
** vice versa.
@@ -82,6 +84,7 @@
** CREATE FUNCTION 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 FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so";
**
** After this the functions will work exactly like native MySQL functions.
** Functions should be created only once.
@@ -94,6 +97,7 @@
** DROP FUNCTION lookup;
** DROP FUNCTION reverse_lookup;
** DROP FUNCTION avgcost;
+** DROP FUNCTION myfunc_argument_name;
**
** The CREATE FUNCTION and DROP FUNCTION update the func@mysql table. All
** Active function will be reloaded on every restart of server
@@ -984,4 +988,46 @@ avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* error )
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 */
diff --git a/tests/udf_test b/tests/udf_test
index 4621a7b34a5..2bdacc34d13 100644
--- a/tests/udf_test
+++ b/tests/udf_test
@@ -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 reverse_lookup RETURNS STRING 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 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);
select avgcost(a,b) from t1;
select avgcost(a,b) from t1 group by a;
+select a, myfunc_argument_name(a) from t1;
drop table t1;
DROP FUNCTION metaphon;
@@ -28,3 +30,4 @@ DROP FUNCTION myfunc_int;
DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost;
+DROP FUNCTION myfunc_argument_name;
diff --git a/tests/udf_test.res b/tests/udf_test.res
index 66634e13616..cd65d3794d8 100644
--- a/tests/udf_test.res
+++ b/tests/udf_test.res
@@ -35,6 +35,12 @@ CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so"
Query OK, 0 rows affected
--------------
+CREATE FUNCTION myfunc_argument_name RETURNS STRING SONAME "udf_example.so"
+--------------
+
+Query OK, 0 rows affected
+
+--------------
select metaphon("hello")
--------------
@@ -107,6 +113,18 @@ avgcost(a,b)
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
--------------
@@ -148,4 +166,10 @@ DROP FUNCTION avgcost
Query OK, 0 rows affected
+--------------
+DROP FUNCTION myfunc_argument_name;
+--------------
+
+Query OK, 0 rows affected
+
Bye