diff options
author | unknown <bell@laptop.sanja.is.com.ua> | 2003-09-28 12:00:30 +0300 |
---|---|---|
committer | unknown <bell@laptop.sanja.is.com.ua> | 2003-09-28 12:00:30 +0300 |
commit | bb9a92cc53aaf805750c03b77bb742b3c7f2d80e (patch) | |
tree | 28781e89211161574909d489abd41ade4e7e3373 | |
parent | 03042c7db4be039b0088de24bd5b7b50f76c91b5 (diff) | |
parent | 07e372cd6b3a89d301fc44b5359fac01e285aa76 (diff) | |
download | mariadb-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.h | 2 | ||||
-rw-r--r-- | sql/item.cc | 7 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_func.cc | 17 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 44 | ||||
-rw-r--r-- | sql/udf_example.cc | 48 | ||||
-rw-r--r-- | tests/udf_test | 3 | ||||
-rw-r--r-- | tests/udf_test.res | 24 |
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 |